LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 10314 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 188 0
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 "storage/block.h"
      75              : 
      76              : typedef struct
      77              : {
      78              :         Oid                     roleoid;                /* role's OID */
      79              :         const char *rolename;           /* role's name */
      80              : } RoleNameItem;
      81              : 
      82              : typedef struct
      83              : {
      84              :         const char *descr;                      /* comment for an object */
      85              :         Oid                     classoid;               /* object class (catalog OID) */
      86              :         Oid                     objoid;                 /* object OID */
      87              :         int                     objsubid;               /* subobject (table column #) */
      88              : } CommentItem;
      89              : 
      90              : typedef struct
      91              : {
      92              :         const char *provider;           /* label provider of this security label */
      93              :         const char *label;                      /* security label for an object */
      94              :         Oid                     classoid;               /* object class (catalog OID) */
      95              :         Oid                     objoid;                 /* object OID */
      96              :         int                     objsubid;               /* subobject (table column #) */
      97              : } SecLabelItem;
      98              : 
      99              : typedef struct
     100              : {
     101              :         Oid                     oid;                    /* object OID */
     102              :         char            relkind;                /* object kind */
     103              :         RelFileNumber relfilenumber;    /* object filenode */
     104              :         Oid                     toast_oid;              /* toast table OID */
     105              :         RelFileNumber toast_relfilenumber;      /* toast table filenode */
     106              :         Oid                     toast_index_oid;        /* toast table index OID */
     107              :         RelFileNumber toast_index_relfilenumber;        /* toast table index filenode */
     108              : } BinaryUpgradeClassOidItem;
     109              : 
     110              : /* sequence types */
     111              : typedef enum SeqType
     112              : {
     113              :         SEQTYPE_SMALLINT,
     114              :         SEQTYPE_INTEGER,
     115              :         SEQTYPE_BIGINT,
     116              : } SeqType;
     117              : 
     118              : static const char *const SeqTypeNames[] =
     119              : {
     120              :         [SEQTYPE_SMALLINT] = "smallint",
     121              :         [SEQTYPE_INTEGER] = "integer",
     122              :         [SEQTYPE_BIGINT] = "bigint",
     123              : };
     124              : 
     125              : StaticAssertDecl(lengthof(SeqTypeNames) == (SEQTYPE_BIGINT + 1),
     126              :                                  "array length mismatch");
     127              : 
     128              : typedef struct
     129              : {
     130              :         Oid                     oid;                    /* sequence OID */
     131              :         SeqType         seqtype;                /* data type of sequence */
     132              :         bool            cycled;                 /* whether sequence cycles */
     133              :         int64           minv;                   /* minimum value */
     134              :         int64           maxv;                   /* maximum value */
     135              :         int64           startv;                 /* start value */
     136              :         int64           incby;                  /* increment value */
     137              :         int64           cache;                  /* cache size */
     138              :         int64           last_value;             /* last value of sequence */
     139              :         bool            is_called;              /* whether nextval advances before returning */
     140              :         bool            null_seqtuple;  /* did pg_get_sequence_data return nulls? */
     141              : } SequenceItem;
     142              : 
     143              : typedef enum OidOptions
     144              : {
     145              :         zeroIsError = 1,
     146              :         zeroAsStar = 2,
     147              :         zeroAsNone = 4,
     148              : } OidOptions;
     149              : 
     150              : /* global decls */
     151              : static bool dosync = true;              /* Issue fsync() to make dump durable on disk. */
     152              : 
     153              : static Oid      g_last_builtin_oid; /* value of the last builtin oid */
     154              : 
     155              : /* The specified names/patterns should to match at least one entity */
     156              : static int      strict_names = 0;
     157              : 
     158              : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
     159              : 
     160              : /*
     161              :  * Object inclusion/exclusion lists
     162              :  *
     163              :  * The string lists record the patterns given by command-line switches,
     164              :  * which we then convert to lists of OIDs of matching objects.
     165              :  */
     166              : static SimpleStringList schema_include_patterns = {NULL, NULL};
     167              : static SimpleOidList schema_include_oids = {NULL, NULL};
     168              : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     169              : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     170              : 
     171              : static SimpleStringList table_include_patterns = {NULL, NULL};
     172              : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
     173              : static SimpleOidList table_include_oids = {NULL, NULL};
     174              : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     175              : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
     176              : static SimpleOidList table_exclude_oids = {NULL, NULL};
     177              : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     178              : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
     179              : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     180              : 
     181              : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
     182              : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
     183              : 
     184              : static SimpleStringList extension_include_patterns = {NULL, NULL};
     185              : static SimpleOidList extension_include_oids = {NULL, NULL};
     186              : 
     187              : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
     188              : static SimpleOidList extension_exclude_oids = {NULL, NULL};
     189              : 
     190              : static const CatalogId nilCatalogId = {0, 0};
     191              : 
     192              : /* override for standard extra_float_digits setting */
     193              : static bool have_extra_float_digits = false;
     194              : static int      extra_float_digits;
     195              : 
     196              : /* sorted table of role names */
     197              : static RoleNameItem *rolenames = NULL;
     198              : static int      nrolenames = 0;
     199              : 
     200              : /* sorted table of comments */
     201              : static CommentItem *comments = NULL;
     202              : static int      ncomments = 0;
     203              : 
     204              : /* sorted table of security labels */
     205              : static SecLabelItem *seclabels = NULL;
     206              : static int      nseclabels = 0;
     207              : 
     208              : /* sorted table of pg_class information for binary upgrade */
     209              : static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
     210              : static int      nbinaryUpgradeClassOids = 0;
     211              : 
     212              : /* sorted table of sequences */
     213              : static SequenceItem *sequences = NULL;
     214              : static int      nsequences = 0;
     215              : 
     216              : /*
     217              :  * For binary upgrade, the dump ID of pg_largeobject_metadata is saved for use
     218              :  * as a dependency for pg_shdepend and any large object comments/seclabels.
     219              :  */
     220              : static DumpId lo_metadata_dumpId;
     221              : 
     222              : /* Maximum number of relations to fetch in a fetchAttributeStats() call. */
     223              : #define MAX_ATTR_STATS_RELS 64
     224              : 
     225              : /*
     226              :  * The default number of rows per INSERT when
     227              :  * --inserts is specified without --rows-per-insert
     228              :  */
     229              : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     230              : 
     231              : /*
     232              :  * Maximum number of large objects to group into a single ArchiveEntry.
     233              :  * At some point we might want to make this user-controllable, but for now
     234              :  * a hard-wired setting will suffice.
     235              :  */
     236              : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
     237              : 
     238              : /*
     239              :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     240              :  */
     241              : #define fmtQualifiedDumpable(obj) \
     242              :         fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     243              :                                    (obj)->dobj.name)
     244              : 
     245              : static void help(const char *progname);
     246              : static void setup_connection(Archive *AH,
     247              :                                                          const char *dumpencoding, const char *dumpsnapshot,
     248              :                                                          char *use_role);
     249              : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     250              : static void expand_schema_name_patterns(Archive *fout,
     251              :                                                                                 SimpleStringList *patterns,
     252              :                                                                                 SimpleOidList *oids,
     253              :                                                                                 bool strict_names);
     254              : static void expand_extension_name_patterns(Archive *fout,
     255              :                                                                                    SimpleStringList *patterns,
     256              :                                                                                    SimpleOidList *oids,
     257              :                                                                                    bool strict_names);
     258              : static void expand_foreign_server_name_patterns(Archive *fout,
     259              :                                                                                                 SimpleStringList *patterns,
     260              :                                                                                                 SimpleOidList *oids);
     261              : static void expand_table_name_patterns(Archive *fout,
     262              :                                                                            SimpleStringList *patterns,
     263              :                                                                            SimpleOidList *oids,
     264              :                                                                            bool strict_names,
     265              :                                                                            bool with_child_tables);
     266              : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
     267              :                                                                   const char *pattern);
     268              : 
     269              : static NamespaceInfo *findNamespace(Oid nsoid);
     270              : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
     271              : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
     272              : static const char *getRoleName(const char *roleoid_str);
     273              : static void collectRoleNames(Archive *fout);
     274              : static void getAdditionalACLs(Archive *fout);
     275              : static void dumpCommentExtended(Archive *fout, const char *type,
     276              :                                                                 const char *name, const char *namespace,
     277              :                                                                 const char *owner, CatalogId catalogId,
     278              :                                                                 int subid, DumpId dumpId,
     279              :                                                                 const char *initdb_comment);
     280              : static inline void dumpComment(Archive *fout, const char *type,
     281              :                                                            const char *name, const char *namespace,
     282              :                                                            const char *owner, CatalogId catalogId,
     283              :                                                            int subid, DumpId dumpId);
     284              : static int      findComments(Oid classoid, Oid objoid, CommentItem **items);
     285              : static void collectComments(Archive *fout);
     286              : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     287              :                                                  const char *namespace, const char *owner,
     288              :                                                  CatalogId catalogId, int subid, DumpId dumpId);
     289              : static int      findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
     290              : static void collectSecLabels(Archive *fout);
     291              : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     292              : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
     293              : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
     294              : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
     295              : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
     296              : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
     297              : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
     298              : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
     299              : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
     300              : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
     301              : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
     302              :                                                                                  PGresult *res);
     303              : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
     304              : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
     305              : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
     306              : static void dumpCast(Archive *fout, const CastInfo *cast);
     307              : static void dumpTransform(Archive *fout, const TransformInfo *transform);
     308              : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
     309              : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
     310              : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
     311              : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
     312              : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
     313              : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
     314              : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
     315              : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
     316              : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
     317              : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
     318              : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
     319              : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
     320              : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
     321              : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
     322              : static void collectSequences(Archive *fout);
     323              : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
     324              : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
     325              : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
     326              : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
     327              : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
     328              : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
     329              : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
     330              : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
     331              : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
     332              : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
     333              : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
     334              : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
     335              : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
     336              : static void dumpUserMappings(Archive *fout,
     337              :                                                          const char *servername, const char *namespace,
     338              :                                                          const char *owner, CatalogId catalogId, DumpId dumpId);
     339              : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
     340              : 
     341              : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     342              :                                           const char *type, const char *name, const char *subname,
     343              :                                           const char *nspname, const char *tag, const char *owner,
     344              :                                           const DumpableAcl *dacl);
     345              : 
     346              : static void getDependencies(Archive *fout);
     347              : static void BuildArchiveDependencies(Archive *fout);
     348              : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
     349              :                                                                          DumpId **dependencies, int *nDeps, int *allocDeps);
     350              : 
     351              : static DumpableObject *createBoundaryObjects(void);
     352              : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     353              :                                                                         DumpableObject *boundaryObjs);
     354              : 
     355              : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
     356              : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     357              : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     358              : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     359              : static void buildMatViewRefreshDependencies(Archive *fout);
     360              : static void getTableDataFKConstraints(void);
     361              : static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
     362              :                                                                   TableInfo *tbinfo, int j,
     363              :                                                                   int i_notnull_name,
     364              :                                                                   int i_notnull_comment,
     365              :                                                                   int i_notnull_invalidoid,
     366              :                                                                   int i_notnull_noinherit,
     367              :                                                                   int i_notnull_islocal,
     368              :                                                                   PQExpBuffer *invalidnotnulloids);
     369              : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
     370              :                                                                            bool is_agg);
     371              : static char *format_function_signature(Archive *fout,
     372              :                                                                            const FuncInfo *finfo, bool honor_quotes);
     373              : static char *convertRegProcReference(const char *proc);
     374              : static char *getFormattedOperatorName(const char *oproid);
     375              : static char *convertTSFunction(Archive *fout, Oid funcOid);
     376              : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     377              : static void getLOs(Archive *fout);
     378              : static void dumpLO(Archive *fout, const LoInfo *loinfo);
     379              : static int      dumpLOs(Archive *fout, const void *arg);
     380              : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
     381              : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
     382              : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
     383              : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
     384              : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
     385              : static void dumpDatabase(Archive *fout);
     386              : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     387              :                                                            const char *dbname, Oid dboid);
     388              : static void dumpEncoding(Archive *AH);
     389              : static void dumpStdStrings(Archive *AH);
     390              : static void dumpSearchPath(Archive *AH);
     391              : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     392              :                                                                                                          PQExpBuffer upgrade_buffer,
     393              :                                                                                                          Oid pg_type_oid,
     394              :                                                                                                          bool force_array_type,
     395              :                                                                                                          bool include_multirange_type);
     396              : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
     397              :                                                                                                 PQExpBuffer upgrade_buffer,
     398              :                                                                                                 const TableInfo *tbinfo);
     399              : static void collectBinaryUpgradeClassOids(Archive *fout);
     400              : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     401              :                                                                                          PQExpBuffer upgrade_buffer,
     402              :                                                                                          Oid pg_class_oid);
     403              : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     404              :                                                                                         const DumpableObject *dobj,
     405              :                                                                                         const char *objtype,
     406              :                                                                                         const char *objname,
     407              :                                                                                         const char *objnamespace);
     408              : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
     409              : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     410              : static bool nonemptyReloptions(const char *reloptions);
     411              : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     412              :                                                                         const char *prefix, Archive *fout);
     413              : static char *get_synchronized_snapshot(Archive *fout);
     414              : static void set_restrict_relation_kind(Archive *AH, const char *value);
     415              : static void setupDumpWorker(Archive *AH);
     416              : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
     417              : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
     418              : static void read_dump_filters(const char *filename, DumpOptions *dopt);
     419              : 
     420              : 
     421              : int
     422            0 : main(int argc, char **argv)
     423              : {
     424            0 :         int                     c;
     425            0 :         const char *filename = NULL;
     426            0 :         const char *format = "p";
     427            0 :         TableInfo  *tblinfo;
     428            0 :         int                     numTables;
     429            0 :         DumpableObject **dobjs;
     430            0 :         int                     numObjs;
     431            0 :         DumpableObject *boundaryObjs;
     432            0 :         int                     i;
     433            0 :         int                     optindex;
     434            0 :         RestoreOptions *ropt;
     435            0 :         Archive    *fout;                       /* the script file */
     436            0 :         bool            g_verbose = false;
     437            0 :         const char *dumpencoding = NULL;
     438            0 :         const char *dumpsnapshot = NULL;
     439            0 :         char       *use_role = NULL;
     440            0 :         int                     numWorkers = 1;
     441            0 :         int                     plainText = 0;
     442            0 :         ArchiveFormat archiveFormat = archUnknown;
     443            0 :         ArchiveMode archiveMode;
     444            0 :         pg_compress_specification compression_spec = {0};
     445            0 :         char       *compression_detail = NULL;
     446            0 :         char       *compression_algorithm_str = "none";
     447            0 :         char       *error_detail = NULL;
     448            0 :         bool            user_compression_defined = false;
     449            0 :         DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     450            0 :         bool            data_only = false;
     451            0 :         bool            schema_only = false;
     452            0 :         bool            statistics_only = false;
     453            0 :         bool            with_statistics = false;
     454            0 :         bool            no_data = false;
     455            0 :         bool            no_schema = false;
     456            0 :         bool            no_statistics = false;
     457              : 
     458              :         static DumpOptions dopt;
     459              : 
     460              :         static struct option long_options[] = {
     461              :                 {"data-only", no_argument, NULL, 'a'},
     462              :                 {"blobs", no_argument, NULL, 'b'},
     463              :                 {"large-objects", no_argument, NULL, 'b'},
     464              :                 {"no-blobs", no_argument, NULL, 'B'},
     465              :                 {"no-large-objects", no_argument, NULL, 'B'},
     466              :                 {"clean", no_argument, NULL, 'c'},
     467              :                 {"create", no_argument, NULL, 'C'},
     468              :                 {"dbname", required_argument, NULL, 'd'},
     469              :                 {"extension", required_argument, NULL, 'e'},
     470              :                 {"file", required_argument, NULL, 'f'},
     471              :                 {"format", required_argument, NULL, 'F'},
     472              :                 {"host", required_argument, NULL, 'h'},
     473              :                 {"jobs", 1, NULL, 'j'},
     474              :                 {"no-reconnect", no_argument, NULL, 'R'},
     475              :                 {"no-owner", no_argument, NULL, 'O'},
     476              :                 {"port", required_argument, NULL, 'p'},
     477              :                 {"schema", required_argument, NULL, 'n'},
     478              :                 {"exclude-schema", required_argument, NULL, 'N'},
     479              :                 {"schema-only", no_argument, NULL, 's'},
     480              :                 {"superuser", required_argument, NULL, 'S'},
     481              :                 {"table", required_argument, NULL, 't'},
     482              :                 {"exclude-table", required_argument, NULL, 'T'},
     483              :                 {"no-password", no_argument, NULL, 'w'},
     484              :                 {"password", no_argument, NULL, 'W'},
     485              :                 {"username", required_argument, NULL, 'U'},
     486              :                 {"verbose", no_argument, NULL, 'v'},
     487              :                 {"no-privileges", no_argument, NULL, 'x'},
     488              :                 {"no-acl", no_argument, NULL, 'x'},
     489              :                 {"compress", required_argument, NULL, 'Z'},
     490              :                 {"encoding", required_argument, NULL, 'E'},
     491              :                 {"help", no_argument, NULL, '?'},
     492              :                 {"version", no_argument, NULL, 'V'},
     493              : 
     494              :                 /*
     495              :                  * the following options don't have an equivalent short option letter
     496              :                  */
     497              :                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     498              :                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     499              :                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
     500              :                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     501              :                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     502              :                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     503              :                 {"exclude-table-data", required_argument, NULL, 4},
     504              :                 {"extra-float-digits", required_argument, NULL, 8},
     505              :                 {"if-exists", no_argument, &dopt.if_exists, 1},
     506              :                 {"inserts", no_argument, NULL, 9},
     507              :                 {"lock-wait-timeout", required_argument, NULL, 2},
     508              :                 {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     509              :                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     510              :                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     511              :                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     512              :                 {"role", required_argument, NULL, 3},
     513              :                 {"section", required_argument, NULL, 5},
     514              :                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     515              :                 {"snapshot", required_argument, NULL, 6},
     516              :                 {"statistics", no_argument, NULL, 22},
     517              :                 {"statistics-only", no_argument, NULL, 18},
     518              :                 {"strict-names", no_argument, &strict_names, 1},
     519              :                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     520              :                 {"no-comments", no_argument, &dopt.no_comments, 1},
     521              :                 {"no-data", no_argument, NULL, 19},
     522              :                 {"no-policies", no_argument, &dopt.no_policies, 1},
     523              :                 {"no-publications", no_argument, &dopt.no_publications, 1},
     524              :                 {"no-schema", no_argument, NULL, 20},
     525              :                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     526              :                 {"no-statistics", no_argument, NULL, 21},
     527              :                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     528              :                 {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     529              :                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     530              :                 {"no-sync", no_argument, NULL, 7},
     531              :                 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     532              :                 {"rows-per-insert", required_argument, NULL, 10},
     533              :                 {"include-foreign-data", required_argument, NULL, 11},
     534              :                 {"table-and-children", required_argument, NULL, 12},
     535              :                 {"exclude-table-and-children", required_argument, NULL, 13},
     536              :                 {"exclude-table-data-and-children", required_argument, NULL, 14},
     537              :                 {"sync-method", required_argument, NULL, 15},
     538              :                 {"filter", required_argument, NULL, 16},
     539              :                 {"exclude-extension", required_argument, NULL, 17},
     540              :                 {"sequence-data", no_argument, &dopt.sequence_data, 1},
     541              :                 {"restrict-key", required_argument, NULL, 25},
     542              : 
     543              :                 {NULL, 0, NULL, 0}
     544              :         };
     545              : 
     546            0 :         pg_logging_init(argv[0]);
     547            0 :         pg_logging_set_level(PG_LOG_WARNING);
     548            0 :         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     549              : 
     550              :         /*
     551              :          * Initialize what we need for parallel execution, especially for thread
     552              :          * support on Windows.
     553              :          */
     554            0 :         init_parallel_dump_utils();
     555              : 
     556            0 :         progname = get_progname(argv[0]);
     557              : 
     558            0 :         if (argc > 1)
     559              :         {
     560            0 :                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     561              :                 {
     562            0 :                         help(progname);
     563            0 :                         exit_nicely(0);
     564              :                 }
     565            0 :                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     566              :                 {
     567            0 :                         puts("pg_dump (PostgreSQL) " PG_VERSION);
     568            0 :                         exit_nicely(0);
     569              :                 }
     570            0 :         }
     571              : 
     572            0 :         InitDumpOptions(&dopt);
     573              : 
     574            0 :         while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     575            0 :                                                         long_options, &optindex)) != -1)
     576              :         {
     577            0 :                 switch (c)
     578              :                 {
     579              :                         case 'a':                       /* Dump data only */
     580            0 :                                 data_only = true;
     581            0 :                                 break;
     582              : 
     583              :                         case 'b':                       /* Dump LOs */
     584            0 :                                 dopt.outputLOs = true;
     585            0 :                                 break;
     586              : 
     587              :                         case 'B':                       /* Don't dump LOs */
     588            0 :                                 dopt.dontOutputLOs = true;
     589            0 :                                 break;
     590              : 
     591              :                         case 'c':                       /* clean (i.e., drop) schema prior to create */
     592            0 :                                 dopt.outputClean = 1;
     593            0 :                                 break;
     594              : 
     595              :                         case 'C':                       /* Create DB */
     596            0 :                                 dopt.outputCreateDB = 1;
     597            0 :                                 break;
     598              : 
     599              :                         case 'd':                       /* database name */
     600            0 :                                 dopt.cparams.dbname = pg_strdup(optarg);
     601            0 :                                 break;
     602              : 
     603              :                         case 'e':                       /* include extension(s) */
     604            0 :                                 simple_string_list_append(&extension_include_patterns, optarg);
     605            0 :                                 dopt.include_everything = false;
     606            0 :                                 break;
     607              : 
     608              :                         case 'E':                       /* Dump encoding */
     609            0 :                                 dumpencoding = pg_strdup(optarg);
     610            0 :                                 break;
     611              : 
     612              :                         case 'f':
     613            0 :                                 filename = pg_strdup(optarg);
     614            0 :                                 break;
     615              : 
     616              :                         case 'F':
     617            0 :                                 format = pg_strdup(optarg);
     618            0 :                                 break;
     619              : 
     620              :                         case 'h':                       /* server host */
     621            0 :                                 dopt.cparams.pghost = pg_strdup(optarg);
     622            0 :                                 break;
     623              : 
     624              :                         case 'j':                       /* number of dump jobs */
     625            0 :                                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     626              :                                                                           PG_MAX_JOBS,
     627              :                                                                           &numWorkers))
     628            0 :                                         exit_nicely(1);
     629            0 :                                 break;
     630              : 
     631              :                         case 'n':                       /* include schema(s) */
     632            0 :                                 simple_string_list_append(&schema_include_patterns, optarg);
     633            0 :                                 dopt.include_everything = false;
     634            0 :                                 break;
     635              : 
     636              :                         case 'N':                       /* exclude schema(s) */
     637            0 :                                 simple_string_list_append(&schema_exclude_patterns, optarg);
     638            0 :                                 break;
     639              : 
     640              :                         case 'O':                       /* Don't reconnect to match owner */
     641            0 :                                 dopt.outputNoOwner = 1;
     642            0 :                                 break;
     643              : 
     644              :                         case 'p':                       /* server port */
     645            0 :                                 dopt.cparams.pgport = pg_strdup(optarg);
     646            0 :                                 break;
     647              : 
     648              :                         case 'R':
     649              :                                 /* no-op, still accepted for backwards compatibility */
     650              :                                 break;
     651              : 
     652              :                         case 's':                       /* dump schema only */
     653            0 :                                 schema_only = true;
     654            0 :                                 break;
     655              : 
     656              :                         case 'S':                       /* Username for superuser in plain text output */
     657            0 :                                 dopt.outputSuperuser = pg_strdup(optarg);
     658            0 :                                 break;
     659              : 
     660              :                         case 't':                       /* include table(s) */
     661            0 :                                 simple_string_list_append(&table_include_patterns, optarg);
     662            0 :                                 dopt.include_everything = false;
     663            0 :                                 break;
     664              : 
     665              :                         case 'T':                       /* exclude table(s) */
     666            0 :                                 simple_string_list_append(&table_exclude_patterns, optarg);
     667            0 :                                 break;
     668              : 
     669              :                         case 'U':
     670            0 :                                 dopt.cparams.username = pg_strdup(optarg);
     671            0 :                                 break;
     672              : 
     673              :                         case 'v':                       /* verbose */
     674            0 :                                 g_verbose = true;
     675            0 :                                 pg_logging_increase_verbosity();
     676            0 :                                 break;
     677              : 
     678              :                         case 'w':
     679            0 :                                 dopt.cparams.promptPassword = TRI_NO;
     680            0 :                                 break;
     681              : 
     682              :                         case 'W':
     683            0 :                                 dopt.cparams.promptPassword = TRI_YES;
     684            0 :                                 break;
     685              : 
     686              :                         case 'x':                       /* skip ACL dump */
     687            0 :                                 dopt.aclsSkip = true;
     688            0 :                                 break;
     689              : 
     690              :                         case 'Z':                       /* Compression */
     691            0 :                                 parse_compress_options(optarg, &compression_algorithm_str,
     692              :                                                                            &compression_detail);
     693            0 :                                 user_compression_defined = true;
     694            0 :                                 break;
     695              : 
     696              :                         case 0:
     697              :                                 /* This covers the long options. */
     698              :                                 break;
     699              : 
     700              :                         case 2:                         /* lock-wait-timeout */
     701            0 :                                 dopt.lockWaitTimeout = pg_strdup(optarg);
     702            0 :                                 break;
     703              : 
     704              :                         case 3:                         /* SET ROLE */
     705            0 :                                 use_role = pg_strdup(optarg);
     706            0 :                                 break;
     707              : 
     708              :                         case 4:                         /* exclude table(s) data */
     709            0 :                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     710            0 :                                 break;
     711              : 
     712              :                         case 5:                         /* section */
     713            0 :                                 set_dump_section(optarg, &dopt.dumpSections);
     714            0 :                                 break;
     715              : 
     716              :                         case 6:                         /* snapshot */
     717            0 :                                 dumpsnapshot = pg_strdup(optarg);
     718            0 :                                 break;
     719              : 
     720              :                         case 7:                         /* no-sync */
     721            0 :                                 dosync = false;
     722            0 :                                 break;
     723              : 
     724              :                         case 8:
     725            0 :                                 have_extra_float_digits = true;
     726            0 :                                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     727              :                                                                           &extra_float_digits))
     728            0 :                                         exit_nicely(1);
     729            0 :                                 break;
     730              : 
     731              :                         case 9:                         /* inserts */
     732              : 
     733              :                                 /*
     734              :                                  * dump_inserts also stores --rows-per-insert, careful not to
     735              :                                  * overwrite that.
     736              :                                  */
     737            0 :                                 if (dopt.dump_inserts == 0)
     738            0 :                                         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     739            0 :                                 break;
     740              : 
     741              :                         case 10:                        /* rows per insert */
     742            0 :                                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     743              :                                                                           &dopt.dump_inserts))
     744            0 :                                         exit_nicely(1);
     745            0 :                                 break;
     746              : 
     747              :                         case 11:                        /* include foreign data */
     748            0 :                                 simple_string_list_append(&foreign_servers_include_patterns,
     749            0 :                                                                                   optarg);
     750            0 :                                 break;
     751              : 
     752              :                         case 12:                        /* include table(s) and their children */
     753            0 :                                 simple_string_list_append(&table_include_patterns_and_children,
     754            0 :                                                                                   optarg);
     755            0 :                                 dopt.include_everything = false;
     756            0 :                                 break;
     757              : 
     758              :                         case 13:                        /* exclude table(s) and their children */
     759            0 :                                 simple_string_list_append(&table_exclude_patterns_and_children,
     760            0 :                                                                                   optarg);
     761            0 :                                 break;
     762              : 
     763              :                         case 14:                        /* exclude data of table(s) and children */
     764            0 :                                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     765            0 :                                                                                   optarg);
     766            0 :                                 break;
     767              : 
     768              :                         case 15:
     769            0 :                                 if (!parse_sync_method(optarg, &sync_method))
     770            0 :                                         exit_nicely(1);
     771            0 :                                 break;
     772              : 
     773              :                         case 16:                        /* read object filters from file */
     774            0 :                                 read_dump_filters(optarg, &dopt);
     775            0 :                                 break;
     776              : 
     777              :                         case 17:                        /* exclude extension(s) */
     778            0 :                                 simple_string_list_append(&extension_exclude_patterns,
     779            0 :                                                                                   optarg);
     780            0 :                                 break;
     781              : 
     782              :                         case 18:
     783            0 :                                 statistics_only = true;
     784            0 :                                 break;
     785              : 
     786              :                         case 19:
     787            0 :                                 no_data = true;
     788            0 :                                 break;
     789              : 
     790              :                         case 20:
     791            0 :                                 no_schema = true;
     792            0 :                                 break;
     793              : 
     794              :                         case 21:
     795            0 :                                 no_statistics = true;
     796            0 :                                 break;
     797              : 
     798              :                         case 22:
     799            0 :                                 with_statistics = true;
     800            0 :                                 break;
     801              : 
     802              :                         case 25:
     803            0 :                                 dopt.restrict_key = pg_strdup(optarg);
     804            0 :                                 break;
     805              : 
     806              :                         default:
     807              :                                 /* getopt_long already emitted a complaint */
     808            0 :                                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     809            0 :                                 exit_nicely(1);
     810              :                 }
     811              :         }
     812              : 
     813              :         /*
     814              :          * Non-option argument specifies database name as long as it wasn't
     815              :          * already specified with -d / --dbname
     816              :          */
     817            0 :         if (optind < argc && dopt.cparams.dbname == NULL)
     818            0 :                 dopt.cparams.dbname = argv[optind++];
     819              : 
     820              :         /* Complain if any arguments remain */
     821            0 :         if (optind < argc)
     822              :         {
     823            0 :                 pg_log_error("too many command-line arguments (first is \"%s\")",
     824              :                                          argv[optind]);
     825            0 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     826            0 :                 exit_nicely(1);
     827              :         }
     828              : 
     829              :         /* --column-inserts implies --inserts */
     830            0 :         if (dopt.column_inserts && dopt.dump_inserts == 0)
     831            0 :                 dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     832              : 
     833              :         /* reject conflicting "-only" options */
     834            0 :         if (data_only && schema_only)
     835            0 :                 pg_fatal("options %s and %s cannot be used together",
     836              :                                  "-s/--schema-only", "-a/--data-only");
     837            0 :         if (schema_only && statistics_only)
     838            0 :                 pg_fatal("options %s and %s cannot be used together",
     839              :                                  "-s/--schema-only", "--statistics-only");
     840            0 :         if (data_only && statistics_only)
     841            0 :                 pg_fatal("options %s and %s cannot be used together",
     842              :                                  "-a/--data-only", "--statistics-only");
     843              : 
     844              :         /* reject conflicting "-only" and "no-" options */
     845            0 :         if (data_only && no_data)
     846            0 :                 pg_fatal("options %s and %s cannot be used together",
     847              :                                  "-a/--data-only", "--no-data");
     848            0 :         if (schema_only && no_schema)
     849            0 :                 pg_fatal("options %s and %s cannot be used together",
     850              :                                  "-s/--schema-only", "--no-schema");
     851            0 :         if (statistics_only && no_statistics)
     852            0 :                 pg_fatal("options %s and %s cannot be used together",
     853              :                                  "--statistics-only", "--no-statistics");
     854              : 
     855              :         /* reject conflicting "no-" options */
     856            0 :         if (with_statistics && no_statistics)
     857            0 :                 pg_fatal("options %s and %s cannot be used together",
     858              :                                  "--statistics", "--no-statistics");
     859              : 
     860              :         /* reject conflicting "-only" options */
     861            0 :         if (data_only && with_statistics)
     862            0 :                 pg_fatal("options %s and %s cannot be used together",
     863              :                                  "-a/--data-only", "--statistics");
     864            0 :         if (schema_only && with_statistics)
     865            0 :                 pg_fatal("options %s and %s cannot be used together",
     866              :                                  "-s/--schema-only", "--statistics");
     867              : 
     868            0 :         if (schema_only && foreign_servers_include_patterns.head != NULL)
     869            0 :                 pg_fatal("options %s and %s cannot be used together",
     870              :                                  "-s/--schema-only", "--include-foreign-data");
     871              : 
     872            0 :         if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     873            0 :                 pg_fatal("option %s is not supported with parallel backup",
     874              :                                  "--include-foreign-data");
     875              : 
     876            0 :         if (data_only && dopt.outputClean)
     877            0 :                 pg_fatal("options %s and %s cannot be used together",
     878              :                                  "-c/--clean", "-a/--data-only");
     879              : 
     880            0 :         if (dopt.if_exists && !dopt.outputClean)
     881            0 :                 pg_fatal("option %s requires option %s",
     882              :                                  "--if-exists", "-c/--clean");
     883              : 
     884              :         /*
     885              :          * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
     886              :          * "--schema-only --no-schema", will have already caused an error in one
     887              :          * of the checks above.
     888              :          */
     889            0 :         dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
     890            0 :                                          data_only) && !no_data;
     891            0 :         dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
     892            0 :                                            schema_only) && !no_schema;
     893            0 :         dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
     894            0 :                                                    (statistics_only || with_statistics)) && !no_statistics;
     895              : 
     896              : 
     897              :         /*
     898              :          * --inserts are already implied above if --column-inserts or
     899              :          * --rows-per-insert were specified.
     900              :          */
     901            0 :         if (dopt.do_nothing && dopt.dump_inserts == 0)
     902            0 :                 pg_fatal("option %s requires option %s, %s, or %s",
     903              :                                  "--on-conflict-do-nothing",
     904              :                                  "--inserts", "--rows-per-insert", "--column-inserts");
     905              : 
     906              :         /* Identify archive format to emit */
     907            0 :         archiveFormat = parseArchiveFormat(format, &archiveMode);
     908              : 
     909              :         /* archiveFormat specific setup */
     910            0 :         if (archiveFormat == archNull)
     911              :         {
     912            0 :                 plainText = 1;
     913              : 
     914              :                 /*
     915              :                  * If you don't provide a restrict key, one will be appointed for you.
     916              :                  */
     917            0 :                 if (!dopt.restrict_key)
     918            0 :                         dopt.restrict_key = generate_restrict_key();
     919            0 :                 if (!dopt.restrict_key)
     920            0 :                         pg_fatal("could not generate restrict key");
     921            0 :                 if (!valid_restrict_key(dopt.restrict_key))
     922            0 :                         pg_fatal("invalid restrict key");
     923            0 :         }
     924            0 :         else if (dopt.restrict_key)
     925            0 :                 pg_fatal("option %s can only be used with %s",
     926              :                                  "--restrict-key", "--format=plain");
     927              : 
     928              :         /*
     929              :          * Custom and directory formats are compressed by default with gzip when
     930              :          * available, not the others.  If gzip is not available, no compression is
     931              :          * done by default.
     932              :          */
     933            0 :         if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     934            0 :                 !user_compression_defined)
     935              :         {
     936              : #ifdef HAVE_LIBZ
     937            0 :                 compression_algorithm_str = "gzip";
     938              : #else
     939              :                 compression_algorithm_str = "none";
     940              : #endif
     941            0 :         }
     942              : 
     943              :         /*
     944              :          * Compression options
     945              :          */
     946            0 :         if (!parse_compress_algorithm(compression_algorithm_str,
     947              :                                                                   &compression_algorithm))
     948            0 :                 pg_fatal("unrecognized compression algorithm: \"%s\"",
     949              :                                  compression_algorithm_str);
     950              : 
     951            0 :         parse_compress_specification(compression_algorithm, compression_detail,
     952              :                                                                  &compression_spec);
     953            0 :         error_detail = validate_compress_specification(&compression_spec);
     954            0 :         if (error_detail != NULL)
     955            0 :                 pg_fatal("invalid compression specification: %s",
     956              :                                  error_detail);
     957              : 
     958            0 :         error_detail = supports_compression(compression_spec);
     959            0 :         if (error_detail != NULL)
     960            0 :                 pg_fatal("%s", error_detail);
     961              : 
     962              :         /*
     963              :          * Disable support for zstd workers for now - these are based on
     964              :          * threading, and it's unclear how it interacts with parallel dumps on
     965              :          * platforms where that relies on threads too (e.g. Windows).
     966              :          */
     967            0 :         if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     968            0 :                 pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     969              :                                            "workers");
     970              : 
     971              :         /*
     972              :          * If emitting an archive format, we always want to emit a DATABASE item,
     973              :          * in case --create is specified at pg_restore time.
     974              :          */
     975            0 :         if (!plainText)
     976            0 :                 dopt.outputCreateDB = 1;
     977              : 
     978              :         /* Parallel backup only in the directory archive format so far */
     979            0 :         if (archiveFormat != archDirectory && numWorkers > 1)
     980            0 :                 pg_fatal("parallel backup only supported by the directory format");
     981              : 
     982              :         /* Open the output file */
     983            0 :         fout = CreateArchive(filename, archiveFormat, compression_spec,
     984            0 :                                                  dosync, archiveMode, setupDumpWorker, sync_method);
     985              : 
     986              :         /* Make dump options accessible right away */
     987            0 :         SetArchiveOptions(fout, &dopt, NULL);
     988              : 
     989              :         /* Register the cleanup hook */
     990            0 :         on_exit_close_archive(fout);
     991              : 
     992              :         /* Let the archiver know how noisy to be */
     993            0 :         fout->verbose = g_verbose;
     994              : 
     995              : 
     996              :         /*
     997              :          * We allow the server to be back to 9.2, and up to any minor release of
     998              :          * our own major version.  (See also version check in pg_dumpall.c.)
     999              :          */
    1000            0 :         fout->minRemoteVersion = 90200;
    1001            0 :         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
    1002              : 
    1003            0 :         fout->numWorkers = numWorkers;
    1004              : 
    1005              :         /*
    1006              :          * Open the database using the Archiver, so it knows about it. Errors mean
    1007              :          * death.
    1008              :          */
    1009            0 :         ConnectDatabaseAhx(fout, &dopt.cparams, false);
    1010            0 :         setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
    1011              : 
    1012              :         /*
    1013              :          * On hot standbys, never try to dump unlogged table data, since it will
    1014              :          * just throw an error.
    1015              :          */
    1016            0 :         if (fout->isStandby)
    1017            0 :                 dopt.no_unlogged_table_data = true;
    1018              : 
    1019              :         /*
    1020              :          * Find the last built-in OID, if needed (prior to 8.1)
    1021              :          *
    1022              :          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
    1023              :          */
    1024            0 :         g_last_builtin_oid = FirstNormalObjectId - 1;
    1025              : 
    1026            0 :         pg_log_info("last built-in OID is %u", g_last_builtin_oid);
    1027              : 
    1028              :         /* Expand schema selection patterns into OID lists */
    1029            0 :         if (schema_include_patterns.head != NULL)
    1030              :         {
    1031            0 :                 expand_schema_name_patterns(fout, &schema_include_patterns,
    1032              :                                                                         &schema_include_oids,
    1033            0 :                                                                         strict_names);
    1034            0 :                 if (schema_include_oids.head == NULL)
    1035            0 :                         pg_fatal("no matching schemas were found");
    1036            0 :         }
    1037            0 :         expand_schema_name_patterns(fout, &schema_exclude_patterns,
    1038              :                                                                 &schema_exclude_oids,
    1039              :                                                                 false);
    1040              :         /* non-matching exclusion patterns aren't an error */
    1041              : 
    1042              :         /* Expand table selection patterns into OID lists */
    1043            0 :         expand_table_name_patterns(fout, &table_include_patterns,
    1044              :                                                            &table_include_oids,
    1045            0 :                                                            strict_names, false);
    1046            0 :         expand_table_name_patterns(fout, &table_include_patterns_and_children,
    1047              :                                                            &table_include_oids,
    1048            0 :                                                            strict_names, true);
    1049            0 :         if ((table_include_patterns.head != NULL ||
    1050            0 :                  table_include_patterns_and_children.head != NULL) &&
    1051            0 :                 table_include_oids.head == NULL)
    1052            0 :                 pg_fatal("no matching tables were found");
    1053              : 
    1054            0 :         expand_table_name_patterns(fout, &table_exclude_patterns,
    1055              :                                                            &table_exclude_oids,
    1056              :                                                            false, false);
    1057            0 :         expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
    1058              :                                                            &table_exclude_oids,
    1059              :                                                            false, true);
    1060              : 
    1061            0 :         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
    1062              :                                                            &tabledata_exclude_oids,
    1063              :                                                            false, false);
    1064            0 :         expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
    1065              :                                                            &tabledata_exclude_oids,
    1066              :                                                            false, true);
    1067              : 
    1068            0 :         expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
    1069              :                                                                                 &foreign_servers_include_oids);
    1070              : 
    1071              :         /* non-matching exclusion patterns aren't an error */
    1072              : 
    1073              :         /* Expand extension selection patterns into OID lists */
    1074            0 :         if (extension_include_patterns.head != NULL)
    1075              :         {
    1076            0 :                 expand_extension_name_patterns(fout, &extension_include_patterns,
    1077              :                                                                            &extension_include_oids,
    1078            0 :                                                                            strict_names);
    1079            0 :                 if (extension_include_oids.head == NULL)
    1080            0 :                         pg_fatal("no matching extensions were found");
    1081            0 :         }
    1082            0 :         expand_extension_name_patterns(fout, &extension_exclude_patterns,
    1083              :                                                                    &extension_exclude_oids,
    1084              :                                                                    false);
    1085              :         /* non-matching exclusion patterns aren't an error */
    1086              : 
    1087              :         /*
    1088              :          * Dumping LOs is the default for dumps where an inclusion switch is not
    1089              :          * used (an "include everything" dump).  -B can be used to exclude LOs
    1090              :          * from those dumps.  -b can be used to include LOs even when an inclusion
    1091              :          * switch is used.
    1092              :          *
    1093              :          * -s means "schema only" and LOs are data, not schema, so we never
    1094              :          * include LOs when -s is used.
    1095              :          */
    1096            0 :         if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
    1097            0 :                 dopt.outputLOs = true;
    1098              : 
    1099              :         /*
    1100              :          * Collect role names so we can map object owner OIDs to names.
    1101              :          */
    1102            0 :         collectRoleNames(fout);
    1103              : 
    1104              :         /*
    1105              :          * Now scan the database and create DumpableObject structs for all the
    1106              :          * objects we intend to dump.
    1107              :          */
    1108            0 :         tblinfo = getSchemaData(fout, &numTables);
    1109              : 
    1110            0 :         if (dopt.dumpData)
    1111              :         {
    1112            0 :                 getTableData(&dopt, tblinfo, numTables, 0);
    1113            0 :                 buildMatViewRefreshDependencies(fout);
    1114            0 :                 if (!dopt.dumpSchema)
    1115            0 :                         getTableDataFKConstraints();
    1116            0 :         }
    1117              : 
    1118            0 :         if (!dopt.dumpData && dopt.sequence_data)
    1119            0 :                 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1120              : 
    1121              :         /*
    1122              :          * For binary upgrade mode, dump pg_largeobject_metadata and the
    1123              :          * associated pg_shdepend rows. This is faster to restore than the
    1124              :          * equivalent set of large object commands.  We can only do this for
    1125              :          * upgrades from v12 and newer; in older versions, pg_largeobject_metadata
    1126              :          * was created WITH OIDS, so the OID column is hidden and won't be dumped.
    1127              :          */
    1128            0 :         if (dopt.binary_upgrade && fout->remoteVersion >= 120000)
    1129              :         {
    1130            0 :                 TableInfo  *lo_metadata = findTableByOid(LargeObjectMetadataRelationId);
    1131            0 :                 TableInfo  *shdepend = findTableByOid(SharedDependRelationId);
    1132              : 
    1133            0 :                 makeTableDataInfo(&dopt, lo_metadata);
    1134            0 :                 makeTableDataInfo(&dopt, shdepend);
    1135              : 
    1136              :                 /*
    1137              :                  * Save pg_largeobject_metadata's dump ID for use as a dependency for
    1138              :                  * pg_shdepend and any large object comments/seclabels.
    1139              :                  */
    1140            0 :                 lo_metadata_dumpId = lo_metadata->dataObj->dobj.dumpId;
    1141            0 :                 addObjectDependency(&shdepend->dataObj->dobj, lo_metadata_dumpId);
    1142              : 
    1143              :                 /*
    1144              :                  * Only dump large object shdepend rows for this database.
    1145              :                  */
    1146            0 :                 shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
    1147              :                         "AND dbid = (SELECT oid FROM pg_database "
    1148              :                         "            WHERE datname = current_database())";
    1149              : 
    1150              :                 /*
    1151              :                  * If upgrading from v16 or newer, only dump large objects with
    1152              :                  * comments/seclabels.  For these upgrades, pg_upgrade can copy/link
    1153              :                  * pg_largeobject_metadata's files (which is usually faster) but we
    1154              :                  * still need to dump LOs with comments/seclabels here so that the
    1155              :                  * subsequent COMMENT and SECURITY LABEL commands work.  pg_upgrade
    1156              :                  * can't copy/link the files from older versions because aclitem
    1157              :                  * (needed by pg_largeobject_metadata.lomacl) changed its storage
    1158              :                  * format in v16.
    1159              :                  */
    1160            0 :                 if (fout->remoteVersion >= 160000)
    1161            0 :                         lo_metadata->dataObj->filtercond = "WHERE oid IN "
    1162              :                                 "(SELECT objoid FROM pg_description "
    1163              :                                 "WHERE classoid = " CppAsString2(LargeObjectRelationId) " "
    1164              :                                 "UNION SELECT objoid FROM pg_seclabel "
    1165              :                                 "WHERE classoid = " CppAsString2(LargeObjectRelationId) ")";
    1166            0 :         }
    1167              : 
    1168              :         /*
    1169              :          * In binary-upgrade mode, we do not have to worry about the actual LO
    1170              :          * data or the associated metadata that resides in the pg_largeobject and
    1171              :          * pg_largeobject_metadata tables, respectively.
    1172              :          *
    1173              :          * However, we do need to collect LO information as there may be comments
    1174              :          * or other information on LOs that we do need to dump out.
    1175              :          */
    1176            0 :         if (dopt.outputLOs || dopt.binary_upgrade)
    1177            0 :                 getLOs(fout);
    1178              : 
    1179              :         /*
    1180              :          * Collect dependency data to assist in ordering the objects.
    1181              :          */
    1182            0 :         getDependencies(fout);
    1183              : 
    1184              :         /*
    1185              :          * Collect ACLs, comments, and security labels, if wanted.
    1186              :          */
    1187            0 :         if (!dopt.aclsSkip)
    1188            0 :                 getAdditionalACLs(fout);
    1189            0 :         if (!dopt.no_comments)
    1190            0 :                 collectComments(fout);
    1191            0 :         if (!dopt.no_security_labels)
    1192            0 :                 collectSecLabels(fout);
    1193              : 
    1194              :         /* For binary upgrade mode, collect required pg_class information. */
    1195            0 :         if (dopt.binary_upgrade)
    1196            0 :                 collectBinaryUpgradeClassOids(fout);
    1197              : 
    1198              :         /* Collect sequence information. */
    1199            0 :         collectSequences(fout);
    1200              : 
    1201              :         /* Lastly, create dummy objects to represent the section boundaries */
    1202            0 :         boundaryObjs = createBoundaryObjects();
    1203              : 
    1204              :         /* Get pointers to all the known DumpableObjects */
    1205            0 :         getDumpableObjects(&dobjs, &numObjs);
    1206              : 
    1207              :         /*
    1208              :          * Add dummy dependencies to enforce the dump section ordering.
    1209              :          */
    1210            0 :         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1211              : 
    1212              :         /*
    1213              :          * Sort the objects into a safe dump order (no forward references).
    1214              :          *
    1215              :          * We rely on dependency information to help us determine a safe order, so
    1216              :          * the initial sort is mostly for cosmetic purposes: we sort by name to
    1217              :          * ensure that logically identical schemas will dump identically.
    1218              :          */
    1219            0 :         sortDumpableObjectsByTypeName(dobjs, numObjs);
    1220              : 
    1221            0 :         sortDumpableObjects(dobjs, numObjs,
    1222            0 :                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1223              : 
    1224              :         /*
    1225              :          * Create archive TOC entries for all the objects to be dumped, in a safe
    1226              :          * order.
    1227              :          */
    1228              : 
    1229              :         /*
    1230              :          * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1231              :          */
    1232            0 :         dumpEncoding(fout);
    1233            0 :         dumpStdStrings(fout);
    1234            0 :         dumpSearchPath(fout);
    1235              : 
    1236              :         /* The database items are always next, unless we don't want them at all */
    1237            0 :         if (dopt.outputCreateDB)
    1238            0 :                 dumpDatabase(fout);
    1239              : 
    1240              :         /* Now the rearrangeable objects. */
    1241            0 :         for (i = 0; i < numObjs; i++)
    1242            0 :                 dumpDumpableObject(fout, dobjs[i]);
    1243              : 
    1244              :         /*
    1245              :          * Set up options info to ensure we dump what we want.
    1246              :          */
    1247            0 :         ropt = NewRestoreOptions();
    1248            0 :         ropt->filename = filename;
    1249              : 
    1250              :         /* if you change this list, see dumpOptionsFromRestoreOptions */
    1251            0 :         ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1252            0 :         ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1253            0 :         ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1254            0 :         ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1255            0 :         ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1256            0 :         ropt->dropSchema = dopt.outputClean;
    1257            0 :         ropt->dumpData = dopt.dumpData;
    1258            0 :         ropt->dumpSchema = dopt.dumpSchema;
    1259            0 :         ropt->dumpStatistics = dopt.dumpStatistics;
    1260            0 :         ropt->if_exists = dopt.if_exists;
    1261            0 :         ropt->column_inserts = dopt.column_inserts;
    1262            0 :         ropt->dumpSections = dopt.dumpSections;
    1263            0 :         ropt->aclsSkip = dopt.aclsSkip;
    1264            0 :         ropt->superuser = dopt.outputSuperuser;
    1265            0 :         ropt->createDB = dopt.outputCreateDB;
    1266            0 :         ropt->noOwner = dopt.outputNoOwner;
    1267            0 :         ropt->noTableAm = dopt.outputNoTableAm;
    1268            0 :         ropt->noTablespace = dopt.outputNoTablespaces;
    1269            0 :         ropt->disable_triggers = dopt.disable_triggers;
    1270            0 :         ropt->use_setsessauth = dopt.use_setsessauth;
    1271            0 :         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1272            0 :         ropt->dump_inserts = dopt.dump_inserts;
    1273            0 :         ropt->no_comments = dopt.no_comments;
    1274            0 :         ropt->no_policies = dopt.no_policies;
    1275            0 :         ropt->no_publications = dopt.no_publications;
    1276            0 :         ropt->no_security_labels = dopt.no_security_labels;
    1277            0 :         ropt->no_subscriptions = dopt.no_subscriptions;
    1278            0 :         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1279            0 :         ropt->include_everything = dopt.include_everything;
    1280            0 :         ropt->enable_row_security = dopt.enable_row_security;
    1281            0 :         ropt->sequence_data = dopt.sequence_data;
    1282            0 :         ropt->binary_upgrade = dopt.binary_upgrade;
    1283            0 :         ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
    1284              : 
    1285            0 :         ropt->compression_spec = compression_spec;
    1286              : 
    1287            0 :         ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1288              : 
    1289            0 :         SetArchiveOptions(fout, &dopt, ropt);
    1290              : 
    1291              :         /* Mark which entries should be output */
    1292            0 :         ProcessArchiveRestoreOptions(fout);
    1293              : 
    1294              :         /*
    1295              :          * The archive's TOC entries are now marked as to which ones will actually
    1296              :          * be output, so we can set up their dependency lists properly. This isn't
    1297              :          * necessary for plain-text output, though.
    1298              :          */
    1299            0 :         if (!plainText)
    1300            0 :                 BuildArchiveDependencies(fout);
    1301              : 
    1302              :         /*
    1303              :          * And finally we can do the actual output.
    1304              :          *
    1305              :          * Note: for non-plain-text output formats, the output file is written
    1306              :          * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1307              :          * right now.
    1308              :          */
    1309            0 :         if (plainText)
    1310            0 :                 RestoreArchive(fout);
    1311              : 
    1312            0 :         CloseArchive(fout);
    1313              : 
    1314            0 :         exit_nicely(0);
    1315              : }
    1316              : 
    1317              : 
    1318              : static void
    1319            0 : help(const char *progname)
    1320              : {
    1321            0 :         printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
    1322            0 :         printf(_("Usage:\n"));
    1323            0 :         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1324              : 
    1325            0 :         printf(_("\nGeneral options:\n"));
    1326            0 :         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1327            0 :         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1328              :                          "                               plain text (default))\n"));
    1329            0 :         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1330            0 :         printf(_("  -v, --verbose                verbose mode\n"));
    1331            0 :         printf(_("  -V, --version                output version information, then exit\n"));
    1332            0 :         printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1333              :                          "                               compress as specified\n"));
    1334            0 :         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1335            0 :         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1336            0 :         printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1337            0 :         printf(_("  -?, --help                   show this help, then exit\n"));
    1338              : 
    1339            0 :         printf(_("\nOptions controlling the output content:\n"));
    1340            0 :         printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
    1341            0 :         printf(_("  -b, --large-objects          include large objects in dump\n"));
    1342            0 :         printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1343            0 :         printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1344            0 :         printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1345            0 :         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1346            0 :         printf(_("  -C, --create                 include commands to create database in dump\n"));
    1347            0 :         printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1348            0 :         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1349            0 :         printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1350            0 :         printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1351            0 :         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1352              :                          "                               plain-text format\n"));
    1353            0 :         printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
    1354            0 :         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1355            0 :         printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1356            0 :         printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1357            0 :         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1358            0 :         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1359            0 :         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1360            0 :         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1361            0 :         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1362            0 :         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1363              :                          "                               access to)\n"));
    1364            0 :         printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1365            0 :         printf(_("  --exclude-table-and-children=PATTERN\n"
    1366              :                          "                               do NOT dump the specified table(s), including\n"
    1367              :                          "                               child and partition tables\n"));
    1368            0 :         printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1369            0 :         printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1370              :                          "                               do NOT dump data for the specified table(s),\n"
    1371              :                          "                               including child and partition tables\n"));
    1372            0 :         printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1373            0 :         printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1374              :                          "                               based on expressions in FILENAME\n"));
    1375            0 :         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1376            0 :         printf(_("  --include-foreign-data=PATTERN\n"
    1377              :                          "                               include data of foreign tables on foreign\n"
    1378              :                          "                               servers matching PATTERN\n"));
    1379            0 :         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1380            0 :         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1381            0 :         printf(_("  --no-comments                do not dump comment commands\n"));
    1382            0 :         printf(_("  --no-data                    do not dump data\n"));
    1383            0 :         printf(_("  --no-policies                do not dump row security policies\n"));
    1384            0 :         printf(_("  --no-publications            do not dump publications\n"));
    1385            0 :         printf(_("  --no-schema                  do not dump schema\n"));
    1386            0 :         printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1387            0 :         printf(_("  --no-statistics              do not dump statistics\n"));
    1388            0 :         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1389            0 :         printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1390            0 :         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1391            0 :         printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1392            0 :         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1393            0 :         printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1394            0 :         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1395            0 :         printf(_("  --restrict-key=RESTRICT_KEY  use provided string as psql \\restrict key\n"));
    1396            0 :         printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1397            0 :         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1398            0 :         printf(_("  --sequence-data              include sequence data in dump\n"));
    1399            0 :         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1400            0 :         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1401            0 :         printf(_("  --statistics                 dump the statistics\n"));
    1402            0 :         printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
    1403            0 :         printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1404              :                          "                               match at least one entity each\n"));
    1405            0 :         printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1406              :                          "                               child and partition tables\n"));
    1407            0 :         printf(_("  --use-set-session-authorization\n"
    1408              :                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1409              :                          "                               ALTER OWNER commands to set ownership\n"));
    1410              : 
    1411            0 :         printf(_("\nConnection options:\n"));
    1412            0 :         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1413            0 :         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1414            0 :         printf(_("  -p, --port=PORT          database server port number\n"));
    1415            0 :         printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1416            0 :         printf(_("  -w, --no-password        never prompt for password\n"));
    1417            0 :         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1418            0 :         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1419              : 
    1420            0 :         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1421              :                          "variable value is used.\n\n"));
    1422            0 :         printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1423            0 :         printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1424            0 : }
    1425              : 
    1426              : static void
    1427            0 : setup_connection(Archive *AH, const char *dumpencoding,
    1428              :                                  const char *dumpsnapshot, char *use_role)
    1429              : {
    1430            0 :         DumpOptions *dopt = AH->dopt;
    1431            0 :         PGconn     *conn = GetConnection(AH);
    1432              : 
    1433            0 :         PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1434              : 
    1435              :         /*
    1436              :          * Set the client encoding if requested.
    1437              :          */
    1438            0 :         if (dumpencoding)
    1439              :         {
    1440            0 :                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1441            0 :                         pg_fatal("invalid client encoding \"%s\" specified",
    1442              :                                          dumpencoding);
    1443            0 :         }
    1444              : 
    1445              :         /*
    1446              :          * Force standard_conforming_strings on, just in case we are dumping from
    1447              :          * an old server that has it disabled.  Without this, literals in views,
    1448              :          * expressions, etc, would be incorrect for modern servers.
    1449              :          */
    1450            0 :         ExecuteSqlStatement(AH, "SET standard_conforming_strings = on");
    1451              : 
    1452              :         /*
    1453              :          * And reflect that to AH->std_strings.  You might think that we should
    1454              :          * just delete that variable and the code that checks it, but that would
    1455              :          * be problematic for pg_restore, which at least for now should still cope
    1456              :          * with archives containing the other setting (cf. processStdStringsEntry
    1457              :          * in pg_backup_archiver.c).
    1458              :          */
    1459            0 :         AH->std_strings = true;
    1460              : 
    1461              :         /*
    1462              :          * Get the active encoding, so we know how to escape strings.
    1463              :          */
    1464            0 :         AH->encoding = PQclientEncoding(conn);
    1465            0 :         setFmtEncoding(AH->encoding);
    1466              : 
    1467              :         /*
    1468              :          * Set the role if requested.  In a parallel dump worker, we'll be passed
    1469              :          * use_role == NULL, but AH->use_role is already set (if user specified it
    1470              :          * originally) and we should use that.
    1471              :          */
    1472            0 :         if (!use_role && AH->use_role)
    1473            0 :                 use_role = AH->use_role;
    1474              : 
    1475              :         /* Set the role if requested */
    1476            0 :         if (use_role)
    1477              :         {
    1478            0 :                 PQExpBuffer query = createPQExpBuffer();
    1479              : 
    1480            0 :                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1481            0 :                 ExecuteSqlStatement(AH, query->data);
    1482            0 :                 destroyPQExpBuffer(query);
    1483              : 
    1484              :                 /* save it for possible later use by parallel workers */
    1485            0 :                 if (!AH->use_role)
    1486            0 :                         AH->use_role = pg_strdup(use_role);
    1487            0 :         }
    1488              : 
    1489              :         /* Set the datestyle to ISO to ensure the dump's portability */
    1490            0 :         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1491              : 
    1492              :         /* Likewise, avoid using sql_standard intervalstyle */
    1493            0 :         ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1494              : 
    1495              :         /*
    1496              :          * Use an explicitly specified extra_float_digits if it has been provided.
    1497              :          * Otherwise, set extra_float_digits so that we can dump float data
    1498              :          * exactly (given correctly implemented float I/O code, anyway).
    1499              :          */
    1500            0 :         if (have_extra_float_digits)
    1501              :         {
    1502            0 :                 PQExpBuffer q = createPQExpBuffer();
    1503              : 
    1504            0 :                 appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1505            0 :                                                   extra_float_digits);
    1506            0 :                 ExecuteSqlStatement(AH, q->data);
    1507            0 :                 destroyPQExpBuffer(q);
    1508            0 :         }
    1509              :         else
    1510            0 :                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1511              : 
    1512              :         /*
    1513              :          * Disable synchronized scanning, to prevent unpredictable changes in row
    1514              :          * ordering across a dump and reload.
    1515              :          */
    1516            0 :         ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1517              : 
    1518              :         /*
    1519              :          * Disable timeouts if supported.
    1520              :          */
    1521            0 :         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1522            0 :         if (AH->remoteVersion >= 90300)
    1523            0 :                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1524            0 :         if (AH->remoteVersion >= 90600)
    1525            0 :                 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1526            0 :         if (AH->remoteVersion >= 170000)
    1527            0 :                 ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1528              : 
    1529              :         /*
    1530              :          * Quote all identifiers, if requested.
    1531              :          */
    1532            0 :         if (quote_all_identifiers)
    1533            0 :                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1534              : 
    1535              :         /*
    1536              :          * Adjust row-security mode, if supported.
    1537              :          */
    1538            0 :         if (AH->remoteVersion >= 90500)
    1539              :         {
    1540            0 :                 if (dopt->enable_row_security)
    1541            0 :                         ExecuteSqlStatement(AH, "SET row_security = on");
    1542              :                 else
    1543            0 :                         ExecuteSqlStatement(AH, "SET row_security = off");
    1544            0 :         }
    1545              : 
    1546              :         /*
    1547              :          * For security reasons, we restrict the expansion of non-system views and
    1548              :          * access to foreign tables during the pg_dump process. This restriction
    1549              :          * is adjusted when dumping foreign table data.
    1550              :          */
    1551            0 :         set_restrict_relation_kind(AH, "view, foreign-table");
    1552              : 
    1553              :         /*
    1554              :          * Initialize prepared-query state to "nothing prepared".  We do this here
    1555              :          * so that a parallel dump worker will have its own state.
    1556              :          */
    1557            0 :         AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
    1558              : 
    1559              :         /*
    1560              :          * Start transaction-snapshot mode transaction to dump consistent data.
    1561              :          */
    1562            0 :         ExecuteSqlStatement(AH, "BEGIN");
    1563              : 
    1564              :         /*
    1565              :          * To support the combination of serializable_deferrable with the jobs
    1566              :          * option we use REPEATABLE READ for the worker connections that are
    1567              :          * passed a snapshot.  As long as the snapshot is acquired in a
    1568              :          * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1569              :          * REPEATABLE READ transaction provides the appropriate integrity
    1570              :          * guarantees.  This is a kluge, but safe for back-patching.
    1571              :          */
    1572            0 :         if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1573            0 :                 ExecuteSqlStatement(AH,
    1574              :                                                         "SET TRANSACTION ISOLATION LEVEL "
    1575              :                                                         "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1576              :         else
    1577            0 :                 ExecuteSqlStatement(AH,
    1578              :                                                         "SET TRANSACTION ISOLATION LEVEL "
    1579              :                                                         "REPEATABLE READ, READ ONLY");
    1580              : 
    1581              :         /*
    1582              :          * If user specified a snapshot to use, select that.  In a parallel dump
    1583              :          * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1584              :          * is already set (if the server can handle it) and we should use that.
    1585              :          */
    1586            0 :         if (dumpsnapshot)
    1587            0 :                 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1588              : 
    1589            0 :         if (AH->sync_snapshot_id)
    1590              :         {
    1591            0 :                 PQExpBuffer query = createPQExpBuffer();
    1592              : 
    1593            0 :                 appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1594            0 :                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1595            0 :                 ExecuteSqlStatement(AH, query->data);
    1596            0 :                 destroyPQExpBuffer(query);
    1597            0 :         }
    1598            0 :         else if (AH->numWorkers > 1)
    1599              :         {
    1600            0 :                 if (AH->isStandby && AH->remoteVersion < 100000)
    1601            0 :                         pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1602            0 :                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1603            0 :         }
    1604            0 : }
    1605              : 
    1606              : /* Set up connection for a parallel worker process */
    1607              : static void
    1608            0 : setupDumpWorker(Archive *AH)
    1609              : {
    1610              :         /*
    1611              :          * We want to re-select all the same values the leader connection is
    1612              :          * using.  We'll have inherited directly-usable values in
    1613              :          * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1614              :          * inherited encoding value back to a string to pass to setup_connection.
    1615              :          */
    1616            0 :         setup_connection(AH,
    1617            0 :                                          pg_encoding_to_char(AH->encoding),
    1618              :                                          NULL,
    1619              :                                          NULL);
    1620            0 : }
    1621              : 
    1622              : static char *
    1623            0 : get_synchronized_snapshot(Archive *fout)
    1624              : {
    1625            0 :         char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1626            0 :         char       *result;
    1627            0 :         PGresult   *res;
    1628              : 
    1629            0 :         res = ExecuteSqlQueryForSingleRow(fout, query);
    1630            0 :         result = pg_strdup(PQgetvalue(res, 0, 0));
    1631            0 :         PQclear(res);
    1632              : 
    1633            0 :         return result;
    1634            0 : }
    1635              : 
    1636              : static ArchiveFormat
    1637            0 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1638              : {
    1639            0 :         ArchiveFormat archiveFormat;
    1640              : 
    1641            0 :         *mode = archModeWrite;
    1642              : 
    1643            0 :         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1644              :         {
    1645              :                 /* This is used by pg_dumpall, and is not documented */
    1646            0 :                 archiveFormat = archNull;
    1647            0 :                 *mode = archModeAppend;
    1648            0 :         }
    1649            0 :         else if (pg_strcasecmp(format, "c") == 0)
    1650            0 :                 archiveFormat = archCustom;
    1651            0 :         else if (pg_strcasecmp(format, "custom") == 0)
    1652            0 :                 archiveFormat = archCustom;
    1653            0 :         else if (pg_strcasecmp(format, "d") == 0)
    1654            0 :                 archiveFormat = archDirectory;
    1655            0 :         else if (pg_strcasecmp(format, "directory") == 0)
    1656            0 :                 archiveFormat = archDirectory;
    1657            0 :         else if (pg_strcasecmp(format, "p") == 0)
    1658            0 :                 archiveFormat = archNull;
    1659            0 :         else if (pg_strcasecmp(format, "plain") == 0)
    1660            0 :                 archiveFormat = archNull;
    1661            0 :         else if (pg_strcasecmp(format, "t") == 0)
    1662            0 :                 archiveFormat = archTar;
    1663            0 :         else if (pg_strcasecmp(format, "tar") == 0)
    1664            0 :                 archiveFormat = archTar;
    1665              :         else
    1666            0 :                 pg_fatal("invalid output format \"%s\" specified", format);
    1667            0 :         return archiveFormat;
    1668            0 : }
    1669              : 
    1670              : /*
    1671              :  * Find the OIDs of all schemas matching the given list of patterns,
    1672              :  * and append them to the given OID list.
    1673              :  */
    1674              : static void
    1675            0 : expand_schema_name_patterns(Archive *fout,
    1676              :                                                         SimpleStringList *patterns,
    1677              :                                                         SimpleOidList *oids,
    1678              :                                                         bool strict_names)
    1679              : {
    1680            0 :         PQExpBuffer query;
    1681            0 :         PGresult   *res;
    1682            0 :         SimpleStringListCell *cell;
    1683            0 :         int                     i;
    1684              : 
    1685            0 :         if (patterns->head == NULL)
    1686            0 :                 return;                                 /* nothing to do */
    1687              : 
    1688            0 :         query = createPQExpBuffer();
    1689              : 
    1690              :         /*
    1691              :          * The loop below runs multiple SELECTs might sometimes result in
    1692              :          * duplicate entries in the OID list, but we don't care.
    1693              :          */
    1694              : 
    1695            0 :         for (cell = patterns->head; cell; cell = cell->next)
    1696              :         {
    1697            0 :                 PQExpBufferData dbbuf;
    1698            0 :                 int                     dotcnt;
    1699              : 
    1700            0 :                 appendPQExpBufferStr(query,
    1701              :                                                          "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1702            0 :                 initPQExpBuffer(&dbbuf);
    1703            0 :                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1704              :                                                           false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1705              :                                                           &dotcnt);
    1706            0 :                 if (dotcnt > 1)
    1707            0 :                         pg_fatal("improper qualified name (too many dotted names): %s",
    1708              :                                          cell->val);
    1709            0 :                 else if (dotcnt == 1)
    1710            0 :                         prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1711            0 :                 termPQExpBuffer(&dbbuf);
    1712              : 
    1713            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1714            0 :                 if (strict_names && PQntuples(res) == 0)
    1715            0 :                         pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1716              : 
    1717            0 :                 for (i = 0; i < PQntuples(res); i++)
    1718              :                 {
    1719            0 :                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1720            0 :                 }
    1721              : 
    1722            0 :                 PQclear(res);
    1723            0 :                 resetPQExpBuffer(query);
    1724            0 :         }
    1725              : 
    1726            0 :         destroyPQExpBuffer(query);
    1727            0 : }
    1728              : 
    1729              : /*
    1730              :  * Find the OIDs of all extensions matching the given list of patterns,
    1731              :  * and append them to the given OID list.
    1732              :  */
    1733              : static void
    1734            0 : expand_extension_name_patterns(Archive *fout,
    1735              :                                                            SimpleStringList *patterns,
    1736              :                                                            SimpleOidList *oids,
    1737              :                                                            bool strict_names)
    1738              : {
    1739            0 :         PQExpBuffer query;
    1740            0 :         PGresult   *res;
    1741            0 :         SimpleStringListCell *cell;
    1742            0 :         int                     i;
    1743              : 
    1744            0 :         if (patterns->head == NULL)
    1745            0 :                 return;                                 /* nothing to do */
    1746              : 
    1747            0 :         query = createPQExpBuffer();
    1748              : 
    1749              :         /*
    1750              :          * The loop below runs multiple SELECTs might sometimes result in
    1751              :          * duplicate entries in the OID list, but we don't care.
    1752              :          */
    1753            0 :         for (cell = patterns->head; cell; cell = cell->next)
    1754              :         {
    1755            0 :                 int                     dotcnt;
    1756              : 
    1757            0 :                 appendPQExpBufferStr(query,
    1758              :                                                          "SELECT oid FROM pg_catalog.pg_extension e\n");
    1759            0 :                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1760              :                                                           false, NULL, "e.extname", NULL, NULL, NULL,
    1761              :                                                           &dotcnt);
    1762            0 :                 if (dotcnt > 0)
    1763            0 :                         pg_fatal("improper qualified name (too many dotted names): %s",
    1764              :                                          cell->val);
    1765              : 
    1766            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1767            0 :                 if (strict_names && PQntuples(res) == 0)
    1768            0 :                         pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1769              : 
    1770            0 :                 for (i = 0; i < PQntuples(res); i++)
    1771              :                 {
    1772            0 :                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1773            0 :                 }
    1774              : 
    1775            0 :                 PQclear(res);
    1776            0 :                 resetPQExpBuffer(query);
    1777            0 :         }
    1778              : 
    1779            0 :         destroyPQExpBuffer(query);
    1780            0 : }
    1781              : 
    1782              : /*
    1783              :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1784              :  * and append them to the given OID list.
    1785              :  */
    1786              : static void
    1787            0 : expand_foreign_server_name_patterns(Archive *fout,
    1788              :                                                                         SimpleStringList *patterns,
    1789              :                                                                         SimpleOidList *oids)
    1790              : {
    1791            0 :         PQExpBuffer query;
    1792            0 :         PGresult   *res;
    1793            0 :         SimpleStringListCell *cell;
    1794            0 :         int                     i;
    1795              : 
    1796            0 :         if (patterns->head == NULL)
    1797            0 :                 return;                                 /* nothing to do */
    1798              : 
    1799            0 :         query = createPQExpBuffer();
    1800              : 
    1801              :         /*
    1802              :          * The loop below runs multiple SELECTs might sometimes result in
    1803              :          * duplicate entries in the OID list, but we don't care.
    1804              :          */
    1805              : 
    1806            0 :         for (cell = patterns->head; cell; cell = cell->next)
    1807              :         {
    1808            0 :                 int                     dotcnt;
    1809              : 
    1810            0 :                 appendPQExpBufferStr(query,
    1811              :                                                          "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1812            0 :                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1813              :                                                           false, NULL, "s.srvname", NULL, NULL, NULL,
    1814              :                                                           &dotcnt);
    1815            0 :                 if (dotcnt > 0)
    1816            0 :                         pg_fatal("improper qualified name (too many dotted names): %s",
    1817              :                                          cell->val);
    1818              : 
    1819            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1820            0 :                 if (PQntuples(res) == 0)
    1821            0 :                         pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1822              : 
    1823            0 :                 for (i = 0; i < PQntuples(res); i++)
    1824            0 :                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1825              : 
    1826            0 :                 PQclear(res);
    1827            0 :                 resetPQExpBuffer(query);
    1828            0 :         }
    1829              : 
    1830            0 :         destroyPQExpBuffer(query);
    1831            0 : }
    1832              : 
    1833              : /*
    1834              :  * Find the OIDs of all tables matching the given list of patterns,
    1835              :  * and append them to the given OID list. See also expand_dbname_patterns()
    1836              :  * in pg_dumpall.c
    1837              :  */
    1838              : static void
    1839            0 : expand_table_name_patterns(Archive *fout,
    1840              :                                                    SimpleStringList *patterns, SimpleOidList *oids,
    1841              :                                                    bool strict_names, bool with_child_tables)
    1842              : {
    1843            0 :         PQExpBuffer query;
    1844            0 :         PGresult   *res;
    1845            0 :         SimpleStringListCell *cell;
    1846            0 :         int                     i;
    1847              : 
    1848            0 :         if (patterns->head == NULL)
    1849            0 :                 return;                                 /* nothing to do */
    1850              : 
    1851            0 :         query = createPQExpBuffer();
    1852              : 
    1853              :         /*
    1854              :          * this might sometimes result in duplicate entries in the OID list, but
    1855              :          * we don't care.
    1856              :          */
    1857              : 
    1858            0 :         for (cell = patterns->head; cell; cell = cell->next)
    1859              :         {
    1860            0 :                 PQExpBufferData dbbuf;
    1861            0 :                 int                     dotcnt;
    1862              : 
    1863              :                 /*
    1864              :                  * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1865              :                  * would be unnecessary given a pg_table_is_visible() variant taking a
    1866              :                  * search_path argument.
    1867              :                  *
    1868              :                  * For with_child_tables, we start with the basic query's results and
    1869              :                  * recursively search the inheritance tree to add child tables.
    1870              :                  */
    1871            0 :                 if (with_child_tables)
    1872              :                 {
    1873            0 :                         appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1874            0 :                 }
    1875              : 
    1876            0 :                 appendPQExpBuffer(query,
    1877              :                                                   "SELECT c.oid"
    1878              :                                                   "\nFROM pg_catalog.pg_class c"
    1879              :                                                   "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1880              :                                                   "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1881              :                                                   "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1882              :                                                   "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1883              :                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1884              :                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1885              :                                                   RELKIND_PARTITIONED_TABLE);
    1886            0 :                 initPQExpBuffer(&dbbuf);
    1887            0 :                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1888              :                                                           false, "n.nspname", "c.relname", NULL,
    1889              :                                                           "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1890              :                                                           &dotcnt);
    1891            0 :                 if (dotcnt > 2)
    1892            0 :                         pg_fatal("improper relation name (too many dotted names): %s",
    1893              :                                          cell->val);
    1894            0 :                 else if (dotcnt == 2)
    1895            0 :                         prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1896            0 :                 termPQExpBuffer(&dbbuf);
    1897              : 
    1898            0 :                 if (with_child_tables)
    1899              :                 {
    1900            0 :                         appendPQExpBufferStr(query, "UNION"
    1901              :                                                                  "\nSELECT i.inhrelid"
    1902              :                                                                  "\nFROM partition_tree p"
    1903              :                                                                  "\n     JOIN pg_catalog.pg_inherits i"
    1904              :                                                                  "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1905              :                                                                  "\n)"
    1906              :                                                                  "\nSELECT relid FROM partition_tree");
    1907            0 :                 }
    1908              : 
    1909            0 :                 ExecuteSqlStatement(fout, "RESET search_path");
    1910            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1911            0 :                 PQclear(ExecuteSqlQueryForSingleRow(fout,
    1912              :                                                                                         ALWAYS_SECURE_SEARCH_PATH_SQL));
    1913            0 :                 if (strict_names && PQntuples(res) == 0)
    1914            0 :                         pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1915              : 
    1916            0 :                 for (i = 0; i < PQntuples(res); i++)
    1917              :                 {
    1918            0 :                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1919            0 :                 }
    1920              : 
    1921            0 :                 PQclear(res);
    1922            0 :                 resetPQExpBuffer(query);
    1923            0 :         }
    1924              : 
    1925            0 :         destroyPQExpBuffer(query);
    1926            0 : }
    1927              : 
    1928              : /*
    1929              :  * Verifies that the connected database name matches the given database name,
    1930              :  * and if not, dies with an error about the given pattern.
    1931              :  *
    1932              :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1933              :  */
    1934              : static void
    1935            0 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1936              : {
    1937            0 :         const char *db;
    1938              : 
    1939            0 :         db = PQdb(conn);
    1940            0 :         if (db == NULL)
    1941            0 :                 pg_fatal("You are currently not connected to a database.");
    1942              : 
    1943            0 :         if (strcmp(db, dbname) != 0)
    1944            0 :                 pg_fatal("cross-database references are not implemented: %s",
    1945              :                                  pattern);
    1946            0 : }
    1947              : 
    1948              : /*
    1949              :  * checkExtensionMembership
    1950              :  *              Determine whether object is an extension member, and if so,
    1951              :  *              record an appropriate dependency and set the object's dump flag.
    1952              :  *
    1953              :  * It's important to call this for each object that could be an extension
    1954              :  * member.  Generally, we integrate this with determining the object's
    1955              :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1956              :  *
    1957              :  * Returns true if object is an extension member, else false.
    1958              :  */
    1959              : static bool
    1960            0 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1961              : {
    1962            0 :         ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1963              : 
    1964            0 :         if (ext == NULL)
    1965            0 :                 return false;
    1966              : 
    1967            0 :         dobj->ext_member = true;
    1968              : 
    1969              :         /* Record dependency so that getDependencies needn't deal with that */
    1970            0 :         addObjectDependency(dobj, ext->dobj.dumpId);
    1971              : 
    1972              :         /*
    1973              :          * In 9.6 and above, mark the member object to have any non-initial ACLs
    1974              :          * dumped.  (Any initial ACLs will be removed later, using data from
    1975              :          * pg_init_privs, so that we'll dump only the delta from the extension's
    1976              :          * initial setup.)
    1977              :          *
    1978              :          * Prior to 9.6, we do not include any extension member components.
    1979              :          *
    1980              :          * In binary upgrades, we still dump all components of the members
    1981              :          * individually, since the idea is to exactly reproduce the database
    1982              :          * contents rather than replace the extension contents with something
    1983              :          * different.
    1984              :          *
    1985              :          * Note: it might be interesting someday to implement storage and delta
    1986              :          * dumping of extension members' RLS policies and/or security labels.
    1987              :          * However there is a pitfall for RLS policies: trying to dump them
    1988              :          * requires getting a lock on their tables, and the calling user might not
    1989              :          * have privileges for that.  We need no lock to examine a table's ACLs,
    1990              :          * so the current feature doesn't have a problem of that sort.
    1991              :          */
    1992            0 :         if (fout->dopt->binary_upgrade)
    1993            0 :                 dobj->dump = ext->dobj.dump;
    1994              :         else
    1995              :         {
    1996            0 :                 if (fout->remoteVersion < 90600)
    1997            0 :                         dobj->dump = DUMP_COMPONENT_NONE;
    1998              :                 else
    1999            0 :                         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    2000              :         }
    2001              : 
    2002            0 :         return true;
    2003            0 : }
    2004              : 
    2005              : /*
    2006              :  * selectDumpableNamespace: policy-setting subroutine
    2007              :  *              Mark a namespace as to be dumped or not
    2008              :  */
    2009              : static void
    2010            0 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    2011              : {
    2012              :         /*
    2013              :          * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    2014              :          * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    2015              :          * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    2016              :          */
    2017            0 :         nsinfo->create = true;
    2018              : 
    2019              :         /*
    2020              :          * If specific tables are being dumped, do not dump any complete
    2021              :          * namespaces. If specific namespaces are being dumped, dump just those
    2022              :          * namespaces. Otherwise, dump all non-system namespaces.
    2023              :          */
    2024            0 :         if (table_include_oids.head != NULL)
    2025            0 :                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2026            0 :         else if (schema_include_oids.head != NULL)
    2027            0 :                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    2028            0 :                         simple_oid_list_member(&schema_include_oids,
    2029            0 :                                                                    nsinfo->dobj.catId.oid) ?
    2030              :                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2031            0 :         else if (fout->remoteVersion >= 90600 &&
    2032            0 :                          strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    2033              :         {
    2034              :                 /*
    2035              :                  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    2036              :                  * they are interesting (and not the original ACLs which were set at
    2037              :                  * initdb time, see pg_init_privs).
    2038              :                  */
    2039            0 :                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    2040            0 :         }
    2041            0 :         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    2042            0 :                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
    2043              :         {
    2044              :                 /* Other system schemas don't get dumped */
    2045            0 :                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2046            0 :         }
    2047            0 :         else if (strcmp(nsinfo->dobj.name, "public") == 0)
    2048              :         {
    2049              :                 /*
    2050              :                  * The public schema is a strange beast that sits in a sort of
    2051              :                  * no-mans-land between being a system object and a user object.
    2052              :                  * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    2053              :                  * a comment and an indication of ownership.  If the owner is the
    2054              :                  * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    2055              :                  * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    2056              :                  */
    2057            0 :                 nsinfo->create = false;
    2058            0 :                 nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2059            0 :                 if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    2060            0 :                         nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    2061            0 :                 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    2062              : 
    2063              :                 /*
    2064              :                  * Also, make like it has a comment even if it doesn't; this is so
    2065              :                  * that we'll emit a command to drop the comment, if appropriate.
    2066              :                  * (Without this, we'd not call dumpCommentExtended for it.)
    2067              :                  */
    2068            0 :                 nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    2069            0 :         }
    2070              :         else
    2071            0 :                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2072              : 
    2073              :         /*
    2074              :          * In any case, a namespace can be excluded by an exclusion switch
    2075              :          */
    2076            0 :         if (nsinfo->dobj.dump_contains &&
    2077            0 :                 simple_oid_list_member(&schema_exclude_oids,
    2078            0 :                                                            nsinfo->dobj.catId.oid))
    2079            0 :                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2080              : 
    2081              :         /*
    2082              :          * If the schema belongs to an extension, allow extension membership to
    2083              :          * override the dump decision for the schema itself.  However, this does
    2084              :          * not change dump_contains, so this won't change what we do with objects
    2085              :          * within the schema.  (If they belong to the extension, they'll get
    2086              :          * suppressed by it, otherwise not.)
    2087              :          */
    2088            0 :         (void) checkExtensionMembership(&nsinfo->dobj, fout);
    2089            0 : }
    2090              : 
    2091              : /*
    2092              :  * selectDumpableTable: policy-setting subroutine
    2093              :  *              Mark a table as to be dumped or not
    2094              :  */
    2095              : static void
    2096            0 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    2097              : {
    2098            0 :         if (checkExtensionMembership(&tbinfo->dobj, fout))
    2099            0 :                 return;                                 /* extension membership overrides all else */
    2100              : 
    2101              :         /*
    2102              :          * If specific tables are being dumped, dump just those tables; else, dump
    2103              :          * according to the parent namespace's dump flag.
    2104              :          */
    2105            0 :         if (table_include_oids.head != NULL)
    2106            0 :                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    2107            0 :                                                                                                    tbinfo->dobj.catId.oid) ?
    2108              :                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2109              :         else
    2110            0 :                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    2111              : 
    2112              :         /*
    2113              :          * In any case, a table can be excluded by an exclusion switch
    2114              :          */
    2115            0 :         if (tbinfo->dobj.dump &&
    2116            0 :                 simple_oid_list_member(&table_exclude_oids,
    2117            0 :                                                            tbinfo->dobj.catId.oid))
    2118            0 :                 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2119            0 : }
    2120              : 
    2121              : /*
    2122              :  * selectDumpableType: policy-setting subroutine
    2123              :  *              Mark a type as to be dumped or not
    2124              :  *
    2125              :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    2126              :  * special type code to facilitate sorting into the desired order.  (We don't
    2127              :  * want to consider those to be ordinary types because that would bring tables
    2128              :  * up into the datatype part of the dump order.)  We still set the object's
    2129              :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    2130              :  * need it so that casts involving such types will be dumped correctly -- see
    2131              :  * dumpCast.  This means the flag should be set the same as for the underlying
    2132              :  * object (the table or base type).
    2133              :  */
    2134              : static void
    2135            0 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    2136              : {
    2137              :         /* skip complex types, except for standalone composite types */
    2138            0 :         if (OidIsValid(tyinfo->typrelid) &&
    2139            0 :                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2140              :         {
    2141            0 :                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2142              : 
    2143            0 :                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2144            0 :                 if (tytable != NULL)
    2145            0 :                         tyinfo->dobj.dump = tytable->dobj.dump;
    2146              :                 else
    2147            0 :                         tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2148              :                 return;
    2149            0 :         }
    2150              : 
    2151              :         /* skip auto-generated array and multirange types */
    2152            0 :         if (tyinfo->isArray || tyinfo->isMultirange)
    2153              :         {
    2154            0 :                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2155              : 
    2156              :                 /*
    2157              :                  * Fall through to set the dump flag; we assume that the subsequent
    2158              :                  * rules will do the same thing as they would for the array's base
    2159              :                  * type or multirange's range type.  (We cannot reliably look up the
    2160              :                  * base type here, since getTypes may not have processed it yet.)
    2161              :                  */
    2162            0 :         }
    2163              : 
    2164            0 :         if (checkExtensionMembership(&tyinfo->dobj, fout))
    2165            0 :                 return;                                 /* extension membership overrides all else */
    2166              : 
    2167              :         /* Dump based on if the contents of the namespace are being dumped */
    2168            0 :         tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    2169            0 : }
    2170              : 
    2171              : /*
    2172              :  * selectDumpableDefaultACL: policy-setting subroutine
    2173              :  *              Mark a default ACL as to be dumped or not
    2174              :  *
    2175              :  * For per-schema default ACLs, dump if the schema is to be dumped.
    2176              :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    2177              :  * and aclsSkip are checked separately.
    2178              :  */
    2179              : static void
    2180            0 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2181              : {
    2182              :         /* Default ACLs can't be extension members */
    2183              : 
    2184            0 :         if (dinfo->dobj.namespace)
    2185              :                 /* default ACLs are considered part of the namespace */
    2186            0 :                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2187              :         else
    2188            0 :                 dinfo->dobj.dump = dopt->include_everything ?
    2189              :                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2190            0 : }
    2191              : 
    2192              : /*
    2193              :  * selectDumpableCast: policy-setting subroutine
    2194              :  *              Mark a cast as to be dumped or not
    2195              :  *
    2196              :  * Casts do not belong to any particular namespace (since they haven't got
    2197              :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2198              :  * casts from built-in ones, we must resort to checking whether the cast's
    2199              :  * OID is in the range reserved for initdb.
    2200              :  */
    2201              : static void
    2202            0 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2203              : {
    2204            0 :         if (checkExtensionMembership(&cast->dobj, fout))
    2205            0 :                 return;                                 /* extension membership overrides all else */
    2206              : 
    2207              :         /*
    2208              :          * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2209              :          * support ACLs currently.
    2210              :          */
    2211            0 :         if (cast->dobj.catId.oid <= g_last_builtin_oid)
    2212            0 :                 cast->dobj.dump = DUMP_COMPONENT_NONE;
    2213              :         else
    2214            0 :                 cast->dobj.dump = fout->dopt->include_everything ?
    2215              :                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2216            0 : }
    2217              : 
    2218              : /*
    2219              :  * selectDumpableProcLang: policy-setting subroutine
    2220              :  *              Mark a procedural language as to be dumped or not
    2221              :  *
    2222              :  * Procedural languages do not belong to any particular namespace.  To
    2223              :  * identify built-in languages, we must resort to checking whether the
    2224              :  * language's OID is in the range reserved for initdb.
    2225              :  */
    2226              : static void
    2227            0 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2228              : {
    2229            0 :         if (checkExtensionMembership(&plang->dobj, fout))
    2230            0 :                 return;                                 /* extension membership overrides all else */
    2231              : 
    2232              :         /*
    2233              :          * Only include procedural languages when we are dumping everything.
    2234              :          *
    2235              :          * For from-initdb procedural languages, only include ACLs, as we do for
    2236              :          * the pg_catalog namespace.  We need this because procedural languages do
    2237              :          * not live in any namespace.
    2238              :          */
    2239            0 :         if (!fout->dopt->include_everything)
    2240            0 :                 plang->dobj.dump = DUMP_COMPONENT_NONE;
    2241              :         else
    2242              :         {
    2243            0 :                 if (plang->dobj.catId.oid <= g_last_builtin_oid)
    2244            0 :                         plang->dobj.dump = fout->remoteVersion < 90600 ?
    2245              :                                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    2246              :                 else
    2247            0 :                         plang->dobj.dump = DUMP_COMPONENT_ALL;
    2248              :         }
    2249            0 : }
    2250              : 
    2251              : /*
    2252              :  * selectDumpableAccessMethod: policy-setting subroutine
    2253              :  *              Mark an access method as to be dumped or not
    2254              :  *
    2255              :  * Access methods do not belong to any particular namespace.  To identify
    2256              :  * built-in access methods, we must resort to checking whether the
    2257              :  * method's OID is in the range reserved for initdb.
    2258              :  */
    2259              : static void
    2260            0 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2261              : {
    2262              :         /* see getAccessMethods() comment about v9.6. */
    2263            0 :         if (fout->remoteVersion < 90600)
    2264              :         {
    2265            0 :                 method->dobj.dump = DUMP_COMPONENT_NONE;
    2266            0 :                 return;
    2267              :         }
    2268              : 
    2269            0 :         if (checkExtensionMembership(&method->dobj, fout))
    2270            0 :                 return;                                 /* extension membership overrides all else */
    2271              : 
    2272              :         /*
    2273              :          * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2274              :          * they do not support ACLs currently.
    2275              :          */
    2276            0 :         if (method->dobj.catId.oid <= g_last_builtin_oid)
    2277            0 :                 method->dobj.dump = DUMP_COMPONENT_NONE;
    2278              :         else
    2279            0 :                 method->dobj.dump = fout->dopt->include_everything ?
    2280              :                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2281            0 : }
    2282              : 
    2283              : /*
    2284              :  * selectDumpableExtension: policy-setting subroutine
    2285              :  *              Mark an extension as to be dumped or not
    2286              :  *
    2287              :  * Built-in extensions should be skipped except for checking ACLs, since we
    2288              :  * assume those will already be installed in the target database.  We identify
    2289              :  * such extensions by their having OIDs in the range reserved for initdb.
    2290              :  * We dump all user-added extensions by default.  No extensions are dumped
    2291              :  * if include_everything is false (i.e., a --schema or --table switch was
    2292              :  * given), except if --extension specifies a list of extensions to dump.
    2293              :  */
    2294              : static void
    2295            0 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2296              : {
    2297              :         /*
    2298              :          * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2299              :          * change permissions on their member objects, if they wish to, and have
    2300              :          * those changes preserved.
    2301              :          */
    2302            0 :         if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
    2303            0 :                 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2304              :         else
    2305              :         {
    2306              :                 /* check if there is a list of extensions to dump */
    2307            0 :                 if (extension_include_oids.head != NULL)
    2308            0 :                         extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2309            0 :                                 simple_oid_list_member(&extension_include_oids,
    2310            0 :                                                                            extinfo->dobj.catId.oid) ?
    2311              :                                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2312              :                 else
    2313            0 :                         extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2314            0 :                                 dopt->include_everything ?
    2315              :                                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2316              : 
    2317              :                 /* check that the extension is not explicitly excluded */
    2318            0 :                 if (extinfo->dobj.dump &&
    2319            0 :                         simple_oid_list_member(&extension_exclude_oids,
    2320            0 :                                                                    extinfo->dobj.catId.oid))
    2321            0 :                         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2322              :         }
    2323            0 : }
    2324              : 
    2325              : /*
    2326              :  * selectDumpablePublicationObject: policy-setting subroutine
    2327              :  *              Mark a publication object as to be dumped or not
    2328              :  *
    2329              :  * A publication can have schemas and tables which have schemas, but those are
    2330              :  * ignored in decision making, because publications are only dumped when we are
    2331              :  * dumping everything.
    2332              :  */
    2333              : static void
    2334            0 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2335              : {
    2336            0 :         if (checkExtensionMembership(dobj, fout))
    2337            0 :                 return;                                 /* extension membership overrides all else */
    2338              : 
    2339            0 :         dobj->dump = fout->dopt->include_everything ?
    2340              :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2341            0 : }
    2342              : 
    2343              : /*
    2344              :  * selectDumpableStatisticsObject: policy-setting subroutine
    2345              :  *              Mark an extended statistics object as to be dumped or not
    2346              :  *
    2347              :  * We dump an extended statistics object if the schema it's in and the table
    2348              :  * it's for are being dumped.  (This'll need more thought if statistics
    2349              :  * objects ever support cross-table stats.)
    2350              :  */
    2351              : static void
    2352            0 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2353              : {
    2354            0 :         if (checkExtensionMembership(&sobj->dobj, fout))
    2355            0 :                 return;                                 /* extension membership overrides all else */
    2356              : 
    2357            0 :         sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2358            0 :         if (sobj->stattable == NULL ||
    2359            0 :                 !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2360            0 :                 sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2361            0 : }
    2362              : 
    2363              : /*
    2364              :  * selectDumpableObject: policy-setting subroutine
    2365              :  *              Mark a generic dumpable object as to be dumped or not
    2366              :  *
    2367              :  * Use this only for object types without a special-case routine above.
    2368              :  */
    2369              : static void
    2370            0 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2371              : {
    2372            0 :         if (checkExtensionMembership(dobj, fout))
    2373            0 :                 return;                                 /* extension membership overrides all else */
    2374              : 
    2375              :         /*
    2376              :          * Default policy is to dump if parent namespace is dumpable, or for
    2377              :          * non-namespace-associated items, dump if we're dumping "everything".
    2378              :          */
    2379            0 :         if (dobj->namespace)
    2380            0 :                 dobj->dump = dobj->namespace->dobj.dump_contains;
    2381              :         else
    2382            0 :                 dobj->dump = fout->dopt->include_everything ?
    2383              :                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2384            0 : }
    2385              : 
    2386              : /*
    2387              :  *      Dump a table's contents for loading using the COPY command
    2388              :  *      - this routine is called by the Archiver when it wants the table
    2389              :  *        to be dumped.
    2390              :  */
    2391              : static int
    2392            0 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2393              : {
    2394            0 :         const TableDataInfo *tdinfo = dcontext;
    2395            0 :         const TableInfo *tbinfo = tdinfo->tdtable;
    2396            0 :         const char *classname = tbinfo->dobj.name;
    2397            0 :         PQExpBuffer q = createPQExpBuffer();
    2398              : 
    2399              :         /*
    2400              :          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2401              :          * which uses it already.
    2402              :          */
    2403            0 :         PQExpBuffer clistBuf = createPQExpBuffer();
    2404            0 :         PGconn     *conn = GetConnection(fout);
    2405            0 :         PGresult   *res;
    2406            0 :         int                     ret;
    2407            0 :         char       *copybuf;
    2408            0 :         const char *column_list;
    2409              : 
    2410            0 :         pg_log_info("dumping contents of table \"%s.%s\"",
    2411              :                                 tbinfo->dobj.namespace->dobj.name, classname);
    2412              : 
    2413              :         /*
    2414              :          * Specify the column list explicitly so that we have no possibility of
    2415              :          * retrieving data in the wrong column order.  (The default column
    2416              :          * ordering of COPY will not be what we want in certain corner cases
    2417              :          * involving ADD COLUMN and inheritance.)
    2418              :          */
    2419            0 :         column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2420              : 
    2421              :         /*
    2422              :          * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
    2423              :          * a filter condition was specified.  For other cases a simple COPY
    2424              :          * suffices.
    2425              :          */
    2426            0 :         if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2427              :         {
    2428              :                 /* Temporary allows to access to foreign tables to dump data */
    2429            0 :                 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2430            0 :                         set_restrict_relation_kind(fout, "view");
    2431              : 
    2432            0 :                 appendPQExpBufferStr(q, "COPY (SELECT ");
    2433              :                 /* klugery to get rid of parens in column list */
    2434            0 :                 if (strlen(column_list) > 2)
    2435              :                 {
    2436            0 :                         appendPQExpBufferStr(q, column_list + 1);
    2437            0 :                         q->data[q->len - 1] = ' ';
    2438            0 :                 }
    2439              :                 else
    2440            0 :                         appendPQExpBufferStr(q, "* ");
    2441              : 
    2442            0 :                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2443            0 :                                                   fmtQualifiedDumpable(tbinfo),
    2444            0 :                                                   tdinfo->filtercond ? tdinfo->filtercond : "");
    2445            0 :         }
    2446              :         else
    2447              :         {
    2448            0 :                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2449            0 :                                                   fmtQualifiedDumpable(tbinfo),
    2450            0 :                                                   column_list);
    2451              :         }
    2452            0 :         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2453            0 :         PQclear(res);
    2454            0 :         destroyPQExpBuffer(clistBuf);
    2455              : 
    2456            0 :         for (;;)
    2457              :         {
    2458            0 :                 ret = PQgetCopyData(conn, &copybuf, 0);
    2459              : 
    2460            0 :                 if (ret < 0)
    2461            0 :                         break;                          /* done or error */
    2462              : 
    2463            0 :                 if (copybuf)
    2464              :                 {
    2465            0 :                         WriteData(fout, copybuf, ret);
    2466            0 :                         PQfreemem(copybuf);
    2467            0 :                 }
    2468              : 
    2469              :                 /* ----------
    2470              :                  * THROTTLE:
    2471              :                  *
    2472              :                  * There was considerable discussion in late July, 2000 regarding
    2473              :                  * slowing down pg_dump when backing up large tables. Users with both
    2474              :                  * slow & fast (multi-processor) machines experienced performance
    2475              :                  * degradation when doing a backup.
    2476              :                  *
    2477              :                  * Initial attempts based on sleeping for a number of ms for each ms
    2478              :                  * of work were deemed too complex, then a simple 'sleep in each loop'
    2479              :                  * implementation was suggested. The latter failed because the loop
    2480              :                  * was too tight. Finally, the following was implemented:
    2481              :                  *
    2482              :                  * If throttle is non-zero, then
    2483              :                  *              See how long since the last sleep.
    2484              :                  *              Work out how long to sleep (based on ratio).
    2485              :                  *              If sleep is more than 100ms, then
    2486              :                  *                      sleep
    2487              :                  *                      reset timer
    2488              :                  *              EndIf
    2489              :                  * EndIf
    2490              :                  *
    2491              :                  * where the throttle value was the number of ms to sleep per ms of
    2492              :                  * work. The calculation was done in each loop.
    2493              :                  *
    2494              :                  * Most of the hard work is done in the backend, and this solution
    2495              :                  * still did not work particularly well: on slow machines, the ratio
    2496              :                  * was 50:1, and on medium paced machines, 1:1, and on fast
    2497              :                  * multi-processor machines, it had little or no effect, for reasons
    2498              :                  * that were unclear.
    2499              :                  *
    2500              :                  * Further discussion ensued, and the proposal was dropped.
    2501              :                  *
    2502              :                  * For those people who want this feature, it can be implemented using
    2503              :                  * gettimeofday in each loop, calculating the time since last sleep,
    2504              :                  * multiplying that by the sleep ratio, then if the result is more
    2505              :                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2506              :                  * function to sleep for a subsecond period ie.
    2507              :                  *
    2508              :                  * select(0, NULL, NULL, NULL, &tvi);
    2509              :                  *
    2510              :                  * This will return after the interval specified in the structure tvi.
    2511              :                  * Finally, call gettimeofday again to save the 'last sleep time'.
    2512              :                  * ----------
    2513              :                  */
    2514              :         }
    2515            0 :         archprintf(fout, "\\.\n\n\n");
    2516              : 
    2517            0 :         if (ret == -2)
    2518              :         {
    2519              :                 /* copy data transfer failed */
    2520            0 :                 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2521            0 :                 pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2522            0 :                 pg_log_error_detail("Command was: %s", q->data);
    2523            0 :                 exit_nicely(1);
    2524              :         }
    2525              : 
    2526              :         /* Check command status and return to normal libpq state */
    2527            0 :         res = PQgetResult(conn);
    2528            0 :         if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2529              :         {
    2530            0 :                 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2531            0 :                 pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2532            0 :                 pg_log_error_detail("Command was: %s", q->data);
    2533            0 :                 exit_nicely(1);
    2534              :         }
    2535            0 :         PQclear(res);
    2536              : 
    2537              :         /* Do this to ensure we've pumped libpq back to idle state */
    2538            0 :         if (PQgetResult(conn) != NULL)
    2539            0 :                 pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2540              :                                            classname);
    2541              : 
    2542            0 :         destroyPQExpBuffer(q);
    2543              : 
    2544              :         /* Revert back the setting */
    2545            0 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2546            0 :                 set_restrict_relation_kind(fout, "view, foreign-table");
    2547              : 
    2548            0 :         return 1;
    2549            0 : }
    2550              : 
    2551              : /*
    2552              :  * Dump table data using INSERT commands.
    2553              :  *
    2554              :  * Caution: when we restore from an archive file direct to database, the
    2555              :  * INSERT commands emitted by this function have to be parsed by
    2556              :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2557              :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2558              :  */
    2559              : static int
    2560            0 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2561              : {
    2562            0 :         const TableDataInfo *tdinfo = dcontext;
    2563            0 :         const TableInfo *tbinfo = tdinfo->tdtable;
    2564            0 :         DumpOptions *dopt = fout->dopt;
    2565            0 :         PQExpBuffer q = createPQExpBuffer();
    2566            0 :         PQExpBuffer insertStmt = NULL;
    2567            0 :         char       *attgenerated;
    2568            0 :         PGresult   *res;
    2569            0 :         int                     nfields,
    2570              :                                 i;
    2571            0 :         int                     rows_per_statement = dopt->dump_inserts;
    2572            0 :         int                     rows_this_statement = 0;
    2573              : 
    2574              :         /* Temporary allows to access to foreign tables to dump data */
    2575            0 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2576            0 :                 set_restrict_relation_kind(fout, "view");
    2577              : 
    2578              :         /*
    2579              :          * If we're going to emit INSERTs with column names, the most efficient
    2580              :          * way to deal with generated columns is to exclude them entirely.  For
    2581              :          * INSERTs without column names, we have to emit DEFAULT rather than the
    2582              :          * actual column value --- but we can save a few cycles by fetching nulls
    2583              :          * rather than the uninteresting-to-us value.
    2584              :          */
    2585            0 :         attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
    2586            0 :         appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2587            0 :         nfields = 0;
    2588            0 :         for (i = 0; i < tbinfo->numatts; i++)
    2589              :         {
    2590            0 :                 if (tbinfo->attisdropped[i])
    2591            0 :                         continue;
    2592            0 :                 if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2593            0 :                         continue;
    2594            0 :                 if (nfields > 0)
    2595            0 :                         appendPQExpBufferStr(q, ", ");
    2596            0 :                 if (tbinfo->attgenerated[i])
    2597            0 :                         appendPQExpBufferStr(q, "NULL");
    2598              :                 else
    2599            0 :                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2600            0 :                 attgenerated[nfields] = tbinfo->attgenerated[i];
    2601            0 :                 nfields++;
    2602            0 :         }
    2603              :         /* Servers before 9.4 will complain about zero-column SELECT */
    2604            0 :         if (nfields == 0)
    2605            0 :                 appendPQExpBufferStr(q, "NULL");
    2606            0 :         appendPQExpBuffer(q, " FROM ONLY %s",
    2607            0 :                                           fmtQualifiedDumpable(tbinfo));
    2608            0 :         if (tdinfo->filtercond)
    2609            0 :                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2610              : 
    2611            0 :         ExecuteSqlStatement(fout, q->data);
    2612              : 
    2613            0 :         while (1)
    2614              :         {
    2615            0 :                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2616              :                                                           PGRES_TUPLES_OK);
    2617              : 
    2618              :                 /* cross-check field count, allowing for dummy NULL if any */
    2619            0 :                 if (nfields != PQnfields(res) &&
    2620            0 :                         !(nfields == 0 && PQnfields(res) == 1))
    2621            0 :                         pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2622              :                                          tbinfo->dobj.name);
    2623              : 
    2624              :                 /*
    2625              :                  * First time through, we build as much of the INSERT statement as
    2626              :                  * possible in "insertStmt", which we can then just print for each
    2627              :                  * statement. If the table happens to have zero dumpable columns then
    2628              :                  * this will be a complete statement, otherwise it will end in
    2629              :                  * "VALUES" and be ready to have the row's column values printed.
    2630              :                  */
    2631            0 :                 if (insertStmt == NULL)
    2632              :                 {
    2633            0 :                         const TableInfo *targettab;
    2634              : 
    2635            0 :                         insertStmt = createPQExpBuffer();
    2636              : 
    2637              :                         /*
    2638              :                          * When load-via-partition-root is set or forced, get the root
    2639              :                          * table name for the partition table, so that we can reload data
    2640              :                          * through the root table.
    2641              :                          */
    2642            0 :                         if (tbinfo->ispartition &&
    2643            0 :                                 (dopt->load_via_partition_root ||
    2644            0 :                                  forcePartitionRootLoad(tbinfo)))
    2645            0 :                                 targettab = getRootTableInfo(tbinfo);
    2646              :                         else
    2647            0 :                                 targettab = tbinfo;
    2648              : 
    2649            0 :                         appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2650            0 :                                                           fmtQualifiedDumpable(targettab));
    2651              : 
    2652              :                         /* corner case for zero-column table */
    2653            0 :                         if (nfields == 0)
    2654              :                         {
    2655            0 :                                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2656            0 :                         }
    2657              :                         else
    2658              :                         {
    2659              :                                 /* append the list of column names if required */
    2660            0 :                                 if (dopt->column_inserts)
    2661              :                                 {
    2662            0 :                                         appendPQExpBufferChar(insertStmt, '(');
    2663            0 :                                         for (int field = 0; field < nfields; field++)
    2664              :                                         {
    2665            0 :                                                 if (field > 0)
    2666            0 :                                                         appendPQExpBufferStr(insertStmt, ", ");
    2667            0 :                                                 appendPQExpBufferStr(insertStmt,
    2668            0 :                                                                                          fmtId(PQfname(res, field)));
    2669            0 :                                         }
    2670            0 :                                         appendPQExpBufferStr(insertStmt, ") ");
    2671            0 :                                 }
    2672              : 
    2673            0 :                                 if (tbinfo->needs_override)
    2674            0 :                                         appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2675              : 
    2676            0 :                                 appendPQExpBufferStr(insertStmt, "VALUES");
    2677              :                         }
    2678            0 :                 }
    2679              : 
    2680            0 :                 for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2681              :                 {
    2682              :                         /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2683            0 :                         if (rows_this_statement == 0)
    2684            0 :                                 archputs(insertStmt->data, fout);
    2685              : 
    2686              :                         /*
    2687              :                          * If it is zero-column table then we've already written the
    2688              :                          * complete statement, which will mean we've disobeyed
    2689              :                          * --rows-per-insert when it's set greater than 1.  We do support
    2690              :                          * a way to make this multi-row with: SELECT UNION ALL SELECT
    2691              :                          * UNION ALL ... but that's non-standard so we should avoid it
    2692              :                          * given that using INSERTs is mostly only ever needed for
    2693              :                          * cross-database exports.
    2694              :                          */
    2695            0 :                         if (nfields == 0)
    2696            0 :                                 continue;
    2697              : 
    2698              :                         /* Emit a row heading */
    2699            0 :                         if (rows_per_statement == 1)
    2700            0 :                                 archputs(" (", fout);
    2701            0 :                         else if (rows_this_statement > 0)
    2702            0 :                                 archputs(",\n\t(", fout);
    2703              :                         else
    2704            0 :                                 archputs("\n\t(", fout);
    2705              : 
    2706            0 :                         for (int field = 0; field < nfields; field++)
    2707              :                         {
    2708            0 :                                 if (field > 0)
    2709            0 :                                         archputs(", ", fout);
    2710            0 :                                 if (attgenerated[field])
    2711              :                                 {
    2712            0 :                                         archputs("DEFAULT", fout);
    2713            0 :                                         continue;
    2714              :                                 }
    2715            0 :                                 if (PQgetisnull(res, tuple, field))
    2716              :                                 {
    2717            0 :                                         archputs("NULL", fout);
    2718            0 :                                         continue;
    2719              :                                 }
    2720              : 
    2721              :                                 /* XXX This code is partially duplicated in ruleutils.c */
    2722            0 :                                 switch (PQftype(res, field))
    2723              :                                 {
    2724              :                                         case INT2OID:
    2725              :                                         case INT4OID:
    2726              :                                         case INT8OID:
    2727              :                                         case OIDOID:
    2728              :                                         case FLOAT4OID:
    2729              :                                         case FLOAT8OID:
    2730              :                                         case NUMERICOID:
    2731              :                                                 {
    2732              :                                                         /*
    2733              :                                                          * These types are printed without quotes unless
    2734              :                                                          * they contain values that aren't accepted by the
    2735              :                                                          * scanner unquoted (e.g., 'NaN').  Note that
    2736              :                                                          * strtod() and friends might accept NaN, so we
    2737              :                                                          * can't use that to test.
    2738              :                                                          *
    2739              :                                                          * In reality we only need to defend against
    2740              :                                                          * infinity and NaN, so we need not get too crazy
    2741              :                                                          * about pattern matching here.
    2742              :                                                          */
    2743            0 :                                                         const char *s = PQgetvalue(res, tuple, field);
    2744              : 
    2745            0 :                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2746            0 :                                                                 archputs(s, fout);
    2747              :                                                         else
    2748            0 :                                                                 archprintf(fout, "'%s'", s);
    2749            0 :                                                 }
    2750            0 :                                                 break;
    2751              : 
    2752              :                                         case BITOID:
    2753              :                                         case VARBITOID:
    2754            0 :                                                 archprintf(fout, "B'%s'",
    2755            0 :                                                                    PQgetvalue(res, tuple, field));
    2756            0 :                                                 break;
    2757              : 
    2758              :                                         case BOOLOID:
    2759            0 :                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2760            0 :                                                         archputs("true", fout);
    2761              :                                                 else
    2762            0 :                                                         archputs("false", fout);
    2763            0 :                                                 break;
    2764              : 
    2765              :                                         default:
    2766              :                                                 /* All other types are printed as string literals. */
    2767            0 :                                                 resetPQExpBuffer(q);
    2768            0 :                                                 appendStringLiteralAH(q,
    2769              :                                                                                           PQgetvalue(res, tuple, field),
    2770              :                                                                                           fout);
    2771            0 :                                                 archputs(q->data, fout);
    2772            0 :                                                 break;
    2773              :                                 }
    2774            0 :                         }
    2775              : 
    2776              :                         /* Terminate the row ... */
    2777            0 :                         archputs(")", fout);
    2778              : 
    2779              :                         /* ... and the statement, if the target no. of rows is reached */
    2780            0 :                         if (++rows_this_statement >= rows_per_statement)
    2781              :                         {
    2782            0 :                                 if (dopt->do_nothing)
    2783            0 :                                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2784              :                                 else
    2785            0 :                                         archputs(";\n", fout);
    2786              :                                 /* Reset the row counter */
    2787            0 :                                 rows_this_statement = 0;
    2788            0 :                         }
    2789            0 :                 }
    2790              : 
    2791            0 :                 if (PQntuples(res) <= 0)
    2792              :                 {
    2793            0 :                         PQclear(res);
    2794            0 :                         break;
    2795              :                 }
    2796            0 :                 PQclear(res);
    2797              :         }
    2798              : 
    2799              :         /* Terminate any statements that didn't make the row count. */
    2800            0 :         if (rows_this_statement > 0)
    2801              :         {
    2802            0 :                 if (dopt->do_nothing)
    2803            0 :                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2804              :                 else
    2805            0 :                         archputs(";\n", fout);
    2806            0 :         }
    2807              : 
    2808            0 :         archputs("\n\n", fout);
    2809              : 
    2810            0 :         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2811              : 
    2812            0 :         destroyPQExpBuffer(q);
    2813            0 :         if (insertStmt != NULL)
    2814            0 :                 destroyPQExpBuffer(insertStmt);
    2815            0 :         free(attgenerated);
    2816              : 
    2817              :         /* Revert back the setting */
    2818            0 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2819            0 :                 set_restrict_relation_kind(fout, "view, foreign-table");
    2820              : 
    2821            0 :         return 1;
    2822            0 : }
    2823              : 
    2824              : /*
    2825              :  * getRootTableInfo:
    2826              :  *     get the root TableInfo for the given partition table.
    2827              :  */
    2828              : static TableInfo *
    2829            0 : getRootTableInfo(const TableInfo *tbinfo)
    2830              : {
    2831            0 :         TableInfo  *parentTbinfo;
    2832              : 
    2833            0 :         Assert(tbinfo->ispartition);
    2834            0 :         Assert(tbinfo->numParents == 1);
    2835              : 
    2836            0 :         parentTbinfo = tbinfo->parents[0];
    2837            0 :         while (parentTbinfo->ispartition)
    2838              :         {
    2839            0 :                 Assert(parentTbinfo->numParents == 1);
    2840            0 :                 parentTbinfo = parentTbinfo->parents[0];
    2841              :         }
    2842              : 
    2843            0 :         return parentTbinfo;
    2844            0 : }
    2845              : 
    2846              : /*
    2847              :  * forcePartitionRootLoad
    2848              :  *     Check if we must force load_via_partition_root for this partition.
    2849              :  *
    2850              :  * This is required if any level of ancestral partitioned table has an
    2851              :  * unsafe partitioning scheme.
    2852              :  */
    2853              : static bool
    2854            0 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2855              : {
    2856            0 :         TableInfo  *parentTbinfo;
    2857              : 
    2858            0 :         Assert(tbinfo->ispartition);
    2859            0 :         Assert(tbinfo->numParents == 1);
    2860              : 
    2861            0 :         parentTbinfo = tbinfo->parents[0];
    2862            0 :         if (parentTbinfo->unsafe_partitions)
    2863            0 :                 return true;
    2864            0 :         while (parentTbinfo->ispartition)
    2865              :         {
    2866            0 :                 Assert(parentTbinfo->numParents == 1);
    2867            0 :                 parentTbinfo = parentTbinfo->parents[0];
    2868            0 :                 if (parentTbinfo->unsafe_partitions)
    2869            0 :                         return true;
    2870              :         }
    2871              : 
    2872            0 :         return false;
    2873            0 : }
    2874              : 
    2875              : /*
    2876              :  * dumpTableData -
    2877              :  *        dump the contents of a single table
    2878              :  *
    2879              :  * Actually, this just makes an ArchiveEntry for the table contents.
    2880              :  */
    2881              : static void
    2882            0 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2883              : {
    2884            0 :         DumpOptions *dopt = fout->dopt;
    2885            0 :         const TableInfo *tbinfo = tdinfo->tdtable;
    2886            0 :         PQExpBuffer copyBuf = createPQExpBuffer();
    2887            0 :         PQExpBuffer clistBuf = createPQExpBuffer();
    2888            0 :         DataDumperPtr dumpFn;
    2889            0 :         char       *tdDefn = NULL;
    2890            0 :         char       *copyStmt;
    2891            0 :         const char *copyFrom;
    2892              : 
    2893              :         /* We had better have loaded per-column details about this table */
    2894            0 :         Assert(tbinfo->interesting);
    2895              : 
    2896              :         /*
    2897              :          * When load-via-partition-root is set or forced, get the root table name
    2898              :          * for the partition table, so that we can reload data through the root
    2899              :          * table.  Then construct a comment to be inserted into the TOC entry's
    2900              :          * defn field, so that such cases can be identified reliably.
    2901              :          */
    2902            0 :         if (tbinfo->ispartition &&
    2903            0 :                 (dopt->load_via_partition_root ||
    2904            0 :                  forcePartitionRootLoad(tbinfo)))
    2905              :         {
    2906            0 :                 const TableInfo *parentTbinfo;
    2907            0 :                 char       *sanitized;
    2908              : 
    2909            0 :                 parentTbinfo = getRootTableInfo(tbinfo);
    2910            0 :                 copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2911            0 :                 sanitized = sanitize_line(copyFrom, true);
    2912            0 :                 printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2913            0 :                                                   sanitized);
    2914            0 :                 free(sanitized);
    2915            0 :                 tdDefn = pg_strdup(copyBuf->data);
    2916            0 :         }
    2917              :         else
    2918            0 :                 copyFrom = fmtQualifiedDumpable(tbinfo);
    2919              : 
    2920            0 :         if (dopt->dump_inserts == 0)
    2921              :         {
    2922              :                 /* Dump/restore using COPY */
    2923            0 :                 dumpFn = dumpTableData_copy;
    2924              :                 /* must use 2 steps here 'cause fmtId is nonreentrant */
    2925            0 :                 printfPQExpBuffer(copyBuf, "COPY %s ",
    2926            0 :                                                   copyFrom);
    2927            0 :                 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2928            0 :                                                   fmtCopyColumnList(tbinfo, clistBuf));
    2929            0 :                 copyStmt = copyBuf->data;
    2930            0 :         }
    2931              :         else
    2932              :         {
    2933              :                 /* Restore using INSERT */
    2934            0 :                 dumpFn = dumpTableData_insert;
    2935            0 :                 copyStmt = NULL;
    2936              :         }
    2937              : 
    2938              :         /*
    2939              :          * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2940              :          * dependency on its table as "special" and pass it to ArchiveEntry now.
    2941              :          * See comments for BuildArchiveDependencies.
    2942              :          */
    2943            0 :         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2944              :         {
    2945            0 :                 TocEntry   *te;
    2946              : 
    2947            0 :                 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2948            0 :                                                   ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2949              :                                                                            .namespace = tbinfo->dobj.namespace->dobj.name,
    2950              :                                                                            .owner = tbinfo->rolname,
    2951              :                                                                            .description = "TABLE DATA",
    2952              :                                                                            .section = SECTION_DATA,
    2953              :                                                                            .createStmt = tdDefn,
    2954              :                                                                            .copyStmt = copyStmt,
    2955              :                                                                            .deps = &(tbinfo->dobj.dumpId),
    2956              :                                                                            .nDeps = 1,
    2957              :                                                                            .dumpFn = dumpFn,
    2958              :                                                                            .dumpArg = tdinfo));
    2959              : 
    2960              :                 /*
    2961              :                  * Set the TocEntry's dataLength in case we are doing a parallel dump
    2962              :                  * and want to order dump jobs by table size.  We choose to measure
    2963              :                  * dataLength in table pages (including TOAST pages) during dump, so
    2964              :                  * no scaling is needed.
    2965              :                  *
    2966              :                  * However, relpages is declared as "integer" in pg_class, and hence
    2967              :                  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2968              :                  * Cast so that we get the right interpretation of table sizes
    2969              :                  * exceeding INT_MAX pages.
    2970              :                  */
    2971            0 :                 te->dataLength = (BlockNumber) tbinfo->relpages;
    2972            0 :                 te->dataLength += (BlockNumber) tbinfo->toastpages;
    2973              : 
    2974              :                 /*
    2975              :                  * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2976              :                  * and instead we'd better worry about integer overflow.  Clamp to
    2977              :                  * INT_MAX if the correct result exceeds that.
    2978              :                  */
    2979              :                 if (sizeof(te->dataLength) == 4 &&
    2980              :                         (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2981              :                          te->dataLength < 0))
    2982              :                         te->dataLength = INT_MAX;
    2983            0 :         }
    2984              : 
    2985            0 :         destroyPQExpBuffer(copyBuf);
    2986            0 :         destroyPQExpBuffer(clistBuf);
    2987            0 : }
    2988              : 
    2989              : /*
    2990              :  * refreshMatViewData -
    2991              :  *        load or refresh the contents of a single materialized view
    2992              :  *
    2993              :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2994              :  * statement.
    2995              :  */
    2996              : static void
    2997            0 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2998              : {
    2999            0 :         TableInfo  *tbinfo = tdinfo->tdtable;
    3000            0 :         PQExpBuffer q;
    3001              : 
    3002              :         /* If the materialized view is not flagged as populated, skip this. */
    3003            0 :         if (!tbinfo->relispopulated)
    3004            0 :                 return;
    3005              : 
    3006            0 :         q = createPQExpBuffer();
    3007              : 
    3008            0 :         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    3009            0 :                                           fmtQualifiedDumpable(tbinfo));
    3010              : 
    3011            0 :         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    3012            0 :                 ArchiveEntry(fout,
    3013            0 :                                          tdinfo->dobj.catId, /* catalog ID */
    3014            0 :                                          tdinfo->dobj.dumpId,        /* dump ID */
    3015            0 :                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    3016              :                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    3017              :                                                                   .owner = tbinfo->rolname,
    3018              :                                                                   .description = "MATERIALIZED VIEW DATA",
    3019              :                                                                   .section = SECTION_POST_DATA,
    3020              :                                                                   .createStmt = q->data,
    3021              :                                                                   .deps = tdinfo->dobj.dependencies,
    3022              :                                                                   .nDeps = tdinfo->dobj.nDeps));
    3023              : 
    3024            0 :         destroyPQExpBuffer(q);
    3025            0 : }
    3026              : 
    3027              : /*
    3028              :  * getTableData -
    3029              :  *        set up dumpable objects representing the contents of tables
    3030              :  */
    3031              : static void
    3032            0 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    3033              : {
    3034            0 :         int                     i;
    3035              : 
    3036            0 :         for (i = 0; i < numTables; i++)
    3037              :         {
    3038            0 :                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    3039            0 :                         (!relkind || tblinfo[i].relkind == relkind))
    3040            0 :                         makeTableDataInfo(dopt, &(tblinfo[i]));
    3041            0 :         }
    3042            0 : }
    3043              : 
    3044              : /*
    3045              :  * Make a dumpable object for the data of this specific table
    3046              :  *
    3047              :  * Note: we make a TableDataInfo if and only if we are going to dump the
    3048              :  * table data; the "dump" field in such objects isn't very interesting.
    3049              :  */
    3050              : static void
    3051            0 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    3052              : {
    3053            0 :         TableDataInfo *tdinfo;
    3054              : 
    3055              :         /*
    3056              :          * Nothing to do if we already decided to dump the table.  This will
    3057              :          * happen for "config" tables.
    3058              :          */
    3059            0 :         if (tbinfo->dataObj != NULL)
    3060            0 :                 return;
    3061              : 
    3062              :         /* Skip VIEWs (no data to dump) */
    3063            0 :         if (tbinfo->relkind == RELKIND_VIEW)
    3064            0 :                 return;
    3065              :         /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    3066            0 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    3067            0 :                 (foreign_servers_include_oids.head == NULL ||
    3068            0 :                  !simple_oid_list_member(&foreign_servers_include_oids,
    3069            0 :                                                                  tbinfo->foreign_server)))
    3070            0 :                 return;
    3071              :         /* Skip partitioned tables (data in partitions) */
    3072            0 :         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    3073            0 :                 return;
    3074              : 
    3075              :         /* Don't dump data in unlogged tables, if so requested */
    3076            0 :         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    3077            0 :                 dopt->no_unlogged_table_data)
    3078            0 :                 return;
    3079              : 
    3080              :         /* Check that the data is not explicitly excluded */
    3081            0 :         if (simple_oid_list_member(&tabledata_exclude_oids,
    3082            0 :                                                            tbinfo->dobj.catId.oid))
    3083            0 :                 return;
    3084              : 
    3085              :         /* OK, let's dump it */
    3086            0 :         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
    3087              : 
    3088            0 :         if (tbinfo->relkind == RELKIND_MATVIEW)
    3089            0 :                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    3090            0 :         else if (tbinfo->relkind == RELKIND_SEQUENCE)
    3091            0 :                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
    3092              :         else
    3093            0 :                 tdinfo->dobj.objType = DO_TABLE_DATA;
    3094              : 
    3095              :         /*
    3096              :          * Note: use tableoid 0 so that this object won't be mistaken for
    3097              :          * something that pg_depend entries apply to.
    3098              :          */
    3099            0 :         tdinfo->dobj.catId.tableoid = 0;
    3100            0 :         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3101            0 :         AssignDumpId(&tdinfo->dobj);
    3102            0 :         tdinfo->dobj.name = tbinfo->dobj.name;
    3103            0 :         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    3104            0 :         tdinfo->tdtable = tbinfo;
    3105            0 :         tdinfo->filtercond = NULL;   /* might get set later */
    3106            0 :         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    3107              : 
    3108              :         /* A TableDataInfo contains data, of course */
    3109            0 :         tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3110              : 
    3111            0 :         tbinfo->dataObj = tdinfo;
    3112              : 
    3113              :         /*
    3114              :          * Materialized view statistics must be restored after the data, because
    3115              :          * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
    3116              :          *
    3117              :          * The dependency is added here because the statistics objects are created
    3118              :          * first.
    3119              :          */
    3120            0 :         if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
    3121              :         {
    3122            0 :                 tbinfo->stats->section = SECTION_POST_DATA;
    3123            0 :                 addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
    3124            0 :         }
    3125              : 
    3126              :         /* Make sure that we'll collect per-column info for this table. */
    3127            0 :         tbinfo->interesting = true;
    3128            0 : }
    3129              : 
    3130              : /*
    3131              :  * The refresh for a materialized view must be dependent on the refresh for
    3132              :  * any materialized view that this one is dependent on.
    3133              :  *
    3134              :  * This must be called after all the objects are created, but before they are
    3135              :  * sorted.
    3136              :  */
    3137              : static void
    3138            0 : buildMatViewRefreshDependencies(Archive *fout)
    3139              : {
    3140            0 :         PQExpBuffer query;
    3141            0 :         PGresult   *res;
    3142            0 :         int                     ntups,
    3143              :                                 i;
    3144            0 :         int                     i_classid,
    3145              :                                 i_objid,
    3146              :                                 i_refobjid;
    3147              : 
    3148              :         /* No Mat Views before 9.3. */
    3149            0 :         if (fout->remoteVersion < 90300)
    3150            0 :                 return;
    3151              : 
    3152            0 :         query = createPQExpBuffer();
    3153              : 
    3154            0 :         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    3155              :                                                  "( "
    3156              :                                                  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    3157              :                                                  "FROM pg_depend d1 "
    3158              :                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
    3159              :                                                  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    3160              :                                                  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    3161              :                                                  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    3162              :                                                  "AND d2.objid = r1.oid "
    3163              :                                                  "AND d2.refobjid <> d1.objid "
    3164              :                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    3165              :                                                  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3166              :                                                  CppAsString2(RELKIND_VIEW) ") "
    3167              :                                                  "WHERE d1.classid = 'pg_class'::regclass "
    3168              :                                                  "UNION "
    3169              :                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
    3170              :                                                  "FROM w "
    3171              :                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    3172              :                                                  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    3173              :                                                  "AND d3.objid = r3.oid "
    3174              :                                                  "AND d3.refobjid <> w.refobjid "
    3175              :                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    3176              :                                                  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3177              :                                                  CppAsString2(RELKIND_VIEW) ") "
    3178              :                                                  ") "
    3179              :                                                  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    3180              :                                                  "FROM w "
    3181              :                                                  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    3182              : 
    3183            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3184              : 
    3185            0 :         ntups = PQntuples(res);
    3186              : 
    3187            0 :         i_classid = PQfnumber(res, "classid");
    3188            0 :         i_objid = PQfnumber(res, "objid");
    3189            0 :         i_refobjid = PQfnumber(res, "refobjid");
    3190              : 
    3191            0 :         for (i = 0; i < ntups; i++)
    3192              :         {
    3193            0 :                 CatalogId       objId;
    3194            0 :                 CatalogId       refobjId;
    3195            0 :                 DumpableObject *dobj;
    3196            0 :                 DumpableObject *refdobj;
    3197            0 :                 TableInfo  *tbinfo;
    3198            0 :                 TableInfo  *reftbinfo;
    3199              : 
    3200            0 :                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3201            0 :                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3202            0 :                 refobjId.tableoid = objId.tableoid;
    3203            0 :                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3204              : 
    3205            0 :                 dobj = findObjectByCatalogId(objId);
    3206            0 :                 if (dobj == NULL)
    3207            0 :                         continue;
    3208              : 
    3209            0 :                 Assert(dobj->objType == DO_TABLE);
    3210            0 :                 tbinfo = (TableInfo *) dobj;
    3211            0 :                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3212            0 :                 dobj = (DumpableObject *) tbinfo->dataObj;
    3213            0 :                 if (dobj == NULL)
    3214            0 :                         continue;
    3215            0 :                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3216              : 
    3217            0 :                 refdobj = findObjectByCatalogId(refobjId);
    3218            0 :                 if (refdobj == NULL)
    3219            0 :                         continue;
    3220              : 
    3221            0 :                 Assert(refdobj->objType == DO_TABLE);
    3222            0 :                 reftbinfo = (TableInfo *) refdobj;
    3223            0 :                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3224            0 :                 refdobj = (DumpableObject *) reftbinfo->dataObj;
    3225            0 :                 if (refdobj == NULL)
    3226            0 :                         continue;
    3227            0 :                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3228              : 
    3229            0 :                 addObjectDependency(dobj, refdobj->dumpId);
    3230              : 
    3231            0 :                 if (!reftbinfo->relispopulated)
    3232            0 :                         tbinfo->relispopulated = false;
    3233            0 :         }
    3234              : 
    3235            0 :         PQclear(res);
    3236              : 
    3237            0 :         destroyPQExpBuffer(query);
    3238            0 : }
    3239              : 
    3240              : /*
    3241              :  * getTableDataFKConstraints -
    3242              :  *        add dump-order dependencies reflecting foreign key constraints
    3243              :  *
    3244              :  * This code is executed only in a data-only dump --- in schema+data dumps
    3245              :  * we handle foreign key issues by not creating the FK constraints until
    3246              :  * after the data is loaded.  In a data-only dump, however, we want to
    3247              :  * order the table data objects in such a way that a table's referenced
    3248              :  * tables are restored first.  (In the presence of circular references or
    3249              :  * self-references this may be impossible; we'll detect and complain about
    3250              :  * that during the dependency sorting step.)
    3251              :  */
    3252              : static void
    3253            0 : getTableDataFKConstraints(void)
    3254              : {
    3255            0 :         DumpableObject **dobjs;
    3256            0 :         int                     numObjs;
    3257            0 :         int                     i;
    3258              : 
    3259              :         /* Search through all the dumpable objects for FK constraints */
    3260            0 :         getDumpableObjects(&dobjs, &numObjs);
    3261            0 :         for (i = 0; i < numObjs; i++)
    3262              :         {
    3263            0 :                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3264              :                 {
    3265            0 :                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3266            0 :                         TableInfo  *ftable;
    3267              : 
    3268              :                         /* Not interesting unless both tables are to be dumped */
    3269            0 :                         if (cinfo->contable == NULL ||
    3270            0 :                                 cinfo->contable->dataObj == NULL)
    3271            0 :                                 continue;
    3272            0 :                         ftable = findTableByOid(cinfo->confrelid);
    3273            0 :                         if (ftable == NULL ||
    3274            0 :                                 ftable->dataObj == NULL)
    3275            0 :                                 continue;
    3276              : 
    3277              :                         /*
    3278              :                          * Okay, make referencing table's TABLE_DATA object depend on the
    3279              :                          * referenced table's TABLE_DATA object.
    3280              :                          */
    3281            0 :                         addObjectDependency(&cinfo->contable->dataObj->dobj,
    3282            0 :                                                                 ftable->dataObj->dobj.dumpId);
    3283            0 :                 }
    3284            0 :         }
    3285            0 :         free(dobjs);
    3286            0 : }
    3287              : 
    3288              : 
    3289              : /*
    3290              :  * dumpDatabase:
    3291              :  *      dump the database definition
    3292              :  */
    3293              : static void
    3294            0 : dumpDatabase(Archive *fout)
    3295              : {
    3296            0 :         DumpOptions *dopt = fout->dopt;
    3297            0 :         PQExpBuffer dbQry = createPQExpBuffer();
    3298            0 :         PQExpBuffer delQry = createPQExpBuffer();
    3299            0 :         PQExpBuffer creaQry = createPQExpBuffer();
    3300            0 :         PQExpBuffer labelq = createPQExpBuffer();
    3301            0 :         PGconn     *conn = GetConnection(fout);
    3302            0 :         PGresult   *res;
    3303            0 :         int                     i_tableoid,
    3304              :                                 i_oid,
    3305              :                                 i_datname,
    3306              :                                 i_datdba,
    3307              :                                 i_encoding,
    3308              :                                 i_datlocprovider,
    3309              :                                 i_collate,
    3310              :                                 i_ctype,
    3311              :                                 i_datlocale,
    3312              :                                 i_daticurules,
    3313              :                                 i_frozenxid,
    3314              :                                 i_minmxid,
    3315              :                                 i_datacl,
    3316              :                                 i_acldefault,
    3317              :                                 i_datistemplate,
    3318              :                                 i_datconnlimit,
    3319              :                                 i_datcollversion,
    3320              :                                 i_tablespace;
    3321            0 :         CatalogId       dbCatId;
    3322            0 :         DumpId          dbDumpId;
    3323            0 :         DumpableAcl dbdacl;
    3324            0 :         const char *datname,
    3325              :                            *dba,
    3326              :                            *encoding,
    3327              :                            *datlocprovider,
    3328              :                            *collate,
    3329              :                            *ctype,
    3330              :                            *locale,
    3331              :                            *icurules,
    3332              :                            *datistemplate,
    3333              :                            *datconnlimit,
    3334              :                            *tablespace;
    3335            0 :         uint32          frozenxid,
    3336              :                                 minmxid;
    3337            0 :         char       *qdatname;
    3338              : 
    3339            0 :         pg_log_info("saving database definition");
    3340              : 
    3341              :         /*
    3342              :          * Fetch the database-level properties for this database.
    3343              :          */
    3344            0 :         appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3345              :                                                  "datdba, "
    3346              :                                                  "pg_encoding_to_char(encoding) AS encoding, "
    3347              :                                                  "datcollate, datctype, datfrozenxid, "
    3348              :                                                  "datacl, acldefault('d', datdba) AS acldefault, "
    3349              :                                                  "datistemplate, datconnlimit, ");
    3350            0 :         if (fout->remoteVersion >= 90300)
    3351            0 :                 appendPQExpBufferStr(dbQry, "datminmxid, ");
    3352              :         else
    3353            0 :                 appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3354            0 :         if (fout->remoteVersion >= 170000)
    3355            0 :                 appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3356            0 :         else if (fout->remoteVersion >= 150000)
    3357            0 :                 appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3358              :         else
    3359            0 :                 appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3360            0 :         if (fout->remoteVersion >= 160000)
    3361            0 :                 appendPQExpBufferStr(dbQry, "daticurules, ");
    3362              :         else
    3363            0 :                 appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3364            0 :         appendPQExpBufferStr(dbQry,
    3365              :                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3366              :                                                  "shobj_description(oid, 'pg_database') AS description "
    3367              :                                                  "FROM pg_database "
    3368              :                                                  "WHERE datname = current_database()");
    3369              : 
    3370            0 :         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3371              : 
    3372            0 :         i_tableoid = PQfnumber(res, "tableoid");
    3373            0 :         i_oid = PQfnumber(res, "oid");
    3374            0 :         i_datname = PQfnumber(res, "datname");
    3375            0 :         i_datdba = PQfnumber(res, "datdba");
    3376            0 :         i_encoding = PQfnumber(res, "encoding");
    3377            0 :         i_datlocprovider = PQfnumber(res, "datlocprovider");
    3378            0 :         i_collate = PQfnumber(res, "datcollate");
    3379            0 :         i_ctype = PQfnumber(res, "datctype");
    3380            0 :         i_datlocale = PQfnumber(res, "datlocale");
    3381            0 :         i_daticurules = PQfnumber(res, "daticurules");
    3382            0 :         i_frozenxid = PQfnumber(res, "datfrozenxid");
    3383            0 :         i_minmxid = PQfnumber(res, "datminmxid");
    3384            0 :         i_datacl = PQfnumber(res, "datacl");
    3385            0 :         i_acldefault = PQfnumber(res, "acldefault");
    3386            0 :         i_datistemplate = PQfnumber(res, "datistemplate");
    3387            0 :         i_datconnlimit = PQfnumber(res, "datconnlimit");
    3388            0 :         i_datcollversion = PQfnumber(res, "datcollversion");
    3389            0 :         i_tablespace = PQfnumber(res, "tablespace");
    3390              : 
    3391            0 :         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3392            0 :         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3393            0 :         datname = PQgetvalue(res, 0, i_datname);
    3394            0 :         dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3395            0 :         encoding = PQgetvalue(res, 0, i_encoding);
    3396            0 :         datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3397            0 :         collate = PQgetvalue(res, 0, i_collate);
    3398            0 :         ctype = PQgetvalue(res, 0, i_ctype);
    3399            0 :         if (!PQgetisnull(res, 0, i_datlocale))
    3400            0 :                 locale = PQgetvalue(res, 0, i_datlocale);
    3401              :         else
    3402            0 :                 locale = NULL;
    3403            0 :         if (!PQgetisnull(res, 0, i_daticurules))
    3404            0 :                 icurules = PQgetvalue(res, 0, i_daticurules);
    3405              :         else
    3406            0 :                 icurules = NULL;
    3407            0 :         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3408            0 :         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3409            0 :         dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3410            0 :         dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3411            0 :         datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3412            0 :         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3413            0 :         tablespace = PQgetvalue(res, 0, i_tablespace);
    3414              : 
    3415            0 :         qdatname = pg_strdup(fmtId(datname));
    3416              : 
    3417              :         /*
    3418              :          * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3419              :          * to preserve that), as well as the encoding, locale, and tablespace
    3420              :          * since those can't be altered later.  Other DB properties are left to
    3421              :          * the DATABASE PROPERTIES entry, so that they can be applied after
    3422              :          * reconnecting to the target DB.
    3423              :          *
    3424              :          * For binary upgrade, we use the FILE_COPY strategy because testing has
    3425              :          * shown it to be faster.  When the server is in binary upgrade mode, it
    3426              :          * will also skip the checkpoints this strategy ordinarily performs.
    3427              :          */
    3428            0 :         if (dopt->binary_upgrade)
    3429              :         {
    3430            0 :                 appendPQExpBuffer(creaQry,
    3431              :                                                   "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3432              :                                                   "OID = %u STRATEGY = FILE_COPY",
    3433            0 :                                                   qdatname, dbCatId.oid);
    3434            0 :         }
    3435              :         else
    3436              :         {
    3437            0 :                 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3438            0 :                                                   qdatname);
    3439              :         }
    3440            0 :         if (strlen(encoding) > 0)
    3441              :         {
    3442            0 :                 appendPQExpBufferStr(creaQry, " ENCODING = ");
    3443            0 :                 appendStringLiteralAH(creaQry, encoding, fout);
    3444            0 :         }
    3445              : 
    3446            0 :         appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3447            0 :         if (datlocprovider[0] == 'b')
    3448            0 :                 appendPQExpBufferStr(creaQry, "builtin");
    3449            0 :         else if (datlocprovider[0] == 'c')
    3450            0 :                 appendPQExpBufferStr(creaQry, "libc");
    3451            0 :         else if (datlocprovider[0] == 'i')
    3452            0 :                 appendPQExpBufferStr(creaQry, "icu");
    3453              :         else
    3454            0 :                 pg_fatal("unrecognized locale provider: %s",
    3455              :                                  datlocprovider);
    3456              : 
    3457            0 :         if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3458              :         {
    3459            0 :                 appendPQExpBufferStr(creaQry, " LOCALE = ");
    3460            0 :                 appendStringLiteralAH(creaQry, collate, fout);
    3461            0 :         }
    3462              :         else
    3463              :         {
    3464            0 :                 if (strlen(collate) > 0)
    3465              :                 {
    3466            0 :                         appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3467            0 :                         appendStringLiteralAH(creaQry, collate, fout);
    3468            0 :                 }
    3469            0 :                 if (strlen(ctype) > 0)
    3470              :                 {
    3471            0 :                         appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3472            0 :                         appendStringLiteralAH(creaQry, ctype, fout);
    3473            0 :                 }
    3474              :         }
    3475            0 :         if (locale)
    3476              :         {
    3477            0 :                 if (datlocprovider[0] == 'b')
    3478            0 :                         appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3479              :                 else
    3480            0 :                         appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3481              : 
    3482            0 :                 appendStringLiteralAH(creaQry, locale, fout);
    3483            0 :         }
    3484              : 
    3485            0 :         if (icurules)
    3486              :         {
    3487            0 :                 appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3488            0 :                 appendStringLiteralAH(creaQry, icurules, fout);
    3489            0 :         }
    3490              : 
    3491              :         /*
    3492              :          * For binary upgrade, carry over the collation version.  For normal
    3493              :          * dump/restore, omit the version, so that it is computed upon restore.
    3494              :          */
    3495            0 :         if (dopt->binary_upgrade)
    3496              :         {
    3497            0 :                 if (!PQgetisnull(res, 0, i_datcollversion))
    3498              :                 {
    3499            0 :                         appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3500            0 :                         appendStringLiteralAH(creaQry,
    3501              :                                                                   PQgetvalue(res, 0, i_datcollversion),
    3502              :                                                                   fout);
    3503            0 :                 }
    3504            0 :         }
    3505              : 
    3506              :         /*
    3507              :          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3508              :          * thing; the decision whether to specify a tablespace should be left till
    3509              :          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3510              :          * label the DATABASE entry with the tablespace and let the normal
    3511              :          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3512              :          * attention to default_tablespace, so that won't work.
    3513              :          */
    3514            0 :         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3515            0 :                 !dopt->outputNoTablespaces)
    3516            0 :                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3517            0 :                                                   fmtId(tablespace));
    3518            0 :         appendPQExpBufferStr(creaQry, ";\n");
    3519              : 
    3520            0 :         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3521            0 :                                           qdatname);
    3522              : 
    3523            0 :         dbDumpId = createDumpId();
    3524              : 
    3525            0 :         ArchiveEntry(fout,
    3526              :                                  dbCatId,               /* catalog ID */
    3527            0 :                                  dbDumpId,              /* dump ID */
    3528            0 :                                  ARCHIVE_OPTS(.tag = datname,
    3529              :                                                           .owner = dba,
    3530              :                                                           .description = "DATABASE",
    3531              :                                                           .section = SECTION_PRE_DATA,
    3532              :                                                           .createStmt = creaQry->data,
    3533              :                                                           .dropStmt = delQry->data));
    3534              : 
    3535              :         /* Compute correct tag for archive entry */
    3536            0 :         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3537              : 
    3538              :         /* Dump DB comment if any */
    3539              :         {
    3540              :                 /*
    3541              :                  * 8.2 and up keep comments on shared objects in a shared table, so we
    3542              :                  * cannot use the dumpComment() code used for other database objects.
    3543              :                  * Be careful that the ArchiveEntry parameters match that function.
    3544              :                  */
    3545            0 :                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3546              : 
    3547            0 :                 if (comment && *comment && !dopt->no_comments)
    3548              :                 {
    3549            0 :                         resetPQExpBuffer(dbQry);
    3550              : 
    3551              :                         /*
    3552              :                          * Generates warning when loaded into a differently-named
    3553              :                          * database.
    3554              :                          */
    3555            0 :                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3556            0 :                         appendStringLiteralAH(dbQry, comment, fout);
    3557            0 :                         appendPQExpBufferStr(dbQry, ";\n");
    3558              : 
    3559            0 :                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3560            0 :                                                  ARCHIVE_OPTS(.tag = labelq->data,
    3561              :                                                                           .owner = dba,
    3562              :                                                                           .description = "COMMENT",
    3563              :                                                                           .section = SECTION_NONE,
    3564              :                                                                           .createStmt = dbQry->data,
    3565              :                                                                           .deps = &dbDumpId,
    3566              :                                                                           .nDeps = 1));
    3567            0 :                 }
    3568            0 :         }
    3569              : 
    3570              :         /* Dump DB security label, if enabled */
    3571            0 :         if (!dopt->no_security_labels)
    3572              :         {
    3573            0 :                 PGresult   *shres;
    3574            0 :                 PQExpBuffer seclabelQry;
    3575              : 
    3576            0 :                 seclabelQry = createPQExpBuffer();
    3577              : 
    3578            0 :                 buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3579            0 :                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3580            0 :                 resetPQExpBuffer(seclabelQry);
    3581            0 :                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3582            0 :                 if (seclabelQry->len > 0)
    3583            0 :                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3584            0 :                                                  ARCHIVE_OPTS(.tag = labelq->data,
    3585              :                                                                           .owner = dba,
    3586              :                                                                           .description = "SECURITY LABEL",
    3587              :                                                                           .section = SECTION_NONE,
    3588              :                                                                           .createStmt = seclabelQry->data,
    3589              :                                                                           .deps = &dbDumpId,
    3590              :                                                                           .nDeps = 1));
    3591            0 :                 destroyPQExpBuffer(seclabelQry);
    3592            0 :                 PQclear(shres);
    3593            0 :         }
    3594              : 
    3595              :         /*
    3596              :          * Dump ACL if any.  Note that we do not support initial privileges
    3597              :          * (pg_init_privs) on databases.
    3598              :          */
    3599            0 :         dbdacl.privtype = 0;
    3600            0 :         dbdacl.initprivs = NULL;
    3601              : 
    3602            0 :         dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3603            0 :                         qdatname, NULL, NULL,
    3604            0 :                         NULL, dba, &dbdacl);
    3605              : 
    3606              :         /*
    3607              :          * Now construct a DATABASE PROPERTIES archive entry to restore any
    3608              :          * non-default database-level properties.  (The reason this must be
    3609              :          * separate is that we cannot put any additional commands into the TOC
    3610              :          * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3611              :          * in an implicit transaction block, and the backend won't allow CREATE
    3612              :          * DATABASE in that context.)
    3613              :          */
    3614            0 :         resetPQExpBuffer(creaQry);
    3615            0 :         resetPQExpBuffer(delQry);
    3616              : 
    3617            0 :         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3618            0 :                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3619            0 :                                                   qdatname, datconnlimit);
    3620              : 
    3621            0 :         if (strcmp(datistemplate, "t") == 0)
    3622              :         {
    3623            0 :                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3624            0 :                                                   qdatname);
    3625              : 
    3626              :                 /*
    3627              :                  * The backend won't accept DROP DATABASE on a template database.  We
    3628              :                  * can deal with that by removing the template marking before the DROP
    3629              :                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3630              :                  * since no such command is currently supported, fake it with a direct
    3631              :                  * UPDATE on pg_database.
    3632              :                  */
    3633            0 :                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3634              :                                                          "SET datistemplate = false WHERE datname = ");
    3635            0 :                 appendStringLiteralAH(delQry, datname, fout);
    3636            0 :                 appendPQExpBufferStr(delQry, ";\n");
    3637            0 :         }
    3638              : 
    3639              :         /*
    3640              :          * We do not restore pg_database.dathasloginevt because it is set
    3641              :          * automatically on login event trigger creation.
    3642              :          */
    3643              : 
    3644              :         /* Add database-specific SET options */
    3645            0 :         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3646              : 
    3647              :         /*
    3648              :          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3649              :          * entry, too, for lack of a better place.
    3650              :          */
    3651            0 :         if (dopt->binary_upgrade)
    3652              :         {
    3653            0 :                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3654            0 :                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3655              :                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3656              :                                                   "WHERE datname = ",
    3657            0 :                                                   frozenxid, minmxid);
    3658            0 :                 appendStringLiteralAH(creaQry, datname, fout);
    3659            0 :                 appendPQExpBufferStr(creaQry, ";\n");
    3660            0 :         }
    3661              : 
    3662            0 :         if (creaQry->len > 0)
    3663            0 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3664            0 :                                          ARCHIVE_OPTS(.tag = datname,
    3665              :                                                                   .owner = dba,
    3666              :                                                                   .description = "DATABASE PROPERTIES",
    3667              :                                                                   .section = SECTION_PRE_DATA,
    3668              :                                                                   .createStmt = creaQry->data,
    3669              :                                                                   .dropStmt = delQry->data,
    3670              :                                                                   .deps = &dbDumpId));
    3671              : 
    3672              :         /*
    3673              :          * pg_largeobject comes from the old system intact, so set its
    3674              :          * relfrozenxids, relminmxids and relfilenode.
    3675              :          *
    3676              :          * pg_largeobject_metadata also comes from the old system intact for
    3677              :          * upgrades from v16 and newer, so set its relfrozenxids, relminmxids, and
    3678              :          * relfilenode, too.  pg_upgrade can't copy/link the files from older
    3679              :          * versions because aclitem (needed by pg_largeobject_metadata.lomacl)
    3680              :          * changed its storage format in v16.
    3681              :          */
    3682            0 :         if (dopt->binary_upgrade)
    3683              :         {
    3684            0 :                 PGresult   *lo_res;
    3685            0 :                 PQExpBuffer loFrozenQry = createPQExpBuffer();
    3686            0 :                 PQExpBuffer loOutQry = createPQExpBuffer();
    3687            0 :                 PQExpBuffer lomOutQry = createPQExpBuffer();
    3688            0 :                 PQExpBuffer loHorizonQry = createPQExpBuffer();
    3689            0 :                 PQExpBuffer lomHorizonQry = createPQExpBuffer();
    3690            0 :                 int                     ii_relfrozenxid,
    3691              :                                         ii_relfilenode,
    3692              :                                         ii_oid,
    3693              :                                         ii_relminmxid;
    3694              : 
    3695            0 :                 if (fout->remoteVersion >= 90300)
    3696            0 :                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3697              :                                                           "FROM pg_catalog.pg_class\n"
    3698              :                                                           "WHERE oid IN (%u, %u, %u, %u);\n",
    3699              :                                                           LargeObjectRelationId, LargeObjectLOidPNIndexId,
    3700              :                                                           LargeObjectMetadataRelationId, LargeObjectMetadataOidIndexId);
    3701              :                 else
    3702            0 :                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3703              :                                                           "FROM pg_catalog.pg_class\n"
    3704              :                                                           "WHERE oid IN (%u, %u);\n",
    3705              :                                                           LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3706              : 
    3707            0 :                 lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3708              : 
    3709            0 :                 ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3710            0 :                 ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3711            0 :                 ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3712            0 :                 ii_oid = PQfnumber(lo_res, "oid");
    3713              : 
    3714            0 :                 appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3715            0 :                 appendPQExpBufferStr(lomHorizonQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
    3716            0 :                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3717            0 :                 appendPQExpBufferStr(lomOutQry, "\n-- For binary upgrade, preserve pg_largeobject_metadata and index relfilenodes\n");
    3718            0 :                 for (int i = 0; i < PQntuples(lo_res); ++i)
    3719              :                 {
    3720            0 :                         Oid                     oid;
    3721            0 :                         RelFileNumber relfilenumber;
    3722            0 :                         PQExpBuffer horizonQry;
    3723            0 :                         PQExpBuffer outQry;
    3724              : 
    3725            0 :                         oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3726            0 :                         relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3727              : 
    3728            0 :                         if (oid == LargeObjectRelationId ||
    3729            0 :                                 oid == LargeObjectLOidPNIndexId)
    3730              :                         {
    3731            0 :                                 horizonQry = loHorizonQry;
    3732            0 :                                 outQry = loOutQry;
    3733            0 :                         }
    3734              :                         else
    3735              :                         {
    3736            0 :                                 horizonQry = lomHorizonQry;
    3737            0 :                                 outQry = lomOutQry;
    3738              :                         }
    3739              : 
    3740            0 :                         appendPQExpBuffer(horizonQry, "UPDATE pg_catalog.pg_class\n"
    3741              :                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3742              :                                                           "WHERE oid = %u;\n",
    3743            0 :                                                           atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3744            0 :                                                           atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3745            0 :                                                           atooid(PQgetvalue(lo_res, i, ii_oid)));
    3746              : 
    3747            0 :                         if (oid == LargeObjectRelationId ||
    3748            0 :                                 oid == LargeObjectMetadataRelationId)
    3749            0 :                                 appendPQExpBuffer(outQry,
    3750              :                                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3751            0 :                                                                   relfilenumber);
    3752            0 :                         else if (oid == LargeObjectLOidPNIndexId ||
    3753            0 :                                          oid == LargeObjectMetadataOidIndexId)
    3754            0 :                                 appendPQExpBuffer(outQry,
    3755              :                                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3756            0 :                                                                   relfilenumber);
    3757            0 :                 }
    3758              : 
    3759            0 :                 appendPQExpBufferStr(loOutQry,
    3760              :                                                          "TRUNCATE pg_catalog.pg_largeobject;\n");
    3761            0 :                 appendPQExpBufferStr(lomOutQry,
    3762              :                                                          "TRUNCATE pg_catalog.pg_largeobject_metadata;\n");
    3763              : 
    3764            0 :                 appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3765            0 :                 appendPQExpBufferStr(lomOutQry, lomHorizonQry->data);
    3766              : 
    3767            0 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3768            0 :                                          ARCHIVE_OPTS(.tag = "pg_largeobject",
    3769              :                                                                   .description = "pg_largeobject",
    3770              :                                                                   .section = SECTION_PRE_DATA,
    3771              :                                                                   .createStmt = loOutQry->data));
    3772              : 
    3773            0 :                 if (fout->remoteVersion >= 160000)
    3774            0 :                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3775            0 :                                                  ARCHIVE_OPTS(.tag = "pg_largeobject_metadata",
    3776              :                                                                           .description = "pg_largeobject_metadata",
    3777              :                                                                           .section = SECTION_PRE_DATA,
    3778              :                                                                           .createStmt = lomOutQry->data));
    3779              : 
    3780            0 :                 PQclear(lo_res);
    3781              : 
    3782            0 :                 destroyPQExpBuffer(loFrozenQry);
    3783            0 :                 destroyPQExpBuffer(loHorizonQry);
    3784            0 :                 destroyPQExpBuffer(lomHorizonQry);
    3785            0 :                 destroyPQExpBuffer(loOutQry);
    3786            0 :                 destroyPQExpBuffer(lomOutQry);
    3787            0 :         }
    3788              : 
    3789            0 :         PQclear(res);
    3790              : 
    3791            0 :         free(qdatname);
    3792            0 :         destroyPQExpBuffer(dbQry);
    3793            0 :         destroyPQExpBuffer(delQry);
    3794            0 :         destroyPQExpBuffer(creaQry);
    3795            0 :         destroyPQExpBuffer(labelq);
    3796            0 : }
    3797              : 
    3798              : /*
    3799              :  * Collect any database-specific or role-and-database-specific SET options
    3800              :  * for this database, and append them to outbuf.
    3801              :  */
    3802              : static void
    3803            0 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3804              :                                    const char *dbname, Oid dboid)
    3805              : {
    3806            0 :         PGconn     *conn = GetConnection(AH);
    3807            0 :         PQExpBuffer buf = createPQExpBuffer();
    3808            0 :         PGresult   *res;
    3809              : 
    3810              :         /* First collect database-specific options */
    3811            0 :         printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3812              :                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3813            0 :                                           dboid);
    3814              : 
    3815            0 :         res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3816              : 
    3817            0 :         for (int i = 0; i < PQntuples(res); i++)
    3818            0 :                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3819            0 :                                                            "DATABASE", dbname, NULL, NULL,
    3820            0 :                                                            outbuf);
    3821              : 
    3822            0 :         PQclear(res);
    3823              : 
    3824              :         /* Now look for role-and-database-specific options */
    3825            0 :         printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3826              :                                           "FROM pg_db_role_setting s, pg_roles r "
    3827              :                                           "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3828            0 :                                           dboid);
    3829              : 
    3830            0 :         res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3831              : 
    3832            0 :         for (int i = 0; i < PQntuples(res); i++)
    3833            0 :                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3834            0 :                                                            "ROLE", PQgetvalue(res, i, 0),
    3835            0 :                                                            "DATABASE", dbname,
    3836            0 :                                                            outbuf);
    3837              : 
    3838            0 :         PQclear(res);
    3839              : 
    3840            0 :         destroyPQExpBuffer(buf);
    3841            0 : }
    3842              : 
    3843              : /*
    3844              :  * dumpEncoding: put the correct encoding into the archive
    3845              :  */
    3846              : static void
    3847            0 : dumpEncoding(Archive *AH)
    3848              : {
    3849            0 :         const char *encname = pg_encoding_to_char(AH->encoding);
    3850            0 :         PQExpBuffer qry = createPQExpBuffer();
    3851              : 
    3852            0 :         pg_log_info("saving encoding = %s", encname);
    3853              : 
    3854            0 :         appendPQExpBufferStr(qry, "SET client_encoding = ");
    3855            0 :         appendStringLiteralAH(qry, encname, AH);
    3856            0 :         appendPQExpBufferStr(qry, ";\n");
    3857              : 
    3858            0 :         ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3859            0 :                                  ARCHIVE_OPTS(.tag = "ENCODING",
    3860              :                                                           .description = "ENCODING",
    3861              :                                                           .section = SECTION_PRE_DATA,
    3862              :                                                           .createStmt = qry->data));
    3863              : 
    3864            0 :         destroyPQExpBuffer(qry);
    3865            0 : }
    3866              : 
    3867              : 
    3868              : /*
    3869              :  * dumpStdStrings: put the correct escape string behavior into the archive
    3870              :  */
    3871              : static void
    3872            0 : dumpStdStrings(Archive *AH)
    3873              : {
    3874            0 :         const char *stdstrings = AH->std_strings ? "on" : "off";
    3875            0 :         PQExpBuffer qry = createPQExpBuffer();
    3876              : 
    3877            0 :         pg_log_info("saving \"standard_conforming_strings = %s\"",
    3878              :                                 stdstrings);
    3879              : 
    3880            0 :         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3881            0 :                                           stdstrings);
    3882              : 
    3883            0 :         ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3884            0 :                                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3885              :                                                           .description = "STDSTRINGS",
    3886              :                                                           .section = SECTION_PRE_DATA,
    3887              :                                                           .createStmt = qry->data));
    3888              : 
    3889            0 :         destroyPQExpBuffer(qry);
    3890            0 : }
    3891              : 
    3892              : /*
    3893              :  * dumpSearchPath: record the active search_path in the archive
    3894              :  */
    3895              : static void
    3896            0 : dumpSearchPath(Archive *AH)
    3897              : {
    3898            0 :         PQExpBuffer qry = createPQExpBuffer();
    3899            0 :         PQExpBuffer path = createPQExpBuffer();
    3900            0 :         PGresult   *res;
    3901            0 :         char      **schemanames = NULL;
    3902            0 :         int                     nschemanames = 0;
    3903            0 :         int                     i;
    3904              : 
    3905              :         /*
    3906              :          * We use the result of current_schemas(), not the search_path GUC,
    3907              :          * because that might contain wildcards such as "$user", which won't
    3908              :          * necessarily have the same value during restore.  Also, this way avoids
    3909              :          * listing schemas that may appear in search_path but not actually exist,
    3910              :          * which seems like a prudent exclusion.
    3911              :          */
    3912            0 :         res = ExecuteSqlQueryForSingleRow(AH,
    3913              :                                                                           "SELECT pg_catalog.current_schemas(false)");
    3914              : 
    3915            0 :         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3916            0 :                 pg_fatal("could not parse result of current_schemas()");
    3917              : 
    3918              :         /*
    3919              :          * We use set_config(), not a simple "SET search_path" command, because
    3920              :          * the latter has less-clean behavior if the search path is empty.  While
    3921              :          * that's likely to get fixed at some point, it seems like a good idea to
    3922              :          * be as backwards-compatible as possible in what we put into archives.
    3923              :          */
    3924            0 :         for (i = 0; i < nschemanames; i++)
    3925              :         {
    3926            0 :                 if (i > 0)
    3927            0 :                         appendPQExpBufferStr(path, ", ");
    3928            0 :                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3929            0 :         }
    3930              : 
    3931            0 :         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3932            0 :         appendStringLiteralAH(qry, path->data, AH);
    3933            0 :         appendPQExpBufferStr(qry, ", false);\n");
    3934              : 
    3935            0 :         pg_log_info("saving \"search_path = %s\"", path->data);
    3936              : 
    3937            0 :         ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3938            0 :                                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3939              :                                                           .description = "SEARCHPATH",
    3940              :                                                           .section = SECTION_PRE_DATA,
    3941              :                                                           .createStmt = qry->data));
    3942              : 
    3943              :         /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3944            0 :         AH->searchpath = pg_strdup(qry->data);
    3945              : 
    3946            0 :         free(schemanames);
    3947            0 :         PQclear(res);
    3948            0 :         destroyPQExpBuffer(qry);
    3949            0 :         destroyPQExpBuffer(path);
    3950            0 : }
    3951              : 
    3952              : 
    3953              : /*
    3954              :  * getLOs:
    3955              :  *      Collect schema-level data about large objects
    3956              :  */
    3957              : static void
    3958            0 : getLOs(Archive *fout)
    3959              : {
    3960            0 :         DumpOptions *dopt = fout->dopt;
    3961            0 :         PQExpBuffer loQry = createPQExpBuffer();
    3962            0 :         PGresult   *res;
    3963            0 :         int                     ntups;
    3964            0 :         int                     i;
    3965            0 :         int                     n;
    3966            0 :         int                     i_oid;
    3967            0 :         int                     i_lomowner;
    3968            0 :         int                     i_lomacl;
    3969            0 :         int                     i_acldefault;
    3970              : 
    3971            0 :         pg_log_info("reading large objects");
    3972              : 
    3973              :         /*
    3974              :          * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3975              :          * with the same owner/ACL appear together.
    3976              :          */
    3977            0 :         appendPQExpBufferStr(loQry,
    3978              :                                                  "SELECT oid, lomowner, lomacl, "
    3979              :                                                  "acldefault('L', lomowner) AS acldefault "
    3980              :                                                  "FROM pg_largeobject_metadata "
    3981              :                                                  "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3982              : 
    3983            0 :         res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3984              : 
    3985            0 :         i_oid = PQfnumber(res, "oid");
    3986            0 :         i_lomowner = PQfnumber(res, "lomowner");
    3987            0 :         i_lomacl = PQfnumber(res, "lomacl");
    3988            0 :         i_acldefault = PQfnumber(res, "acldefault");
    3989              : 
    3990            0 :         ntups = PQntuples(res);
    3991              : 
    3992              :         /*
    3993              :          * Group the blobs into suitably-sized groups that have the same owner and
    3994              :          * ACL setting, and build a metadata and a data DumpableObject for each
    3995              :          * group.  (If we supported initprivs for blobs, we'd have to insist that
    3996              :          * groups also share initprivs settings, since the DumpableObject only has
    3997              :          * room for one.)  i is the index of the first tuple in the current group,
    3998              :          * and n is the number of tuples we include in the group.
    3999              :          */
    4000            0 :         for (i = 0; i < ntups; i += n)
    4001              :         {
    4002            0 :                 Oid                     thisoid = atooid(PQgetvalue(res, i, i_oid));
    4003            0 :                 char       *thisowner = PQgetvalue(res, i, i_lomowner);
    4004            0 :                 char       *thisacl = PQgetvalue(res, i, i_lomacl);
    4005            0 :                 LoInfo     *loinfo;
    4006            0 :                 DumpableObject *lodata;
    4007            0 :                 char            namebuf[64];
    4008              : 
    4009              :                 /* Scan to find first tuple not to be included in group */
    4010            0 :                 n = 1;
    4011            0 :                 while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    4012              :                 {
    4013            0 :                         if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    4014            0 :                                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    4015            0 :                                 break;
    4016            0 :                         n++;
    4017              :                 }
    4018              : 
    4019              :                 /* Build the metadata DumpableObject */
    4020            0 :                 loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    4021              : 
    4022            0 :                 loinfo->dobj.objType = DO_LARGE_OBJECT;
    4023            0 :                 loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    4024            0 :                 loinfo->dobj.catId.oid = thisoid;
    4025            0 :                 AssignDumpId(&loinfo->dobj);
    4026              : 
    4027            0 :                 if (n > 1)
    4028            0 :                         snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    4029            0 :                                          atooid(PQgetvalue(res, i + n - 1, i_oid)));
    4030              :                 else
    4031            0 :                         snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    4032            0 :                 loinfo->dobj.name = pg_strdup(namebuf);
    4033            0 :                 loinfo->dacl.acl = pg_strdup(thisacl);
    4034            0 :                 loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    4035            0 :                 loinfo->dacl.privtype = 0;
    4036            0 :                 loinfo->dacl.initprivs = NULL;
    4037            0 :                 loinfo->rolname = getRoleName(thisowner);
    4038            0 :                 loinfo->numlos = n;
    4039            0 :                 loinfo->looids[0] = thisoid;
    4040              :                 /* Collect OIDs of the remaining blobs in this group */
    4041            0 :                 for (int k = 1; k < n; k++)
    4042              :                 {
    4043            0 :                         CatalogId       extraID;
    4044              : 
    4045            0 :                         loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    4046              : 
    4047              :                         /* Make sure we can look up loinfo by any of the blobs' OIDs */
    4048            0 :                         extraID.tableoid = LargeObjectRelationId;
    4049            0 :                         extraID.oid = loinfo->looids[k];
    4050            0 :                         recordAdditionalCatalogID(extraID, &loinfo->dobj);
    4051            0 :                 }
    4052              : 
    4053              :                 /* LOs have data */
    4054            0 :                 loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    4055              : 
    4056              :                 /* Mark whether LO group has a non-empty ACL */
    4057            0 :                 if (!PQgetisnull(res, i, i_lomacl))
    4058            0 :                         loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    4059              : 
    4060              :                 /*
    4061              :                  * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
    4062              :                  * as it will be copied by pg_upgrade, which simply copies the
    4063              :                  * pg_largeobject table. We *do* however dump out anything but the
    4064              :                  * data, as pg_upgrade copies just pg_largeobject, but not
    4065              :                  * pg_largeobject_metadata, after the dump is restored.  In versions
    4066              :                  * before v12, this is done via proper large object commands.  In
    4067              :                  * newer versions, we dump the content of pg_largeobject_metadata and
    4068              :                  * any associated pg_shdepend rows, which is faster to restore.  (On
    4069              :                  * <v12, pg_largeobject_metadata was created WITH OIDS, so the OID
    4070              :                  * column is hidden and won't be dumped.)
    4071              :                  */
    4072            0 :                 if (dopt->binary_upgrade)
    4073              :                 {
    4074            0 :                         if (fout->remoteVersion >= 120000)
    4075              :                         {
    4076              :                                 /*
    4077              :                                  * We should've saved pg_largeobject_metadata's dump ID before
    4078              :                                  * this point.
    4079              :                                  */
    4080            0 :                                 Assert(lo_metadata_dumpId);
    4081              : 
    4082            0 :                                 loinfo->dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL | DUMP_COMPONENT_DEFINITION);
    4083              : 
    4084              :                                 /*
    4085              :                                  * Mark the large object as dependent on
    4086              :                                  * pg_largeobject_metadata so that any large object
    4087              :                                  * comments/seclables are dumped after it.
    4088              :                                  */
    4089            0 :                                 loinfo->dobj.dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    4090            0 :                                 loinfo->dobj.dependencies[0] = lo_metadata_dumpId;
    4091            0 :                                 loinfo->dobj.nDeps = loinfo->dobj.allocDeps = 1;
    4092            0 :                         }
    4093              :                         else
    4094            0 :                                 loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
    4095            0 :                 }
    4096              : 
    4097              :                 /*
    4098              :                  * Create a "BLOBS" data item for the group, too. This is just a
    4099              :                  * placeholder for sorting; it carries no data now.
    4100              :                  */
    4101            0 :                 lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
    4102            0 :                 lodata->objType = DO_LARGE_OBJECT_DATA;
    4103            0 :                 lodata->catId = nilCatalogId;
    4104            0 :                 AssignDumpId(lodata);
    4105            0 :                 lodata->name = pg_strdup(namebuf);
    4106            0 :                 lodata->components |= DUMP_COMPONENT_DATA;
    4107              :                 /* Set up explicit dependency from data to metadata */
    4108            0 :                 lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    4109            0 :                 lodata->dependencies[0] = loinfo->dobj.dumpId;
    4110            0 :                 lodata->nDeps = lodata->allocDeps = 1;
    4111            0 :         }
    4112              : 
    4113            0 :         PQclear(res);
    4114            0 :         destroyPQExpBuffer(loQry);
    4115            0 : }
    4116              : 
    4117              : /*
    4118              :  * dumpLO
    4119              :  *
    4120              :  * dump the definition (metadata) of the given large object group
    4121              :  */
    4122              : static void
    4123            0 : dumpLO(Archive *fout, const LoInfo *loinfo)
    4124              : {
    4125            0 :         PQExpBuffer cquery = createPQExpBuffer();
    4126              : 
    4127              :         /*
    4128              :          * The "definition" is just a newline-separated list of OIDs.  We need to
    4129              :          * put something into the dropStmt too, but it can just be a comment.
    4130              :          */
    4131            0 :         for (int i = 0; i < loinfo->numlos; i++)
    4132            0 :                 appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    4133              : 
    4134            0 :         if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4135            0 :                 ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    4136            0 :                                          ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    4137              :                                                                   .owner = loinfo->rolname,
    4138              :                                                                   .description = "BLOB METADATA",
    4139              :                                                                   .section = SECTION_DATA,
    4140              :                                                                   .createStmt = cquery->data,
    4141              :                                                                   .dropStmt = "-- dummy"));
    4142              : 
    4143              :         /*
    4144              :          * Dump per-blob comments and seclabels if any.  We assume these are rare
    4145              :          * enough that it's okay to generate retail TOC entries for them.
    4146              :          */
    4147            0 :         if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    4148              :                                                          DUMP_COMPONENT_SECLABEL))
    4149              :         {
    4150            0 :                 for (int i = 0; i < loinfo->numlos; i++)
    4151              :                 {
    4152            0 :                         CatalogId       catId;
    4153            0 :                         char            namebuf[32];
    4154              : 
    4155              :                         /* Build identifying info for this blob */
    4156            0 :                         catId.tableoid = loinfo->dobj.catId.tableoid;
    4157            0 :                         catId.oid = loinfo->looids[i];
    4158            0 :                         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    4159              : 
    4160            0 :                         if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4161            0 :                                 dumpComment(fout, "LARGE OBJECT", namebuf,
    4162            0 :                                                         NULL, loinfo->rolname,
    4163            0 :                                                         catId, 0, loinfo->dobj.dumpId);
    4164              : 
    4165            0 :                         if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4166            0 :                                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    4167            0 :                                                          NULL, loinfo->rolname,
    4168            0 :                                                          catId, 0, loinfo->dobj.dumpId);
    4169            0 :                 }
    4170            0 :         }
    4171              : 
    4172              :         /*
    4173              :          * Dump the ACLs if any (remember that all blobs in the group will have
    4174              :          * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    4175              :          * there's more, make a "LARGE OBJECTS" entry that really contains only
    4176              :          * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    4177              :          * string to emit a mutated version for each blob.
    4178              :          */
    4179            0 :         if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    4180              :         {
    4181            0 :                 char            namebuf[32];
    4182              : 
    4183              :                 /* Build identifying info for the first blob */
    4184            0 :                 snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    4185              : 
    4186            0 :                 if (loinfo->numlos > 1)
    4187              :                 {
    4188            0 :                         char            tagbuf[64];
    4189              : 
    4190            0 :                         snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    4191            0 :                                          loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    4192              : 
    4193            0 :                         dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4194            0 :                                         "LARGE OBJECT", namebuf, NULL, NULL,
    4195            0 :                                         tagbuf, loinfo->rolname, &loinfo->dacl);
    4196            0 :                 }
    4197              :                 else
    4198              :                 {
    4199            0 :                         dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4200            0 :                                         "LARGE OBJECT", namebuf, NULL, NULL,
    4201            0 :                                         NULL, loinfo->rolname, &loinfo->dacl);
    4202              :                 }
    4203            0 :         }
    4204              : 
    4205            0 :         destroyPQExpBuffer(cquery);
    4206            0 : }
    4207              : 
    4208              : /*
    4209              :  * dumpLOs:
    4210              :  *      dump the data contents of the large objects in the given group
    4211              :  */
    4212              : static int
    4213            0 : dumpLOs(Archive *fout, const void *arg)
    4214              : {
    4215            0 :         const LoInfo *loinfo = (const LoInfo *) arg;
    4216            0 :         PGconn     *conn = GetConnection(fout);
    4217            0 :         char            buf[LOBBUFSIZE];
    4218              : 
    4219            0 :         pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    4220              : 
    4221            0 :         for (int i = 0; i < loinfo->numlos; i++)
    4222              :         {
    4223            0 :                 Oid                     loOid = loinfo->looids[i];
    4224            0 :                 int                     loFd;
    4225            0 :                 int                     cnt;
    4226              : 
    4227              :                 /* Open the LO */
    4228            0 :                 loFd = lo_open(conn, loOid, INV_READ);
    4229            0 :                 if (loFd == -1)
    4230            0 :                         pg_fatal("could not open large object %u: %s",
    4231              :                                          loOid, PQerrorMessage(conn));
    4232              : 
    4233            0 :                 StartLO(fout, loOid);
    4234              : 
    4235              :                 /* Now read it in chunks, sending data to archive */
    4236            0 :                 do
    4237              :                 {
    4238            0 :                         cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4239            0 :                         if (cnt < 0)
    4240            0 :                                 pg_fatal("error reading large object %u: %s",
    4241              :                                                  loOid, PQerrorMessage(conn));
    4242              : 
    4243            0 :                         WriteData(fout, buf, cnt);
    4244            0 :                 } while (cnt > 0);
    4245              : 
    4246            0 :                 lo_close(conn, loFd);
    4247              : 
    4248            0 :                 EndLO(fout, loOid);
    4249            0 :         }
    4250              : 
    4251            0 :         return 1;
    4252            0 : }
    4253              : 
    4254              : /*
    4255              :  * getPolicies
    4256              :  *        get information about all RLS policies on dumpable tables.
    4257              :  */
    4258              : void
    4259            0 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4260              : {
    4261            0 :         DumpOptions *dopt = fout->dopt;
    4262            0 :         PQExpBuffer query;
    4263            0 :         PQExpBuffer tbloids;
    4264            0 :         PGresult   *res;
    4265            0 :         PolicyInfo *polinfo;
    4266            0 :         int                     i_oid;
    4267            0 :         int                     i_tableoid;
    4268            0 :         int                     i_polrelid;
    4269            0 :         int                     i_polname;
    4270            0 :         int                     i_polcmd;
    4271            0 :         int                     i_polpermissive;
    4272            0 :         int                     i_polroles;
    4273            0 :         int                     i_polqual;
    4274            0 :         int                     i_polwithcheck;
    4275            0 :         int                     i,
    4276              :                                 j,
    4277              :                                 ntups;
    4278              : 
    4279              :         /* No policies before 9.5 */
    4280            0 :         if (fout->remoteVersion < 90500)
    4281            0 :                 return;
    4282              : 
    4283              :         /* Skip if --no-policies was specified */
    4284            0 :         if (dopt->no_policies)
    4285            0 :                 return;
    4286              : 
    4287            0 :         query = createPQExpBuffer();
    4288            0 :         tbloids = createPQExpBuffer();
    4289              : 
    4290              :         /*
    4291              :          * Identify tables of interest, and check which ones have RLS enabled.
    4292              :          */
    4293            0 :         appendPQExpBufferChar(tbloids, '{');
    4294            0 :         for (i = 0; i < numTables; i++)
    4295              :         {
    4296            0 :                 TableInfo  *tbinfo = &tblinfo[i];
    4297              : 
    4298              :                 /* Ignore row security on tables not to be dumped */
    4299            0 :                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4300            0 :                         continue;
    4301              : 
    4302              :                 /* It can't have RLS or policies if it's not a table */
    4303            0 :                 if (tbinfo->relkind != RELKIND_RELATION &&
    4304            0 :                         tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4305            0 :                         continue;
    4306              : 
    4307              :                 /* Add it to the list of table OIDs to be probed below */
    4308            0 :                 if (tbloids->len > 1)     /* do we have more than the '{'? */
    4309            0 :                         appendPQExpBufferChar(tbloids, ',');
    4310            0 :                 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4311              : 
    4312              :                 /* Is RLS enabled?  (That's separate from whether it has policies) */
    4313            0 :                 if (tbinfo->rowsec)
    4314              :                 {
    4315            0 :                         tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4316              : 
    4317              :                         /*
    4318              :                          * We represent RLS being enabled on a table by creating a
    4319              :                          * PolicyInfo object with null polname.
    4320              :                          *
    4321              :                          * Note: use tableoid 0 so that this object won't be mistaken for
    4322              :                          * something that pg_depend entries apply to.
    4323              :                          */
    4324            0 :                         polinfo = pg_malloc(sizeof(PolicyInfo));
    4325            0 :                         polinfo->dobj.objType = DO_POLICY;
    4326            0 :                         polinfo->dobj.catId.tableoid = 0;
    4327            0 :                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4328            0 :                         AssignDumpId(&polinfo->dobj);
    4329            0 :                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4330            0 :                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4331            0 :                         polinfo->poltable = tbinfo;
    4332            0 :                         polinfo->polname = NULL;
    4333            0 :                         polinfo->polcmd = '\0';
    4334            0 :                         polinfo->polpermissive = 0;
    4335            0 :                         polinfo->polroles = NULL;
    4336            0 :                         polinfo->polqual = NULL;
    4337            0 :                         polinfo->polwithcheck = NULL;
    4338            0 :                 }
    4339            0 :         }
    4340            0 :         appendPQExpBufferChar(tbloids, '}');
    4341              : 
    4342              :         /*
    4343              :          * Now, read all RLS policies belonging to the tables of interest, and
    4344              :          * create PolicyInfo objects for them.  (Note that we must filter the
    4345              :          * results server-side not locally, because we dare not apply pg_get_expr
    4346              :          * to tables we don't have lock on.)
    4347              :          */
    4348            0 :         pg_log_info("reading row-level security policies");
    4349              : 
    4350            0 :         printfPQExpBuffer(query,
    4351              :                                           "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4352            0 :         if (fout->remoteVersion >= 100000)
    4353            0 :                 appendPQExpBufferStr(query, "pol.polpermissive, ");
    4354              :         else
    4355            0 :                 appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4356            0 :         appendPQExpBuffer(query,
    4357              :                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4358              :                                           "   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, "
    4359              :                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4360              :                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4361              :                                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4362              :                                           "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4363            0 :                                           tbloids->data);
    4364              : 
    4365            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4366              : 
    4367            0 :         ntups = PQntuples(res);
    4368            0 :         if (ntups > 0)
    4369              :         {
    4370            0 :                 i_oid = PQfnumber(res, "oid");
    4371            0 :                 i_tableoid = PQfnumber(res, "tableoid");
    4372            0 :                 i_polrelid = PQfnumber(res, "polrelid");
    4373            0 :                 i_polname = PQfnumber(res, "polname");
    4374            0 :                 i_polcmd = PQfnumber(res, "polcmd");
    4375            0 :                 i_polpermissive = PQfnumber(res, "polpermissive");
    4376            0 :                 i_polroles = PQfnumber(res, "polroles");
    4377            0 :                 i_polqual = PQfnumber(res, "polqual");
    4378            0 :                 i_polwithcheck = PQfnumber(res, "polwithcheck");
    4379              : 
    4380            0 :                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
    4381              : 
    4382            0 :                 for (j = 0; j < ntups; j++)
    4383              :                 {
    4384            0 :                         Oid                     polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4385            0 :                         TableInfo  *tbinfo = findTableByOid(polrelid);
    4386              : 
    4387            0 :                         tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4388              : 
    4389            0 :                         polinfo[j].dobj.objType = DO_POLICY;
    4390            0 :                         polinfo[j].dobj.catId.tableoid =
    4391            0 :                                 atooid(PQgetvalue(res, j, i_tableoid));
    4392            0 :                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4393            0 :                         AssignDumpId(&polinfo[j].dobj);
    4394            0 :                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4395            0 :                         polinfo[j].poltable = tbinfo;
    4396            0 :                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4397            0 :                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4398              : 
    4399            0 :                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4400            0 :                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4401              : 
    4402            0 :                         if (PQgetisnull(res, j, i_polroles))
    4403            0 :                                 polinfo[j].polroles = NULL;
    4404              :                         else
    4405            0 :                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4406              : 
    4407            0 :                         if (PQgetisnull(res, j, i_polqual))
    4408            0 :                                 polinfo[j].polqual = NULL;
    4409              :                         else
    4410            0 :                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4411              : 
    4412            0 :                         if (PQgetisnull(res, j, i_polwithcheck))
    4413            0 :                                 polinfo[j].polwithcheck = NULL;
    4414              :                         else
    4415            0 :                                 polinfo[j].polwithcheck
    4416            0 :                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4417            0 :                 }
    4418            0 :         }
    4419              : 
    4420            0 :         PQclear(res);
    4421              : 
    4422            0 :         destroyPQExpBuffer(query);
    4423            0 :         destroyPQExpBuffer(tbloids);
    4424            0 : }
    4425              : 
    4426              : /*
    4427              :  * dumpPolicy
    4428              :  *        dump the definition of the given policy
    4429              :  */
    4430              : static void
    4431            0 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4432              : {
    4433            0 :         DumpOptions *dopt = fout->dopt;
    4434            0 :         TableInfo  *tbinfo = polinfo->poltable;
    4435            0 :         PQExpBuffer query;
    4436            0 :         PQExpBuffer delqry;
    4437            0 :         PQExpBuffer polprefix;
    4438            0 :         char       *qtabname;
    4439            0 :         const char *cmd;
    4440            0 :         char       *tag;
    4441              : 
    4442              :         /* Do nothing if not dumping schema */
    4443            0 :         if (!dopt->dumpSchema)
    4444            0 :                 return;
    4445              : 
    4446              :         /*
    4447              :          * If polname is NULL, then this record is just indicating that ROW LEVEL
    4448              :          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4449              :          * ROW LEVEL SECURITY.
    4450              :          */
    4451            0 :         if (polinfo->polname == NULL)
    4452              :         {
    4453            0 :                 query = createPQExpBuffer();
    4454              : 
    4455            0 :                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4456            0 :                                                   fmtQualifiedDumpable(tbinfo));
    4457              : 
    4458              :                 /*
    4459              :                  * We must emit the ROW SECURITY object's dependency on its table
    4460              :                  * explicitly, because it will not match anything in pg_depend (unlike
    4461              :                  * the case for other PolicyInfo objects).
    4462              :                  */
    4463            0 :                 if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4464            0 :                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4465            0 :                                                  ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4466              :                                                                           .namespace = polinfo->dobj.namespace->dobj.name,
    4467              :                                                                           .owner = tbinfo->rolname,
    4468              :                                                                           .description = "ROW SECURITY",
    4469              :                                                                           .section = SECTION_POST_DATA,
    4470              :                                                                           .createStmt = query->data,
    4471              :                                                                           .deps = &(tbinfo->dobj.dumpId),
    4472              :                                                                           .nDeps = 1));
    4473              : 
    4474            0 :                 destroyPQExpBuffer(query);
    4475            0 :                 return;
    4476              :         }
    4477              : 
    4478            0 :         if (polinfo->polcmd == '*')
    4479            0 :                 cmd = "";
    4480            0 :         else if (polinfo->polcmd == 'r')
    4481            0 :                 cmd = " FOR SELECT";
    4482            0 :         else if (polinfo->polcmd == 'a')
    4483            0 :                 cmd = " FOR INSERT";
    4484            0 :         else if (polinfo->polcmd == 'w')
    4485            0 :                 cmd = " FOR UPDATE";
    4486            0 :         else if (polinfo->polcmd == 'd')
    4487            0 :                 cmd = " FOR DELETE";
    4488              :         else
    4489            0 :                 pg_fatal("unexpected policy command type: %c",
    4490              :                                  polinfo->polcmd);
    4491              : 
    4492            0 :         query = createPQExpBuffer();
    4493            0 :         delqry = createPQExpBuffer();
    4494            0 :         polprefix = createPQExpBuffer();
    4495              : 
    4496            0 :         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4497              : 
    4498            0 :         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4499              : 
    4500            0 :         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4501            0 :                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4502              : 
    4503            0 :         if (polinfo->polroles != NULL)
    4504            0 :                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4505              : 
    4506            0 :         if (polinfo->polqual != NULL)
    4507            0 :                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4508              : 
    4509            0 :         if (polinfo->polwithcheck != NULL)
    4510            0 :                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4511              : 
    4512            0 :         appendPQExpBufferStr(query, ";\n");
    4513              : 
    4514            0 :         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4515            0 :         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4516              : 
    4517            0 :         appendPQExpBuffer(polprefix, "POLICY %s ON",
    4518            0 :                                           fmtId(polinfo->polname));
    4519              : 
    4520            0 :         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4521              : 
    4522            0 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4523            0 :                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4524            0 :                                          ARCHIVE_OPTS(.tag = tag,
    4525              :                                                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4526              :                                                                   .owner = tbinfo->rolname,
    4527              :                                                                   .description = "POLICY",
    4528              :                                                                   .section = SECTION_POST_DATA,
    4529              :                                                                   .createStmt = query->data,
    4530              :                                                                   .dropStmt = delqry->data));
    4531              : 
    4532            0 :         if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4533            0 :                 dumpComment(fout, polprefix->data, qtabname,
    4534            0 :                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4535            0 :                                         polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4536              : 
    4537            0 :         free(tag);
    4538            0 :         destroyPQExpBuffer(query);
    4539            0 :         destroyPQExpBuffer(delqry);
    4540            0 :         destroyPQExpBuffer(polprefix);
    4541            0 :         free(qtabname);
    4542            0 : }
    4543              : 
    4544              : /*
    4545              :  * getPublications
    4546              :  *        get information about publications
    4547              :  */
    4548              : void
    4549            0 : getPublications(Archive *fout)
    4550              : {
    4551            0 :         DumpOptions *dopt = fout->dopt;
    4552            0 :         PQExpBuffer query;
    4553            0 :         PGresult   *res;
    4554            0 :         PublicationInfo *pubinfo;
    4555            0 :         int                     i_tableoid;
    4556            0 :         int                     i_oid;
    4557            0 :         int                     i_pubname;
    4558            0 :         int                     i_pubowner;
    4559            0 :         int                     i_puballtables;
    4560            0 :         int                     i_puballsequences;
    4561            0 :         int                     i_pubinsert;
    4562            0 :         int                     i_pubupdate;
    4563            0 :         int                     i_pubdelete;
    4564            0 :         int                     i_pubtruncate;
    4565            0 :         int                     i_pubviaroot;
    4566            0 :         int                     i_pubgencols;
    4567            0 :         int                     i,
    4568              :                                 ntups;
    4569              : 
    4570            0 :         if (dopt->no_publications || fout->remoteVersion < 100000)
    4571            0 :                 return;
    4572              : 
    4573            0 :         query = createPQExpBuffer();
    4574              : 
    4575              :         /* Get the publications. */
    4576            0 :         appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4577              :                                                  "p.pubowner, p.puballtables, p.pubinsert, "
    4578              :                                                  "p.pubupdate, p.pubdelete, ");
    4579              : 
    4580            0 :         if (fout->remoteVersion >= 110000)
    4581            0 :                 appendPQExpBufferStr(query, "p.pubtruncate, ");
    4582              :         else
    4583            0 :                 appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4584              : 
    4585            0 :         if (fout->remoteVersion >= 130000)
    4586            0 :                 appendPQExpBufferStr(query, "p.pubviaroot, ");
    4587              :         else
    4588            0 :                 appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4589              : 
    4590            0 :         if (fout->remoteVersion >= 180000)
    4591            0 :                 appendPQExpBufferStr(query, "p.pubgencols, ");
    4592              :         else
    4593            0 :                 appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
    4594              : 
    4595            0 :         if (fout->remoteVersion >= 190000)
    4596            0 :                 appendPQExpBufferStr(query, "p.puballsequences ");
    4597              :         else
    4598            0 :                 appendPQExpBufferStr(query, "false AS puballsequences ");
    4599              : 
    4600            0 :         appendPQExpBufferStr(query, "FROM pg_publication p");
    4601              : 
    4602            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4603              : 
    4604            0 :         ntups = PQntuples(res);
    4605              : 
    4606            0 :         if (ntups == 0)
    4607            0 :                 goto cleanup;
    4608              : 
    4609            0 :         i_tableoid = PQfnumber(res, "tableoid");
    4610            0 :         i_oid = PQfnumber(res, "oid");
    4611            0 :         i_pubname = PQfnumber(res, "pubname");
    4612            0 :         i_pubowner = PQfnumber(res, "pubowner");
    4613            0 :         i_puballtables = PQfnumber(res, "puballtables");
    4614            0 :         i_puballsequences = PQfnumber(res, "puballsequences");
    4615            0 :         i_pubinsert = PQfnumber(res, "pubinsert");
    4616            0 :         i_pubupdate = PQfnumber(res, "pubupdate");
    4617            0 :         i_pubdelete = PQfnumber(res, "pubdelete");
    4618            0 :         i_pubtruncate = PQfnumber(res, "pubtruncate");
    4619            0 :         i_pubviaroot = PQfnumber(res, "pubviaroot");
    4620            0 :         i_pubgencols = PQfnumber(res, "pubgencols");
    4621              : 
    4622            0 :         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
    4623              : 
    4624            0 :         for (i = 0; i < ntups; i++)
    4625              :         {
    4626            0 :                 pubinfo[i].dobj.objType = DO_PUBLICATION;
    4627            0 :                 pubinfo[i].dobj.catId.tableoid =
    4628            0 :                         atooid(PQgetvalue(res, i, i_tableoid));
    4629            0 :                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4630            0 :                 AssignDumpId(&pubinfo[i].dobj);
    4631            0 :                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4632            0 :                 pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4633            0 :                 pubinfo[i].puballtables =
    4634            0 :                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4635            0 :                 pubinfo[i].puballsequences =
    4636            0 :                         (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
    4637            0 :                 pubinfo[i].pubinsert =
    4638            0 :                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4639            0 :                 pubinfo[i].pubupdate =
    4640            0 :                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4641            0 :                 pubinfo[i].pubdelete =
    4642            0 :                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4643            0 :                 pubinfo[i].pubtruncate =
    4644            0 :                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4645            0 :                 pubinfo[i].pubviaroot =
    4646            0 :                         (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4647            0 :                 pubinfo[i].pubgencols_type =
    4648            0 :                         *(PQgetvalue(res, i, i_pubgencols));
    4649              : 
    4650              :                 /* Decide whether we want to dump it */
    4651            0 :                 selectDumpableObject(&(pubinfo[i].dobj), fout);
    4652            0 :         }
    4653              : 
    4654              : cleanup:
    4655            0 :         PQclear(res);
    4656              : 
    4657            0 :         destroyPQExpBuffer(query);
    4658            0 : }
    4659              : 
    4660              : /*
    4661              :  * dumpPublication
    4662              :  *        dump the definition of the given publication
    4663              :  */
    4664              : static void
    4665            0 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4666              : {
    4667            0 :         DumpOptions *dopt = fout->dopt;
    4668            0 :         PQExpBuffer delq;
    4669            0 :         PQExpBuffer query;
    4670            0 :         char       *qpubname;
    4671            0 :         bool            first = true;
    4672              : 
    4673              :         /* Do nothing if not dumping schema */
    4674            0 :         if (!dopt->dumpSchema)
    4675            0 :                 return;
    4676              : 
    4677            0 :         delq = createPQExpBuffer();
    4678            0 :         query = createPQExpBuffer();
    4679              : 
    4680            0 :         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4681              : 
    4682            0 :         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4683            0 :                                           qpubname);
    4684              : 
    4685            0 :         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4686            0 :                                           qpubname);
    4687              : 
    4688            0 :         if (pubinfo->puballtables && pubinfo->puballsequences)
    4689            0 :                 appendPQExpBufferStr(query, " FOR ALL TABLES, ALL SEQUENCES");
    4690            0 :         else if (pubinfo->puballtables)
    4691            0 :                 appendPQExpBufferStr(query, " FOR ALL TABLES");
    4692            0 :         else if (pubinfo->puballsequences)
    4693            0 :                 appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
    4694              : 
    4695            0 :         appendPQExpBufferStr(query, " WITH (publish = '");
    4696            0 :         if (pubinfo->pubinsert)
    4697              :         {
    4698            0 :                 appendPQExpBufferStr(query, "insert");
    4699            0 :                 first = false;
    4700            0 :         }
    4701              : 
    4702            0 :         if (pubinfo->pubupdate)
    4703              :         {
    4704            0 :                 if (!first)
    4705            0 :                         appendPQExpBufferStr(query, ", ");
    4706              : 
    4707            0 :                 appendPQExpBufferStr(query, "update");
    4708            0 :                 first = false;
    4709            0 :         }
    4710              : 
    4711            0 :         if (pubinfo->pubdelete)
    4712              :         {
    4713            0 :                 if (!first)
    4714            0 :                         appendPQExpBufferStr(query, ", ");
    4715              : 
    4716            0 :                 appendPQExpBufferStr(query, "delete");
    4717            0 :                 first = false;
    4718            0 :         }
    4719              : 
    4720            0 :         if (pubinfo->pubtruncate)
    4721              :         {
    4722            0 :                 if (!first)
    4723            0 :                         appendPQExpBufferStr(query, ", ");
    4724              : 
    4725            0 :                 appendPQExpBufferStr(query, "truncate");
    4726            0 :                 first = false;
    4727            0 :         }
    4728              : 
    4729            0 :         appendPQExpBufferChar(query, '\'');
    4730              : 
    4731            0 :         if (pubinfo->pubviaroot)
    4732            0 :                 appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4733              : 
    4734            0 :         if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4735            0 :                 appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4736              : 
    4737            0 :         appendPQExpBufferStr(query, ");\n");
    4738              : 
    4739            0 :         if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4740            0 :                 ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4741            0 :                                          ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4742              :                                                                   .owner = pubinfo->rolname,
    4743              :                                                                   .description = "PUBLICATION",
    4744              :                                                                   .section = SECTION_POST_DATA,
    4745              :                                                                   .createStmt = query->data,
    4746              :                                                                   .dropStmt = delq->data));
    4747              : 
    4748            0 :         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4749            0 :                 dumpComment(fout, "PUBLICATION", qpubname,
    4750            0 :                                         NULL, pubinfo->rolname,
    4751            0 :                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4752              : 
    4753            0 :         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4754            0 :                 dumpSecLabel(fout, "PUBLICATION", qpubname,
    4755            0 :                                          NULL, pubinfo->rolname,
    4756            0 :                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4757              : 
    4758            0 :         destroyPQExpBuffer(delq);
    4759            0 :         destroyPQExpBuffer(query);
    4760            0 :         free(qpubname);
    4761            0 : }
    4762              : 
    4763              : /*
    4764              :  * getPublicationNamespaces
    4765              :  *        get information about publication membership for dumpable schemas.
    4766              :  */
    4767              : void
    4768            0 : getPublicationNamespaces(Archive *fout)
    4769              : {
    4770            0 :         PQExpBuffer query;
    4771            0 :         PGresult   *res;
    4772            0 :         PublicationSchemaInfo *pubsinfo;
    4773            0 :         DumpOptions *dopt = fout->dopt;
    4774            0 :         int                     i_tableoid;
    4775            0 :         int                     i_oid;
    4776            0 :         int                     i_pnpubid;
    4777            0 :         int                     i_pnnspid;
    4778            0 :         int                     i,
    4779              :                                 j,
    4780              :                                 ntups;
    4781              : 
    4782            0 :         if (dopt->no_publications || fout->remoteVersion < 150000)
    4783            0 :                 return;
    4784              : 
    4785            0 :         query = createPQExpBuffer();
    4786              : 
    4787              :         /* Collect all publication membership info. */
    4788            0 :         appendPQExpBufferStr(query,
    4789              :                                                  "SELECT tableoid, oid, pnpubid, pnnspid "
    4790              :                                                  "FROM pg_catalog.pg_publication_namespace");
    4791            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4792              : 
    4793            0 :         ntups = PQntuples(res);
    4794              : 
    4795            0 :         i_tableoid = PQfnumber(res, "tableoid");
    4796            0 :         i_oid = PQfnumber(res, "oid");
    4797            0 :         i_pnpubid = PQfnumber(res, "pnpubid");
    4798            0 :         i_pnnspid = PQfnumber(res, "pnnspid");
    4799              : 
    4800              :         /* this allocation may be more than we need */
    4801            0 :         pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
    4802            0 :         j = 0;
    4803              : 
    4804            0 :         for (i = 0; i < ntups; i++)
    4805              :         {
    4806            0 :                 Oid                     pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4807            0 :                 Oid                     pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4808            0 :                 PublicationInfo *pubinfo;
    4809            0 :                 NamespaceInfo *nspinfo;
    4810              : 
    4811              :                 /*
    4812              :                  * Ignore any entries for which we aren't interested in either the
    4813              :                  * publication or the rel.
    4814              :                  */
    4815            0 :                 pubinfo = findPublicationByOid(pnpubid);
    4816            0 :                 if (pubinfo == NULL)
    4817            0 :                         continue;
    4818            0 :                 nspinfo = findNamespaceByOid(pnnspid);
    4819            0 :                 if (nspinfo == NULL)
    4820            0 :                         continue;
    4821              : 
    4822              :                 /* OK, make a DumpableObject for this relationship */
    4823            0 :                 pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4824            0 :                 pubsinfo[j].dobj.catId.tableoid =
    4825            0 :                         atooid(PQgetvalue(res, i, i_tableoid));
    4826            0 :                 pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4827            0 :                 AssignDumpId(&pubsinfo[j].dobj);
    4828            0 :                 pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4829            0 :                 pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4830            0 :                 pubsinfo[j].publication = pubinfo;
    4831            0 :                 pubsinfo[j].pubschema = nspinfo;
    4832              : 
    4833              :                 /* Decide whether we want to dump it */
    4834            0 :                 selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4835              : 
    4836            0 :                 j++;
    4837            0 :         }
    4838              : 
    4839            0 :         PQclear(res);
    4840            0 :         destroyPQExpBuffer(query);
    4841            0 : }
    4842              : 
    4843              : /*
    4844              :  * getPublicationTables
    4845              :  *        get information about publication membership for dumpable tables.
    4846              :  */
    4847              : void
    4848            0 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4849              : {
    4850            0 :         PQExpBuffer query;
    4851            0 :         PGresult   *res;
    4852            0 :         PublicationRelInfo *pubrinfo;
    4853            0 :         DumpOptions *dopt = fout->dopt;
    4854            0 :         int                     i_tableoid;
    4855            0 :         int                     i_oid;
    4856            0 :         int                     i_prpubid;
    4857            0 :         int                     i_prrelid;
    4858            0 :         int                     i_prrelqual;
    4859            0 :         int                     i_prattrs;
    4860            0 :         int                     i,
    4861              :                                 j,
    4862              :                                 ntups;
    4863              : 
    4864            0 :         if (dopt->no_publications || fout->remoteVersion < 100000)
    4865            0 :                 return;
    4866              : 
    4867            0 :         query = createPQExpBuffer();
    4868              : 
    4869              :         /* Collect all publication membership info. */
    4870            0 :         if (fout->remoteVersion >= 150000)
    4871            0 :                 appendPQExpBufferStr(query,
    4872              :                                                          "SELECT tableoid, oid, prpubid, prrelid, "
    4873              :                                                          "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4874              :                                                          "(CASE\n"
    4875              :                                                          "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4876              :                                                          "    (SELECT array_agg(attname)\n"
    4877              :                                                          "       FROM\n"
    4878              :                                                          "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4879              :                                                          "         pg_catalog.pg_attribute\n"
    4880              :                                                          "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4881              :                                                          "  ELSE NULL END) prattrs "
    4882              :                                                          "FROM pg_catalog.pg_publication_rel pr");
    4883              :         else
    4884            0 :                 appendPQExpBufferStr(query,
    4885              :                                                          "SELECT tableoid, oid, prpubid, prrelid, "
    4886              :                                                          "NULL AS prrelqual, NULL AS prattrs "
    4887              :                                                          "FROM pg_catalog.pg_publication_rel");
    4888            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4889              : 
    4890            0 :         ntups = PQntuples(res);
    4891              : 
    4892            0 :         i_tableoid = PQfnumber(res, "tableoid");
    4893            0 :         i_oid = PQfnumber(res, "oid");
    4894            0 :         i_prpubid = PQfnumber(res, "prpubid");
    4895            0 :         i_prrelid = PQfnumber(res, "prrelid");
    4896            0 :         i_prrelqual = PQfnumber(res, "prrelqual");
    4897            0 :         i_prattrs = PQfnumber(res, "prattrs");
    4898              : 
    4899              :         /* this allocation may be more than we need */
    4900            0 :         pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
    4901            0 :         j = 0;
    4902              : 
    4903            0 :         for (i = 0; i < ntups; i++)
    4904              :         {
    4905            0 :                 Oid                     prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4906            0 :                 Oid                     prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4907            0 :                 PublicationInfo *pubinfo;
    4908            0 :                 TableInfo  *tbinfo;
    4909              : 
    4910              :                 /*
    4911              :                  * Ignore any entries for which we aren't interested in either the
    4912              :                  * publication or the rel.
    4913              :                  */
    4914            0 :                 pubinfo = findPublicationByOid(prpubid);
    4915            0 :                 if (pubinfo == NULL)
    4916            0 :                         continue;
    4917            0 :                 tbinfo = findTableByOid(prrelid);
    4918            0 :                 if (tbinfo == NULL)
    4919            0 :                         continue;
    4920              : 
    4921              :                 /* OK, make a DumpableObject for this relationship */
    4922            0 :                 pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4923            0 :                 pubrinfo[j].dobj.catId.tableoid =
    4924            0 :                         atooid(PQgetvalue(res, i, i_tableoid));
    4925            0 :                 pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4926            0 :                 AssignDumpId(&pubrinfo[j].dobj);
    4927            0 :                 pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4928            0 :                 pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4929            0 :                 pubrinfo[j].publication = pubinfo;
    4930            0 :                 pubrinfo[j].pubtable = tbinfo;
    4931            0 :                 if (PQgetisnull(res, i, i_prrelqual))
    4932            0 :                         pubrinfo[j].pubrelqual = NULL;
    4933              :                 else
    4934            0 :                         pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4935              : 
    4936            0 :                 if (!PQgetisnull(res, i, i_prattrs))
    4937              :                 {
    4938            0 :                         char      **attnames;
    4939            0 :                         int                     nattnames;
    4940            0 :                         PQExpBuffer attribs;
    4941              : 
    4942            0 :                         if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4943              :                                                           &attnames, &nattnames))
    4944            0 :                                 pg_fatal("could not parse %s array", "prattrs");
    4945            0 :                         attribs = createPQExpBuffer();
    4946            0 :                         for (int k = 0; k < nattnames; k++)
    4947              :                         {
    4948            0 :                                 if (k > 0)
    4949            0 :                                         appendPQExpBufferStr(attribs, ", ");
    4950              : 
    4951            0 :                                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4952            0 :                         }
    4953            0 :                         pubrinfo[j].pubrattrs = attribs->data;
    4954            0 :                         free(attribs);          /* but not attribs->data */
    4955            0 :                         free(attnames);
    4956            0 :                 }
    4957              :                 else
    4958            0 :                         pubrinfo[j].pubrattrs = NULL;
    4959              : 
    4960              :                 /* Decide whether we want to dump it */
    4961            0 :                 selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    4962              : 
    4963            0 :                 j++;
    4964            0 :         }
    4965              : 
    4966            0 :         PQclear(res);
    4967            0 :         destroyPQExpBuffer(query);
    4968            0 : }
    4969              : 
    4970              : /*
    4971              :  * dumpPublicationNamespace
    4972              :  *        dump the definition of the given publication schema mapping.
    4973              :  */
    4974              : static void
    4975            0 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    4976              : {
    4977            0 :         DumpOptions *dopt = fout->dopt;
    4978            0 :         NamespaceInfo *schemainfo = pubsinfo->pubschema;
    4979            0 :         PublicationInfo *pubinfo = pubsinfo->publication;
    4980            0 :         PQExpBuffer query;
    4981            0 :         char       *tag;
    4982              : 
    4983              :         /* Do nothing if not dumping schema */
    4984            0 :         if (!dopt->dumpSchema)
    4985            0 :                 return;
    4986              : 
    4987            0 :         tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    4988              : 
    4989            0 :         query = createPQExpBuffer();
    4990              : 
    4991            0 :         appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    4992            0 :         appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    4993              : 
    4994              :         /*
    4995              :          * There is no point in creating drop query as the drop is done by schema
    4996              :          * drop.
    4997              :          */
    4998            0 :         if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4999            0 :                 ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    5000            0 :                                          ARCHIVE_OPTS(.tag = tag,
    5001              :                                                                   .namespace = schemainfo->dobj.name,
    5002              :                                                                   .owner = pubinfo->rolname,
    5003              :                                                                   .description = "PUBLICATION TABLES IN SCHEMA",
    5004              :                                                                   .section = SECTION_POST_DATA,
    5005              :                                                                   .createStmt = query->data));
    5006              : 
    5007              :         /* These objects can't currently have comments or seclabels */
    5008              : 
    5009            0 :         free(tag);
    5010            0 :         destroyPQExpBuffer(query);
    5011            0 : }
    5012              : 
    5013              : /*
    5014              :  * dumpPublicationTable
    5015              :  *        dump the definition of the given publication table mapping
    5016              :  */
    5017              : static void
    5018            0 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    5019              : {
    5020            0 :         DumpOptions *dopt = fout->dopt;
    5021            0 :         PublicationInfo *pubinfo = pubrinfo->publication;
    5022            0 :         TableInfo  *tbinfo = pubrinfo->pubtable;
    5023            0 :         PQExpBuffer query;
    5024            0 :         char       *tag;
    5025              : 
    5026              :         /* Do nothing if not dumping schema */
    5027            0 :         if (!dopt->dumpSchema)
    5028            0 :                 return;
    5029              : 
    5030            0 :         tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    5031              : 
    5032            0 :         query = createPQExpBuffer();
    5033              : 
    5034            0 :         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    5035            0 :                                           fmtId(pubinfo->dobj.name));
    5036            0 :         appendPQExpBuffer(query, " %s",
    5037            0 :                                           fmtQualifiedDumpable(tbinfo));
    5038              : 
    5039            0 :         if (pubrinfo->pubrattrs)
    5040            0 :                 appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    5041              : 
    5042            0 :         if (pubrinfo->pubrelqual)
    5043              :         {
    5044              :                 /*
    5045              :                  * It's necessary to add parentheses around the expression because
    5046              :                  * pg_get_expr won't supply the parentheses for things like WHERE
    5047              :                  * TRUE.
    5048              :                  */
    5049            0 :                 appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    5050            0 :         }
    5051            0 :         appendPQExpBufferStr(query, ";\n");
    5052              : 
    5053              :         /*
    5054              :          * There is no point in creating a drop query as the drop is done by table
    5055              :          * drop.  (If you think to change this, see also _printTocEntry().)
    5056              :          * Although this object doesn't really have ownership as such, set the
    5057              :          * owner field anyway to ensure that the command is run by the correct
    5058              :          * role at restore time.
    5059              :          */
    5060            0 :         if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5061            0 :                 ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    5062            0 :                                          ARCHIVE_OPTS(.tag = tag,
    5063              :                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    5064              :                                                                   .owner = pubinfo->rolname,
    5065              :                                                                   .description = "PUBLICATION TABLE",
    5066              :                                                                   .section = SECTION_POST_DATA,
    5067              :                                                                   .createStmt = query->data));
    5068              : 
    5069              :         /* These objects can't currently have comments or seclabels */
    5070              : 
    5071            0 :         free(tag);
    5072            0 :         destroyPQExpBuffer(query);
    5073            0 : }
    5074              : 
    5075              : /*
    5076              :  * Is the currently connected user a superuser?
    5077              :  */
    5078              : static bool
    5079            0 : is_superuser(Archive *fout)
    5080              : {
    5081            0 :         ArchiveHandle *AH = (ArchiveHandle *) fout;
    5082            0 :         const char *val;
    5083              : 
    5084            0 :         val = PQparameterStatus(AH->connection, "is_superuser");
    5085              : 
    5086            0 :         if (val && strcmp(val, "on") == 0)
    5087            0 :                 return true;
    5088              : 
    5089            0 :         return false;
    5090            0 : }
    5091              : 
    5092              : /*
    5093              :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    5094              :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    5095              :  * the setting query is effective only where available.
    5096              :  */
    5097              : static void
    5098            0 : set_restrict_relation_kind(Archive *AH, const char *value)
    5099              : {
    5100            0 :         PQExpBuffer query = createPQExpBuffer();
    5101            0 :         PGresult   *res;
    5102              : 
    5103            0 :         appendPQExpBuffer(query,
    5104              :                                           "SELECT set_config(name, '%s', false) "
    5105              :                                           "FROM pg_settings "
    5106              :                                           "WHERE name = 'restrict_nonsystem_relation_kind'",
    5107            0 :                                           value);
    5108            0 :         res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    5109              : 
    5110            0 :         PQclear(res);
    5111            0 :         destroyPQExpBuffer(query);
    5112            0 : }
    5113              : 
    5114              : /*
    5115              :  * getSubscriptions
    5116              :  *        get information about subscriptions
    5117              :  */
    5118              : void
    5119            0 : getSubscriptions(Archive *fout)
    5120              : {
    5121            0 :         DumpOptions *dopt = fout->dopt;
    5122            0 :         PQExpBuffer query;
    5123            0 :         PGresult   *res;
    5124            0 :         SubscriptionInfo *subinfo;
    5125            0 :         int                     i_tableoid;
    5126            0 :         int                     i_oid;
    5127            0 :         int                     i_subname;
    5128            0 :         int                     i_subowner;
    5129            0 :         int                     i_subbinary;
    5130            0 :         int                     i_substream;
    5131            0 :         int                     i_subtwophasestate;
    5132            0 :         int                     i_subdisableonerr;
    5133            0 :         int                     i_subpasswordrequired;
    5134            0 :         int                     i_subrunasowner;
    5135            0 :         int                     i_subconninfo;
    5136            0 :         int                     i_subslotname;
    5137            0 :         int                     i_subsynccommit;
    5138            0 :         int                     i_subpublications;
    5139            0 :         int                     i_suborigin;
    5140            0 :         int                     i_suboriginremotelsn;
    5141            0 :         int                     i_subenabled;
    5142            0 :         int                     i_subfailover;
    5143            0 :         int                     i_subretaindeadtuples;
    5144            0 :         int                     i_submaxretention;
    5145            0 :         int                     i,
    5146              :                                 ntups;
    5147              : 
    5148            0 :         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    5149            0 :                 return;
    5150              : 
    5151            0 :         if (!is_superuser(fout))
    5152              :         {
    5153            0 :                 int                     n;
    5154              : 
    5155            0 :                 res = ExecuteSqlQuery(fout,
    5156              :                                                           "SELECT count(*) FROM pg_subscription "
    5157              :                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
    5158              :                                                           "                 WHERE datname = current_database())",
    5159              :                                                           PGRES_TUPLES_OK);
    5160            0 :                 n = atoi(PQgetvalue(res, 0, 0));
    5161            0 :                 if (n > 0)
    5162            0 :                         pg_log_warning("subscriptions not dumped because current user is not a superuser");
    5163            0 :                 PQclear(res);
    5164              :                 return;
    5165            0 :         }
    5166              : 
    5167            0 :         query = createPQExpBuffer();
    5168              : 
    5169              :         /* Get the subscriptions in current database. */
    5170            0 :         appendPQExpBufferStr(query,
    5171              :                                                  "SELECT s.tableoid, s.oid, s.subname,\n"
    5172              :                                                  " s.subowner,\n"
    5173              :                                                  " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    5174              :                                                  " s.subpublications,\n");
    5175              : 
    5176            0 :         if (fout->remoteVersion >= 140000)
    5177            0 :                 appendPQExpBufferStr(query, " s.subbinary,\n");
    5178              :         else
    5179            0 :                 appendPQExpBufferStr(query, " false AS subbinary,\n");
    5180              : 
    5181            0 :         if (fout->remoteVersion >= 140000)
    5182            0 :                 appendPQExpBufferStr(query, " s.substream,\n");
    5183              :         else
    5184            0 :                 appendPQExpBufferStr(query, " 'f' AS substream,\n");
    5185              : 
    5186            0 :         if (fout->remoteVersion >= 150000)
    5187            0 :                 appendPQExpBufferStr(query,
    5188              :                                                          " s.subtwophasestate,\n"
    5189              :                                                          " s.subdisableonerr,\n");
    5190              :         else
    5191            0 :                 appendPQExpBuffer(query,
    5192              :                                                   " '%c' AS subtwophasestate,\n"
    5193              :                                                   " false AS subdisableonerr,\n",
    5194              :                                                   LOGICALREP_TWOPHASE_STATE_DISABLED);
    5195              : 
    5196            0 :         if (fout->remoteVersion >= 160000)
    5197            0 :                 appendPQExpBufferStr(query,
    5198              :                                                          " s.subpasswordrequired,\n"
    5199              :                                                          " s.subrunasowner,\n"
    5200              :                                                          " s.suborigin,\n");
    5201              :         else
    5202            0 :                 appendPQExpBuffer(query,
    5203              :                                                   " 't' AS subpasswordrequired,\n"
    5204              :                                                   " 't' AS subrunasowner,\n"
    5205              :                                                   " '%s' AS suborigin,\n",
    5206              :                                                   LOGICALREP_ORIGIN_ANY);
    5207              : 
    5208            0 :         if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5209            0 :                 appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    5210              :                                                          " s.subenabled,\n");
    5211              :         else
    5212            0 :                 appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    5213              :                                                          " false AS subenabled,\n");
    5214              : 
    5215            0 :         if (fout->remoteVersion >= 170000)
    5216            0 :                 appendPQExpBufferStr(query,
    5217              :                                                          " s.subfailover,\n");
    5218              :         else
    5219            0 :                 appendPQExpBufferStr(query,
    5220              :                                                          " false AS subfailover,\n");
    5221              : 
    5222            0 :         if (fout->remoteVersion >= 190000)
    5223            0 :                 appendPQExpBufferStr(query,
    5224              :                                                          " s.subretaindeadtuples,\n");
    5225              :         else
    5226            0 :                 appendPQExpBufferStr(query,
    5227              :                                                          " false AS subretaindeadtuples,\n");
    5228              : 
    5229            0 :         if (fout->remoteVersion >= 190000)
    5230            0 :                 appendPQExpBufferStr(query,
    5231              :                                                          " s.submaxretention\n");
    5232              :         else
    5233            0 :                 appendPQExpBuffer(query,
    5234              :                                                   " 0 AS submaxretention\n");
    5235              : 
    5236            0 :         appendPQExpBufferStr(query,
    5237              :                                                  "FROM pg_subscription s\n");
    5238              : 
    5239            0 :         if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5240            0 :                 appendPQExpBufferStr(query,
    5241              :                                                          "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    5242              :                                                          "    ON o.external_id = 'pg_' || s.oid::text \n");
    5243              : 
    5244            0 :         appendPQExpBufferStr(query,
    5245              :                                                  "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    5246              :                                                  "                   WHERE datname = current_database())");
    5247              : 
    5248            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5249              : 
    5250            0 :         ntups = PQntuples(res);
    5251              : 
    5252              :         /*
    5253              :          * Get subscription fields. We don't include subskiplsn in the dump as
    5254              :          * after restoring the dump this value may no longer be relevant.
    5255              :          */
    5256            0 :         i_tableoid = PQfnumber(res, "tableoid");
    5257            0 :         i_oid = PQfnumber(res, "oid");
    5258            0 :         i_subname = PQfnumber(res, "subname");
    5259            0 :         i_subowner = PQfnumber(res, "subowner");
    5260            0 :         i_subenabled = PQfnumber(res, "subenabled");
    5261            0 :         i_subbinary = PQfnumber(res, "subbinary");
    5262            0 :         i_substream = PQfnumber(res, "substream");
    5263            0 :         i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5264            0 :         i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5265            0 :         i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5266            0 :         i_subrunasowner = PQfnumber(res, "subrunasowner");
    5267            0 :         i_subfailover = PQfnumber(res, "subfailover");
    5268            0 :         i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
    5269            0 :         i_submaxretention = PQfnumber(res, "submaxretention");
    5270            0 :         i_subconninfo = PQfnumber(res, "subconninfo");
    5271            0 :         i_subslotname = PQfnumber(res, "subslotname");
    5272            0 :         i_subsynccommit = PQfnumber(res, "subsynccommit");
    5273            0 :         i_subpublications = PQfnumber(res, "subpublications");
    5274            0 :         i_suborigin = PQfnumber(res, "suborigin");
    5275            0 :         i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5276              : 
    5277            0 :         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
    5278              : 
    5279            0 :         for (i = 0; i < ntups; i++)
    5280              :         {
    5281            0 :                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5282            0 :                 subinfo[i].dobj.catId.tableoid =
    5283            0 :                         atooid(PQgetvalue(res, i, i_tableoid));
    5284            0 :                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5285            0 :                 AssignDumpId(&subinfo[i].dobj);
    5286            0 :                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5287            0 :                 subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5288              : 
    5289            0 :                 subinfo[i].subenabled =
    5290            0 :                         (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5291            0 :                 subinfo[i].subbinary =
    5292            0 :                         (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5293            0 :                 subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5294            0 :                 subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5295            0 :                 subinfo[i].subdisableonerr =
    5296            0 :                         (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5297            0 :                 subinfo[i].subpasswordrequired =
    5298            0 :                         (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5299            0 :                 subinfo[i].subrunasowner =
    5300            0 :                         (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5301            0 :                 subinfo[i].subfailover =
    5302            0 :                         (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5303            0 :                 subinfo[i].subretaindeadtuples =
    5304            0 :                         (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
    5305            0 :                 subinfo[i].submaxretention =
    5306            0 :                         atoi(PQgetvalue(res, i, i_submaxretention));
    5307            0 :                 subinfo[i].subconninfo =
    5308            0 :                         pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5309            0 :                 if (PQgetisnull(res, i, i_subslotname))
    5310            0 :                         subinfo[i].subslotname = NULL;
    5311              :                 else
    5312            0 :                         subinfo[i].subslotname =
    5313            0 :                                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5314            0 :                 subinfo[i].subsynccommit =
    5315            0 :                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5316            0 :                 subinfo[i].subpublications =
    5317            0 :                         pg_strdup(PQgetvalue(res, i, i_subpublications));
    5318            0 :                 subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5319            0 :                 if (PQgetisnull(res, i, i_suboriginremotelsn))
    5320            0 :                         subinfo[i].suboriginremotelsn = NULL;
    5321              :                 else
    5322            0 :                         subinfo[i].suboriginremotelsn =
    5323            0 :                                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5324              : 
    5325              :                 /* Decide whether we want to dump it */
    5326            0 :                 selectDumpableObject(&(subinfo[i].dobj), fout);
    5327            0 :         }
    5328            0 :         PQclear(res);
    5329              : 
    5330            0 :         destroyPQExpBuffer(query);
    5331            0 : }
    5332              : 
    5333              : /*
    5334              :  * getSubscriptionRelations
    5335              :  *        Get information about subscription membership for dumpable relations. This
    5336              :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5337              :  */
    5338              : void
    5339            0 : getSubscriptionRelations(Archive *fout)
    5340              : {
    5341            0 :         DumpOptions *dopt = fout->dopt;
    5342            0 :         SubscriptionInfo *subinfo = NULL;
    5343            0 :         SubRelInfo *subrinfo;
    5344            0 :         PGresult   *res;
    5345            0 :         int                     i_srsubid;
    5346            0 :         int                     i_srrelid;
    5347            0 :         int                     i_srsubstate;
    5348            0 :         int                     i_srsublsn;
    5349            0 :         int                     ntups;
    5350            0 :         Oid                     last_srsubid = InvalidOid;
    5351              : 
    5352            0 :         if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5353            0 :                 fout->remoteVersion < 170000)
    5354            0 :                 return;
    5355              : 
    5356            0 :         res = ExecuteSqlQuery(fout,
    5357              :                                                   "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5358              :                                                   "FROM pg_catalog.pg_subscription_rel "
    5359              :                                                   "ORDER BY srsubid",
    5360              :                                                   PGRES_TUPLES_OK);
    5361            0 :         ntups = PQntuples(res);
    5362            0 :         if (ntups == 0)
    5363            0 :                 goto cleanup;
    5364              : 
    5365              :         /* Get pg_subscription_rel attributes */
    5366            0 :         i_srsubid = PQfnumber(res, "srsubid");
    5367            0 :         i_srrelid = PQfnumber(res, "srrelid");
    5368            0 :         i_srsubstate = PQfnumber(res, "srsubstate");
    5369            0 :         i_srsublsn = PQfnumber(res, "srsublsn");
    5370              : 
    5371            0 :         subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
    5372            0 :         for (int i = 0; i < ntups; i++)
    5373              :         {
    5374            0 :                 Oid                     cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5375            0 :                 Oid                     relid = atooid(PQgetvalue(res, i, i_srrelid));
    5376            0 :                 TableInfo  *tblinfo;
    5377              : 
    5378              :                 /*
    5379              :                  * If we switched to a new subscription, check if the subscription
    5380              :                  * exists.
    5381              :                  */
    5382            0 :                 if (cur_srsubid != last_srsubid)
    5383              :                 {
    5384            0 :                         subinfo = findSubscriptionByOid(cur_srsubid);
    5385            0 :                         if (subinfo == NULL)
    5386            0 :                                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5387              : 
    5388            0 :                         last_srsubid = cur_srsubid;
    5389            0 :                 }
    5390              : 
    5391            0 :                 tblinfo = findTableByOid(relid);
    5392            0 :                 if (tblinfo == NULL)
    5393            0 :                         pg_fatal("failed sanity check, relation with OID %u not found",
    5394              :                                          relid);
    5395              : 
    5396              :                 /* OK, make a DumpableObject for this relationship */
    5397            0 :                 subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5398            0 :                 subrinfo[i].dobj.catId.tableoid = relid;
    5399            0 :                 subrinfo[i].dobj.catId.oid = cur_srsubid;
    5400            0 :                 AssignDumpId(&subrinfo[i].dobj);
    5401            0 :                 subrinfo[i].dobj.namespace = tblinfo->dobj.namespace;
    5402            0 :                 subrinfo[i].dobj.name = tblinfo->dobj.name;
    5403            0 :                 subrinfo[i].subinfo = subinfo;
    5404            0 :                 subrinfo[i].tblinfo = tblinfo;
    5405            0 :                 subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5406            0 :                 if (PQgetisnull(res, i, i_srsublsn))
    5407            0 :                         subrinfo[i].srsublsn = NULL;
    5408              :                 else
    5409            0 :                         subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5410              : 
    5411              :                 /* Decide whether we want to dump it */
    5412            0 :                 selectDumpableObject(&(subrinfo[i].dobj), fout);
    5413            0 :         }
    5414              : 
    5415              : cleanup:
    5416            0 :         PQclear(res);
    5417            0 : }
    5418              : 
    5419              : /*
    5420              :  * dumpSubscriptionTable
    5421              :  *        Dump the definition of the given subscription table mapping. This will be
    5422              :  *    used only in binary-upgrade mode for PG17 or later versions.
    5423              :  */
    5424              : static void
    5425            0 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5426              : {
    5427            0 :         DumpOptions *dopt = fout->dopt;
    5428            0 :         SubscriptionInfo *subinfo = subrinfo->subinfo;
    5429            0 :         PQExpBuffer query;
    5430            0 :         char       *tag;
    5431              : 
    5432              :         /* Do nothing if not dumping schema */
    5433            0 :         if (!dopt->dumpSchema)
    5434            0 :                 return;
    5435              : 
    5436            0 :         Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5437              : 
    5438            0 :         tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->tblinfo->dobj.name);
    5439              : 
    5440            0 :         query = createPQExpBuffer();
    5441              : 
    5442            0 :         if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5443              :         {
    5444              :                 /*
    5445              :                  * binary_upgrade_add_sub_rel_state will add the subscription relation
    5446              :                  * to pg_subscription_rel table. This will be used only in
    5447              :                  * binary-upgrade mode.
    5448              :                  */
    5449            0 :                 appendPQExpBufferStr(query,
    5450              :                                                          "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5451            0 :                 appendPQExpBufferStr(query,
    5452              :                                                          "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5453            0 :                 appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5454            0 :                 appendPQExpBuffer(query,
    5455              :                                                   ", %u, '%c'",
    5456            0 :                                                   subrinfo->tblinfo->dobj.catId.oid,
    5457            0 :                                                   subrinfo->srsubstate);
    5458              : 
    5459            0 :                 if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5460            0 :                         appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5461              :                 else
    5462            0 :                         appendPQExpBufferStr(query, ", NULL");
    5463              : 
    5464            0 :                 appendPQExpBufferStr(query, ");\n");
    5465            0 :         }
    5466              : 
    5467              :         /*
    5468              :          * There is no point in creating a drop query as the drop is done by table
    5469              :          * drop.  (If you think to change this, see also _printTocEntry().)
    5470              :          * Although this object doesn't really have ownership as such, set the
    5471              :          * owner field anyway to ensure that the command is run by the correct
    5472              :          * role at restore time.
    5473              :          */
    5474            0 :         if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5475            0 :                 ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5476            0 :                                          ARCHIVE_OPTS(.tag = tag,
    5477              :                                                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5478              :                                                                   .owner = subinfo->rolname,
    5479              :                                                                   .description = "SUBSCRIPTION TABLE",
    5480              :                                                                   .section = SECTION_POST_DATA,
    5481              :                                                                   .createStmt = query->data));
    5482              : 
    5483              :         /* These objects can't currently have comments or seclabels */
    5484              : 
    5485            0 :         free(tag);
    5486            0 :         destroyPQExpBuffer(query);
    5487            0 : }
    5488              : 
    5489              : /*
    5490              :  * dumpSubscription
    5491              :  *        dump the definition of the given subscription
    5492              :  */
    5493              : static void
    5494            0 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5495              : {
    5496            0 :         DumpOptions *dopt = fout->dopt;
    5497            0 :         PQExpBuffer delq;
    5498            0 :         PQExpBuffer query;
    5499            0 :         PQExpBuffer publications;
    5500            0 :         char       *qsubname;
    5501            0 :         char      **pubnames = NULL;
    5502            0 :         int                     npubnames = 0;
    5503            0 :         int                     i;
    5504              : 
    5505              :         /* Do nothing if not dumping schema */
    5506            0 :         if (!dopt->dumpSchema)
    5507            0 :                 return;
    5508              : 
    5509            0 :         delq = createPQExpBuffer();
    5510            0 :         query = createPQExpBuffer();
    5511              : 
    5512            0 :         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5513              : 
    5514            0 :         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5515            0 :                                           qsubname);
    5516              : 
    5517            0 :         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
    5518            0 :                                           qsubname);
    5519            0 :         appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5520              : 
    5521              :         /* Build list of quoted publications and append them to query. */
    5522            0 :         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5523            0 :                 pg_fatal("could not parse %s array", "subpublications");
    5524              : 
    5525            0 :         publications = createPQExpBuffer();
    5526            0 :         for (i = 0; i < npubnames; i++)
    5527              :         {
    5528            0 :                 if (i > 0)
    5529            0 :                         appendPQExpBufferStr(publications, ", ");
    5530              : 
    5531            0 :                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5532            0 :         }
    5533              : 
    5534            0 :         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5535            0 :         if (subinfo->subslotname)
    5536            0 :                 appendStringLiteralAH(query, subinfo->subslotname, fout);
    5537              :         else
    5538            0 :                 appendPQExpBufferStr(query, "NONE");
    5539              : 
    5540            0 :         if (subinfo->subbinary)
    5541            0 :                 appendPQExpBufferStr(query, ", binary = true");
    5542              : 
    5543            0 :         if (subinfo->substream == LOGICALREP_STREAM_ON)
    5544            0 :                 appendPQExpBufferStr(query, ", streaming = on");
    5545            0 :         else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5546            0 :                 appendPQExpBufferStr(query, ", streaming = parallel");
    5547              :         else
    5548            0 :                 appendPQExpBufferStr(query, ", streaming = off");
    5549              : 
    5550            0 :         if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5551            0 :                 appendPQExpBufferStr(query, ", two_phase = on");
    5552              : 
    5553            0 :         if (subinfo->subdisableonerr)
    5554            0 :                 appendPQExpBufferStr(query, ", disable_on_error = true");
    5555              : 
    5556            0 :         if (!subinfo->subpasswordrequired)
    5557            0 :                 appendPQExpBufferStr(query, ", password_required = false");
    5558              : 
    5559            0 :         if (subinfo->subrunasowner)
    5560            0 :                 appendPQExpBufferStr(query, ", run_as_owner = true");
    5561              : 
    5562            0 :         if (subinfo->subfailover)
    5563            0 :                 appendPQExpBufferStr(query, ", failover = true");
    5564              : 
    5565            0 :         if (subinfo->subretaindeadtuples)
    5566            0 :                 appendPQExpBufferStr(query, ", retain_dead_tuples = true");
    5567              : 
    5568            0 :         if (subinfo->submaxretention)
    5569            0 :                 appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
    5570              : 
    5571            0 :         if (strcmp(subinfo->subsynccommit, "off") != 0)
    5572            0 :                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5573              : 
    5574            0 :         if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5575            0 :                 appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5576              : 
    5577            0 :         appendPQExpBufferStr(query, ");\n");
    5578              : 
    5579              :         /*
    5580              :          * In binary-upgrade mode, we allow the replication to continue after the
    5581              :          * upgrade.
    5582              :          */
    5583            0 :         if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5584              :         {
    5585            0 :                 if (subinfo->suboriginremotelsn)
    5586              :                 {
    5587              :                         /*
    5588              :                          * Preserve the remote_lsn for the subscriber's replication
    5589              :                          * origin. This value is required to start the replication from
    5590              :                          * the position before the upgrade. This value will be stale if
    5591              :                          * the publisher gets upgraded before the subscriber node.
    5592              :                          * However, this shouldn't be a problem as the upgrade of the
    5593              :                          * publisher ensures that all the transactions were replicated
    5594              :                          * before upgrading it.
    5595              :                          */
    5596            0 :                         appendPQExpBufferStr(query,
    5597              :                                                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5598            0 :                         appendPQExpBufferStr(query,
    5599              :                                                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5600            0 :                         appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5601            0 :                         appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5602            0 :                 }
    5603              : 
    5604            0 :                 if (subinfo->subenabled)
    5605              :                 {
    5606              :                         /*
    5607              :                          * Enable the subscription to allow the replication to continue
    5608              :                          * after the upgrade.
    5609              :                          */
    5610            0 :                         appendPQExpBufferStr(query,
    5611              :                                                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5612            0 :                         appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5613            0 :                 }
    5614            0 :         }
    5615              : 
    5616            0 :         if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5617            0 :                 ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5618            0 :                                          ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5619              :                                                                   .owner = subinfo->rolname,
    5620              :                                                                   .description = "SUBSCRIPTION",
    5621              :                                                                   .section = SECTION_POST_DATA,
    5622              :                                                                   .createStmt = query->data,
    5623              :                                                                   .dropStmt = delq->data));
    5624              : 
    5625            0 :         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5626            0 :                 dumpComment(fout, "SUBSCRIPTION", qsubname,
    5627            0 :                                         NULL, subinfo->rolname,
    5628            0 :                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5629              : 
    5630            0 :         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5631            0 :                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5632            0 :                                          NULL, subinfo->rolname,
    5633            0 :                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5634              : 
    5635            0 :         destroyPQExpBuffer(publications);
    5636            0 :         free(pubnames);
    5637              : 
    5638            0 :         destroyPQExpBuffer(delq);
    5639            0 :         destroyPQExpBuffer(query);
    5640            0 :         free(qsubname);
    5641            0 : }
    5642              : 
    5643              : /*
    5644              :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5645              :  * the object needs.
    5646              :  */
    5647              : static void
    5648            0 : append_depends_on_extension(Archive *fout,
    5649              :                                                         PQExpBuffer create,
    5650              :                                                         const DumpableObject *dobj,
    5651              :                                                         const char *catalog,
    5652              :                                                         const char *keyword,
    5653              :                                                         const char *objname)
    5654              : {
    5655            0 :         if (dobj->depends_on_ext)
    5656              :         {
    5657            0 :                 char       *nm;
    5658            0 :                 PGresult   *res;
    5659            0 :                 PQExpBuffer query;
    5660            0 :                 int                     ntups;
    5661            0 :                 int                     i_extname;
    5662            0 :                 int                     i;
    5663              : 
    5664              :                 /* dodge fmtId() non-reentrancy */
    5665            0 :                 nm = pg_strdup(objname);
    5666              : 
    5667            0 :                 query = createPQExpBuffer();
    5668            0 :                 appendPQExpBuffer(query,
    5669              :                                                   "SELECT e.extname "
    5670              :                                                   "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5671              :                                                   "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5672              :                                                   "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5673              :                                                   "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5674            0 :                                                   catalog,
    5675            0 :                                                   dobj->catId.oid);
    5676            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5677            0 :                 ntups = PQntuples(res);
    5678            0 :                 i_extname = PQfnumber(res, "extname");
    5679            0 :                 for (i = 0; i < ntups; i++)
    5680              :                 {
    5681            0 :                         appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5682            0 :                                                           keyword, nm,
    5683            0 :                                                           fmtId(PQgetvalue(res, i, i_extname)));
    5684            0 :                 }
    5685              : 
    5686            0 :                 PQclear(res);
    5687            0 :                 destroyPQExpBuffer(query);
    5688            0 :                 pg_free(nm);
    5689            0 :         }
    5690            0 : }
    5691              : 
    5692              : static Oid
    5693            0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5694              : {
    5695              :         /*
    5696              :          * If the old version didn't assign an array type, but the new version
    5697              :          * does, we must select an unused type OID to assign.  This currently only
    5698              :          * happens for domains, when upgrading pre-v11 to v11 and up.
    5699              :          *
    5700              :          * Note: local state here is kind of ugly, but we must have some, since we
    5701              :          * mustn't choose the same unused OID more than once.
    5702              :          */
    5703              :         static Oid      next_possible_free_oid = FirstNormalObjectId;
    5704            0 :         PGresult   *res;
    5705            0 :         bool            is_dup;
    5706              : 
    5707            0 :         do
    5708              :         {
    5709            0 :                 ++next_possible_free_oid;
    5710            0 :                 printfPQExpBuffer(upgrade_query,
    5711              :                                                   "SELECT EXISTS(SELECT 1 "
    5712              :                                                   "FROM pg_catalog.pg_type "
    5713              :                                                   "WHERE oid = '%u'::pg_catalog.oid);",
    5714            0 :                                                   next_possible_free_oid);
    5715            0 :                 res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5716            0 :                 is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5717            0 :                 PQclear(res);
    5718            0 :         } while (is_dup);
    5719              : 
    5720            0 :         return next_possible_free_oid;
    5721            0 : }
    5722              : 
    5723              : static void
    5724            0 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5725              :                                                                                  PQExpBuffer upgrade_buffer,
    5726              :                                                                                  Oid pg_type_oid,
    5727              :                                                                                  bool force_array_type,
    5728              :                                                                                  bool include_multirange_type)
    5729              : {
    5730            0 :         PQExpBuffer upgrade_query = createPQExpBuffer();
    5731            0 :         PGresult   *res;
    5732            0 :         Oid                     pg_type_array_oid;
    5733            0 :         Oid                     pg_type_multirange_oid;
    5734            0 :         Oid                     pg_type_multirange_array_oid;
    5735            0 :         TypeInfo   *tinfo;
    5736              : 
    5737            0 :         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5738            0 :         appendPQExpBuffer(upgrade_buffer,
    5739              :                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5740            0 :                                           pg_type_oid);
    5741              : 
    5742            0 :         tinfo = findTypeByOid(pg_type_oid);
    5743            0 :         if (tinfo)
    5744            0 :                 pg_type_array_oid = tinfo->typarray;
    5745              :         else
    5746            0 :                 pg_type_array_oid = InvalidOid;
    5747              : 
    5748            0 :         if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5749            0 :                 pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5750              : 
    5751            0 :         if (OidIsValid(pg_type_array_oid))
    5752              :         {
    5753            0 :                 appendPQExpBufferStr(upgrade_buffer,
    5754              :                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5755            0 :                 appendPQExpBuffer(upgrade_buffer,
    5756              :                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5757            0 :                                                   pg_type_array_oid);
    5758            0 :         }
    5759              : 
    5760              :         /*
    5761              :          * Pre-set the multirange type oid and its own array type oid.
    5762              :          */
    5763            0 :         if (include_multirange_type)
    5764              :         {
    5765            0 :                 if (fout->remoteVersion >= 140000)
    5766              :                 {
    5767            0 :                         printfPQExpBuffer(upgrade_query,
    5768              :                                                           "SELECT t.oid, t.typarray "
    5769              :                                                           "FROM pg_catalog.pg_type t "
    5770              :                                                           "JOIN pg_catalog.pg_range r "
    5771              :                                                           "ON t.oid = r.rngmultitypid "
    5772              :                                                           "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5773            0 :                                                           pg_type_oid);
    5774              : 
    5775            0 :                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5776              : 
    5777            0 :                         pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5778            0 :                         pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5779              : 
    5780            0 :                         PQclear(res);
    5781            0 :                 }
    5782              :                 else
    5783              :                 {
    5784            0 :                         pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5785            0 :                         pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5786              :                 }
    5787              : 
    5788            0 :                 appendPQExpBufferStr(upgrade_buffer,
    5789              :                                                          "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5790            0 :                 appendPQExpBuffer(upgrade_buffer,
    5791              :                                                   "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5792            0 :                                                   pg_type_multirange_oid);
    5793            0 :                 appendPQExpBufferStr(upgrade_buffer,
    5794              :                                                          "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5795            0 :                 appendPQExpBuffer(upgrade_buffer,
    5796              :                                                   "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5797            0 :                                                   pg_type_multirange_array_oid);
    5798            0 :         }
    5799              : 
    5800            0 :         destroyPQExpBuffer(upgrade_query);
    5801            0 : }
    5802              : 
    5803              : static void
    5804            0 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5805              :                                                                         PQExpBuffer upgrade_buffer,
    5806              :                                                                         const TableInfo *tbinfo)
    5807              : {
    5808            0 :         Oid                     pg_type_oid = tbinfo->reltype;
    5809              : 
    5810            0 :         if (OidIsValid(pg_type_oid))
    5811            0 :                 binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5812            0 :                                                                                                  pg_type_oid, false, false);
    5813            0 : }
    5814              : 
    5815              : /*
    5816              :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5817              :  */
    5818              : static int
    5819            0 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5820              : {
    5821            0 :         BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5822            0 :         BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5823              : 
    5824            0 :         return pg_cmp_u32(v1.oid, v2.oid);
    5825            0 : }
    5826              : 
    5827              : /*
    5828              :  * collectBinaryUpgradeClassOids
    5829              :  *
    5830              :  * Construct a table of pg_class information required for
    5831              :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5832              :  * lookup.
    5833              :  */
    5834              : static void
    5835            0 : collectBinaryUpgradeClassOids(Archive *fout)
    5836              : {
    5837            0 :         PGresult   *res;
    5838            0 :         const char *query;
    5839              : 
    5840            0 :         query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5841              :                 "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5842              :                 "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5843              :                 "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5844              :                 "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5845              :                 "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5846              :                 "ORDER BY c.oid;";
    5847              : 
    5848            0 :         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5849              : 
    5850            0 :         nbinaryUpgradeClassOids = PQntuples(res);
    5851            0 :         binaryUpgradeClassOids = (BinaryUpgradeClassOidItem *)
    5852            0 :                 pg_malloc(nbinaryUpgradeClassOids * sizeof(BinaryUpgradeClassOidItem));
    5853              : 
    5854            0 :         for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5855              :         {
    5856            0 :                 binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5857            0 :                 binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5858            0 :                 binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5859            0 :                 binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5860            0 :                 binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5861            0 :                 binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5862            0 :                 binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5863            0 :         }
    5864              : 
    5865            0 :         PQclear(res);
    5866            0 : }
    5867              : 
    5868              : static void
    5869            0 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5870              :                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5871              : {
    5872            0 :         BinaryUpgradeClassOidItem key = {0};
    5873            0 :         BinaryUpgradeClassOidItem *entry;
    5874              : 
    5875            0 :         Assert(binaryUpgradeClassOids);
    5876              : 
    5877              :         /*
    5878              :          * Preserve the OID and relfilenumber of the table, table's index, table's
    5879              :          * toast table and toast table's index if any.
    5880              :          *
    5881              :          * One complexity is that the current table definition might not require
    5882              :          * the creation of a TOAST table, but the old database might have a TOAST
    5883              :          * table that was created earlier, before some wide columns were dropped.
    5884              :          * By setting the TOAST oid we force creation of the TOAST heap and index
    5885              :          * by the new backend, so we can copy the files during binary upgrade
    5886              :          * without worrying about this case.
    5887              :          */
    5888            0 :         key.oid = pg_class_oid;
    5889            0 :         entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5890              :                                         sizeof(BinaryUpgradeClassOidItem),
    5891              :                                         BinaryUpgradeClassOidItemCmp);
    5892              : 
    5893            0 :         appendPQExpBufferStr(upgrade_buffer,
    5894              :                                                  "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5895              : 
    5896            0 :         if (entry->relkind != RELKIND_INDEX &&
    5897            0 :                 entry->relkind != RELKIND_PARTITIONED_INDEX)
    5898              :         {
    5899            0 :                 appendPQExpBuffer(upgrade_buffer,
    5900              :                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5901            0 :                                                   pg_class_oid);
    5902              : 
    5903              :                 /*
    5904              :                  * Not every relation has storage. Also, in a pre-v12 database,
    5905              :                  * partitioned tables have a relfilenumber, which should not be
    5906              :                  * preserved when upgrading.
    5907              :                  */
    5908            0 :                 if (RelFileNumberIsValid(entry->relfilenumber) &&
    5909            0 :                         entry->relkind != RELKIND_PARTITIONED_TABLE)
    5910            0 :                         appendPQExpBuffer(upgrade_buffer,
    5911              :                                                           "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5912            0 :                                                           entry->relfilenumber);
    5913              : 
    5914              :                 /*
    5915              :                  * In a pre-v12 database, partitioned tables might be marked as having
    5916              :                  * toast tables, but we should ignore them if so.
    5917              :                  */
    5918            0 :                 if (OidIsValid(entry->toast_oid) &&
    5919            0 :                         entry->relkind != RELKIND_PARTITIONED_TABLE)
    5920              :                 {
    5921            0 :                         appendPQExpBuffer(upgrade_buffer,
    5922              :                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    5923            0 :                                                           entry->toast_oid);
    5924            0 :                         appendPQExpBuffer(upgrade_buffer,
    5925              :                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    5926            0 :                                                           entry->toast_relfilenumber);
    5927              : 
    5928              :                         /* every toast table has an index */
    5929            0 :                         appendPQExpBuffer(upgrade_buffer,
    5930              :                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5931            0 :                                                           entry->toast_index_oid);
    5932            0 :                         appendPQExpBuffer(upgrade_buffer,
    5933              :                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5934            0 :                                                           entry->toast_index_relfilenumber);
    5935            0 :                 }
    5936            0 :         }
    5937              :         else
    5938              :         {
    5939              :                 /* Preserve the OID and relfilenumber of the index */
    5940            0 :                 appendPQExpBuffer(upgrade_buffer,
    5941              :                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5942            0 :                                                   pg_class_oid);
    5943            0 :                 appendPQExpBuffer(upgrade_buffer,
    5944              :                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5945            0 :                                                   entry->relfilenumber);
    5946              :         }
    5947              : 
    5948            0 :         appendPQExpBufferChar(upgrade_buffer, '\n');
    5949            0 : }
    5950              : 
    5951              : /*
    5952              :  * If the DumpableObject is a member of an extension, add a suitable
    5953              :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    5954              :  *
    5955              :  * For somewhat historical reasons, objname should already be quoted,
    5956              :  * but not objnamespace (if any).
    5957              :  */
    5958              : static void
    5959            0 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    5960              :                                                                 const DumpableObject *dobj,
    5961              :                                                                 const char *objtype,
    5962              :                                                                 const char *objname,
    5963              :                                                                 const char *objnamespace)
    5964              : {
    5965            0 :         DumpableObject *extobj = NULL;
    5966            0 :         int                     i;
    5967              : 
    5968            0 :         if (!dobj->ext_member)
    5969            0 :                 return;
    5970              : 
    5971              :         /*
    5972              :          * Find the parent extension.  We could avoid this search if we wanted to
    5973              :          * add a link field to DumpableObject, but the space costs of that would
    5974              :          * be considerable.  We assume that member objects could only have a
    5975              :          * direct dependency on their own extension, not any others.
    5976              :          */
    5977            0 :         for (i = 0; i < dobj->nDeps; i++)
    5978              :         {
    5979            0 :                 extobj = findObjectByDumpId(dobj->dependencies[i]);
    5980            0 :                 if (extobj && extobj->objType == DO_EXTENSION)
    5981            0 :                         break;
    5982            0 :                 extobj = NULL;
    5983            0 :         }
    5984            0 :         if (extobj == NULL)
    5985            0 :                 pg_fatal("could not find parent extension for %s %s",
    5986              :                                  objtype, objname);
    5987              : 
    5988            0 :         appendPQExpBufferStr(upgrade_buffer,
    5989              :                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
    5990            0 :         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    5991            0 :                                           fmtId(extobj->name),
    5992            0 :                                           objtype);
    5993            0 :         if (objnamespace && *objnamespace)
    5994            0 :                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    5995            0 :         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    5996            0 : }
    5997              : 
    5998              : /*
    5999              :  * getNamespaces:
    6000              :  *        get information about all namespaces in the system catalogs
    6001              :  */
    6002              : void
    6003            0 : getNamespaces(Archive *fout)
    6004              : {
    6005            0 :         PGresult   *res;
    6006            0 :         int                     ntups;
    6007            0 :         int                     i;
    6008            0 :         PQExpBuffer query;
    6009            0 :         NamespaceInfo *nsinfo;
    6010            0 :         int                     i_tableoid;
    6011            0 :         int                     i_oid;
    6012            0 :         int                     i_nspname;
    6013            0 :         int                     i_nspowner;
    6014            0 :         int                     i_nspacl;
    6015            0 :         int                     i_acldefault;
    6016              : 
    6017            0 :         query = createPQExpBuffer();
    6018              : 
    6019              :         /*
    6020              :          * we fetch all namespaces including system ones, so that every object we
    6021              :          * read in can be linked to a containing namespace.
    6022              :          */
    6023            0 :         appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    6024              :                                                  "n.nspowner, "
    6025              :                                                  "n.nspacl, "
    6026              :                                                  "acldefault('n', n.nspowner) AS acldefault "
    6027              :                                                  "FROM pg_namespace n");
    6028              : 
    6029            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6030              : 
    6031            0 :         ntups = PQntuples(res);
    6032              : 
    6033            0 :         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
    6034              : 
    6035            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6036            0 :         i_oid = PQfnumber(res, "oid");
    6037            0 :         i_nspname = PQfnumber(res, "nspname");
    6038            0 :         i_nspowner = PQfnumber(res, "nspowner");
    6039            0 :         i_nspacl = PQfnumber(res, "nspacl");
    6040            0 :         i_acldefault = PQfnumber(res, "acldefault");
    6041              : 
    6042            0 :         for (i = 0; i < ntups; i++)
    6043              :         {
    6044            0 :                 const char *nspowner;
    6045              : 
    6046            0 :                 nsinfo[i].dobj.objType = DO_NAMESPACE;
    6047            0 :                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6048            0 :                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6049            0 :                 AssignDumpId(&nsinfo[i].dobj);
    6050            0 :                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    6051            0 :                 nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    6052            0 :                 nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6053            0 :                 nsinfo[i].dacl.privtype = 0;
    6054            0 :                 nsinfo[i].dacl.initprivs = NULL;
    6055            0 :                 nspowner = PQgetvalue(res, i, i_nspowner);
    6056            0 :                 nsinfo[i].nspowner = atooid(nspowner);
    6057            0 :                 nsinfo[i].rolname = getRoleName(nspowner);
    6058              : 
    6059              :                 /* Decide whether to dump this namespace */
    6060            0 :                 selectDumpableNamespace(&nsinfo[i], fout);
    6061              : 
    6062              :                 /* Mark whether namespace has an ACL */
    6063            0 :                 if (!PQgetisnull(res, i, i_nspacl))
    6064            0 :                         nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6065              : 
    6066              :                 /*
    6067              :                  * We ignore any pg_init_privs.initprivs entry for the public schema
    6068              :                  * and assume a predetermined default, for several reasons.  First,
    6069              :                  * dropping and recreating the schema removes its pg_init_privs entry,
    6070              :                  * but an empty destination database starts with this ACL nonetheless.
    6071              :                  * Second, we support dump/reload of public schema ownership changes.
    6072              :                  * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    6073              :                  * initprivs continues to reflect the initial owner.  Hence,
    6074              :                  * synthesize the value that nspacl will have after the restore's
    6075              :                  * ALTER SCHEMA OWNER.  Third, this makes the destination database
    6076              :                  * match the source's ACL, even if the latter was an initdb-default
    6077              :                  * ACL, which changed in v15.  An upgrade pulls in changes to most
    6078              :                  * system object ACLs that the DBA had not customized.  We've made the
    6079              :                  * public schema depart from that, because changing its ACL so easily
    6080              :                  * breaks applications.
    6081              :                  */
    6082            0 :                 if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    6083              :                 {
    6084            0 :                         PQExpBuffer aclarray = createPQExpBuffer();
    6085            0 :                         PQExpBuffer aclitem = createPQExpBuffer();
    6086              : 
    6087              :                         /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    6088            0 :                         appendPQExpBufferChar(aclarray, '{');
    6089            0 :                         quoteAclUserName(aclitem, nsinfo[i].rolname);
    6090            0 :                         appendPQExpBufferStr(aclitem, "=UC/");
    6091            0 :                         quoteAclUserName(aclitem, nsinfo[i].rolname);
    6092            0 :                         appendPGArray(aclarray, aclitem->data);
    6093            0 :                         resetPQExpBuffer(aclitem);
    6094            0 :                         appendPQExpBufferStr(aclitem, "=U/");
    6095            0 :                         quoteAclUserName(aclitem, nsinfo[i].rolname);
    6096            0 :                         appendPGArray(aclarray, aclitem->data);
    6097            0 :                         appendPQExpBufferChar(aclarray, '}');
    6098              : 
    6099            0 :                         nsinfo[i].dacl.privtype = 'i';
    6100            0 :                         nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    6101            0 :                         nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6102              : 
    6103            0 :                         destroyPQExpBuffer(aclarray);
    6104            0 :                         destroyPQExpBuffer(aclitem);
    6105            0 :                 }
    6106            0 :         }
    6107              : 
    6108            0 :         PQclear(res);
    6109            0 :         destroyPQExpBuffer(query);
    6110            0 : }
    6111              : 
    6112              : /*
    6113              :  * findNamespace:
    6114              :  *              given a namespace OID, look up the info read by getNamespaces
    6115              :  */
    6116              : static NamespaceInfo *
    6117            0 : findNamespace(Oid nsoid)
    6118              : {
    6119            0 :         NamespaceInfo *nsinfo;
    6120              : 
    6121            0 :         nsinfo = findNamespaceByOid(nsoid);
    6122            0 :         if (nsinfo == NULL)
    6123            0 :                 pg_fatal("schema with OID %u does not exist", nsoid);
    6124            0 :         return nsinfo;
    6125            0 : }
    6126              : 
    6127              : /*
    6128              :  * getExtensions:
    6129              :  *        read all extensions in the system catalogs and return them in the
    6130              :  * ExtensionInfo* structure
    6131              :  *
    6132              :  *      numExtensions is set to the number of extensions read in
    6133              :  */
    6134              : ExtensionInfo *
    6135            0 : getExtensions(Archive *fout, int *numExtensions)
    6136              : {
    6137            0 :         DumpOptions *dopt = fout->dopt;
    6138            0 :         PGresult   *res;
    6139            0 :         int                     ntups;
    6140            0 :         int                     i;
    6141            0 :         PQExpBuffer query;
    6142            0 :         ExtensionInfo *extinfo = NULL;
    6143            0 :         int                     i_tableoid;
    6144            0 :         int                     i_oid;
    6145            0 :         int                     i_extname;
    6146            0 :         int                     i_nspname;
    6147            0 :         int                     i_extrelocatable;
    6148            0 :         int                     i_extversion;
    6149            0 :         int                     i_extconfig;
    6150            0 :         int                     i_extcondition;
    6151              : 
    6152            0 :         query = createPQExpBuffer();
    6153              : 
    6154            0 :         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    6155              :                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    6156              :                                                  "FROM pg_extension x "
    6157              :                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
    6158              : 
    6159            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6160              : 
    6161            0 :         ntups = PQntuples(res);
    6162            0 :         if (ntups == 0)
    6163            0 :                 goto cleanup;
    6164              : 
    6165            0 :         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
    6166              : 
    6167            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6168            0 :         i_oid = PQfnumber(res, "oid");
    6169            0 :         i_extname = PQfnumber(res, "extname");
    6170            0 :         i_nspname = PQfnumber(res, "nspname");
    6171            0 :         i_extrelocatable = PQfnumber(res, "extrelocatable");
    6172            0 :         i_extversion = PQfnumber(res, "extversion");
    6173            0 :         i_extconfig = PQfnumber(res, "extconfig");
    6174            0 :         i_extcondition = PQfnumber(res, "extcondition");
    6175              : 
    6176            0 :         for (i = 0; i < ntups; i++)
    6177              :         {
    6178            0 :                 extinfo[i].dobj.objType = DO_EXTENSION;
    6179            0 :                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6180            0 :                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6181            0 :                 AssignDumpId(&extinfo[i].dobj);
    6182            0 :                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    6183            0 :                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    6184            0 :                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    6185            0 :                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    6186            0 :                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    6187            0 :                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    6188              : 
    6189              :                 /* Decide whether we want to dump it */
    6190            0 :                 selectDumpableExtension(&(extinfo[i]), dopt);
    6191            0 :         }
    6192              : 
    6193              : cleanup:
    6194            0 :         PQclear(res);
    6195            0 :         destroyPQExpBuffer(query);
    6196              : 
    6197            0 :         *numExtensions = ntups;
    6198              : 
    6199            0 :         return extinfo;
    6200            0 : }
    6201              : 
    6202              : /*
    6203              :  * getTypes:
    6204              :  *        get information about all types in the system catalogs
    6205              :  *
    6206              :  * NB: this must run after getFuncs() because we assume we can do
    6207              :  * findFuncByOid().
    6208              :  */
    6209              : void
    6210            0 : getTypes(Archive *fout)
    6211              : {
    6212            0 :         PGresult   *res;
    6213            0 :         int                     ntups;
    6214            0 :         int                     i;
    6215            0 :         PQExpBuffer query = createPQExpBuffer();
    6216            0 :         TypeInfo   *tyinfo;
    6217            0 :         ShellTypeInfo *stinfo;
    6218            0 :         int                     i_tableoid;
    6219            0 :         int                     i_oid;
    6220            0 :         int                     i_typname;
    6221            0 :         int                     i_typnamespace;
    6222            0 :         int                     i_typacl;
    6223            0 :         int                     i_acldefault;
    6224            0 :         int                     i_typowner;
    6225            0 :         int                     i_typelem;
    6226            0 :         int                     i_typrelid;
    6227            0 :         int                     i_typrelkind;
    6228            0 :         int                     i_typtype;
    6229            0 :         int                     i_typisdefined;
    6230            0 :         int                     i_isarray;
    6231            0 :         int                     i_typarray;
    6232              : 
    6233              :         /*
    6234              :          * we include even the built-in types because those may be used as array
    6235              :          * elements by user-defined types
    6236              :          *
    6237              :          * we filter out the built-in types when we dump out the types
    6238              :          *
    6239              :          * same approach for undefined (shell) types and array types
    6240              :          *
    6241              :          * Note: as of 8.3 we can reliably detect whether a type is an
    6242              :          * auto-generated array type by checking the element type's typarray.
    6243              :          * (Before that the test is capable of generating false positives.) We
    6244              :          * still check for name beginning with '_', though, so as to avoid the
    6245              :          * cost of the subselect probe for all standard types.  This would have to
    6246              :          * be revisited if the backend ever allows renaming of array types.
    6247              :          */
    6248            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    6249              :                                                  "typnamespace, typacl, "
    6250              :                                                  "acldefault('T', typowner) AS acldefault, "
    6251              :                                                  "typowner, "
    6252              :                                                  "typelem, typrelid, typarray, "
    6253              :                                                  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    6254              :                                                  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    6255              :                                                  "typtype, typisdefined, "
    6256              :                                                  "typname[0] = '_' AND typelem != 0 AND "
    6257              :                                                  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    6258              :                                                  "FROM pg_type");
    6259              : 
    6260            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6261              : 
    6262            0 :         ntups = PQntuples(res);
    6263              : 
    6264            0 :         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
    6265              : 
    6266            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6267            0 :         i_oid = PQfnumber(res, "oid");
    6268            0 :         i_typname = PQfnumber(res, "typname");
    6269            0 :         i_typnamespace = PQfnumber(res, "typnamespace");
    6270            0 :         i_typacl = PQfnumber(res, "typacl");
    6271            0 :         i_acldefault = PQfnumber(res, "acldefault");
    6272            0 :         i_typowner = PQfnumber(res, "typowner");
    6273            0 :         i_typelem = PQfnumber(res, "typelem");
    6274            0 :         i_typrelid = PQfnumber(res, "typrelid");
    6275            0 :         i_typrelkind = PQfnumber(res, "typrelkind");
    6276            0 :         i_typtype = PQfnumber(res, "typtype");
    6277            0 :         i_typisdefined = PQfnumber(res, "typisdefined");
    6278            0 :         i_isarray = PQfnumber(res, "isarray");
    6279            0 :         i_typarray = PQfnumber(res, "typarray");
    6280              : 
    6281            0 :         for (i = 0; i < ntups; i++)
    6282              :         {
    6283            0 :                 tyinfo[i].dobj.objType = DO_TYPE;
    6284            0 :                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6285            0 :                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6286            0 :                 AssignDumpId(&tyinfo[i].dobj);
    6287            0 :                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6288            0 :                 tyinfo[i].dobj.namespace =
    6289            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6290            0 :                 tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6291            0 :                 tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6292            0 :                 tyinfo[i].dacl.privtype = 0;
    6293            0 :                 tyinfo[i].dacl.initprivs = NULL;
    6294            0 :                 tyinfo[i].ftypname = NULL;      /* may get filled later */
    6295            0 :                 tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6296            0 :                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6297            0 :                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6298            0 :                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6299            0 :                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6300            0 :                 tyinfo[i].shellType = NULL;
    6301              : 
    6302            0 :                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6303            0 :                         tyinfo[i].isDefined = true;
    6304              :                 else
    6305            0 :                         tyinfo[i].isDefined = false;
    6306              : 
    6307            0 :                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6308            0 :                         tyinfo[i].isArray = true;
    6309              :                 else
    6310            0 :                         tyinfo[i].isArray = false;
    6311              : 
    6312            0 :                 tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6313              : 
    6314            0 :                 if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6315            0 :                         tyinfo[i].isMultirange = true;
    6316              :                 else
    6317            0 :                         tyinfo[i].isMultirange = false;
    6318              : 
    6319              :                 /* Decide whether we want to dump it */
    6320            0 :                 selectDumpableType(&tyinfo[i], fout);
    6321              : 
    6322              :                 /* Mark whether type has an ACL */
    6323            0 :                 if (!PQgetisnull(res, i, i_typacl))
    6324            0 :                         tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6325              : 
    6326              :                 /*
    6327              :                  * If it's a domain, fetch info about its constraints, if any
    6328              :                  */
    6329            0 :                 tyinfo[i].nDomChecks = 0;
    6330            0 :                 tyinfo[i].domChecks = NULL;
    6331            0 :                 tyinfo[i].notnull = NULL;
    6332            0 :                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6333            0 :                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6334            0 :                         getDomainConstraints(fout, &(tyinfo[i]));
    6335              : 
    6336              :                 /*
    6337              :                  * If it's a base type, make a DumpableObject representing a shell
    6338              :                  * definition of the type.  We will need to dump that ahead of the I/O
    6339              :                  * functions for the type.  Similarly, range types need a shell
    6340              :                  * definition in case they have a canonicalize function.
    6341              :                  *
    6342              :                  * Note: the shell type doesn't have a catId.  You might think it
    6343              :                  * should copy the base type's catId, but then it might capture the
    6344              :                  * pg_depend entries for the type, which we don't want.
    6345              :                  */
    6346            0 :                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6347            0 :                         (tyinfo[i].typtype == TYPTYPE_BASE ||
    6348            0 :                          tyinfo[i].typtype == TYPTYPE_RANGE))
    6349              :                 {
    6350            0 :                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
    6351            0 :                         stinfo->dobj.objType = DO_SHELL_TYPE;
    6352            0 :                         stinfo->dobj.catId = nilCatalogId;
    6353            0 :                         AssignDumpId(&stinfo->dobj);
    6354            0 :                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6355            0 :                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6356            0 :                         stinfo->baseType = &(tyinfo[i]);
    6357            0 :                         tyinfo[i].shellType = stinfo;
    6358              : 
    6359              :                         /*
    6360              :                          * Initially mark the shell type as not to be dumped.  We'll only
    6361              :                          * dump it if the I/O or canonicalize functions need to be dumped;
    6362              :                          * this is taken care of while sorting dependencies.
    6363              :                          */
    6364            0 :                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6365            0 :                 }
    6366            0 :         }
    6367              : 
    6368            0 :         PQclear(res);
    6369              : 
    6370            0 :         destroyPQExpBuffer(query);
    6371            0 : }
    6372              : 
    6373              : /*
    6374              :  * getOperators:
    6375              :  *        get information about all operators in the system catalogs
    6376              :  */
    6377              : void
    6378            0 : getOperators(Archive *fout)
    6379              : {
    6380            0 :         PGresult   *res;
    6381            0 :         int                     ntups;
    6382            0 :         int                     i;
    6383            0 :         PQExpBuffer query = createPQExpBuffer();
    6384            0 :         OprInfo    *oprinfo;
    6385            0 :         int                     i_tableoid;
    6386            0 :         int                     i_oid;
    6387            0 :         int                     i_oprname;
    6388            0 :         int                     i_oprnamespace;
    6389            0 :         int                     i_oprowner;
    6390            0 :         int                     i_oprkind;
    6391            0 :         int                     i_oprleft;
    6392            0 :         int                     i_oprright;
    6393            0 :         int                     i_oprcode;
    6394              : 
    6395              :         /*
    6396              :          * find all operators, including builtin operators; we filter out
    6397              :          * system-defined operators at dump-out time.
    6398              :          */
    6399              : 
    6400            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6401              :                                                  "oprnamespace, "
    6402              :                                                  "oprowner, "
    6403              :                                                  "oprkind, "
    6404              :                                                  "oprleft, "
    6405              :                                                  "oprright, "
    6406              :                                                  "oprcode::oid AS oprcode "
    6407              :                                                  "FROM pg_operator");
    6408              : 
    6409            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6410              : 
    6411            0 :         ntups = PQntuples(res);
    6412              : 
    6413            0 :         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
    6414              : 
    6415            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6416            0 :         i_oid = PQfnumber(res, "oid");
    6417            0 :         i_oprname = PQfnumber(res, "oprname");
    6418            0 :         i_oprnamespace = PQfnumber(res, "oprnamespace");
    6419            0 :         i_oprowner = PQfnumber(res, "oprowner");
    6420            0 :         i_oprkind = PQfnumber(res, "oprkind");
    6421            0 :         i_oprleft = PQfnumber(res, "oprleft");
    6422            0 :         i_oprright = PQfnumber(res, "oprright");
    6423            0 :         i_oprcode = PQfnumber(res, "oprcode");
    6424              : 
    6425            0 :         for (i = 0; i < ntups; i++)
    6426              :         {
    6427            0 :                 oprinfo[i].dobj.objType = DO_OPERATOR;
    6428            0 :                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6429            0 :                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6430            0 :                 AssignDumpId(&oprinfo[i].dobj);
    6431            0 :                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6432            0 :                 oprinfo[i].dobj.namespace =
    6433            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6434            0 :                 oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6435            0 :                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6436            0 :                 oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
    6437            0 :                 oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
    6438            0 :                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6439              : 
    6440              :                 /* Decide whether we want to dump it */
    6441            0 :                 selectDumpableObject(&(oprinfo[i].dobj), fout);
    6442            0 :         }
    6443              : 
    6444            0 :         PQclear(res);
    6445              : 
    6446            0 :         destroyPQExpBuffer(query);
    6447            0 : }
    6448              : 
    6449              : /*
    6450              :  * getCollations:
    6451              :  *        get information about all collations in the system catalogs
    6452              :  */
    6453              : void
    6454            0 : getCollations(Archive *fout)
    6455              : {
    6456            0 :         PGresult   *res;
    6457            0 :         int                     ntups;
    6458            0 :         int                     i;
    6459            0 :         PQExpBuffer query;
    6460            0 :         CollInfo   *collinfo;
    6461            0 :         int                     i_tableoid;
    6462            0 :         int                     i_oid;
    6463            0 :         int                     i_collname;
    6464            0 :         int                     i_collnamespace;
    6465            0 :         int                     i_collowner;
    6466            0 :         int                     i_collencoding;
    6467              : 
    6468            0 :         query = createPQExpBuffer();
    6469              : 
    6470              :         /*
    6471              :          * find all collations, including builtin collations; we filter out
    6472              :          * system-defined collations at dump-out time.
    6473              :          */
    6474              : 
    6475            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6476              :                                                  "collnamespace, "
    6477              :                                                  "collowner, "
    6478              :                                                  "collencoding "
    6479              :                                                  "FROM pg_collation");
    6480              : 
    6481            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6482              : 
    6483            0 :         ntups = PQntuples(res);
    6484              : 
    6485            0 :         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
    6486              : 
    6487            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6488            0 :         i_oid = PQfnumber(res, "oid");
    6489            0 :         i_collname = PQfnumber(res, "collname");
    6490            0 :         i_collnamespace = PQfnumber(res, "collnamespace");
    6491            0 :         i_collowner = PQfnumber(res, "collowner");
    6492            0 :         i_collencoding = PQfnumber(res, "collencoding");
    6493              : 
    6494            0 :         for (i = 0; i < ntups; i++)
    6495              :         {
    6496            0 :                 collinfo[i].dobj.objType = DO_COLLATION;
    6497            0 :                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6498            0 :                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6499            0 :                 AssignDumpId(&collinfo[i].dobj);
    6500            0 :                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6501            0 :                 collinfo[i].dobj.namespace =
    6502            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6503            0 :                 collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6504            0 :                 collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
    6505              : 
    6506              :                 /* Decide whether we want to dump it */
    6507            0 :                 selectDumpableObject(&(collinfo[i].dobj), fout);
    6508            0 :         }
    6509              : 
    6510            0 :         PQclear(res);
    6511              : 
    6512            0 :         destroyPQExpBuffer(query);
    6513            0 : }
    6514              : 
    6515              : /*
    6516              :  * getConversions:
    6517              :  *        get information about all conversions in the system catalogs
    6518              :  */
    6519              : void
    6520            0 : getConversions(Archive *fout)
    6521              : {
    6522            0 :         PGresult   *res;
    6523            0 :         int                     ntups;
    6524            0 :         int                     i;
    6525            0 :         PQExpBuffer query;
    6526            0 :         ConvInfo   *convinfo;
    6527            0 :         int                     i_tableoid;
    6528            0 :         int                     i_oid;
    6529            0 :         int                     i_conname;
    6530            0 :         int                     i_connamespace;
    6531            0 :         int                     i_conowner;
    6532              : 
    6533            0 :         query = createPQExpBuffer();
    6534              : 
    6535              :         /*
    6536              :          * find all conversions, including builtin conversions; we filter out
    6537              :          * system-defined conversions at dump-out time.
    6538              :          */
    6539              : 
    6540            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6541              :                                                  "connamespace, "
    6542              :                                                  "conowner "
    6543              :                                                  "FROM pg_conversion");
    6544              : 
    6545            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6546              : 
    6547            0 :         ntups = PQntuples(res);
    6548              : 
    6549            0 :         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
    6550              : 
    6551            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6552            0 :         i_oid = PQfnumber(res, "oid");
    6553            0 :         i_conname = PQfnumber(res, "conname");
    6554            0 :         i_connamespace = PQfnumber(res, "connamespace");
    6555            0 :         i_conowner = PQfnumber(res, "conowner");
    6556              : 
    6557            0 :         for (i = 0; i < ntups; i++)
    6558              :         {
    6559            0 :                 convinfo[i].dobj.objType = DO_CONVERSION;
    6560            0 :                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6561            0 :                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6562            0 :                 AssignDumpId(&convinfo[i].dobj);
    6563            0 :                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6564            0 :                 convinfo[i].dobj.namespace =
    6565            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6566            0 :                 convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6567              : 
    6568              :                 /* Decide whether we want to dump it */
    6569            0 :                 selectDumpableObject(&(convinfo[i].dobj), fout);
    6570            0 :         }
    6571              : 
    6572            0 :         PQclear(res);
    6573              : 
    6574            0 :         destroyPQExpBuffer(query);
    6575            0 : }
    6576              : 
    6577              : /*
    6578              :  * getAccessMethods:
    6579              :  *        get information about all user-defined access methods
    6580              :  */
    6581              : void
    6582            0 : getAccessMethods(Archive *fout)
    6583              : {
    6584            0 :         PGresult   *res;
    6585            0 :         int                     ntups;
    6586            0 :         int                     i;
    6587            0 :         PQExpBuffer query;
    6588            0 :         AccessMethodInfo *aminfo;
    6589            0 :         int                     i_tableoid;
    6590            0 :         int                     i_oid;
    6591            0 :         int                     i_amname;
    6592            0 :         int                     i_amhandler;
    6593            0 :         int                     i_amtype;
    6594              : 
    6595            0 :         query = createPQExpBuffer();
    6596              : 
    6597              :         /*
    6598              :          * Select all access methods from pg_am table.  v9.6 introduced CREATE
    6599              :          * ACCESS METHOD, so earlier versions usually have only built-in access
    6600              :          * methods.  v9.6 also changed the access method API, replacing dozens of
    6601              :          * pg_am columns with amhandler.  Even if a user created an access method
    6602              :          * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
    6603              :          * columns to a v9.6+ CREATE ACCESS METHOD.  Hence, before v9.6, read
    6604              :          * pg_am just to facilitate findAccessMethodByOid() providing the
    6605              :          * OID-to-name mapping.
    6606              :          */
    6607            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
    6608            0 :         if (fout->remoteVersion >= 90600)
    6609            0 :                 appendPQExpBufferStr(query,
    6610              :                                                          "amtype, "
    6611              :                                                          "amhandler::pg_catalog.regproc AS amhandler ");
    6612              :         else
    6613            0 :                 appendPQExpBufferStr(query,
    6614              :                                                          "'i'::pg_catalog.\"char\" AS amtype, "
    6615              :                                                          "'-'::pg_catalog.regproc AS amhandler ");
    6616            0 :         appendPQExpBufferStr(query, "FROM pg_am");
    6617              : 
    6618            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6619              : 
    6620            0 :         ntups = PQntuples(res);
    6621              : 
    6622            0 :         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
    6623              : 
    6624            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6625            0 :         i_oid = PQfnumber(res, "oid");
    6626            0 :         i_amname = PQfnumber(res, "amname");
    6627            0 :         i_amhandler = PQfnumber(res, "amhandler");
    6628            0 :         i_amtype = PQfnumber(res, "amtype");
    6629              : 
    6630            0 :         for (i = 0; i < ntups; i++)
    6631              :         {
    6632            0 :                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6633            0 :                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6634            0 :                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6635            0 :                 AssignDumpId(&aminfo[i].dobj);
    6636            0 :                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6637            0 :                 aminfo[i].dobj.namespace = NULL;
    6638            0 :                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6639            0 :                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6640              : 
    6641              :                 /* Decide whether we want to dump it */
    6642            0 :                 selectDumpableAccessMethod(&(aminfo[i]), fout);
    6643            0 :         }
    6644              : 
    6645            0 :         PQclear(res);
    6646              : 
    6647            0 :         destroyPQExpBuffer(query);
    6648            0 : }
    6649              : 
    6650              : 
    6651              : /*
    6652              :  * getOpclasses:
    6653              :  *        get information about all opclasses in the system catalogs
    6654              :  */
    6655              : void
    6656            0 : getOpclasses(Archive *fout)
    6657              : {
    6658            0 :         PGresult   *res;
    6659            0 :         int                     ntups;
    6660            0 :         int                     i;
    6661            0 :         PQExpBuffer query = createPQExpBuffer();
    6662            0 :         OpclassInfo *opcinfo;
    6663            0 :         int                     i_tableoid;
    6664            0 :         int                     i_oid;
    6665            0 :         int                     i_opcmethod;
    6666            0 :         int                     i_opcname;
    6667            0 :         int                     i_opcnamespace;
    6668            0 :         int                     i_opcowner;
    6669              : 
    6670              :         /*
    6671              :          * find all opclasses, including builtin opclasses; we filter out
    6672              :          * system-defined opclasses at dump-out time.
    6673              :          */
    6674              : 
    6675            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
    6676              :                                                  "opcnamespace, "
    6677              :                                                  "opcowner "
    6678              :                                                  "FROM pg_opclass");
    6679              : 
    6680            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6681              : 
    6682            0 :         ntups = PQntuples(res);
    6683              : 
    6684            0 :         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
    6685              : 
    6686            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6687            0 :         i_oid = PQfnumber(res, "oid");
    6688            0 :         i_opcmethod = PQfnumber(res, "opcmethod");
    6689            0 :         i_opcname = PQfnumber(res, "opcname");
    6690            0 :         i_opcnamespace = PQfnumber(res, "opcnamespace");
    6691            0 :         i_opcowner = PQfnumber(res, "opcowner");
    6692              : 
    6693            0 :         for (i = 0; i < ntups; i++)
    6694              :         {
    6695            0 :                 opcinfo[i].dobj.objType = DO_OPCLASS;
    6696            0 :                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6697            0 :                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6698            0 :                 AssignDumpId(&opcinfo[i].dobj);
    6699            0 :                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6700            0 :                 opcinfo[i].dobj.namespace =
    6701            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6702            0 :                 opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
    6703            0 :                 opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6704              : 
    6705              :                 /* Decide whether we want to dump it */
    6706            0 :                 selectDumpableObject(&(opcinfo[i].dobj), fout);
    6707            0 :         }
    6708              : 
    6709            0 :         PQclear(res);
    6710              : 
    6711            0 :         destroyPQExpBuffer(query);
    6712            0 : }
    6713              : 
    6714              : /*
    6715              :  * getOpfamilies:
    6716              :  *        get information about all opfamilies in the system catalogs
    6717              :  */
    6718              : void
    6719            0 : getOpfamilies(Archive *fout)
    6720              : {
    6721            0 :         PGresult   *res;
    6722            0 :         int                     ntups;
    6723            0 :         int                     i;
    6724            0 :         PQExpBuffer query;
    6725            0 :         OpfamilyInfo *opfinfo;
    6726            0 :         int                     i_tableoid;
    6727            0 :         int                     i_oid;
    6728            0 :         int                     i_opfmethod;
    6729            0 :         int                     i_opfname;
    6730            0 :         int                     i_opfnamespace;
    6731            0 :         int                     i_opfowner;
    6732              : 
    6733            0 :         query = createPQExpBuffer();
    6734              : 
    6735              :         /*
    6736              :          * find all opfamilies, including builtin opfamilies; we filter out
    6737              :          * system-defined opfamilies at dump-out time.
    6738              :          */
    6739              : 
    6740            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
    6741              :                                                  "opfnamespace, "
    6742              :                                                  "opfowner "
    6743              :                                                  "FROM pg_opfamily");
    6744              : 
    6745            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6746              : 
    6747            0 :         ntups = PQntuples(res);
    6748              : 
    6749            0 :         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
    6750              : 
    6751            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6752            0 :         i_oid = PQfnumber(res, "oid");
    6753            0 :         i_opfname = PQfnumber(res, "opfname");
    6754            0 :         i_opfmethod = PQfnumber(res, "opfmethod");
    6755            0 :         i_opfnamespace = PQfnumber(res, "opfnamespace");
    6756            0 :         i_opfowner = PQfnumber(res, "opfowner");
    6757              : 
    6758            0 :         for (i = 0; i < ntups; i++)
    6759              :         {
    6760            0 :                 opfinfo[i].dobj.objType = DO_OPFAMILY;
    6761            0 :                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6762            0 :                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6763            0 :                 AssignDumpId(&opfinfo[i].dobj);
    6764            0 :                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6765            0 :                 opfinfo[i].dobj.namespace =
    6766            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6767            0 :                 opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
    6768            0 :                 opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6769              : 
    6770              :                 /* Decide whether we want to dump it */
    6771            0 :                 selectDumpableObject(&(opfinfo[i].dobj), fout);
    6772            0 :         }
    6773              : 
    6774            0 :         PQclear(res);
    6775              : 
    6776            0 :         destroyPQExpBuffer(query);
    6777            0 : }
    6778              : 
    6779              : /*
    6780              :  * getAggregates:
    6781              :  *        get information about all user-defined aggregates in the system catalogs
    6782              :  */
    6783              : void
    6784            0 : getAggregates(Archive *fout)
    6785              : {
    6786            0 :         DumpOptions *dopt = fout->dopt;
    6787            0 :         PGresult   *res;
    6788            0 :         int                     ntups;
    6789            0 :         int                     i;
    6790            0 :         PQExpBuffer query = createPQExpBuffer();
    6791            0 :         AggInfo    *agginfo;
    6792            0 :         int                     i_tableoid;
    6793            0 :         int                     i_oid;
    6794            0 :         int                     i_aggname;
    6795            0 :         int                     i_aggnamespace;
    6796            0 :         int                     i_pronargs;
    6797            0 :         int                     i_proargtypes;
    6798            0 :         int                     i_proowner;
    6799            0 :         int                     i_aggacl;
    6800            0 :         int                     i_acldefault;
    6801              : 
    6802              :         /*
    6803              :          * Find all interesting aggregates.  See comment in getFuncs() for the
    6804              :          * rationale behind the filtering logic.
    6805              :          */
    6806            0 :         if (fout->remoteVersion >= 90600)
    6807              :         {
    6808            0 :                 const char *agg_check;
    6809              : 
    6810            0 :                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6811              :                                          : "p.proisagg");
    6812              : 
    6813            0 :                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6814              :                                                   "p.proname AS aggname, "
    6815              :                                                   "p.pronamespace AS aggnamespace, "
    6816              :                                                   "p.pronargs, p.proargtypes, "
    6817              :                                                   "p.proowner, "
    6818              :                                                   "p.proacl AS aggacl, "
    6819              :                                                   "acldefault('f', p.proowner) AS acldefault "
    6820              :                                                   "FROM pg_proc p "
    6821              :                                                   "LEFT JOIN pg_init_privs pip ON "
    6822              :                                                   "(p.oid = pip.objoid "
    6823              :                                                   "AND pip.classoid = 'pg_proc'::regclass "
    6824              :                                                   "AND pip.objsubid = 0) "
    6825              :                                                   "WHERE %s AND ("
    6826              :                                                   "p.pronamespace != "
    6827              :                                                   "(SELECT oid FROM pg_namespace "
    6828              :                                                   "WHERE nspname = 'pg_catalog') OR "
    6829              :                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
    6830            0 :                                                   agg_check);
    6831            0 :                 if (dopt->binary_upgrade)
    6832            0 :                         appendPQExpBufferStr(query,
    6833              :                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6834              :                                                                  "classid = 'pg_proc'::regclass AND "
    6835              :                                                                  "objid = p.oid AND "
    6836              :                                                                  "refclassid = 'pg_extension'::regclass AND "
    6837              :                                                                  "deptype = 'e')");
    6838            0 :                 appendPQExpBufferChar(query, ')');
    6839            0 :         }
    6840              :         else
    6841              :         {
    6842            0 :                 appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6843              :                                                          "pronamespace AS aggnamespace, "
    6844              :                                                          "pronargs, proargtypes, "
    6845              :                                                          "proowner, "
    6846              :                                                          "proacl AS aggacl, "
    6847              :                                                          "acldefault('f', proowner) AS acldefault "
    6848              :                                                          "FROM pg_proc p "
    6849              :                                                          "WHERE proisagg AND ("
    6850              :                                                          "pronamespace != "
    6851              :                                                          "(SELECT oid FROM pg_namespace "
    6852              :                                                          "WHERE nspname = 'pg_catalog')");
    6853            0 :                 if (dopt->binary_upgrade)
    6854            0 :                         appendPQExpBufferStr(query,
    6855              :                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6856              :                                                                  "classid = 'pg_proc'::regclass AND "
    6857              :                                                                  "objid = p.oid AND "
    6858              :                                                                  "refclassid = 'pg_extension'::regclass AND "
    6859              :                                                                  "deptype = 'e')");
    6860            0 :                 appendPQExpBufferChar(query, ')');
    6861              :         }
    6862              : 
    6863            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6864              : 
    6865            0 :         ntups = PQntuples(res);
    6866              : 
    6867            0 :         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
    6868              : 
    6869            0 :         i_tableoid = PQfnumber(res, "tableoid");
    6870            0 :         i_oid = PQfnumber(res, "oid");
    6871            0 :         i_aggname = PQfnumber(res, "aggname");
    6872            0 :         i_aggnamespace = PQfnumber(res, "aggnamespace");
    6873            0 :         i_pronargs = PQfnumber(res, "pronargs");
    6874            0 :         i_proargtypes = PQfnumber(res, "proargtypes");
    6875            0 :         i_proowner = PQfnumber(res, "proowner");
    6876            0 :         i_aggacl = PQfnumber(res, "aggacl");
    6877            0 :         i_acldefault = PQfnumber(res, "acldefault");
    6878              : 
    6879            0 :         for (i = 0; i < ntups; i++)
    6880              :         {
    6881            0 :                 agginfo[i].aggfn.dobj.objType = DO_AGG;
    6882            0 :                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6883            0 :                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6884            0 :                 AssignDumpId(&agginfo[i].aggfn.dobj);
    6885            0 :                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6886            0 :                 agginfo[i].aggfn.dobj.namespace =
    6887            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6888            0 :                 agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6889            0 :                 agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6890            0 :                 agginfo[i].aggfn.dacl.privtype = 0;
    6891            0 :                 agginfo[i].aggfn.dacl.initprivs = NULL;
    6892            0 :                 agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6893            0 :                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6894            0 :                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
    6895            0 :                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6896            0 :                 if (agginfo[i].aggfn.nargs == 0)
    6897            0 :                         agginfo[i].aggfn.argtypes = NULL;
    6898              :                 else
    6899              :                 {
    6900            0 :                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
    6901            0 :                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6902            0 :                                                   agginfo[i].aggfn.argtypes,
    6903            0 :                                                   agginfo[i].aggfn.nargs);
    6904              :                 }
    6905            0 :                 agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6906              : 
    6907              :                 /* Decide whether we want to dump it */
    6908            0 :                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6909              : 
    6910              :                 /* Mark whether aggregate has an ACL */
    6911            0 :                 if (!PQgetisnull(res, i, i_aggacl))
    6912            0 :                         agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6913            0 :         }
    6914              : 
    6915            0 :         PQclear(res);
    6916              : 
    6917            0 :         destroyPQExpBuffer(query);
    6918            0 : }
    6919              : 
    6920              : /*
    6921              :  * getFuncs:
    6922              :  *        get information about all user-defined functions in the system catalogs
    6923              :  */
    6924              : void
    6925            0 : getFuncs(Archive *fout)
    6926              : {
    6927            0 :         DumpOptions *dopt = fout->dopt;
    6928            0 :         PGresult   *res;
    6929            0 :         int                     ntups;
    6930            0 :         int                     i;
    6931            0 :         PQExpBuffer query = createPQExpBuffer();
    6932            0 :         FuncInfo   *finfo;
    6933            0 :         int                     i_tableoid;
    6934            0 :         int                     i_oid;
    6935            0 :         int                     i_proname;
    6936            0 :         int                     i_pronamespace;
    6937            0 :         int                     i_proowner;
    6938            0 :         int                     i_prolang;
    6939            0 :         int                     i_pronargs;
    6940            0 :         int                     i_proargtypes;
    6941            0 :         int                     i_prorettype;
    6942            0 :         int                     i_proacl;
    6943            0 :         int                     i_acldefault;
    6944              : 
    6945              :         /*
    6946              :          * Find all interesting functions.  This is a bit complicated:
    6947              :          *
    6948              :          * 1. Always exclude aggregates; those are handled elsewhere.
    6949              :          *
    6950              :          * 2. Always exclude functions that are internally dependent on something
    6951              :          * else, since presumably those will be created as a result of creating
    6952              :          * the something else.  This currently acts only to suppress constructor
    6953              :          * functions for range types.  Note this is OK only because the
    6954              :          * constructors don't have any dependencies the range type doesn't have;
    6955              :          * otherwise we might not get creation ordering correct.
    6956              :          *
    6957              :          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    6958              :          * they're members of extensions and we are in binary-upgrade mode then
    6959              :          * include them, since we want to dump extension members individually in
    6960              :          * that mode.  Also, if they are used by casts or transforms then we need
    6961              :          * to gather the information about them, though they won't be dumped if
    6962              :          * they are built-in.  Also, in 9.6 and up, include functions in
    6963              :          * pg_catalog if they have an ACL different from what's shown in
    6964              :          * pg_init_privs (so we have to join to pg_init_privs; annoying).
    6965              :          */
    6966            0 :         if (fout->remoteVersion >= 90600)
    6967              :         {
    6968            0 :                 const char *not_agg_check;
    6969              : 
    6970            0 :                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    6971              :                                                  : "NOT p.proisagg");
    6972              : 
    6973            0 :                 appendPQExpBuffer(query,
    6974              :                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    6975              :                                                   "p.pronargs, p.proargtypes, p.prorettype, "
    6976              :                                                   "p.proacl, "
    6977              :                                                   "acldefault('f', p.proowner) AS acldefault, "
    6978              :                                                   "p.pronamespace, "
    6979              :                                                   "p.proowner "
    6980              :                                                   "FROM pg_proc p "
    6981              :                                                   "LEFT JOIN pg_init_privs pip ON "
    6982              :                                                   "(p.oid = pip.objoid "
    6983              :                                                   "AND pip.classoid = 'pg_proc'::regclass "
    6984              :                                                   "AND pip.objsubid = 0) "
    6985              :                                                   "WHERE %s"
    6986              :                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6987              :                                                   "WHERE classid = 'pg_proc'::regclass AND "
    6988              :                                                   "objid = p.oid AND deptype = 'i')"
    6989              :                                                   "\n  AND ("
    6990              :                                                   "\n  pronamespace != "
    6991              :                                                   "(SELECT oid FROM pg_namespace "
    6992              :                                                   "WHERE nspname = 'pg_catalog')"
    6993              :                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6994              :                                                   "\n  WHERE pg_cast.oid > %u "
    6995              :                                                   "\n  AND p.oid = pg_cast.castfunc)"
    6996              :                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6997              :                                                   "\n  WHERE pg_transform.oid > %u AND "
    6998              :                                                   "\n  (p.oid = pg_transform.trffromsql"
    6999              :                                                   "\n  OR p.oid = pg_transform.trftosql))",
    7000            0 :                                                   not_agg_check,
    7001            0 :                                                   g_last_builtin_oid,
    7002            0 :                                                   g_last_builtin_oid);
    7003            0 :                 if (dopt->binary_upgrade)
    7004            0 :                         appendPQExpBufferStr(query,
    7005              :                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    7006              :                                                                  "classid = 'pg_proc'::regclass AND "
    7007              :                                                                  "objid = p.oid AND "
    7008              :                                                                  "refclassid = 'pg_extension'::regclass AND "
    7009              :                                                                  "deptype = 'e')");
    7010            0 :                 appendPQExpBufferStr(query,
    7011              :                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    7012            0 :                 appendPQExpBufferChar(query, ')');
    7013            0 :         }
    7014              :         else
    7015              :         {
    7016            0 :                 appendPQExpBuffer(query,
    7017              :                                                   "SELECT tableoid, oid, proname, prolang, "
    7018              :                                                   "pronargs, proargtypes, prorettype, proacl, "
    7019              :                                                   "acldefault('f', proowner) AS acldefault, "
    7020              :                                                   "pronamespace, "
    7021              :                                                   "proowner "
    7022              :                                                   "FROM pg_proc p "
    7023              :                                                   "WHERE NOT proisagg"
    7024              :                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    7025              :                                                   "WHERE classid = 'pg_proc'::regclass AND "
    7026              :                                                   "objid = p.oid AND deptype = 'i')"
    7027              :                                                   "\n  AND ("
    7028              :                                                   "\n  pronamespace != "
    7029              :                                                   "(SELECT oid FROM pg_namespace "
    7030              :                                                   "WHERE nspname = 'pg_catalog')"
    7031              :                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    7032              :                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
    7033              :                                                   "\n  AND p.oid = pg_cast.castfunc)",
    7034            0 :                                                   g_last_builtin_oid);
    7035              : 
    7036            0 :                 if (fout->remoteVersion >= 90500)
    7037            0 :                         appendPQExpBuffer(query,
    7038              :                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    7039              :                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
    7040              :                                                           "\n  AND (p.oid = pg_transform.trffromsql"
    7041              :                                                           "\n  OR p.oid = pg_transform.trftosql))",
    7042            0 :                                                           g_last_builtin_oid);
    7043              : 
    7044            0 :                 if (dopt->binary_upgrade)
    7045            0 :                         appendPQExpBufferStr(query,
    7046              :                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    7047              :                                                                  "classid = 'pg_proc'::regclass AND "
    7048              :                                                                  "objid = p.oid AND "
    7049              :                                                                  "refclassid = 'pg_extension'::regclass AND "
    7050              :                                                                  "deptype = 'e')");
    7051            0 :                 appendPQExpBufferChar(query, ')');
    7052              :         }
    7053              : 
    7054            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7055              : 
    7056            0 :         ntups = PQntuples(res);
    7057              : 
    7058            0 :         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
    7059              : 
    7060            0 :         i_tableoid = PQfnumber(res, "tableoid");
    7061            0 :         i_oid = PQfnumber(res, "oid");
    7062            0 :         i_proname = PQfnumber(res, "proname");
    7063            0 :         i_pronamespace = PQfnumber(res, "pronamespace");
    7064            0 :         i_proowner = PQfnumber(res, "proowner");
    7065            0 :         i_prolang = PQfnumber(res, "prolang");
    7066            0 :         i_pronargs = PQfnumber(res, "pronargs");
    7067            0 :         i_proargtypes = PQfnumber(res, "proargtypes");
    7068            0 :         i_prorettype = PQfnumber(res, "prorettype");
    7069            0 :         i_proacl = PQfnumber(res, "proacl");
    7070            0 :         i_acldefault = PQfnumber(res, "acldefault");
    7071              : 
    7072            0 :         for (i = 0; i < ntups; i++)
    7073              :         {
    7074            0 :                 finfo[i].dobj.objType = DO_FUNC;
    7075            0 :                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7076            0 :                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7077            0 :                 AssignDumpId(&finfo[i].dobj);
    7078            0 :                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    7079            0 :                 finfo[i].dobj.namespace =
    7080            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    7081            0 :                 finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    7082            0 :                 finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7083            0 :                 finfo[i].dacl.privtype = 0;
    7084            0 :                 finfo[i].dacl.initprivs = NULL;
    7085            0 :                 finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    7086            0 :                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    7087            0 :                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    7088            0 :                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    7089            0 :                 if (finfo[i].nargs == 0)
    7090            0 :                         finfo[i].argtypes = NULL;
    7091              :                 else
    7092              :                 {
    7093            0 :                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
    7094            0 :                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
    7095            0 :                                                   finfo[i].argtypes, finfo[i].nargs);
    7096              :                 }
    7097            0 :                 finfo[i].postponed_def = false; /* might get set during sort */
    7098              : 
    7099              :                 /* Decide whether we want to dump it */
    7100            0 :                 selectDumpableObject(&(finfo[i].dobj), fout);
    7101              : 
    7102              :                 /* Mark whether function has an ACL */
    7103            0 :                 if (!PQgetisnull(res, i, i_proacl))
    7104            0 :                         finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7105            0 :         }
    7106              : 
    7107            0 :         PQclear(res);
    7108              : 
    7109            0 :         destroyPQExpBuffer(query);
    7110            0 : }
    7111              : 
    7112              : /*
    7113              :  * getRelationStatistics
    7114              :  *    register the statistics object as a dependent of the relation.
    7115              :  *
    7116              :  * reltuples is passed as a string to avoid complexities in converting from/to
    7117              :  * floating point.
    7118              :  */
    7119              : static RelStatsInfo *
    7120            0 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
    7121              :                                           char *reltuples, int32 relallvisible,
    7122              :                                           int32 relallfrozen, char relkind,
    7123              :                                           char **indAttNames, int nindAttNames)
    7124              : {
    7125            0 :         if (!fout->dopt->dumpStatistics)
    7126            0 :                 return NULL;
    7127              : 
    7128            0 :         if ((relkind == RELKIND_RELATION) ||
    7129            0 :                 (relkind == RELKIND_PARTITIONED_TABLE) ||
    7130            0 :                 (relkind == RELKIND_INDEX) ||
    7131            0 :                 (relkind == RELKIND_PARTITIONED_INDEX) ||
    7132            0 :                 (relkind == RELKIND_MATVIEW ||
    7133            0 :                  relkind == RELKIND_FOREIGN_TABLE))
    7134              :         {
    7135            0 :                 RelStatsInfo *info = pg_malloc0(sizeof(RelStatsInfo));
    7136            0 :                 DumpableObject *dobj = &info->dobj;
    7137              : 
    7138            0 :                 dobj->objType = DO_REL_STATS;
    7139            0 :                 dobj->catId.tableoid = 0;
    7140            0 :                 dobj->catId.oid = 0;
    7141            0 :                 AssignDumpId(dobj);
    7142            0 :                 dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    7143            0 :                 dobj->dependencies[0] = rel->dumpId;
    7144            0 :                 dobj->nDeps = 1;
    7145            0 :                 dobj->allocDeps = 1;
    7146            0 :                 dobj->components |= DUMP_COMPONENT_STATISTICS;
    7147            0 :                 dobj->name = pg_strdup(rel->name);
    7148            0 :                 dobj->namespace = rel->namespace;
    7149            0 :                 info->relpages = relpages;
    7150            0 :                 info->reltuples = pstrdup(reltuples);
    7151            0 :                 info->relallvisible = relallvisible;
    7152            0 :                 info->relallfrozen = relallfrozen;
    7153            0 :                 info->relkind = relkind;
    7154            0 :                 info->indAttNames = indAttNames;
    7155            0 :                 info->nindAttNames = nindAttNames;
    7156              : 
    7157              :                 /*
    7158              :                  * Ordinarily, stats go in SECTION_DATA for tables and
    7159              :                  * SECTION_POST_DATA for indexes.
    7160              :                  *
    7161              :                  * However, the section may be updated later for materialized view
    7162              :                  * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
    7163              :                  * the stats, so the stats must be restored after the data. Also, the
    7164              :                  * materialized view definition may be postponed to SECTION_POST_DATA
    7165              :                  * (see repairMatViewBoundaryMultiLoop()).
    7166              :                  */
    7167            0 :                 switch (info->relkind)
    7168              :                 {
    7169              :                         case RELKIND_RELATION:
    7170              :                         case RELKIND_PARTITIONED_TABLE:
    7171              :                         case RELKIND_MATVIEW:
    7172              :                         case RELKIND_FOREIGN_TABLE:
    7173            0 :                                 info->section = SECTION_DATA;
    7174            0 :                                 break;
    7175              :                         case RELKIND_INDEX:
    7176              :                         case RELKIND_PARTITIONED_INDEX:
    7177            0 :                                 info->section = SECTION_POST_DATA;
    7178            0 :                                 break;
    7179              :                         default:
    7180            0 :                                 pg_fatal("cannot dump statistics for relation kind \"%c\"",
    7181              :                                                  info->relkind);
    7182            0 :                 }
    7183              : 
    7184            0 :                 return info;
    7185            0 :         }
    7186            0 :         return NULL;
    7187            0 : }
    7188              : 
    7189              : /*
    7190              :  * getTables
    7191              :  *        read all the tables (no indexes) in the system catalogs,
    7192              :  *        and return them as an array of TableInfo structures
    7193              :  *
    7194              :  * *numTables is set to the number of tables read in
    7195              :  */
    7196              : TableInfo *
    7197            0 : getTables(Archive *fout, int *numTables)
    7198              : {
    7199            0 :         DumpOptions *dopt = fout->dopt;
    7200            0 :         PGresult   *res;
    7201            0 :         int                     ntups;
    7202            0 :         int                     i;
    7203            0 :         PQExpBuffer query = createPQExpBuffer();
    7204            0 :         TableInfo  *tblinfo;
    7205            0 :         int                     i_reltableoid;
    7206            0 :         int                     i_reloid;
    7207            0 :         int                     i_relname;
    7208            0 :         int                     i_relnamespace;
    7209            0 :         int                     i_relkind;
    7210            0 :         int                     i_reltype;
    7211            0 :         int                     i_relowner;
    7212            0 :         int                     i_relchecks;
    7213            0 :         int                     i_relhasindex;
    7214            0 :         int                     i_relhasrules;
    7215            0 :         int                     i_relpages;
    7216            0 :         int                     i_reltuples;
    7217            0 :         int                     i_relallvisible;
    7218            0 :         int                     i_relallfrozen;
    7219            0 :         int                     i_toastpages;
    7220            0 :         int                     i_owning_tab;
    7221            0 :         int                     i_owning_col;
    7222            0 :         int                     i_reltablespace;
    7223            0 :         int                     i_relhasoids;
    7224            0 :         int                     i_relhastriggers;
    7225            0 :         int                     i_relpersistence;
    7226            0 :         int                     i_relispopulated;
    7227            0 :         int                     i_relreplident;
    7228            0 :         int                     i_relrowsec;
    7229            0 :         int                     i_relforcerowsec;
    7230            0 :         int                     i_relfrozenxid;
    7231            0 :         int                     i_toastfrozenxid;
    7232            0 :         int                     i_toastoid;
    7233            0 :         int                     i_relminmxid;
    7234            0 :         int                     i_toastminmxid;
    7235            0 :         int                     i_reloptions;
    7236            0 :         int                     i_checkoption;
    7237            0 :         int                     i_toastreloptions;
    7238            0 :         int                     i_reloftype;
    7239            0 :         int                     i_foreignserver;
    7240            0 :         int                     i_amname;
    7241            0 :         int                     i_is_identity_sequence;
    7242            0 :         int                     i_relacl;
    7243            0 :         int                     i_acldefault;
    7244            0 :         int                     i_ispartition;
    7245              : 
    7246              :         /*
    7247              :          * Find all the tables and table-like objects.
    7248              :          *
    7249              :          * We must fetch all tables in this phase because otherwise we cannot
    7250              :          * correctly identify inherited columns, owned sequences, etc.
    7251              :          *
    7252              :          * We include system catalogs, so that we can work if a user table is
    7253              :          * defined to inherit from a system catalog (pretty weird, but...)
    7254              :          *
    7255              :          * Note: in this phase we should collect only a minimal amount of
    7256              :          * information about each table, basically just enough to decide if it is
    7257              :          * interesting.  In particular, since we do not yet have lock on any user
    7258              :          * table, we MUST NOT invoke any server-side data collection functions
    7259              :          * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    7260              :          * wrong answers if any concurrent DDL is happening.
    7261              :          */
    7262              : 
    7263            0 :         appendPQExpBufferStr(query,
    7264              :                                                  "SELECT c.tableoid, c.oid, c.relname, "
    7265              :                                                  "c.relnamespace, c.relkind, c.reltype, "
    7266              :                                                  "c.relowner, "
    7267              :                                                  "c.relchecks, "
    7268              :                                                  "c.relhasindex, c.relhasrules, c.relpages, "
    7269              :                                                  "c.reltuples, c.relallvisible, ");
    7270              : 
    7271            0 :         if (fout->remoteVersion >= 180000)
    7272            0 :                 appendPQExpBufferStr(query, "c.relallfrozen, ");
    7273              :         else
    7274            0 :                 appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7275              : 
    7276            0 :         appendPQExpBufferStr(query,
    7277              :                                                  "c.relhastriggers, c.relpersistence, "
    7278              :                                                  "c.reloftype, "
    7279              :                                                  "c.relacl, "
    7280              :                                                  "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    7281              :                                                  " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    7282              :                                                  "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    7283              :                                                  "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    7284              :                                                  "ELSE 0 END AS foreignserver, "
    7285              :                                                  "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    7286              :                                                  "tc.oid AS toid, "
    7287              :                                                  "tc.relpages AS toastpages, "
    7288              :                                                  "tc.reloptions AS toast_reloptions, "
    7289              :                                                  "d.refobjid AS owning_tab, "
    7290              :                                                  "d.refobjsubid AS owning_col, "
    7291              :                                                  "tsp.spcname AS reltablespace, ");
    7292              : 
    7293            0 :         if (fout->remoteVersion >= 120000)
    7294            0 :                 appendPQExpBufferStr(query,
    7295              :                                                          "false AS relhasoids, ");
    7296              :         else
    7297            0 :                 appendPQExpBufferStr(query,
    7298              :                                                          "c.relhasoids, ");
    7299              : 
    7300            0 :         if (fout->remoteVersion >= 90300)
    7301            0 :                 appendPQExpBufferStr(query,
    7302              :                                                          "c.relispopulated, ");
    7303              :         else
    7304            0 :                 appendPQExpBufferStr(query,
    7305              :                                                          "'t' as relispopulated, ");
    7306              : 
    7307            0 :         if (fout->remoteVersion >= 90400)
    7308            0 :                 appendPQExpBufferStr(query,
    7309              :                                                          "c.relreplident, ");
    7310              :         else
    7311            0 :                 appendPQExpBufferStr(query,
    7312              :                                                          "'d' AS relreplident, ");
    7313              : 
    7314            0 :         if (fout->remoteVersion >= 90500)
    7315            0 :                 appendPQExpBufferStr(query,
    7316              :                                                          "c.relrowsecurity, c.relforcerowsecurity, ");
    7317              :         else
    7318            0 :                 appendPQExpBufferStr(query,
    7319              :                                                          "false AS relrowsecurity, "
    7320              :                                                          "false AS relforcerowsecurity, ");
    7321              : 
    7322            0 :         if (fout->remoteVersion >= 90300)
    7323            0 :                 appendPQExpBufferStr(query,
    7324              :                                                          "c.relminmxid, tc.relminmxid AS tminmxid, ");
    7325              :         else
    7326            0 :                 appendPQExpBufferStr(query,
    7327              :                                                          "0 AS relminmxid, 0 AS tminmxid, ");
    7328              : 
    7329            0 :         if (fout->remoteVersion >= 90300)
    7330            0 :                 appendPQExpBufferStr(query,
    7331              :                                                          "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    7332              :                                                          "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    7333              :                                                          "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    7334              :         else
    7335            0 :                 appendPQExpBufferStr(query,
    7336              :                                                          "c.reloptions, NULL AS checkoption, ");
    7337              : 
    7338            0 :         if (fout->remoteVersion >= 90600)
    7339            0 :                 appendPQExpBufferStr(query,
    7340              :                                                          "am.amname, ");
    7341              :         else
    7342            0 :                 appendPQExpBufferStr(query,
    7343              :                                                          "NULL AS amname, ");
    7344              : 
    7345            0 :         if (fout->remoteVersion >= 90600)
    7346            0 :                 appendPQExpBufferStr(query,
    7347              :                                                          "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    7348              :         else
    7349            0 :                 appendPQExpBufferStr(query,
    7350              :                                                          "false AS is_identity_sequence, ");
    7351              : 
    7352            0 :         if (fout->remoteVersion >= 100000)
    7353            0 :                 appendPQExpBufferStr(query,
    7354              :                                                          "c.relispartition AS ispartition ");
    7355              :         else
    7356            0 :                 appendPQExpBufferStr(query,
    7357              :                                                          "false AS ispartition ");
    7358              : 
    7359              :         /*
    7360              :          * Left join to pg_depend to pick up dependency info linking sequences to
    7361              :          * their owning column, if any (note this dependency is AUTO except for
    7362              :          * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    7363              :          * collect the spcname.
    7364              :          */
    7365            0 :         appendPQExpBufferStr(query,
    7366              :                                                  "\nFROM pg_class c\n"
    7367              :                                                  "LEFT JOIN pg_depend d ON "
    7368              :                                                  "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    7369              :                                                  "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    7370              :                                                  "d.objsubid = 0 AND "
    7371              :                                                  "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    7372              :                                                  "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    7373              : 
    7374              :         /*
    7375              :          * In 9.6 and up, left join to pg_am to pick up the amname.
    7376              :          */
    7377            0 :         if (fout->remoteVersion >= 90600)
    7378            0 :                 appendPQExpBufferStr(query,
    7379              :                                                          "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    7380              : 
    7381              :         /*
    7382              :          * We purposefully ignore toast OIDs for partitioned tables; the reason is
    7383              :          * that versions 10 and 11 have them, but later versions do not, so
    7384              :          * emitting them causes the upgrade to fail.
    7385              :          */
    7386            0 :         appendPQExpBufferStr(query,
    7387              :                                                  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    7388              :                                                  " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    7389              :                                                  " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    7390              : 
    7391              :         /*
    7392              :          * Restrict to interesting relkinds (in particular, not indexes).  Not all
    7393              :          * relkinds are possible in older servers, but it's not worth the trouble
    7394              :          * to emit a version-dependent list.
    7395              :          *
    7396              :          * Composite-type table entries won't be dumped as such, but we have to
    7397              :          * make a DumpableObject for them so that we can track dependencies of the
    7398              :          * composite type (pg_depend entries for columns of the composite type
    7399              :          * link to the pg_class entry not the pg_type entry).
    7400              :          */
    7401            0 :         appendPQExpBufferStr(query,
    7402              :                                                  "WHERE c.relkind IN ("
    7403              :                                                  CppAsString2(RELKIND_RELATION) ", "
    7404              :                                                  CppAsString2(RELKIND_SEQUENCE) ", "
    7405              :                                                  CppAsString2(RELKIND_VIEW) ", "
    7406              :                                                  CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    7407              :                                                  CppAsString2(RELKIND_MATVIEW) ", "
    7408              :                                                  CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    7409              :                                                  CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
    7410              :                                                  "ORDER BY c.oid");
    7411              : 
    7412            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7413              : 
    7414            0 :         ntups = PQntuples(res);
    7415              : 
    7416            0 :         *numTables = ntups;
    7417              : 
    7418              :         /*
    7419              :          * Extract data from result and lock dumpable tables.  We do the locking
    7420              :          * before anything else, to minimize the window wherein a table could
    7421              :          * disappear under us.
    7422              :          *
    7423              :          * Note that we have to save info about all tables here, even when dumping
    7424              :          * only one, because we don't yet know which tables might be inheritance
    7425              :          * ancestors of the target table.
    7426              :          */
    7427            0 :         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
    7428              : 
    7429            0 :         i_reltableoid = PQfnumber(res, "tableoid");
    7430            0 :         i_reloid = PQfnumber(res, "oid");
    7431            0 :         i_relname = PQfnumber(res, "relname");
    7432            0 :         i_relnamespace = PQfnumber(res, "relnamespace");
    7433            0 :         i_relkind = PQfnumber(res, "relkind");
    7434            0 :         i_reltype = PQfnumber(res, "reltype");
    7435            0 :         i_relowner = PQfnumber(res, "relowner");
    7436            0 :         i_relchecks = PQfnumber(res, "relchecks");
    7437            0 :         i_relhasindex = PQfnumber(res, "relhasindex");
    7438            0 :         i_relhasrules = PQfnumber(res, "relhasrules");
    7439            0 :         i_relpages = PQfnumber(res, "relpages");
    7440            0 :         i_reltuples = PQfnumber(res, "reltuples");
    7441            0 :         i_relallvisible = PQfnumber(res, "relallvisible");
    7442            0 :         i_relallfrozen = PQfnumber(res, "relallfrozen");
    7443            0 :         i_toastpages = PQfnumber(res, "toastpages");
    7444            0 :         i_owning_tab = PQfnumber(res, "owning_tab");
    7445            0 :         i_owning_col = PQfnumber(res, "owning_col");
    7446            0 :         i_reltablespace = PQfnumber(res, "reltablespace");
    7447            0 :         i_relhasoids = PQfnumber(res, "relhasoids");
    7448            0 :         i_relhastriggers = PQfnumber(res, "relhastriggers");
    7449            0 :         i_relpersistence = PQfnumber(res, "relpersistence");
    7450            0 :         i_relispopulated = PQfnumber(res, "relispopulated");
    7451            0 :         i_relreplident = PQfnumber(res, "relreplident");
    7452            0 :         i_relrowsec = PQfnumber(res, "relrowsecurity");
    7453            0 :         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7454            0 :         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7455            0 :         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7456            0 :         i_toastoid = PQfnumber(res, "toid");
    7457            0 :         i_relminmxid = PQfnumber(res, "relminmxid");
    7458            0 :         i_toastminmxid = PQfnumber(res, "tminmxid");
    7459            0 :         i_reloptions = PQfnumber(res, "reloptions");
    7460            0 :         i_checkoption = PQfnumber(res, "checkoption");
    7461            0 :         i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7462            0 :         i_reloftype = PQfnumber(res, "reloftype");
    7463            0 :         i_foreignserver = PQfnumber(res, "foreignserver");
    7464            0 :         i_amname = PQfnumber(res, "amname");
    7465            0 :         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7466            0 :         i_relacl = PQfnumber(res, "relacl");
    7467            0 :         i_acldefault = PQfnumber(res, "acldefault");
    7468            0 :         i_ispartition = PQfnumber(res, "ispartition");
    7469              : 
    7470            0 :         if (dopt->lockWaitTimeout)
    7471              :         {
    7472              :                 /*
    7473              :                  * Arrange to fail instead of waiting forever for a table lock.
    7474              :                  *
    7475              :                  * NB: this coding assumes that the only queries issued within the
    7476              :                  * following loop are LOCK TABLEs; else the timeout may be undesirably
    7477              :                  * applied to other things too.
    7478              :                  */
    7479            0 :                 resetPQExpBuffer(query);
    7480            0 :                 appendPQExpBufferStr(query, "SET statement_timeout = ");
    7481            0 :                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7482            0 :                 ExecuteSqlStatement(fout, query->data);
    7483            0 :         }
    7484              : 
    7485            0 :         resetPQExpBuffer(query);
    7486              : 
    7487            0 :         for (i = 0; i < ntups; i++)
    7488              :         {
    7489            0 :                 int32           relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
    7490            0 :                 int32           relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
    7491              : 
    7492            0 :                 tblinfo[i].dobj.objType = DO_TABLE;
    7493            0 :                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7494            0 :                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7495            0 :                 AssignDumpId(&tblinfo[i].dobj);
    7496            0 :                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7497            0 :                 tblinfo[i].dobj.namespace =
    7498            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7499            0 :                 tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7500            0 :                 tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7501            0 :                 tblinfo[i].dacl.privtype = 0;
    7502            0 :                 tblinfo[i].dacl.initprivs = NULL;
    7503            0 :                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7504            0 :                 tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7505            0 :                 tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7506            0 :                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7507            0 :                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7508            0 :                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7509            0 :                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7510            0 :                 if (PQgetisnull(res, i, i_toastpages))
    7511            0 :                         tblinfo[i].toastpages = 0;
    7512              :                 else
    7513            0 :                         tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7514            0 :                 if (PQgetisnull(res, i, i_owning_tab))
    7515              :                 {
    7516            0 :                         tblinfo[i].owning_tab = InvalidOid;
    7517            0 :                         tblinfo[i].owning_col = 0;
    7518            0 :                 }
    7519              :                 else
    7520              :                 {
    7521            0 :                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7522            0 :                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7523              :                 }
    7524            0 :                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7525            0 :                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7526            0 :                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7527            0 :                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7528            0 :                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7529            0 :                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7530            0 :                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7531            0 :                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7532            0 :                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7533            0 :                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7534            0 :                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7535            0 :                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7536            0 :                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7537            0 :                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7538            0 :                 if (PQgetisnull(res, i, i_checkoption))
    7539            0 :                         tblinfo[i].checkoption = NULL;
    7540              :                 else
    7541            0 :                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7542            0 :                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7543            0 :                 tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7544            0 :                 tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7545            0 :                 if (PQgetisnull(res, i, i_amname))
    7546            0 :                         tblinfo[i].amname = NULL;
    7547              :                 else
    7548            0 :                         tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7549            0 :                 tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7550            0 :                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7551              : 
    7552              :                 /* other fields were zeroed above */
    7553              : 
    7554              :                 /*
    7555              :                  * Decide whether we want to dump this table.
    7556              :                  */
    7557            0 :                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7558            0 :                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7559              :                 else
    7560            0 :                         selectDumpableTable(&tblinfo[i], fout);
    7561              : 
    7562              :                 /*
    7563              :                  * Now, consider the table "interesting" if we need to dump its
    7564              :                  * definition, data or its statistics.  Later on, we'll skip a lot of
    7565              :                  * data collection for uninteresting tables.
    7566              :                  *
    7567              :                  * Note: the "interesting" flag will also be set by flagInhTables for
    7568              :                  * parents of interesting tables, so that we collect necessary
    7569              :                  * inheritance info even when the parents are not themselves being
    7570              :                  * dumped.  This is the main reason why we need an "interesting" flag
    7571              :                  * that's separate from the components-to-dump bitmask.
    7572              :                  */
    7573            0 :                 tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7574              :                                                                   (DUMP_COMPONENT_DEFINITION |
    7575              :                                                                    DUMP_COMPONENT_DATA |
    7576            0 :                                                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7577              : 
    7578            0 :                 tblinfo[i].dummy_view = false;  /* might get set during sort */
    7579            0 :                 tblinfo[i].postponed_def = false;       /* might get set during sort */
    7580              : 
    7581              :                 /* Tables have data */
    7582            0 :                 tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7583              : 
    7584              :                 /* Mark whether table has an ACL */
    7585            0 :                 if (!PQgetisnull(res, i, i_relacl))
    7586            0 :                         tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7587            0 :                 tblinfo[i].hascolumnACLs = false;       /* may get set later */
    7588              : 
    7589              :                 /* Add statistics */
    7590            0 :                 if (tblinfo[i].interesting)
    7591              :                 {
    7592            0 :                         RelStatsInfo *stats;
    7593              : 
    7594            0 :                         stats = getRelationStatistics(fout, &tblinfo[i].dobj,
    7595            0 :                                                                                   tblinfo[i].relpages,
    7596            0 :                                                                                   PQgetvalue(res, i, i_reltuples),
    7597            0 :                                                                                   relallvisible, relallfrozen,
    7598            0 :                                                                                   tblinfo[i].relkind, NULL, 0);
    7599            0 :                         if (tblinfo[i].relkind == RELKIND_MATVIEW)
    7600            0 :                                 tblinfo[i].stats = stats;
    7601            0 :                 }
    7602              : 
    7603              :                 /*
    7604              :                  * Read-lock target tables to make sure they aren't DROPPED or altered
    7605              :                  * in schema before we get around to dumping them.
    7606              :                  *
    7607              :                  * Note that we don't explicitly lock parents of the target tables; we
    7608              :                  * assume our lock on the child is enough to prevent schema
    7609              :                  * alterations to parent tables.
    7610              :                  *
    7611              :                  * NOTE: it'd be kinda nice to lock other relations too, not only
    7612              :                  * plain or partitioned tables, but the backend doesn't presently
    7613              :                  * allow that.
    7614              :                  *
    7615              :                  * We only need to lock the table for certain components; see
    7616              :                  * pg_dump.h
    7617              :                  */
    7618            0 :                 if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7619            0 :                         (tblinfo[i].relkind == RELKIND_RELATION ||
    7620            0 :                          tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7621              :                 {
    7622              :                         /*
    7623              :                          * Tables are locked in batches.  When dumping from a remote
    7624              :                          * server this can save a significant amount of time by reducing
    7625              :                          * the number of round trips.
    7626              :                          */
    7627            0 :                         if (query->len == 0)
    7628            0 :                                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7629            0 :                                                                   fmtQualifiedDumpable(&tblinfo[i]));
    7630              :                         else
    7631              :                         {
    7632            0 :                                 appendPQExpBuffer(query, ", %s",
    7633            0 :                                                                   fmtQualifiedDumpable(&tblinfo[i]));
    7634              : 
    7635              :                                 /* Arbitrarily end a batch when query length reaches 100K. */
    7636            0 :                                 if (query->len >= 100000)
    7637              :                                 {
    7638              :                                         /* Lock another batch of tables. */
    7639            0 :                                         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7640            0 :                                         ExecuteSqlStatement(fout, query->data);
    7641            0 :                                         resetPQExpBuffer(query);
    7642            0 :                                 }
    7643              :                         }
    7644            0 :                 }
    7645            0 :         }
    7646              : 
    7647            0 :         if (query->len != 0)
    7648              :         {
    7649              :                 /* Lock the tables in the last batch. */
    7650            0 :                 appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7651            0 :                 ExecuteSqlStatement(fout, query->data);
    7652            0 :         }
    7653              : 
    7654            0 :         if (dopt->lockWaitTimeout)
    7655              :         {
    7656            0 :                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7657            0 :         }
    7658              : 
    7659            0 :         PQclear(res);
    7660              : 
    7661            0 :         destroyPQExpBuffer(query);
    7662              : 
    7663            0 :         return tblinfo;
    7664            0 : }
    7665              : 
    7666              : /*
    7667              :  * getOwnedSeqs
    7668              :  *        identify owned sequences and mark them as dumpable if owning table is
    7669              :  *
    7670              :  * We used to do this in getTables(), but it's better to do it after the
    7671              :  * index used by findTableByOid() has been set up.
    7672              :  */
    7673              : void
    7674            0 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7675              : {
    7676            0 :         int                     i;
    7677              : 
    7678              :         /*
    7679              :          * Force sequences that are "owned" by table columns to be dumped whenever
    7680              :          * their owning table is being dumped.
    7681              :          */
    7682            0 :         for (i = 0; i < numTables; i++)
    7683              :         {
    7684            0 :                 TableInfo  *seqinfo = &tblinfo[i];
    7685            0 :                 TableInfo  *owning_tab;
    7686              : 
    7687            0 :                 if (!OidIsValid(seqinfo->owning_tab))
    7688            0 :                         continue;                       /* not an owned sequence */
    7689              : 
    7690            0 :                 owning_tab = findTableByOid(seqinfo->owning_tab);
    7691            0 :                 if (owning_tab == NULL)
    7692            0 :                         pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7693              :                                          seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7694              : 
    7695              :                 /*
    7696              :                  * For an identity sequence, dump exactly the same components for the
    7697              :                  * sequence as for the owning table.  This is important because we
    7698              :                  * treat the identity sequence as an integral part of the table.  For
    7699              :                  * example, there is not any DDL command that allows creation of such
    7700              :                  * a sequence independently of the table.
    7701              :                  *
    7702              :                  * For other owned sequences such as serial sequences, we need to dump
    7703              :                  * the components that are being dumped for the table and any
    7704              :                  * components that the sequence is explicitly marked with.
    7705              :                  *
    7706              :                  * We can't simply use the set of components which are being dumped
    7707              :                  * for the table as the table might be in an extension (and only the
    7708              :                  * non-extension components, eg: ACLs if changed, security labels, and
    7709              :                  * policies, are being dumped) while the sequence is not (and
    7710              :                  * therefore the definition and other components should also be
    7711              :                  * dumped).
    7712              :                  *
    7713              :                  * If the sequence is part of the extension then it should be properly
    7714              :                  * marked by checkExtensionMembership() and this will be a no-op as
    7715              :                  * the table will be equivalently marked.
    7716              :                  */
    7717            0 :                 if (seqinfo->is_identity_sequence)
    7718            0 :                         seqinfo->dobj.dump = owning_tab->dobj.dump;
    7719              :                 else
    7720            0 :                         seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7721              : 
    7722              :                 /* Make sure that necessary data is available if we're dumping it */
    7723            0 :                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7724              :                 {
    7725            0 :                         seqinfo->interesting = true;
    7726            0 :                         owning_tab->interesting = true;
    7727            0 :                 }
    7728            0 :         }
    7729            0 : }
    7730              : 
    7731              : /*
    7732              :  * getInherits
    7733              :  *        read all the inheritance information
    7734              :  * from the system catalogs return them in the InhInfo* structure
    7735              :  *
    7736              :  * numInherits is set to the number of pairs read in
    7737              :  */
    7738              : InhInfo *
    7739            0 : getInherits(Archive *fout, int *numInherits)
    7740              : {
    7741            0 :         PGresult   *res;
    7742            0 :         int                     ntups;
    7743            0 :         int                     i;
    7744            0 :         PQExpBuffer query = createPQExpBuffer();
    7745            0 :         InhInfo    *inhinfo;
    7746              : 
    7747            0 :         int                     i_inhrelid;
    7748            0 :         int                     i_inhparent;
    7749              : 
    7750              :         /* find all the inheritance information */
    7751            0 :         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7752              : 
    7753            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7754              : 
    7755            0 :         ntups = PQntuples(res);
    7756              : 
    7757            0 :         *numInherits = ntups;
    7758              : 
    7759            0 :         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
    7760              : 
    7761            0 :         i_inhrelid = PQfnumber(res, "inhrelid");
    7762            0 :         i_inhparent = PQfnumber(res, "inhparent");
    7763              : 
    7764            0 :         for (i = 0; i < ntups; i++)
    7765              :         {
    7766            0 :                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7767            0 :                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7768            0 :         }
    7769              : 
    7770            0 :         PQclear(res);
    7771              : 
    7772            0 :         destroyPQExpBuffer(query);
    7773              : 
    7774            0 :         return inhinfo;
    7775            0 : }
    7776              : 
    7777              : /*
    7778              :  * getPartitioningInfo
    7779              :  *        get information about partitioning
    7780              :  *
    7781              :  * For the most part, we only collect partitioning info about tables we
    7782              :  * intend to dump.  However, this function has to consider all partitioned
    7783              :  * tables in the database, because we need to know about parents of partitions
    7784              :  * we are going to dump even if the parents themselves won't be dumped.
    7785              :  *
    7786              :  * Specifically, what we need to know is whether each partitioned table
    7787              :  * has an "unsafe" partitioning scheme that requires us to force
    7788              :  * load-via-partition-root mode for its children.  Currently the only case
    7789              :  * for which we force that is hash partitioning on enum columns, since the
    7790              :  * hash codes depend on enum value OIDs which won't be replicated across
    7791              :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7792              :  * might be necessary, but we expect users to cope with them.
    7793              :  */
    7794              : void
    7795            0 : getPartitioningInfo(Archive *fout)
    7796              : {
    7797            0 :         PQExpBuffer query;
    7798            0 :         PGresult   *res;
    7799            0 :         int                     ntups;
    7800              : 
    7801              :         /* hash partitioning didn't exist before v11 */
    7802            0 :         if (fout->remoteVersion < 110000)
    7803            0 :                 return;
    7804              :         /* needn't bother if not dumping data */
    7805            0 :         if (!fout->dopt->dumpData)
    7806            0 :                 return;
    7807              : 
    7808            0 :         query = createPQExpBuffer();
    7809              : 
    7810              :         /*
    7811              :          * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7812              :          * appears among the partition opclasses.  We needn't check partstrat.
    7813              :          *
    7814              :          * Note that this query may well retrieve info about tables we aren't
    7815              :          * going to dump and hence have no lock on.  That's okay since we need not
    7816              :          * invoke any unsafe server-side functions.
    7817              :          */
    7818            0 :         appendPQExpBufferStr(query,
    7819              :                                                  "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7820              :                                                  "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7821              :                                                  "ON c.opcmethod = a.oid\n"
    7822              :                                                  "WHERE opcname = 'enum_ops' "
    7823              :                                                  "AND opcnamespace = 'pg_catalog'::regnamespace "
    7824              :                                                  "AND amname = 'hash') = ANY(partclass)");
    7825              : 
    7826            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7827              : 
    7828            0 :         ntups = PQntuples(res);
    7829              : 
    7830            0 :         for (int i = 0; i < ntups; i++)
    7831              :         {
    7832            0 :                 Oid                     tabrelid = atooid(PQgetvalue(res, i, 0));
    7833            0 :                 TableInfo  *tbinfo;
    7834              : 
    7835            0 :                 tbinfo = findTableByOid(tabrelid);
    7836            0 :                 if (tbinfo == NULL)
    7837            0 :                         pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7838              :                                          tabrelid);
    7839            0 :                 tbinfo->unsafe_partitions = true;
    7840            0 :         }
    7841              : 
    7842            0 :         PQclear(res);
    7843              : 
    7844            0 :         destroyPQExpBuffer(query);
    7845            0 : }
    7846              : 
    7847              : /*
    7848              :  * getIndexes
    7849              :  *        get information about every index on a dumpable table
    7850              :  *
    7851              :  * Note: index data is not returned directly to the caller, but it
    7852              :  * does get entered into the DumpableObject tables.
    7853              :  */
    7854              : void
    7855            0 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7856              : {
    7857            0 :         PQExpBuffer query = createPQExpBuffer();
    7858            0 :         PQExpBuffer tbloids = createPQExpBuffer();
    7859            0 :         PGresult   *res;
    7860            0 :         int                     ntups;
    7861            0 :         int                     curtblindx;
    7862            0 :         IndxInfo   *indxinfo;
    7863            0 :         int                     i_tableoid,
    7864              :                                 i_oid,
    7865              :                                 i_indrelid,
    7866              :                                 i_indexname,
    7867              :                                 i_relpages,
    7868              :                                 i_reltuples,
    7869              :                                 i_relallvisible,
    7870              :                                 i_relallfrozen,
    7871              :                                 i_parentidx,
    7872              :                                 i_indexdef,
    7873              :                                 i_indnkeyatts,
    7874              :                                 i_indnatts,
    7875              :                                 i_indkey,
    7876              :                                 i_indisclustered,
    7877              :                                 i_indisreplident,
    7878              :                                 i_indnullsnotdistinct,
    7879              :                                 i_contype,
    7880              :                                 i_conname,
    7881              :                                 i_condeferrable,
    7882              :                                 i_condeferred,
    7883              :                                 i_conperiod,
    7884              :                                 i_contableoid,
    7885              :                                 i_conoid,
    7886              :                                 i_condef,
    7887              :                                 i_indattnames,
    7888              :                                 i_tablespace,
    7889              :                                 i_indreloptions,
    7890              :                                 i_indstatcols,
    7891              :                                 i_indstatvals;
    7892              : 
    7893              :         /*
    7894              :          * We want to perform just one query against pg_index.  However, we
    7895              :          * mustn't try to select every row of the catalog and then sort it out on
    7896              :          * the client side, because some of the server-side functions we need
    7897              :          * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7898              :          * build an array of the OIDs of tables we care about (and now have lock
    7899              :          * on!), and use a WHERE clause to constrain which rows are selected.
    7900              :          */
    7901            0 :         appendPQExpBufferChar(tbloids, '{');
    7902            0 :         for (int i = 0; i < numTables; i++)
    7903              :         {
    7904            0 :                 TableInfo  *tbinfo = &tblinfo[i];
    7905              : 
    7906            0 :                 if (!tbinfo->hasindex)
    7907            0 :                         continue;
    7908              : 
    7909              :                 /*
    7910              :                  * We can ignore indexes of uninteresting tables.
    7911              :                  */
    7912            0 :                 if (!tbinfo->interesting)
    7913            0 :                         continue;
    7914              : 
    7915              :                 /* OK, we need info for this table */
    7916            0 :                 if (tbloids->len > 1)     /* do we have more than the '{'? */
    7917            0 :                         appendPQExpBufferChar(tbloids, ',');
    7918            0 :                 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    7919            0 :         }
    7920            0 :         appendPQExpBufferChar(tbloids, '}');
    7921              : 
    7922            0 :         appendPQExpBufferStr(query,
    7923              :                                                  "SELECT t.tableoid, t.oid, i.indrelid, "
    7924              :                                                  "t.relname AS indexname, "
    7925              :                                                  "t.relpages, t.reltuples, t.relallvisible, ");
    7926              : 
    7927            0 :         if (fout->remoteVersion >= 180000)
    7928            0 :                 appendPQExpBufferStr(query, "t.relallfrozen, ");
    7929              :         else
    7930            0 :                 appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7931              : 
    7932            0 :         appendPQExpBufferStr(query,
    7933              :                                                  "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7934              :                                                  "i.indkey, i.indisclustered, "
    7935              :                                                  "c.contype, c.conname, "
    7936              :                                                  "c.condeferrable, c.condeferred, "
    7937              :                                                  "c.tableoid AS contableoid, "
    7938              :                                                  "c.oid AS conoid, "
    7939              :                                                  "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    7940              :                                                  "CASE WHEN i.indexprs IS NOT NULL THEN "
    7941              :                                                  "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
    7942              :                                                  "  FROM pg_catalog.pg_attribute "
    7943              :                                                  "  WHERE attrelid = i.indexrelid) "
    7944              :                                                  "ELSE NULL END AS indattnames, "
    7945              :                                                  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7946              :                                                  "t.reloptions AS indreloptions, ");
    7947              : 
    7948              : 
    7949            0 :         if (fout->remoteVersion >= 90400)
    7950            0 :                 appendPQExpBufferStr(query,
    7951              :                                                          "i.indisreplident, ");
    7952              :         else
    7953            0 :                 appendPQExpBufferStr(query,
    7954              :                                                          "false AS indisreplident, ");
    7955              : 
    7956            0 :         if (fout->remoteVersion >= 110000)
    7957            0 :                 appendPQExpBufferStr(query,
    7958              :                                                          "inh.inhparent AS parentidx, "
    7959              :                                                          "i.indnkeyatts AS indnkeyatts, "
    7960              :                                                          "i.indnatts AS indnatts, "
    7961              :                                                          "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    7962              :                                                          "  FROM pg_catalog.pg_attribute "
    7963              :                                                          "  WHERE attrelid = i.indexrelid AND "
    7964              :                                                          "    attstattarget >= 0) AS indstatcols, "
    7965              :                                                          "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    7966              :                                                          "  FROM pg_catalog.pg_attribute "
    7967              :                                                          "  WHERE attrelid = i.indexrelid AND "
    7968              :                                                          "    attstattarget >= 0) AS indstatvals, ");
    7969              :         else
    7970            0 :                 appendPQExpBufferStr(query,
    7971              :                                                          "0 AS parentidx, "
    7972              :                                                          "i.indnatts AS indnkeyatts, "
    7973              :                                                          "i.indnatts AS indnatts, "
    7974              :                                                          "'' AS indstatcols, "
    7975              :                                                          "'' AS indstatvals, ");
    7976              : 
    7977            0 :         if (fout->remoteVersion >= 150000)
    7978            0 :                 appendPQExpBufferStr(query,
    7979              :                                                          "i.indnullsnotdistinct, ");
    7980              :         else
    7981            0 :                 appendPQExpBufferStr(query,
    7982              :                                                          "false AS indnullsnotdistinct, ");
    7983              : 
    7984            0 :         if (fout->remoteVersion >= 180000)
    7985            0 :                 appendPQExpBufferStr(query,
    7986              :                                                          "c.conperiod ");
    7987              :         else
    7988            0 :                 appendPQExpBufferStr(query,
    7989              :                                                          "NULL AS conperiod ");
    7990              : 
    7991              :         /*
    7992              :          * The point of the messy-looking outer join is to find a constraint that
    7993              :          * is related by an internal dependency link to the index. If we find one,
    7994              :          * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    7995              :          * index won't have more than one internal dependency.
    7996              :          *
    7997              :          * Note: the check on conrelid is redundant, but useful because that
    7998              :          * column is indexed while conindid is not.
    7999              :          */
    8000            0 :         if (fout->remoteVersion >= 110000)
    8001              :         {
    8002            0 :                 appendPQExpBuffer(query,
    8003              :                                                   "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8004              :                                                   "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    8005              :                                                   "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    8006              :                                                   "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    8007              :                                                   "LEFT JOIN pg_catalog.pg_constraint c "
    8008              :                                                   "ON (i.indrelid = c.conrelid AND "
    8009              :                                                   "i.indexrelid = c.conindid AND "
    8010              :                                                   "c.contype IN ('p','u','x')) "
    8011              :                                                   "LEFT JOIN pg_catalog.pg_inherits inh "
    8012              :                                                   "ON (inh.inhrelid = indexrelid) "
    8013              :                                                   "WHERE (i.indisvalid OR t2.relkind = 'p') "
    8014              :                                                   "AND i.indisready "
    8015              :                                                   "ORDER BY i.indrelid, indexname",
    8016            0 :                                                   tbloids->data);
    8017            0 :         }
    8018              :         else
    8019              :         {
    8020              :                 /*
    8021              :                  * the test on indisready is necessary in 9.2, and harmless in
    8022              :                  * earlier/later versions
    8023              :                  */
    8024            0 :                 appendPQExpBuffer(query,
    8025              :                                                   "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8026              :                                                   "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    8027              :                                                   "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    8028              :                                                   "LEFT JOIN pg_catalog.pg_constraint c "
    8029              :                                                   "ON (i.indrelid = c.conrelid AND "
    8030              :                                                   "i.indexrelid = c.conindid AND "
    8031              :                                                   "c.contype IN ('p','u','x')) "
    8032              :                                                   "WHERE i.indisvalid AND i.indisready "
    8033              :                                                   "ORDER BY i.indrelid, indexname",
    8034            0 :                                                   tbloids->data);
    8035              :         }
    8036              : 
    8037            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8038              : 
    8039            0 :         ntups = PQntuples(res);
    8040              : 
    8041            0 :         i_tableoid = PQfnumber(res, "tableoid");
    8042            0 :         i_oid = PQfnumber(res, "oid");
    8043            0 :         i_indrelid = PQfnumber(res, "indrelid");
    8044            0 :         i_indexname = PQfnumber(res, "indexname");
    8045            0 :         i_relpages = PQfnumber(res, "relpages");
    8046            0 :         i_reltuples = PQfnumber(res, "reltuples");
    8047            0 :         i_relallvisible = PQfnumber(res, "relallvisible");
    8048            0 :         i_relallfrozen = PQfnumber(res, "relallfrozen");
    8049            0 :         i_parentidx = PQfnumber(res, "parentidx");
    8050            0 :         i_indexdef = PQfnumber(res, "indexdef");
    8051            0 :         i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    8052            0 :         i_indnatts = PQfnumber(res, "indnatts");
    8053            0 :         i_indkey = PQfnumber(res, "indkey");
    8054            0 :         i_indisclustered = PQfnumber(res, "indisclustered");
    8055            0 :         i_indisreplident = PQfnumber(res, "indisreplident");
    8056            0 :         i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    8057            0 :         i_contype = PQfnumber(res, "contype");
    8058            0 :         i_conname = PQfnumber(res, "conname");
    8059            0 :         i_condeferrable = PQfnumber(res, "condeferrable");
    8060            0 :         i_condeferred = PQfnumber(res, "condeferred");
    8061            0 :         i_conperiod = PQfnumber(res, "conperiod");
    8062            0 :         i_contableoid = PQfnumber(res, "contableoid");
    8063            0 :         i_conoid = PQfnumber(res, "conoid");
    8064            0 :         i_condef = PQfnumber(res, "condef");
    8065            0 :         i_indattnames = PQfnumber(res, "indattnames");
    8066            0 :         i_tablespace = PQfnumber(res, "tablespace");
    8067            0 :         i_indreloptions = PQfnumber(res, "indreloptions");
    8068            0 :         i_indstatcols = PQfnumber(res, "indstatcols");
    8069            0 :         i_indstatvals = PQfnumber(res, "indstatvals");
    8070              : 
    8071            0 :         indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
    8072              : 
    8073              :         /*
    8074              :          * Outer loop iterates once per table, not once per row.  Incrementing of
    8075              :          * j is handled by the inner loop.
    8076              :          */
    8077            0 :         curtblindx = -1;
    8078            0 :         for (int j = 0; j < ntups;)
    8079              :         {
    8080            0 :                 Oid                     indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    8081            0 :                 TableInfo  *tbinfo = NULL;
    8082            0 :                 char      **indAttNames = NULL;
    8083            0 :                 int                     nindAttNames = 0;
    8084            0 :                 int                     numinds;
    8085              : 
    8086              :                 /* Count rows for this table */
    8087            0 :                 for (numinds = 1; numinds < ntups - j; numinds++)
    8088            0 :                         if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    8089            0 :                                 break;
    8090              : 
    8091              :                 /*
    8092              :                  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8093              :                  * order.
    8094              :                  */
    8095            0 :                 while (++curtblindx < numTables)
    8096              :                 {
    8097            0 :                         tbinfo = &tblinfo[curtblindx];
    8098            0 :                         if (tbinfo->dobj.catId.oid == indrelid)
    8099            0 :                                 break;
    8100              :                 }
    8101            0 :                 if (curtblindx >= numTables)
    8102            0 :                         pg_fatal("unrecognized table OID %u", indrelid);
    8103              :                 /* cross-check that we only got requested tables */
    8104            0 :                 if (!tbinfo->hasindex ||
    8105            0 :                         !tbinfo->interesting)
    8106            0 :                         pg_fatal("unexpected index data for table \"%s\"",
    8107              :                                          tbinfo->dobj.name);
    8108              : 
    8109              :                 /* Save data for this table */
    8110            0 :                 tbinfo->indexes = indxinfo + j;
    8111            0 :                 tbinfo->numIndexes = numinds;
    8112              : 
    8113            0 :                 for (int c = 0; c < numinds; c++, j++)
    8114              :                 {
    8115            0 :                         char            contype;
    8116            0 :                         char            indexkind;
    8117            0 :                         RelStatsInfo *relstats;
    8118            0 :                         int32           relpages = atoi(PQgetvalue(res, j, i_relpages));
    8119            0 :                         int32           relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
    8120            0 :                         int32           relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
    8121              : 
    8122            0 :                         indxinfo[j].dobj.objType = DO_INDEX;
    8123            0 :                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8124            0 :                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8125            0 :                         AssignDumpId(&indxinfo[j].dobj);
    8126            0 :                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    8127            0 :                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    8128            0 :                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8129            0 :                         indxinfo[j].indextable = tbinfo;
    8130            0 :                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    8131            0 :                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    8132            0 :                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    8133            0 :                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    8134            0 :                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    8135            0 :                         indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    8136            0 :                         indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    8137            0 :                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
    8138            0 :                         parseOidArray(PQgetvalue(res, j, i_indkey),
    8139            0 :                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
    8140            0 :                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    8141            0 :                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    8142            0 :                         indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    8143            0 :                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    8144            0 :                         indxinfo[j].partattaches = (SimplePtrList)
    8145            0 :                         {
    8146              :                                 NULL, NULL
    8147              :                         };
    8148              : 
    8149            0 :                         if (indxinfo[j].parentidx == 0)
    8150            0 :                                 indexkind = RELKIND_INDEX;
    8151              :                         else
    8152            0 :                                 indexkind = RELKIND_PARTITIONED_INDEX;
    8153              : 
    8154            0 :                         if (!PQgetisnull(res, j, i_indattnames))
    8155              :                         {
    8156            0 :                                 if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
    8157              :                                                                   &indAttNames, &nindAttNames))
    8158            0 :                                         pg_fatal("could not parse %s array", "indattnames");
    8159            0 :                         }
    8160              : 
    8161            0 :                         relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
    8162            0 :                                                                                          PQgetvalue(res, j, i_reltuples),
    8163            0 :                                                                                          relallvisible, relallfrozen, indexkind,
    8164            0 :                                                                                          indAttNames, nindAttNames);
    8165              : 
    8166            0 :                         contype = *(PQgetvalue(res, j, i_contype));
    8167            0 :                         if (contype == 'p' || contype == 'u' || contype == 'x')
    8168              :                         {
    8169              :                                 /*
    8170              :                                  * If we found a constraint matching the index, create an
    8171              :                                  * entry for it.
    8172              :                                  */
    8173            0 :                                 ConstraintInfo *constrinfo;
    8174              : 
    8175            0 :                                 constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
    8176            0 :                                 constrinfo->dobj.objType = DO_CONSTRAINT;
    8177            0 :                                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8178            0 :                                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8179            0 :                                 AssignDumpId(&constrinfo->dobj);
    8180            0 :                                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    8181            0 :                                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8182            0 :                                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    8183            0 :                                 constrinfo->contable = tbinfo;
    8184            0 :                                 constrinfo->condomain = NULL;
    8185            0 :                                 constrinfo->contype = contype;
    8186            0 :                                 if (contype == 'x')
    8187            0 :                                         constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8188              :                                 else
    8189            0 :                                         constrinfo->condef = NULL;
    8190            0 :                                 constrinfo->confrelid = InvalidOid;
    8191            0 :                                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    8192            0 :                                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    8193            0 :                                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    8194            0 :                                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    8195            0 :                                 constrinfo->conislocal = true;
    8196            0 :                                 constrinfo->separate = true;
    8197              : 
    8198            0 :                                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    8199            0 :                                 if (relstats != NULL)
    8200            0 :                                         addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    8201            0 :                         }
    8202              :                         else
    8203              :                         {
    8204              :                                 /* Plain secondary index */
    8205            0 :                                 indxinfo[j].indexconstraint = 0;
    8206              :                         }
    8207            0 :                 }
    8208            0 :         }
    8209              : 
    8210            0 :         PQclear(res);
    8211              : 
    8212            0 :         destroyPQExpBuffer(query);
    8213            0 :         destroyPQExpBuffer(tbloids);
    8214            0 : }
    8215              : 
    8216              : /*
    8217              :  * getExtendedStatistics
    8218              :  *        get information about extended-statistics objects.
    8219              :  *
    8220              :  * Note: extended statistics data is not returned directly to the caller, but
    8221              :  * it does get entered into the DumpableObject tables.
    8222              :  */
    8223              : void
    8224            0 : getExtendedStatistics(Archive *fout)
    8225              : {
    8226            0 :         PQExpBuffer query;
    8227            0 :         PGresult   *res;
    8228            0 :         StatsExtInfo *statsextinfo;
    8229            0 :         int                     ntups;
    8230            0 :         int                     i_tableoid;
    8231            0 :         int                     i_oid;
    8232            0 :         int                     i_stxname;
    8233            0 :         int                     i_stxnamespace;
    8234            0 :         int                     i_stxowner;
    8235            0 :         int                     i_stxrelid;
    8236            0 :         int                     i_stattarget;
    8237            0 :         int                     i;
    8238              : 
    8239              :         /* Extended statistics were new in v10 */
    8240            0 :         if (fout->remoteVersion < 100000)
    8241            0 :                 return;
    8242              : 
    8243            0 :         query = createPQExpBuffer();
    8244              : 
    8245            0 :         if (fout->remoteVersion < 130000)
    8246            0 :                 appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8247              :                                                          "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    8248              :                                                          "FROM pg_catalog.pg_statistic_ext");
    8249              :         else
    8250            0 :                 appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8251              :                                                          "stxnamespace, stxowner, stxrelid, stxstattarget "
    8252              :                                                          "FROM pg_catalog.pg_statistic_ext");
    8253              : 
    8254            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8255              : 
    8256            0 :         ntups = PQntuples(res);
    8257              : 
    8258            0 :         i_tableoid = PQfnumber(res, "tableoid");
    8259            0 :         i_oid = PQfnumber(res, "oid");
    8260            0 :         i_stxname = PQfnumber(res, "stxname");
    8261            0 :         i_stxnamespace = PQfnumber(res, "stxnamespace");
    8262            0 :         i_stxowner = PQfnumber(res, "stxowner");
    8263            0 :         i_stxrelid = PQfnumber(res, "stxrelid");
    8264            0 :         i_stattarget = PQfnumber(res, "stxstattarget");
    8265              : 
    8266            0 :         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
    8267              : 
    8268            0 :         for (i = 0; i < ntups; i++)
    8269              :         {
    8270            0 :                 statsextinfo[i].dobj.objType = DO_STATSEXT;
    8271            0 :                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8272            0 :                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8273            0 :                 AssignDumpId(&statsextinfo[i].dobj);
    8274            0 :                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    8275            0 :                 statsextinfo[i].dobj.namespace =
    8276            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    8277            0 :                 statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    8278            0 :                 statsextinfo[i].stattable =
    8279            0 :                         findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    8280            0 :                 if (PQgetisnull(res, i, i_stattarget))
    8281            0 :                         statsextinfo[i].stattarget = -1;
    8282              :                 else
    8283            0 :                         statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    8284              : 
    8285              :                 /* Decide whether we want to dump it */
    8286            0 :                 selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    8287            0 :         }
    8288              : 
    8289            0 :         PQclear(res);
    8290            0 :         destroyPQExpBuffer(query);
    8291            0 : }
    8292              : 
    8293              : /*
    8294              :  * getConstraints
    8295              :  *
    8296              :  * Get info about constraints on dumpable tables.
    8297              :  *
    8298              :  * Currently handles foreign keys only.
    8299              :  * Unique and primary key constraints are handled with indexes,
    8300              :  * while check constraints are processed in getTableAttrs().
    8301              :  */
    8302              : void
    8303            0 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    8304              : {
    8305            0 :         PQExpBuffer query = createPQExpBuffer();
    8306            0 :         PQExpBuffer tbloids = createPQExpBuffer();
    8307            0 :         PGresult   *res;
    8308            0 :         int                     ntups;
    8309            0 :         int                     curtblindx;
    8310            0 :         TableInfo  *tbinfo = NULL;
    8311            0 :         ConstraintInfo *constrinfo;
    8312            0 :         int                     i_contableoid,
    8313              :                                 i_conoid,
    8314              :                                 i_conrelid,
    8315              :                                 i_conname,
    8316              :                                 i_confrelid,
    8317              :                                 i_conindid,
    8318              :                                 i_condef;
    8319              : 
    8320              :         /*
    8321              :          * We want to perform just one query against pg_constraint.  However, we
    8322              :          * mustn't try to select every row of the catalog and then sort it out on
    8323              :          * the client side, because some of the server-side functions we need
    8324              :          * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8325              :          * build an array of the OIDs of tables we care about (and now have lock
    8326              :          * on!), and use a WHERE clause to constrain which rows are selected.
    8327              :          */
    8328            0 :         appendPQExpBufferChar(tbloids, '{');
    8329            0 :         for (int i = 0; i < numTables; i++)
    8330              :         {
    8331            0 :                 TableInfo  *tinfo = &tblinfo[i];
    8332              : 
    8333            0 :                 if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8334            0 :                         continue;
    8335              : 
    8336              :                 /* OK, we need info for this table */
    8337            0 :                 if (tbloids->len > 1)     /* do we have more than the '{'? */
    8338            0 :                         appendPQExpBufferChar(tbloids, ',');
    8339            0 :                 appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    8340            0 :         }
    8341            0 :         appendPQExpBufferChar(tbloids, '}');
    8342              : 
    8343            0 :         appendPQExpBufferStr(query,
    8344              :                                                  "SELECT c.tableoid, c.oid, "
    8345              :                                                  "conrelid, conname, confrelid, ");
    8346            0 :         if (fout->remoteVersion >= 110000)
    8347            0 :                 appendPQExpBufferStr(query, "conindid, ");
    8348              :         else
    8349            0 :                 appendPQExpBufferStr(query, "0 AS conindid, ");
    8350            0 :         appendPQExpBuffer(query,
    8351              :                                           "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    8352              :                                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8353              :                                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    8354              :                                           "WHERE contype = 'f' ",
    8355            0 :                                           tbloids->data);
    8356            0 :         if (fout->remoteVersion >= 110000)
    8357            0 :                 appendPQExpBufferStr(query,
    8358              :                                                          "AND conparentid = 0 ");
    8359            0 :         appendPQExpBufferStr(query,
    8360              :                                                  "ORDER BY conrelid, conname");
    8361              : 
    8362            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8363              : 
    8364            0 :         ntups = PQntuples(res);
    8365              : 
    8366            0 :         i_contableoid = PQfnumber(res, "tableoid");
    8367            0 :         i_conoid = PQfnumber(res, "oid");
    8368            0 :         i_conrelid = PQfnumber(res, "conrelid");
    8369            0 :         i_conname = PQfnumber(res, "conname");
    8370            0 :         i_confrelid = PQfnumber(res, "confrelid");
    8371            0 :         i_conindid = PQfnumber(res, "conindid");
    8372            0 :         i_condef = PQfnumber(res, "condef");
    8373              : 
    8374            0 :         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8375              : 
    8376            0 :         curtblindx = -1;
    8377            0 :         for (int j = 0; j < ntups; j++)
    8378              :         {
    8379            0 :                 Oid                     conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    8380            0 :                 TableInfo  *reftable;
    8381              : 
    8382              :                 /*
    8383              :                  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8384              :                  * order.
    8385              :                  */
    8386            0 :                 if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    8387              :                 {
    8388            0 :                         while (++curtblindx < numTables)
    8389              :                         {
    8390            0 :                                 tbinfo = &tblinfo[curtblindx];
    8391            0 :                                 if (tbinfo->dobj.catId.oid == conrelid)
    8392            0 :                                         break;
    8393              :                         }
    8394            0 :                         if (curtblindx >= numTables)
    8395            0 :                                 pg_fatal("unrecognized table OID %u", conrelid);
    8396            0 :                 }
    8397              : 
    8398            0 :                 constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8399            0 :                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8400            0 :                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8401            0 :                 AssignDumpId(&constrinfo[j].dobj);
    8402            0 :                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8403            0 :                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8404            0 :                 constrinfo[j].contable = tbinfo;
    8405            0 :                 constrinfo[j].condomain = NULL;
    8406            0 :                 constrinfo[j].contype = 'f';
    8407            0 :                 constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8408            0 :                 constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8409            0 :                 constrinfo[j].conindex = 0;
    8410            0 :                 constrinfo[j].condeferrable = false;
    8411            0 :                 constrinfo[j].condeferred = false;
    8412            0 :                 constrinfo[j].conislocal = true;
    8413            0 :                 constrinfo[j].separate = true;
    8414              : 
    8415              :                 /*
    8416              :                  * Restoring an FK that points to a partitioned table requires that
    8417              :                  * all partition indexes have been attached beforehand. Ensure that
    8418              :                  * happens by making the constraint depend on each index partition
    8419              :                  * attach object.
    8420              :                  */
    8421            0 :                 reftable = findTableByOid(constrinfo[j].confrelid);
    8422            0 :                 if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    8423              :                 {
    8424            0 :                         Oid                     indexOid = atooid(PQgetvalue(res, j, i_conindid));
    8425              : 
    8426            0 :                         if (indexOid != InvalidOid)
    8427              :                         {
    8428            0 :                                 for (int k = 0; k < reftable->numIndexes; k++)
    8429              :                                 {
    8430            0 :                                         IndxInfo   *refidx;
    8431              : 
    8432              :                                         /* not our index? */
    8433            0 :                                         if (reftable->indexes[k].dobj.catId.oid != indexOid)
    8434            0 :                                                 continue;
    8435              : 
    8436            0 :                                         refidx = &reftable->indexes[k];
    8437            0 :                                         addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    8438            0 :                                         break;
    8439            0 :                                 }
    8440            0 :                         }
    8441            0 :                 }
    8442            0 :         }
    8443              : 
    8444            0 :         PQclear(res);
    8445              : 
    8446            0 :         destroyPQExpBuffer(query);
    8447            0 :         destroyPQExpBuffer(tbloids);
    8448            0 : }
    8449              : 
    8450              : /*
    8451              :  * addConstrChildIdxDeps
    8452              :  *
    8453              :  * Recursive subroutine for getConstraints
    8454              :  *
    8455              :  * Given an object representing a foreign key constraint and an index on the
    8456              :  * partitioned table it references, mark the constraint object as dependent
    8457              :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    8458              :  * drilling down to their partitions if any.  This ensures that the FK is not
    8459              :  * restored until the index is fully marked valid.
    8460              :  */
    8461              : static void
    8462            0 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    8463              : {
    8464            0 :         SimplePtrListCell *cell;
    8465              : 
    8466            0 :         Assert(dobj->objType == DO_FK_CONSTRAINT);
    8467              : 
    8468            0 :         for (cell = refidx->partattaches.head; cell; cell = cell->next)
    8469              :         {
    8470            0 :                 IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    8471              : 
    8472            0 :                 addObjectDependency(dobj, attach->dobj.dumpId);
    8473              : 
    8474            0 :                 if (attach->partitionIdx->partattaches.head != NULL)
    8475            0 :                         addConstrChildIdxDeps(dobj, attach->partitionIdx);
    8476            0 :         }
    8477            0 : }
    8478              : 
    8479              : /*
    8480              :  * getDomainConstraints
    8481              :  *
    8482              :  * Get info about constraints on a domain.
    8483              :  */
    8484              : static void
    8485            0 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8486              : {
    8487            0 :         ConstraintInfo *constrinfo;
    8488            0 :         PQExpBuffer query = createPQExpBuffer();
    8489            0 :         PGresult   *res;
    8490            0 :         int                     i_tableoid,
    8491              :                                 i_oid,
    8492              :                                 i_conname,
    8493              :                                 i_consrc,
    8494              :                                 i_convalidated,
    8495              :                                 i_contype;
    8496            0 :         int                     ntups;
    8497              : 
    8498            0 :         if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8499              :         {
    8500              :                 /*
    8501              :                  * Set up query for constraint-specific details.  For servers 17 and
    8502              :                  * up, domains have constraints of type 'n' as well as 'c', otherwise
    8503              :                  * just the latter.
    8504              :                  */
    8505            0 :                 appendPQExpBuffer(query,
    8506              :                                                   "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8507              :                                                   "SELECT tableoid, oid, conname, "
    8508              :                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8509              :                                                   "convalidated, contype "
    8510              :                                                   "FROM pg_catalog.pg_constraint "
    8511              :                                                   "WHERE contypid = $1 AND contype IN (%s) "
    8512              :                                                   "ORDER BY conname",
    8513            0 :                                                   fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
    8514              : 
    8515            0 :                 ExecuteSqlStatement(fout, query->data);
    8516              : 
    8517            0 :                 fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8518            0 :         }
    8519              : 
    8520            0 :         printfPQExpBuffer(query,
    8521              :                                           "EXECUTE getDomainConstraints('%u')",
    8522            0 :                                           tyinfo->dobj.catId.oid);
    8523              : 
    8524            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8525              : 
    8526            0 :         ntups = PQntuples(res);
    8527              : 
    8528            0 :         i_tableoid = PQfnumber(res, "tableoid");
    8529            0 :         i_oid = PQfnumber(res, "oid");
    8530            0 :         i_conname = PQfnumber(res, "conname");
    8531            0 :         i_consrc = PQfnumber(res, "consrc");
    8532            0 :         i_convalidated = PQfnumber(res, "convalidated");
    8533            0 :         i_contype = PQfnumber(res, "contype");
    8534              : 
    8535            0 :         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8536            0 :         tyinfo->domChecks = constrinfo;
    8537              : 
    8538              :         /* 'i' tracks result rows; 'j' counts CHECK constraints */
    8539            0 :         for (int i = 0, j = 0; i < ntups; i++)
    8540              :         {
    8541            0 :                 bool            validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
    8542            0 :                 char            contype = (PQgetvalue(res, i, i_contype))[0];
    8543            0 :                 ConstraintInfo *constraint;
    8544              : 
    8545            0 :                 if (contype == CONSTRAINT_CHECK)
    8546              :                 {
    8547            0 :                         constraint = &constrinfo[j++];
    8548            0 :                         tyinfo->nDomChecks++;
    8549            0 :                 }
    8550              :                 else
    8551              :                 {
    8552            0 :                         Assert(contype == CONSTRAINT_NOTNULL);
    8553            0 :                         Assert(tyinfo->notnull == NULL);
    8554              :                         /* use last item in array for the not-null constraint */
    8555            0 :                         tyinfo->notnull = &(constrinfo[ntups - 1]);
    8556            0 :                         constraint = tyinfo->notnull;
    8557              :                 }
    8558              : 
    8559            0 :                 constraint->dobj.objType = DO_CONSTRAINT;
    8560            0 :                 constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8561            0 :                 constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8562            0 :                 AssignDumpId(&(constraint->dobj));
    8563            0 :                 constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8564            0 :                 constraint->dobj.namespace = tyinfo->dobj.namespace;
    8565            0 :                 constraint->contable = NULL;
    8566            0 :                 constraint->condomain = tyinfo;
    8567            0 :                 constraint->contype = contype;
    8568            0 :                 constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8569            0 :                 constraint->confrelid = InvalidOid;
    8570            0 :                 constraint->conindex = 0;
    8571            0 :                 constraint->condeferrable = false;
    8572            0 :                 constraint->condeferred = false;
    8573            0 :                 constraint->conislocal = true;
    8574              : 
    8575            0 :                 constraint->separate = !validated;
    8576              : 
    8577              :                 /*
    8578              :                  * Make the domain depend on the constraint, ensuring it won't be
    8579              :                  * output till any constraint dependencies are OK.  If the constraint
    8580              :                  * has not been validated, it's going to be dumped after the domain
    8581              :                  * anyway, so this doesn't matter.
    8582              :                  */
    8583            0 :                 if (validated)
    8584            0 :                         addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
    8585            0 :         }
    8586              : 
    8587            0 :         PQclear(res);
    8588              : 
    8589            0 :         destroyPQExpBuffer(query);
    8590            0 : }
    8591              : 
    8592              : /*
    8593              :  * getRules
    8594              :  *        get basic information about every rule in the system
    8595              :  */
    8596              : void
    8597            0 : getRules(Archive *fout)
    8598              : {
    8599            0 :         PGresult   *res;
    8600            0 :         int                     ntups;
    8601            0 :         int                     i;
    8602            0 :         PQExpBuffer query = createPQExpBuffer();
    8603            0 :         RuleInfo   *ruleinfo;
    8604            0 :         int                     i_tableoid;
    8605            0 :         int                     i_oid;
    8606            0 :         int                     i_rulename;
    8607            0 :         int                     i_ruletable;
    8608            0 :         int                     i_ev_type;
    8609            0 :         int                     i_is_instead;
    8610            0 :         int                     i_ev_enabled;
    8611              : 
    8612            0 :         appendPQExpBufferStr(query, "SELECT "
    8613              :                                                  "tableoid, oid, rulename, "
    8614              :                                                  "ev_class AS ruletable, ev_type, is_instead, "
    8615              :                                                  "ev_enabled "
    8616              :                                                  "FROM pg_rewrite "
    8617              :                                                  "ORDER BY oid");
    8618              : 
    8619            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8620              : 
    8621            0 :         ntups = PQntuples(res);
    8622              : 
    8623            0 :         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
    8624              : 
    8625            0 :         i_tableoid = PQfnumber(res, "tableoid");
    8626            0 :         i_oid = PQfnumber(res, "oid");
    8627            0 :         i_rulename = PQfnumber(res, "rulename");
    8628            0 :         i_ruletable = PQfnumber(res, "ruletable");
    8629            0 :         i_ev_type = PQfnumber(res, "ev_type");
    8630            0 :         i_is_instead = PQfnumber(res, "is_instead");
    8631            0 :         i_ev_enabled = PQfnumber(res, "ev_enabled");
    8632              : 
    8633            0 :         for (i = 0; i < ntups; i++)
    8634              :         {
    8635            0 :                 Oid                     ruletableoid;
    8636              : 
    8637            0 :                 ruleinfo[i].dobj.objType = DO_RULE;
    8638            0 :                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8639            0 :                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8640            0 :                 AssignDumpId(&ruleinfo[i].dobj);
    8641            0 :                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8642            0 :                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8643            0 :                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8644            0 :                 if (ruleinfo[i].ruletable == NULL)
    8645            0 :                         pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8646              :                                          ruletableoid, ruleinfo[i].dobj.catId.oid);
    8647            0 :                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8648            0 :                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8649            0 :                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8650            0 :                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8651            0 :                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8652            0 :                 if (ruleinfo[i].ruletable)
    8653              :                 {
    8654              :                         /*
    8655              :                          * If the table is a view or materialized view, force its ON
    8656              :                          * SELECT rule to be sorted before the view itself --- this
    8657              :                          * ensures that any dependencies for the rule affect the table's
    8658              :                          * positioning. Other rules are forced to appear after their
    8659              :                          * table.
    8660              :                          */
    8661            0 :                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8662            0 :                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8663            0 :                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8664              :                         {
    8665            0 :                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8666            0 :                                                                         ruleinfo[i].dobj.dumpId);
    8667              :                                 /* We'll merge the rule into CREATE VIEW, if possible */
    8668            0 :                                 ruleinfo[i].separate = false;
    8669            0 :                         }
    8670              :                         else
    8671              :                         {
    8672            0 :                                 addObjectDependency(&ruleinfo[i].dobj,
    8673            0 :                                                                         ruleinfo[i].ruletable->dobj.dumpId);
    8674            0 :                                 ruleinfo[i].separate = true;
    8675              :                         }
    8676            0 :                 }
    8677              :                 else
    8678            0 :                         ruleinfo[i].separate = true;
    8679            0 :         }
    8680              : 
    8681            0 :         PQclear(res);
    8682              : 
    8683            0 :         destroyPQExpBuffer(query);
    8684            0 : }
    8685              : 
    8686              : /*
    8687              :  * getTriggers
    8688              :  *        get information about every trigger on a dumpable table
    8689              :  *
    8690              :  * Note: trigger data is not returned directly to the caller, but it
    8691              :  * does get entered into the DumpableObject tables.
    8692              :  */
    8693              : void
    8694            0 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8695              : {
    8696            0 :         PQExpBuffer query = createPQExpBuffer();
    8697            0 :         PQExpBuffer tbloids = createPQExpBuffer();
    8698            0 :         PGresult   *res;
    8699            0 :         int                     ntups;
    8700            0 :         int                     curtblindx;
    8701            0 :         TriggerInfo *tginfo;
    8702            0 :         int                     i_tableoid,
    8703              :                                 i_oid,
    8704              :                                 i_tgrelid,
    8705              :                                 i_tgname,
    8706              :                                 i_tgenabled,
    8707              :                                 i_tgispartition,
    8708              :                                 i_tgdef;
    8709              : 
    8710              :         /*
    8711              :          * We want to perform just one query against pg_trigger.  However, we
    8712              :          * mustn't try to select every row of the catalog and then sort it out on
    8713              :          * the client side, because some of the server-side functions we need
    8714              :          * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8715              :          * build an array of the OIDs of tables we care about (and now have lock
    8716              :          * on!), and use a WHERE clause to constrain which rows are selected.
    8717              :          */
    8718            0 :         appendPQExpBufferChar(tbloids, '{');
    8719            0 :         for (int i = 0; i < numTables; i++)
    8720              :         {
    8721            0 :                 TableInfo  *tbinfo = &tblinfo[i];
    8722              : 
    8723            0 :                 if (!tbinfo->hastriggers ||
    8724            0 :                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8725            0 :                         continue;
    8726              : 
    8727              :                 /* OK, we need info for this table */
    8728            0 :                 if (tbloids->len > 1)     /* do we have more than the '{'? */
    8729            0 :                         appendPQExpBufferChar(tbloids, ',');
    8730            0 :                 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8731            0 :         }
    8732            0 :         appendPQExpBufferChar(tbloids, '}');
    8733              : 
    8734            0 :         if (fout->remoteVersion >= 150000)
    8735              :         {
    8736              :                 /*
    8737              :                  * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8738              :                  * result in non-forward-compatible dumps of WHEN clauses due to
    8739              :                  * under-parenthesization.
    8740              :                  *
    8741              :                  * NB: We need to see partition triggers in case the tgenabled flag
    8742              :                  * has been changed from the parent.
    8743              :                  */
    8744            0 :                 appendPQExpBuffer(query,
    8745              :                                                   "SELECT t.tgrelid, t.tgname, "
    8746              :                                                   "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8747              :                                                   "t.tgenabled, t.tableoid, t.oid, "
    8748              :                                                   "t.tgparentid <> 0 AS tgispartition\n"
    8749              :                                                   "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8750              :                                                   "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8751              :                                                   "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8752              :                                                   "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8753              :                                                   "OR t.tgenabled != u.tgenabled) "
    8754              :                                                   "ORDER BY t.tgrelid, t.tgname",
    8755            0 :                                                   tbloids->data);
    8756            0 :         }
    8757            0 :         else if (fout->remoteVersion >= 130000)
    8758              :         {
    8759              :                 /*
    8760              :                  * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8761              :                  * result in non-forward-compatible dumps of WHEN clauses due to
    8762              :                  * under-parenthesization.
    8763              :                  *
    8764              :                  * NB: We need to see tgisinternal triggers in partitions, in case the
    8765              :                  * tgenabled flag has been changed from the parent.
    8766              :                  */
    8767            0 :                 appendPQExpBuffer(query,
    8768              :                                                   "SELECT t.tgrelid, t.tgname, "
    8769              :                                                   "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8770              :                                                   "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8771              :                                                   "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8772              :                                                   "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8773              :                                                   "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8774              :                                                   "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8775              :                                                   "ORDER BY t.tgrelid, t.tgname",
    8776            0 :                                                   tbloids->data);
    8777            0 :         }
    8778            0 :         else if (fout->remoteVersion >= 110000)
    8779              :         {
    8780              :                 /*
    8781              :                  * NB: We need to see tgisinternal triggers in partitions, in case the
    8782              :                  * tgenabled flag has been changed from the parent. No tgparentid in
    8783              :                  * version 11-12, so we have to match them via pg_depend.
    8784              :                  *
    8785              :                  * See above about pretty=true in pg_get_triggerdef.
    8786              :                  */
    8787            0 :                 appendPQExpBuffer(query,
    8788              :                                                   "SELECT t.tgrelid, t.tgname, "
    8789              :                                                   "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8790              :                                                   "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8791              :                                                   "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8792              :                                                   "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8793              :                                                   "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8794              :                                                   " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8795              :                                                   " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8796              :                                                   " d.objid = t.oid "
    8797              :                                                   "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8798              :                                                   "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8799              :                                                   "ORDER BY t.tgrelid, t.tgname",
    8800            0 :                                                   tbloids->data);
    8801            0 :         }
    8802              :         else
    8803              :         {
    8804              :                 /* See above about pretty=true in pg_get_triggerdef */
    8805            0 :                 appendPQExpBuffer(query,
    8806              :                                                   "SELECT t.tgrelid, t.tgname, "
    8807              :                                                   "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8808              :                                                   "t.tgenabled, false as tgispartition, "
    8809              :                                                   "t.tableoid, t.oid "
    8810              :                                                   "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8811              :                                                   "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8812              :                                                   "WHERE NOT tgisinternal "
    8813              :                                                   "ORDER BY t.tgrelid, t.tgname",
    8814            0 :                                                   tbloids->data);
    8815              :         }
    8816              : 
    8817            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8818              : 
    8819            0 :         ntups = PQntuples(res);
    8820              : 
    8821            0 :         i_tableoid = PQfnumber(res, "tableoid");
    8822            0 :         i_oid = PQfnumber(res, "oid");
    8823            0 :         i_tgrelid = PQfnumber(res, "tgrelid");
    8824            0 :         i_tgname = PQfnumber(res, "tgname");
    8825            0 :         i_tgenabled = PQfnumber(res, "tgenabled");
    8826            0 :         i_tgispartition = PQfnumber(res, "tgispartition");
    8827            0 :         i_tgdef = PQfnumber(res, "tgdef");
    8828              : 
    8829            0 :         tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
    8830              : 
    8831              :         /*
    8832              :          * Outer loop iterates once per table, not once per row.  Incrementing of
    8833              :          * j is handled by the inner loop.
    8834              :          */
    8835            0 :         curtblindx = -1;
    8836            0 :         for (int j = 0; j < ntups;)
    8837              :         {
    8838            0 :                 Oid                     tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8839            0 :                 TableInfo  *tbinfo = NULL;
    8840            0 :                 int                     numtrigs;
    8841              : 
    8842              :                 /* Count rows for this table */
    8843            0 :                 for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8844            0 :                         if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8845            0 :                                 break;
    8846              : 
    8847              :                 /*
    8848              :                  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8849              :                  * order.
    8850              :                  */
    8851            0 :                 while (++curtblindx < numTables)
    8852              :                 {
    8853            0 :                         tbinfo = &tblinfo[curtblindx];
    8854            0 :                         if (tbinfo->dobj.catId.oid == tgrelid)
    8855            0 :                                 break;
    8856              :                 }
    8857            0 :                 if (curtblindx >= numTables)
    8858            0 :                         pg_fatal("unrecognized table OID %u", tgrelid);
    8859              : 
    8860              :                 /* Save data for this table */
    8861            0 :                 tbinfo->triggers = tginfo + j;
    8862            0 :                 tbinfo->numTriggers = numtrigs;
    8863              : 
    8864            0 :                 for (int c = 0; c < numtrigs; c++, j++)
    8865              :                 {
    8866            0 :                         tginfo[j].dobj.objType = DO_TRIGGER;
    8867            0 :                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8868            0 :                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8869            0 :                         AssignDumpId(&tginfo[j].dobj);
    8870            0 :                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8871            0 :                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8872            0 :                         tginfo[j].tgtable = tbinfo;
    8873            0 :                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8874            0 :                         tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8875            0 :                         tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8876            0 :                 }
    8877            0 :         }
    8878              : 
    8879            0 :         PQclear(res);
    8880              : 
    8881            0 :         destroyPQExpBuffer(query);
    8882            0 :         destroyPQExpBuffer(tbloids);
    8883            0 : }
    8884              : 
    8885              : /*
    8886              :  * getEventTriggers
    8887              :  *        get information about event triggers
    8888              :  */
    8889              : void
    8890            0 : getEventTriggers(Archive *fout)
    8891              : {
    8892            0 :         int                     i;
    8893            0 :         PQExpBuffer query;
    8894            0 :         PGresult   *res;
    8895            0 :         EventTriggerInfo *evtinfo;
    8896            0 :         int                     i_tableoid,
    8897              :                                 i_oid,
    8898              :                                 i_evtname,
    8899              :                                 i_evtevent,
    8900              :                                 i_evtowner,
    8901              :                                 i_evttags,
    8902              :                                 i_evtfname,
    8903              :                                 i_evtenabled;
    8904            0 :         int                     ntups;
    8905              : 
    8906              :         /* Before 9.3, there are no event triggers */
    8907            0 :         if (fout->remoteVersion < 90300)
    8908            0 :                 return;
    8909              : 
    8910            0 :         query = createPQExpBuffer();
    8911              : 
    8912            0 :         appendPQExpBufferStr(query,
    8913              :                                                  "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8914              :                                                  "evtevent, evtowner, "
    8915              :                                                  "array_to_string(array("
    8916              :                                                  "select quote_literal(x) "
    8917              :                                                  " from unnest(evttags) as t(x)), ', ') as evttags, "
    8918              :                                                  "e.evtfoid::regproc as evtfname "
    8919              :                                                  "FROM pg_event_trigger e "
    8920              :                                                  "ORDER BY e.oid");
    8921              : 
    8922            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8923              : 
    8924            0 :         ntups = PQntuples(res);
    8925              : 
    8926            0 :         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
    8927              : 
    8928            0 :         i_tableoid = PQfnumber(res, "tableoid");
    8929            0 :         i_oid = PQfnumber(res, "oid");
    8930            0 :         i_evtname = PQfnumber(res, "evtname");
    8931            0 :         i_evtevent = PQfnumber(res, "evtevent");
    8932            0 :         i_evtowner = PQfnumber(res, "evtowner");
    8933            0 :         i_evttags = PQfnumber(res, "evttags");
    8934            0 :         i_evtfname = PQfnumber(res, "evtfname");
    8935            0 :         i_evtenabled = PQfnumber(res, "evtenabled");
    8936              : 
    8937            0 :         for (i = 0; i < ntups; i++)
    8938              :         {
    8939            0 :                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    8940            0 :                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8941            0 :                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8942            0 :                 AssignDumpId(&evtinfo[i].dobj);
    8943            0 :                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    8944            0 :                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    8945            0 :                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    8946            0 :                 evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    8947            0 :                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    8948            0 :                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    8949            0 :                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    8950              : 
    8951              :                 /* Decide whether we want to dump it */
    8952            0 :                 selectDumpableObject(&(evtinfo[i].dobj), fout);
    8953            0 :         }
    8954              : 
    8955            0 :         PQclear(res);
    8956              : 
    8957            0 :         destroyPQExpBuffer(query);
    8958            0 : }
    8959              : 
    8960              : /*
    8961              :  * getProcLangs
    8962              :  *        get basic information about every procedural language in the system
    8963              :  *
    8964              :  * NB: this must run after getFuncs() because we assume we can do
    8965              :  * findFuncByOid().
    8966              :  */
    8967              : void
    8968            0 : getProcLangs(Archive *fout)
    8969              : {
    8970            0 :         PGresult   *res;
    8971            0 :         int                     ntups;
    8972            0 :         int                     i;
    8973            0 :         PQExpBuffer query = createPQExpBuffer();
    8974            0 :         ProcLangInfo *planginfo;
    8975            0 :         int                     i_tableoid;
    8976            0 :         int                     i_oid;
    8977            0 :         int                     i_lanname;
    8978            0 :         int                     i_lanpltrusted;
    8979            0 :         int                     i_lanplcallfoid;
    8980            0 :         int                     i_laninline;
    8981            0 :         int                     i_lanvalidator;
    8982            0 :         int                     i_lanacl;
    8983            0 :         int                     i_acldefault;
    8984            0 :         int                     i_lanowner;
    8985              : 
    8986            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8987              :                                                  "lanname, lanpltrusted, lanplcallfoid, "
    8988              :                                                  "laninline, lanvalidator, "
    8989              :                                                  "lanacl, "
    8990              :                                                  "acldefault('l', lanowner) AS acldefault, "
    8991              :                                                  "lanowner "
    8992              :                                                  "FROM pg_language "
    8993              :                                                  "WHERE lanispl "
    8994              :                                                  "ORDER BY oid");
    8995              : 
    8996            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8997              : 
    8998            0 :         ntups = PQntuples(res);
    8999              : 
    9000            0 :         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
    9001              : 
    9002            0 :         i_tableoid = PQfnumber(res, "tableoid");
    9003            0 :         i_oid = PQfnumber(res, "oid");
    9004            0 :         i_lanname = PQfnumber(res, "lanname");
    9005            0 :         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    9006            0 :         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    9007            0 :         i_laninline = PQfnumber(res, "laninline");
    9008            0 :         i_lanvalidator = PQfnumber(res, "lanvalidator");
    9009            0 :         i_lanacl = PQfnumber(res, "lanacl");
    9010            0 :         i_acldefault = PQfnumber(res, "acldefault");
    9011            0 :         i_lanowner = PQfnumber(res, "lanowner");
    9012              : 
    9013            0 :         for (i = 0; i < ntups; i++)
    9014              :         {
    9015            0 :                 planginfo[i].dobj.objType = DO_PROCLANG;
    9016            0 :                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9017            0 :                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9018            0 :                 AssignDumpId(&planginfo[i].dobj);
    9019              : 
    9020            0 :                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    9021            0 :                 planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    9022            0 :                 planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9023            0 :                 planginfo[i].dacl.privtype = 0;
    9024            0 :                 planginfo[i].dacl.initprivs = NULL;
    9025            0 :                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    9026            0 :                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    9027            0 :                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    9028            0 :                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    9029            0 :                 planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    9030              : 
    9031              :                 /* Decide whether we want to dump it */
    9032            0 :                 selectDumpableProcLang(&(planginfo[i]), fout);
    9033              : 
    9034              :                 /* Mark whether language has an ACL */
    9035            0 :                 if (!PQgetisnull(res, i, i_lanacl))
    9036            0 :                         planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9037            0 :         }
    9038              : 
    9039            0 :         PQclear(res);
    9040              : 
    9041            0 :         destroyPQExpBuffer(query);
    9042            0 : }
    9043              : 
    9044              : /*
    9045              :  * getCasts
    9046              :  *        get basic information about most casts in the system
    9047              :  *
    9048              :  * Skip casts from a range to its multirange, since we'll create those
    9049              :  * automatically.
    9050              :  */
    9051              : void
    9052            0 : getCasts(Archive *fout)
    9053              : {
    9054            0 :         PGresult   *res;
    9055            0 :         int                     ntups;
    9056            0 :         int                     i;
    9057            0 :         PQExpBuffer query = createPQExpBuffer();
    9058            0 :         CastInfo   *castinfo;
    9059            0 :         int                     i_tableoid;
    9060            0 :         int                     i_oid;
    9061            0 :         int                     i_castsource;
    9062            0 :         int                     i_casttarget;
    9063            0 :         int                     i_castfunc;
    9064            0 :         int                     i_castcontext;
    9065            0 :         int                     i_castmethod;
    9066              : 
    9067            0 :         if (fout->remoteVersion >= 140000)
    9068              :         {
    9069            0 :                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9070              :                                                          "castsource, casttarget, castfunc, castcontext, "
    9071              :                                                          "castmethod "
    9072              :                                                          "FROM pg_cast c "
    9073              :                                                          "WHERE NOT EXISTS ( "
    9074              :                                                          "SELECT 1 FROM pg_range r "
    9075              :                                                          "WHERE c.castsource = r.rngtypid "
    9076              :                                                          "AND c.casttarget = r.rngmultitypid "
    9077              :                                                          ") "
    9078              :                                                          "ORDER BY 3,4");
    9079            0 :         }
    9080              :         else
    9081              :         {
    9082            0 :                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9083              :                                                          "castsource, casttarget, castfunc, castcontext, "
    9084              :                                                          "castmethod "
    9085              :                                                          "FROM pg_cast ORDER BY 3,4");
    9086              :         }
    9087              : 
    9088            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9089              : 
    9090            0 :         ntups = PQntuples(res);
    9091              : 
    9092            0 :         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
    9093              : 
    9094            0 :         i_tableoid = PQfnumber(res, "tableoid");
    9095            0 :         i_oid = PQfnumber(res, "oid");
    9096            0 :         i_castsource = PQfnumber(res, "castsource");
    9097            0 :         i_casttarget = PQfnumber(res, "casttarget");
    9098            0 :         i_castfunc = PQfnumber(res, "castfunc");
    9099            0 :         i_castcontext = PQfnumber(res, "castcontext");
    9100            0 :         i_castmethod = PQfnumber(res, "castmethod");
    9101              : 
    9102            0 :         for (i = 0; i < ntups; i++)
    9103              :         {
    9104            0 :                 PQExpBufferData namebuf;
    9105            0 :                 TypeInfo   *sTypeInfo;
    9106            0 :                 TypeInfo   *tTypeInfo;
    9107              : 
    9108            0 :                 castinfo[i].dobj.objType = DO_CAST;
    9109            0 :                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9110            0 :                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9111            0 :                 AssignDumpId(&castinfo[i].dobj);
    9112            0 :                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    9113            0 :                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    9114            0 :                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    9115            0 :                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    9116            0 :                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    9117              : 
    9118              :                 /*
    9119              :                  * Try to name cast as concatenation of typnames.  This is only used
    9120              :                  * for purposes of sorting.  If we fail to find either type, the name
    9121              :                  * will be an empty string.
    9122              :                  */
    9123            0 :                 initPQExpBuffer(&namebuf);
    9124            0 :                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
    9125            0 :                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    9126            0 :                 if (sTypeInfo && tTypeInfo)
    9127            0 :                         appendPQExpBuffer(&namebuf, "%s %s",
    9128            0 :                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    9129            0 :                 castinfo[i].dobj.name = namebuf.data;
    9130              : 
    9131              :                 /* Decide whether we want to dump it */
    9132            0 :                 selectDumpableCast(&(castinfo[i]), fout);
    9133            0 :         }
    9134              : 
    9135            0 :         PQclear(res);
    9136              : 
    9137            0 :         destroyPQExpBuffer(query);
    9138            0 : }
    9139              : 
    9140              : static char *
    9141            0 : get_language_name(Archive *fout, Oid langid)
    9142              : {
    9143            0 :         PQExpBuffer query;
    9144            0 :         PGresult   *res;
    9145            0 :         char       *lanname;
    9146              : 
    9147            0 :         query = createPQExpBuffer();
    9148            0 :         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    9149            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
    9150            0 :         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    9151            0 :         destroyPQExpBuffer(query);
    9152            0 :         PQclear(res);
    9153              : 
    9154            0 :         return lanname;
    9155            0 : }
    9156              : 
    9157              : /*
    9158              :  * getTransforms
    9159              :  *        get basic information about every transform in the system
    9160              :  */
    9161              : void
    9162            0 : getTransforms(Archive *fout)
    9163              : {
    9164            0 :         PGresult   *res;
    9165            0 :         int                     ntups;
    9166            0 :         int                     i;
    9167            0 :         PQExpBuffer query;
    9168            0 :         TransformInfo *transforminfo;
    9169            0 :         int                     i_tableoid;
    9170            0 :         int                     i_oid;
    9171            0 :         int                     i_trftype;
    9172            0 :         int                     i_trflang;
    9173            0 :         int                     i_trffromsql;
    9174            0 :         int                     i_trftosql;
    9175              : 
    9176              :         /* Transforms didn't exist pre-9.5 */
    9177            0 :         if (fout->remoteVersion < 90500)
    9178            0 :                 return;
    9179              : 
    9180            0 :         query = createPQExpBuffer();
    9181              : 
    9182            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9183              :                                                  "trftype, trflang, trffromsql::oid, trftosql::oid "
    9184              :                                                  "FROM pg_transform "
    9185              :                                                  "ORDER BY 3,4");
    9186              : 
    9187            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9188              : 
    9189            0 :         ntups = PQntuples(res);
    9190              : 
    9191            0 :         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
    9192              : 
    9193            0 :         i_tableoid = PQfnumber(res, "tableoid");
    9194            0 :         i_oid = PQfnumber(res, "oid");
    9195            0 :         i_trftype = PQfnumber(res, "trftype");
    9196            0 :         i_trflang = PQfnumber(res, "trflang");
    9197            0 :         i_trffromsql = PQfnumber(res, "trffromsql");
    9198            0 :         i_trftosql = PQfnumber(res, "trftosql");
    9199              : 
    9200            0 :         for (i = 0; i < ntups; i++)
    9201              :         {
    9202            0 :                 PQExpBufferData namebuf;
    9203            0 :                 TypeInfo   *typeInfo;
    9204            0 :                 char       *lanname;
    9205              : 
    9206            0 :                 transforminfo[i].dobj.objType = DO_TRANSFORM;
    9207            0 :                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9208            0 :                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9209            0 :                 AssignDumpId(&transforminfo[i].dobj);
    9210            0 :                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    9211            0 :                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    9212            0 :                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    9213            0 :                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    9214              : 
    9215              :                 /*
    9216              :                  * Try to name transform as concatenation of type and language name.
    9217              :                  * This is only used for purposes of sorting.  If we fail to find
    9218              :                  * either, the name will be an empty string.
    9219              :                  */
    9220            0 :                 initPQExpBuffer(&namebuf);
    9221            0 :                 typeInfo = findTypeByOid(transforminfo[i].trftype);
    9222            0 :                 lanname = get_language_name(fout, transforminfo[i].trflang);
    9223            0 :                 if (typeInfo && lanname)
    9224            0 :                         appendPQExpBuffer(&namebuf, "%s %s",
    9225            0 :                                                           typeInfo->dobj.name, lanname);
    9226            0 :                 transforminfo[i].dobj.name = namebuf.data;
    9227            0 :                 free(lanname);
    9228              : 
    9229              :                 /* Decide whether we want to dump it */
    9230            0 :                 selectDumpableObject(&(transforminfo[i].dobj), fout);
    9231            0 :         }
    9232              : 
    9233            0 :         PQclear(res);
    9234              : 
    9235            0 :         destroyPQExpBuffer(query);
    9236            0 : }
    9237              : 
    9238              : /*
    9239              :  * getTableAttrs -
    9240              :  *        for each interesting table, read info about its attributes
    9241              :  *        (names, types, default values, CHECK constraints, etc)
    9242              :  *
    9243              :  *      modifies tblinfo
    9244              :  */
    9245              : void
    9246            0 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    9247              : {
    9248            0 :         DumpOptions *dopt = fout->dopt;
    9249            0 :         PQExpBuffer q = createPQExpBuffer();
    9250            0 :         PQExpBuffer tbloids = createPQExpBuffer();
    9251            0 :         PQExpBuffer checkoids = createPQExpBuffer();
    9252            0 :         PQExpBuffer invalidnotnulloids = NULL;
    9253            0 :         PGresult   *res;
    9254            0 :         int                     ntups;
    9255            0 :         int                     curtblindx;
    9256            0 :         int                     i_attrelid;
    9257            0 :         int                     i_attnum;
    9258            0 :         int                     i_attname;
    9259            0 :         int                     i_atttypname;
    9260            0 :         int                     i_attstattarget;
    9261            0 :         int                     i_attstorage;
    9262            0 :         int                     i_typstorage;
    9263            0 :         int                     i_attidentity;
    9264            0 :         int                     i_attgenerated;
    9265            0 :         int                     i_attisdropped;
    9266            0 :         int                     i_attlen;
    9267            0 :         int                     i_attalign;
    9268            0 :         int                     i_attislocal;
    9269            0 :         int                     i_notnull_name;
    9270            0 :         int                     i_notnull_comment;
    9271            0 :         int                     i_notnull_noinherit;
    9272            0 :         int                     i_notnull_islocal;
    9273            0 :         int                     i_notnull_invalidoid;
    9274            0 :         int                     i_attoptions;
    9275            0 :         int                     i_attcollation;
    9276            0 :         int                     i_attcompression;
    9277            0 :         int                     i_attfdwoptions;
    9278            0 :         int                     i_attmissingval;
    9279            0 :         int                     i_atthasdef;
    9280              : 
    9281              :         /*
    9282              :          * We want to perform just one query against pg_attribute, and then just
    9283              :          * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    9284              :          * (for CHECK constraints and for NOT NULL constraints).  However, we
    9285              :          * mustn't try to select every row of those catalogs and then sort it out
    9286              :          * on the client side, because some of the server-side functions we need
    9287              :          * would be unsafe to apply to tables we don't have lock on.  Hence, we
    9288              :          * build an array of the OIDs of tables we care about (and now have lock
    9289              :          * on!), and use a WHERE clause to constrain which rows are selected.
    9290              :          */
    9291            0 :         appendPQExpBufferChar(tbloids, '{');
    9292            0 :         appendPQExpBufferChar(checkoids, '{');
    9293            0 :         for (int i = 0; i < numTables; i++)
    9294              :         {
    9295            0 :                 TableInfo  *tbinfo = &tblinfo[i];
    9296              : 
    9297              :                 /* Don't bother to collect info for sequences */
    9298            0 :                 if (tbinfo->relkind == RELKIND_SEQUENCE)
    9299            0 :                         continue;
    9300              : 
    9301              :                 /*
    9302              :                  * Don't bother with uninteresting tables, either.  For binary
    9303              :                  * upgrades, this is bypassed for pg_largeobject_metadata and
    9304              :                  * pg_shdepend so that the columns names are collected for the
    9305              :                  * corresponding COPY commands.  Restoring the data for those catalogs
    9306              :                  * is faster than restoring the equivalent set of large object
    9307              :                  * commands.  We can only do this for upgrades from v12 and newer; in
    9308              :                  * older versions, pg_largeobject_metadata was created WITH OIDS, so
    9309              :                  * the OID column is hidden and won't be dumped.
    9310              :                  */
    9311            0 :                 if (!tbinfo->interesting &&
    9312            0 :                         !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
    9313            0 :                           (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9314            0 :                            tbinfo->dobj.catId.oid == SharedDependRelationId)))
    9315            0 :                         continue;
    9316              : 
    9317              :                 /* OK, we need info for this table */
    9318            0 :                 if (tbloids->len > 1)     /* do we have more than the '{'? */
    9319            0 :                         appendPQExpBufferChar(tbloids, ',');
    9320            0 :                 appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9321              : 
    9322            0 :                 if (tbinfo->ncheck > 0)
    9323              :                 {
    9324              :                         /* Also make a list of the ones with check constraints */
    9325            0 :                         if (checkoids->len > 1) /* do we have more than the '{'? */
    9326            0 :                                 appendPQExpBufferChar(checkoids, ',');
    9327            0 :                         appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    9328            0 :                 }
    9329            0 :         }
    9330            0 :         appendPQExpBufferChar(tbloids, '}');
    9331            0 :         appendPQExpBufferChar(checkoids, '}');
    9332              : 
    9333              :         /*
    9334              :          * Find all the user attributes and their types.
    9335              :          *
    9336              :          * Since we only want to dump COLLATE clauses for attributes whose
    9337              :          * collation is different from their type's default, we use a CASE here to
    9338              :          * suppress uninteresting attcollations cheaply.
    9339              :          */
    9340            0 :         appendPQExpBufferStr(q,
    9341              :                                                  "SELECT\n"
    9342              :                                                  "a.attrelid,\n"
    9343              :                                                  "a.attnum,\n"
    9344              :                                                  "a.attname,\n"
    9345              :                                                  "a.attstattarget,\n"
    9346              :                                                  "a.attstorage,\n"
    9347              :                                                  "t.typstorage,\n"
    9348              :                                                  "a.atthasdef,\n"
    9349              :                                                  "a.attisdropped,\n"
    9350              :                                                  "a.attlen,\n"
    9351              :                                                  "a.attalign,\n"
    9352              :                                                  "a.attislocal,\n"
    9353              :                                                  "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    9354              :                                                  "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    9355              :                                                  "CASE WHEN a.attcollation <> t.typcollation "
    9356              :                                                  "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    9357              :                                                  "pg_catalog.array_to_string(ARRAY("
    9358              :                                                  "SELECT pg_catalog.quote_ident(option_name) || "
    9359              :                                                  "' ' || pg_catalog.quote_literal(option_value) "
    9360              :                                                  "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    9361              :                                                  "ORDER BY option_name"
    9362              :                                                  "), E',\n    ') AS attfdwoptions,\n");
    9363              : 
    9364              :         /*
    9365              :          * Find out any NOT NULL markings for each column.  In 18 and up we read
    9366              :          * pg_constraint to obtain the constraint name, and for valid constraints
    9367              :          * also pg_description to obtain its comment.  notnull_noinherit is set
    9368              :          * according to the NO INHERIT property.  For versions prior to 18, we
    9369              :          * store an empty string as the name when a constraint is marked as
    9370              :          * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    9371              :          * without a name); also, such cases are never NO INHERIT.
    9372              :          *
    9373              :          * For invalid constraints, we need to store their OIDs for processing
    9374              :          * elsewhere, so we bring the pg_constraint.oid value when the constraint
    9375              :          * is invalid, and NULL otherwise.  Their comments are handled not here
    9376              :          * but by collectComments, because they're their own dumpable object.
    9377              :          *
    9378              :          * We track in notnull_islocal whether the constraint was defined directly
    9379              :          * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    9380              :          * might modify this later.
    9381              :          */
    9382            0 :         if (fout->remoteVersion >= 180000)
    9383            0 :                 appendPQExpBufferStr(q,
    9384              :                                                          "co.conname AS notnull_name,\n"
    9385              :                                                          "CASE WHEN co.convalidated THEN pt.description"
    9386              :                                                          " ELSE NULL END AS notnull_comment,\n"
    9387              :                                                          "CASE WHEN NOT co.convalidated THEN co.oid "
    9388              :                                                          "ELSE NULL END AS notnull_invalidoid,\n"
    9389              :                                                          "co.connoinherit AS notnull_noinherit,\n"
    9390              :                                                          "co.conislocal AS notnull_islocal,\n");
    9391              :         else
    9392            0 :                 appendPQExpBufferStr(q,
    9393              :                                                          "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    9394              :                                                          "NULL AS notnull_comment,\n"
    9395              :                                                          "NULL AS notnull_invalidoid,\n"
    9396              :                                                          "false AS notnull_noinherit,\n"
    9397              :                                                          "CASE WHEN a.attislocal THEN true\n"
    9398              :                                                          "     WHEN a.attnotnull AND NOT a.attislocal THEN true\n"
    9399              :                                                          "     ELSE false\n"
    9400              :                                                          "END AS notnull_islocal,\n");
    9401              : 
    9402            0 :         if (fout->remoteVersion >= 140000)
    9403            0 :                 appendPQExpBufferStr(q,
    9404              :                                                          "a.attcompression AS attcompression,\n");
    9405              :         else
    9406            0 :                 appendPQExpBufferStr(q,
    9407              :                                                          "'' AS attcompression,\n");
    9408              : 
    9409            0 :         if (fout->remoteVersion >= 100000)
    9410            0 :                 appendPQExpBufferStr(q,
    9411              :                                                          "a.attidentity,\n");
    9412              :         else
    9413            0 :                 appendPQExpBufferStr(q,
    9414              :                                                          "'' AS attidentity,\n");
    9415              : 
    9416            0 :         if (fout->remoteVersion >= 110000)
    9417            0 :                 appendPQExpBufferStr(q,
    9418              :                                                          "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    9419              :                                                          "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    9420              :         else
    9421            0 :                 appendPQExpBufferStr(q,
    9422              :                                                          "NULL AS attmissingval,\n");
    9423              : 
    9424            0 :         if (fout->remoteVersion >= 120000)
    9425            0 :                 appendPQExpBufferStr(q,
    9426              :                                                          "a.attgenerated\n");
    9427              :         else
    9428            0 :                 appendPQExpBufferStr(q,
    9429              :                                                          "'' AS attgenerated\n");
    9430              : 
    9431              :         /* need left join to pg_type to not fail on dropped columns ... */
    9432            0 :         appendPQExpBuffer(q,
    9433              :                                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9434              :                                           "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    9435              :                                           "LEFT JOIN pg_catalog.pg_type t "
    9436              :                                           "ON (a.atttypid = t.oid)\n",
    9437            0 :                                           tbloids->data);
    9438              : 
    9439              :         /*
    9440              :          * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    9441              :          * entries and pg_description to get their comments.
    9442              :          */
    9443            0 :         if (fout->remoteVersion >= 180000)
    9444            0 :                 appendPQExpBufferStr(q,
    9445              :                                                          " LEFT JOIN pg_catalog.pg_constraint co ON "
    9446              :                                                          "(a.attrelid = co.conrelid\n"
    9447              :                                                          "   AND co.contype = 'n' AND "
    9448              :                                                          "co.conkey = array[a.attnum])\n"
    9449              :                                                          " LEFT JOIN pg_catalog.pg_description pt ON "
    9450              :                                                          "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
    9451              : 
    9452            0 :         appendPQExpBufferStr(q,
    9453              :                                                  "WHERE a.attnum > 0::pg_catalog.int2\n"
    9454              :                                                  "ORDER BY a.attrelid, a.attnum");
    9455              : 
    9456            0 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9457              : 
    9458            0 :         ntups = PQntuples(res);
    9459              : 
    9460            0 :         i_attrelid = PQfnumber(res, "attrelid");
    9461            0 :         i_attnum = PQfnumber(res, "attnum");
    9462            0 :         i_attname = PQfnumber(res, "attname");
    9463            0 :         i_atttypname = PQfnumber(res, "atttypname");
    9464            0 :         i_attstattarget = PQfnumber(res, "attstattarget");
    9465            0 :         i_attstorage = PQfnumber(res, "attstorage");
    9466            0 :         i_typstorage = PQfnumber(res, "typstorage");
    9467            0 :         i_attidentity = PQfnumber(res, "attidentity");
    9468            0 :         i_attgenerated = PQfnumber(res, "attgenerated");
    9469            0 :         i_attisdropped = PQfnumber(res, "attisdropped");
    9470            0 :         i_attlen = PQfnumber(res, "attlen");
    9471            0 :         i_attalign = PQfnumber(res, "attalign");
    9472            0 :         i_attislocal = PQfnumber(res, "attislocal");
    9473            0 :         i_notnull_name = PQfnumber(res, "notnull_name");
    9474            0 :         i_notnull_comment = PQfnumber(res, "notnull_comment");
    9475            0 :         i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
    9476            0 :         i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9477            0 :         i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9478            0 :         i_attoptions = PQfnumber(res, "attoptions");
    9479            0 :         i_attcollation = PQfnumber(res, "attcollation");
    9480            0 :         i_attcompression = PQfnumber(res, "attcompression");
    9481            0 :         i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9482            0 :         i_attmissingval = PQfnumber(res, "attmissingval");
    9483            0 :         i_atthasdef = PQfnumber(res, "atthasdef");
    9484              : 
    9485              :         /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9486            0 :         resetPQExpBuffer(tbloids);
    9487            0 :         appendPQExpBufferChar(tbloids, '{');
    9488              : 
    9489              :         /*
    9490              :          * Outer loop iterates once per table, not once per row.  Incrementing of
    9491              :          * r is handled by the inner loop.
    9492              :          */
    9493            0 :         curtblindx = -1;
    9494            0 :         for (int r = 0; r < ntups;)
    9495              :         {
    9496            0 :                 Oid                     attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9497            0 :                 TableInfo  *tbinfo = NULL;
    9498            0 :                 int                     numatts;
    9499            0 :                 bool            hasdefaults;
    9500              : 
    9501              :                 /* Count rows for this table */
    9502            0 :                 for (numatts = 1; numatts < ntups - r; numatts++)
    9503            0 :                         if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9504            0 :                                 break;
    9505              : 
    9506              :                 /*
    9507              :                  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9508              :                  * order.
    9509              :                  */
    9510            0 :                 while (++curtblindx < numTables)
    9511              :                 {
    9512            0 :                         tbinfo = &tblinfo[curtblindx];
    9513            0 :                         if (tbinfo->dobj.catId.oid == attrelid)
    9514            0 :                                 break;
    9515              :                 }
    9516            0 :                 if (curtblindx >= numTables)
    9517            0 :                         pg_fatal("unrecognized table OID %u", attrelid);
    9518              :                 /* cross-check that we only got requested tables */
    9519            0 :                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9520            0 :                         (!tbinfo->interesting &&
    9521            0 :                          !(fout->dopt->binary_upgrade && fout->remoteVersion >= 120000 &&
    9522            0 :                            (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9523            0 :                                 tbinfo->dobj.catId.oid == SharedDependRelationId))))
    9524            0 :                         pg_fatal("unexpected column data for table \"%s\"",
    9525              :                                          tbinfo->dobj.name);
    9526              : 
    9527              :                 /* Save data for this table */
    9528            0 :                 tbinfo->numatts = numatts;
    9529            0 :                 tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
    9530            0 :                 tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
    9531            0 :                 tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
    9532            0 :                 tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
    9533            0 :                 tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
    9534            0 :                 tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
    9535            0 :                 tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
    9536            0 :                 tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
    9537            0 :                 tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
    9538            0 :                 tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
    9539            0 :                 tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9540            0 :                 tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9541            0 :                 tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
    9542            0 :                 tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
    9543            0 :                 tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9544            0 :                 tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
    9545            0 :                 tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
    9546            0 :                 tbinfo->notnull_comment = (char **) pg_malloc(numatts * sizeof(char *));
    9547            0 :                 tbinfo->notnull_invalid = (bool *) pg_malloc(numatts * sizeof(bool));
    9548            0 :                 tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
    9549            0 :                 tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9550            0 :                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
    9551            0 :                 hasdefaults = false;
    9552              : 
    9553            0 :                 for (int j = 0; j < numatts; j++, r++)
    9554              :                 {
    9555            0 :                         if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
    9556            0 :                                 pg_fatal("invalid column numbering in table \"%s\"",
    9557              :                                                  tbinfo->dobj.name);
    9558            0 :                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9559            0 :                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9560            0 :                         if (PQgetisnull(res, r, i_attstattarget))
    9561            0 :                                 tbinfo->attstattarget[j] = -1;
    9562              :                         else
    9563            0 :                                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9564            0 :                         tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9565            0 :                         tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9566            0 :                         tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9567            0 :                         tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9568            0 :                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9569            0 :                         tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9570            0 :                         tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9571            0 :                         tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9572            0 :                         tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9573              : 
    9574              :                         /* Handle not-null constraint name and flags */
    9575            0 :                         determineNotNullFlags(fout, res, r,
    9576            0 :                                                                   tbinfo, j,
    9577            0 :                                                                   i_notnull_name,
    9578            0 :                                                                   i_notnull_comment,
    9579            0 :                                                                   i_notnull_invalidoid,
    9580            0 :                                                                   i_notnull_noinherit,
    9581            0 :                                                                   i_notnull_islocal,
    9582              :                                                                   &invalidnotnulloids);
    9583              : 
    9584            0 :                         tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
    9585            0 :                                 NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
    9586            0 :                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9587            0 :                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9588            0 :                         tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9589            0 :                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9590            0 :                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9591            0 :                         tbinfo->attrdefs[j] = NULL; /* fix below */
    9592            0 :                         if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9593            0 :                                 hasdefaults = true;
    9594            0 :                 }
    9595              : 
    9596            0 :                 if (hasdefaults)
    9597              :                 {
    9598              :                         /* Collect OIDs of interesting tables that have defaults */
    9599            0 :                         if (tbloids->len > 1)     /* do we have more than the '{'? */
    9600            0 :                                 appendPQExpBufferChar(tbloids, ',');
    9601            0 :                         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9602            0 :                 }
    9603            0 :         }
    9604              : 
    9605              :         /* If invalidnotnulloids has any data, finalize it */
    9606            0 :         if (invalidnotnulloids != NULL)
    9607            0 :                 appendPQExpBufferChar(invalidnotnulloids, '}');
    9608              : 
    9609            0 :         PQclear(res);
    9610              : 
    9611              :         /*
    9612              :          * Now get info about column defaults.  This is skipped for a data-only
    9613              :          * dump, as it is only needed for table schemas.
    9614              :          */
    9615            0 :         if (dopt->dumpSchema && tbloids->len > 1)
    9616              :         {
    9617            0 :                 AttrDefInfo *attrdefs;
    9618            0 :                 int                     numDefaults;
    9619            0 :                 TableInfo  *tbinfo = NULL;
    9620              : 
    9621            0 :                 pg_log_info("finding table default expressions");
    9622              : 
    9623            0 :                 appendPQExpBufferChar(tbloids, '}');
    9624              : 
    9625            0 :                 printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9626              :                                                   "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9627              :                                                   "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9628              :                                                   "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9629              :                                                   "ORDER BY a.adrelid, a.adnum",
    9630            0 :                                                   tbloids->data);
    9631              : 
    9632            0 :                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9633              : 
    9634            0 :                 numDefaults = PQntuples(res);
    9635            0 :                 attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
    9636              : 
    9637            0 :                 curtblindx = -1;
    9638            0 :                 for (int j = 0; j < numDefaults; j++)
    9639              :                 {
    9640            0 :                         Oid                     adtableoid = atooid(PQgetvalue(res, j, 0));
    9641            0 :                         Oid                     adoid = atooid(PQgetvalue(res, j, 1));
    9642            0 :                         Oid                     adrelid = atooid(PQgetvalue(res, j, 2));
    9643            0 :                         int                     adnum = atoi(PQgetvalue(res, j, 3));
    9644            0 :                         char       *adsrc = PQgetvalue(res, j, 4);
    9645              : 
    9646              :                         /*
    9647              :                          * Locate the associated TableInfo; we rely on tblinfo[] being in
    9648              :                          * OID order.
    9649              :                          */
    9650            0 :                         if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9651              :                         {
    9652            0 :                                 while (++curtblindx < numTables)
    9653              :                                 {
    9654            0 :                                         tbinfo = &tblinfo[curtblindx];
    9655            0 :                                         if (tbinfo->dobj.catId.oid == adrelid)
    9656            0 :                                                 break;
    9657              :                                 }
    9658            0 :                                 if (curtblindx >= numTables)
    9659            0 :                                         pg_fatal("unrecognized table OID %u", adrelid);
    9660            0 :                         }
    9661              : 
    9662            0 :                         if (adnum <= 0 || adnum > tbinfo->numatts)
    9663            0 :                                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9664              :                                                  adnum, tbinfo->dobj.name);
    9665              : 
    9666              :                         /*
    9667              :                          * dropped columns shouldn't have defaults, but just in case,
    9668              :                          * ignore 'em
    9669              :                          */
    9670            0 :                         if (tbinfo->attisdropped[adnum - 1])
    9671            0 :                                 continue;
    9672              : 
    9673            0 :                         attrdefs[j].dobj.objType = DO_ATTRDEF;
    9674            0 :                         attrdefs[j].dobj.catId.tableoid = adtableoid;
    9675            0 :                         attrdefs[j].dobj.catId.oid = adoid;
    9676            0 :                         AssignDumpId(&attrdefs[j].dobj);
    9677            0 :                         attrdefs[j].adtable = tbinfo;
    9678            0 :                         attrdefs[j].adnum = adnum;
    9679            0 :                         attrdefs[j].adef_expr = pg_strdup(adsrc);
    9680              : 
    9681            0 :                         attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9682            0 :                         attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9683              : 
    9684            0 :                         attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9685              : 
    9686              :                         /*
    9687              :                          * Figure out whether the default/generation expression should be
    9688              :                          * dumped as part of the main CREATE TABLE (or similar) command or
    9689              :                          * as a separate ALTER TABLE (or similar) command. The preference
    9690              :                          * is to put it into the CREATE command, but in some cases that's
    9691              :                          * not possible.
    9692              :                          */
    9693            0 :                         if (tbinfo->attgenerated[adnum - 1])
    9694              :                         {
    9695              :                                 /*
    9696              :                                  * Column generation expressions cannot be dumped separately,
    9697              :                                  * because there is no syntax for it.  By setting separate to
    9698              :                                  * false here we prevent the "default" from being processed as
    9699              :                                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9700              :                                  * it as not to be dumped at all, if possible (that is, if it
    9701              :                                  * can be inherited from a parent).
    9702              :                                  */
    9703            0 :                                 attrdefs[j].separate = false;
    9704            0 :                         }
    9705            0 :                         else if (tbinfo->relkind == RELKIND_VIEW)
    9706              :                         {
    9707              :                                 /*
    9708              :                                  * Defaults on a VIEW must always be dumped as separate ALTER
    9709              :                                  * TABLE commands.
    9710              :                                  */
    9711            0 :                                 attrdefs[j].separate = true;
    9712            0 :                         }
    9713            0 :                         else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9714              :                         {
    9715              :                                 /* column will be suppressed, print default separately */
    9716            0 :                                 attrdefs[j].separate = true;
    9717            0 :                         }
    9718              :                         else
    9719              :                         {
    9720            0 :                                 attrdefs[j].separate = false;
    9721              :                         }
    9722              : 
    9723            0 :                         if (!attrdefs[j].separate)
    9724              :                         {
    9725              :                                 /*
    9726              :                                  * Mark the default as needing to appear before the table, so
    9727              :                                  * that any dependencies it has must be emitted before the
    9728              :                                  * CREATE TABLE.  If this is not possible, we'll change to
    9729              :                                  * "separate" mode while sorting dependencies.
    9730              :                                  */
    9731            0 :                                 addObjectDependency(&tbinfo->dobj,
    9732            0 :                                                                         attrdefs[j].dobj.dumpId);
    9733            0 :                         }
    9734              : 
    9735            0 :                         tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9736            0 :                 }
    9737              : 
    9738            0 :                 PQclear(res);
    9739            0 :         }
    9740              : 
    9741              :         /*
    9742              :          * Get info about NOT NULL NOT VALID constraints.  This is skipped for a
    9743              :          * data-only dump, as it is only needed for table schemas.
    9744              :          */
    9745            0 :         if (dopt->dumpSchema && invalidnotnulloids)
    9746              :         {
    9747            0 :                 ConstraintInfo *constrs;
    9748            0 :                 int                     numConstrs;
    9749            0 :                 int                     i_tableoid;
    9750            0 :                 int                     i_oid;
    9751            0 :                 int                     i_conrelid;
    9752            0 :                 int                     i_conname;
    9753            0 :                 int                     i_consrc;
    9754            0 :                 int                     i_conislocal;
    9755              : 
    9756            0 :                 pg_log_info("finding invalid not-null constraints");
    9757              : 
    9758            0 :                 resetPQExpBuffer(q);
    9759            0 :                 appendPQExpBuffer(q,
    9760              :                                                   "SELECT c.tableoid, c.oid, conrelid, conname, "
    9761              :                                                   "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9762              :                                                   "conislocal, convalidated "
    9763              :                                                   "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
    9764              :                                                   "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
    9765              :                                                   "ORDER BY c.conrelid, c.conname",
    9766            0 :                                                   invalidnotnulloids->data);
    9767              : 
    9768            0 :                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9769              : 
    9770            0 :                 numConstrs = PQntuples(res);
    9771            0 :                 constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9772              : 
    9773            0 :                 i_tableoid = PQfnumber(res, "tableoid");
    9774            0 :                 i_oid = PQfnumber(res, "oid");
    9775            0 :                 i_conrelid = PQfnumber(res, "conrelid");
    9776            0 :                 i_conname = PQfnumber(res, "conname");
    9777            0 :                 i_consrc = PQfnumber(res, "consrc");
    9778            0 :                 i_conislocal = PQfnumber(res, "conislocal");
    9779              : 
    9780              :                 /* As above, this loop iterates once per table, not once per row */
    9781            0 :                 curtblindx = -1;
    9782            0 :                 for (int j = 0; j < numConstrs;)
    9783              :                 {
    9784            0 :                         Oid                     conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9785            0 :                         TableInfo  *tbinfo = NULL;
    9786            0 :                         int                     numcons;
    9787              : 
    9788              :                         /* Count rows for this table */
    9789            0 :                         for (numcons = 1; numcons < numConstrs - j; numcons++)
    9790            0 :                                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9791            0 :                                         break;
    9792              : 
    9793              :                         /*
    9794              :                          * Locate the associated TableInfo; we rely on tblinfo[] being in
    9795              :                          * OID order.
    9796              :                          */
    9797            0 :                         while (++curtblindx < numTables)
    9798              :                         {
    9799            0 :                                 tbinfo = &tblinfo[curtblindx];
    9800            0 :                                 if (tbinfo->dobj.catId.oid == conrelid)
    9801            0 :                                         break;
    9802              :                         }
    9803            0 :                         if (curtblindx >= numTables)
    9804            0 :                                 pg_fatal("unrecognized table OID %u", conrelid);
    9805              : 
    9806            0 :                         for (int c = 0; c < numcons; c++, j++)
    9807              :                         {
    9808            0 :                                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9809            0 :                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9810            0 :                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9811            0 :                                 AssignDumpId(&constrs[j].dobj);
    9812            0 :                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9813            0 :                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9814            0 :                                 constrs[j].contable = tbinfo;
    9815            0 :                                 constrs[j].condomain = NULL;
    9816            0 :                                 constrs[j].contype = 'n';
    9817            0 :                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9818            0 :                                 constrs[j].confrelid = InvalidOid;
    9819            0 :                                 constrs[j].conindex = 0;
    9820            0 :                                 constrs[j].condeferrable = false;
    9821            0 :                                 constrs[j].condeferred = false;
    9822            0 :                                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9823              : 
    9824              :                                 /*
    9825              :                                  * All invalid not-null constraints must be dumped separately,
    9826              :                                  * because CREATE TABLE would not create them as invalid, and
    9827              :                                  * also because they must be created after potentially
    9828              :                                  * violating data has been loaded.
    9829              :                                  */
    9830            0 :                                 constrs[j].separate = true;
    9831              : 
    9832            0 :                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9833            0 :                         }
    9834            0 :                 }
    9835            0 :                 PQclear(res);
    9836            0 :         }
    9837              : 
    9838              :         /*
    9839              :          * Get info about table CHECK constraints.  This is skipped for a
    9840              :          * data-only dump, as it is only needed for table schemas.
    9841              :          */
    9842            0 :         if (dopt->dumpSchema && checkoids->len > 2)
    9843              :         {
    9844            0 :                 ConstraintInfo *constrs;
    9845            0 :                 int                     numConstrs;
    9846            0 :                 int                     i_tableoid;
    9847            0 :                 int                     i_oid;
    9848            0 :                 int                     i_conrelid;
    9849            0 :                 int                     i_conname;
    9850            0 :                 int                     i_consrc;
    9851            0 :                 int                     i_conislocal;
    9852            0 :                 int                     i_convalidated;
    9853              : 
    9854            0 :                 pg_log_info("finding table check constraints");
    9855              : 
    9856            0 :                 resetPQExpBuffer(q);
    9857            0 :                 appendPQExpBuffer(q,
    9858              :                                                   "SELECT c.tableoid, c.oid, conrelid, conname, "
    9859              :                                                   "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9860              :                                                   "conislocal, convalidated "
    9861              :                                                   "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9862              :                                                   "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9863              :                                                   "WHERE contype = 'c' "
    9864              :                                                   "ORDER BY c.conrelid, c.conname",
    9865            0 :                                                   checkoids->data);
    9866              : 
    9867            0 :                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9868              : 
    9869            0 :                 numConstrs = PQntuples(res);
    9870            0 :                 constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9871              : 
    9872            0 :                 i_tableoid = PQfnumber(res, "tableoid");
    9873            0 :                 i_oid = PQfnumber(res, "oid");
    9874            0 :                 i_conrelid = PQfnumber(res, "conrelid");
    9875            0 :                 i_conname = PQfnumber(res, "conname");
    9876            0 :                 i_consrc = PQfnumber(res, "consrc");
    9877            0 :                 i_conislocal = PQfnumber(res, "conislocal");
    9878            0 :                 i_convalidated = PQfnumber(res, "convalidated");
    9879              : 
    9880              :                 /* As above, this loop iterates once per table, not once per row */
    9881            0 :                 curtblindx = -1;
    9882            0 :                 for (int j = 0; j < numConstrs;)
    9883              :                 {
    9884            0 :                         Oid                     conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9885            0 :                         TableInfo  *tbinfo = NULL;
    9886            0 :                         int                     numcons;
    9887              : 
    9888              :                         /* Count rows for this table */
    9889            0 :                         for (numcons = 1; numcons < numConstrs - j; numcons++)
    9890            0 :                                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9891            0 :                                         break;
    9892              : 
    9893              :                         /*
    9894              :                          * Locate the associated TableInfo; we rely on tblinfo[] being in
    9895              :                          * OID order.
    9896              :                          */
    9897            0 :                         while (++curtblindx < numTables)
    9898              :                         {
    9899            0 :                                 tbinfo = &tblinfo[curtblindx];
    9900            0 :                                 if (tbinfo->dobj.catId.oid == conrelid)
    9901            0 :                                         break;
    9902              :                         }
    9903            0 :                         if (curtblindx >= numTables)
    9904            0 :                                 pg_fatal("unrecognized table OID %u", conrelid);
    9905              : 
    9906            0 :                         if (numcons != tbinfo->ncheck)
    9907              :                         {
    9908            0 :                                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    9909              :                                                                           "expected %d check constraints on table \"%s\" but found %d",
    9910              :                                                                           tbinfo->ncheck),
    9911              :                                                          tbinfo->ncheck, tbinfo->dobj.name, numcons);
    9912            0 :                                 pg_log_error_hint("The system catalogs might be corrupted.");
    9913            0 :                                 exit_nicely(1);
    9914              :                         }
    9915              : 
    9916            0 :                         tbinfo->checkexprs = constrs + j;
    9917              : 
    9918            0 :                         for (int c = 0; c < numcons; c++, j++)
    9919              :                         {
    9920            0 :                                 bool            validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
    9921              : 
    9922            0 :                                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9923            0 :                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9924            0 :                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9925            0 :                                 AssignDumpId(&constrs[j].dobj);
    9926            0 :                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9927            0 :                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9928            0 :                                 constrs[j].contable = tbinfo;
    9929            0 :                                 constrs[j].condomain = NULL;
    9930            0 :                                 constrs[j].contype = 'c';
    9931            0 :                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9932            0 :                                 constrs[j].confrelid = InvalidOid;
    9933            0 :                                 constrs[j].conindex = 0;
    9934            0 :                                 constrs[j].condeferrable = false;
    9935            0 :                                 constrs[j].condeferred = false;
    9936            0 :                                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9937              : 
    9938              :                                 /*
    9939              :                                  * An unvalidated constraint needs to be dumped separately, so
    9940              :                                  * that potentially-violating existing data is loaded before
    9941              :                                  * the constraint.
    9942              :                                  */
    9943            0 :                                 constrs[j].separate = !validated;
    9944              : 
    9945            0 :                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9946              : 
    9947              :                                 /*
    9948              :                                  * Mark the constraint as needing to appear before the table
    9949              :                                  * --- this is so that any other dependencies of the
    9950              :                                  * constraint will be emitted before we try to create the
    9951              :                                  * table.  If the constraint is to be dumped separately, it
    9952              :                                  * will be dumped after data is loaded anyway, so don't do it.
    9953              :                                  * (There's an automatic dependency in the opposite direction
    9954              :                                  * anyway, so don't need to add one manually here.)
    9955              :                                  */
    9956            0 :                                 if (!constrs[j].separate)
    9957            0 :                                         addObjectDependency(&tbinfo->dobj,
    9958            0 :                                                                                 constrs[j].dobj.dumpId);
    9959              : 
    9960              :                                 /*
    9961              :                                  * We will detect later whether the constraint must be split
    9962              :                                  * out from the table definition.
    9963              :                                  */
    9964            0 :                         }
    9965            0 :                 }
    9966              : 
    9967            0 :                 PQclear(res);
    9968            0 :         }
    9969              : 
    9970            0 :         destroyPQExpBuffer(q);
    9971            0 :         destroyPQExpBuffer(tbloids);
    9972            0 :         destroyPQExpBuffer(checkoids);
    9973            0 : }
    9974              : 
    9975              : /*
    9976              :  * Based on the getTableAttrs query's row corresponding to one column, set
    9977              :  * the name and flags to handle a not-null constraint for that column in
    9978              :  * the tbinfo struct.
    9979              :  *
    9980              :  * Result row 'r' is for tbinfo's attribute 'j'.
    9981              :  *
    9982              :  * There are four possibilities:
    9983              :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
    9984              :  *    (the constraint name) remains NULL.
    9985              :  * 2) The column has a constraint with no name (this is the case when
    9986              :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
    9987              :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
    9988              :  * 3) The column has an invalid not-null constraint.  This must be treated
    9989              :  *    as a separate object (because it must be created after the table data
    9990              :  *    is loaded).  So we add its OID to invalidnotnulloids for processing
    9991              :  *    elsewhere and do nothing further with it here.  We distinguish this
    9992              :  *    case because the "notnull_invalidoid" column has been set to a non-NULL
    9993              :  *    value, which is the constraint OID.  Valid constraints have a null OID.
    9994              :  * 4) The column has a constraint with a known name; in that case
    9995              :  *    notnull_constrs carries that name and dumpTableSchema will print
    9996              :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
    9997              :  *    (table_column_not_null) and there's no comment on the constraint,
    9998              :  *    there's no need to print that name in the dump, so notnull_constrs
    9999              :  *    is set to the empty string and it behaves as case 2.
   10000              :  *
   10001              :  * In a child table that inherits from a parent already containing NOT NULL
   10002              :  * constraints and the columns in the child don't have their own NOT NULL
   10003              :  * declarations, we suppress printing constraints in the child: the
   10004              :  * constraints are acquired at the point where the child is attached to the
   10005              :  * parent.  This is tracked in ->notnull_islocal; for servers pre-18 this is
   10006              :  * set not here but in flagInhAttrs.  That flag is also used when the
   10007              :  * constraint was validated in a child but all its parent have it as NOT
   10008              :  * VALID.
   10009              :  *
   10010              :  * Any of these constraints might have the NO INHERIT bit.  If so we set
   10011              :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
   10012              :  *
   10013              :  * In case 4 above, the name comparison is a bit of a hack; it actually fails
   10014              :  * to do the right thing in all but the trivial case.  However, the downside
   10015              :  * of getting it wrong is simply that the name is printed rather than
   10016              :  * suppressed, so it's not a big deal.
   10017              :  *
   10018              :  * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
   10019              :  * constraints are found, it is initialized and filled with the array of
   10020              :  * OIDs of such constraints, for later processing.
   10021              :  */
   10022              : static void
   10023            0 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
   10024              :                                           TableInfo *tbinfo, int j,
   10025              :                                           int i_notnull_name,
   10026              :                                           int i_notnull_comment,
   10027              :                                           int i_notnull_invalidoid,
   10028              :                                           int i_notnull_noinherit,
   10029              :                                           int i_notnull_islocal,
   10030              :                                           PQExpBuffer *invalidnotnulloids)
   10031              : {
   10032            0 :         DumpOptions *dopt = fout->dopt;
   10033              : 
   10034              :         /*
   10035              :          * If this not-null constraint is not valid, list its OID in
   10036              :          * invalidnotnulloids and do nothing further.  It'll be processed
   10037              :          * elsewhere later.
   10038              :          *
   10039              :          * Because invalid not-null constraints are rare, we don't want to malloc
   10040              :          * invalidnotnulloids until we're sure we're going it need it, which
   10041              :          * happens here.
   10042              :          */
   10043            0 :         if (!PQgetisnull(res, r, i_notnull_invalidoid))
   10044              :         {
   10045            0 :                 char       *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
   10046              : 
   10047            0 :                 if (*invalidnotnulloids == NULL)
   10048              :                 {
   10049            0 :                         *invalidnotnulloids = createPQExpBuffer();
   10050            0 :                         appendPQExpBufferChar(*invalidnotnulloids, '{');
   10051            0 :                         appendPQExpBufferStr(*invalidnotnulloids, constroid);
   10052            0 :                 }
   10053              :                 else
   10054            0 :                         appendPQExpBuffer(*invalidnotnulloids, ",%s", constroid);
   10055              : 
   10056              :                 /*
   10057              :                  * Track when a parent constraint is invalid for the cases where a
   10058              :                  * child constraint has been validated independenly.
   10059              :                  */
   10060            0 :                 tbinfo->notnull_invalid[j] = true;
   10061              : 
   10062              :                 /* nothing else to do */
   10063            0 :                 tbinfo->notnull_constrs[j] = NULL;
   10064              :                 return;
   10065            0 :         }
   10066              : 
   10067              :         /*
   10068              :          * notnull_noinh is straight from the query result. notnull_islocal also,
   10069              :          * though flagInhAttrs may change that one later.
   10070              :          */
   10071            0 :         tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
   10072            0 :         tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
   10073            0 :         tbinfo->notnull_invalid[j] = false;
   10074              : 
   10075              :         /*
   10076              :          * Determine a constraint name to use.  If the column is not marked not-
   10077              :          * null, we set NULL which cues ... to do nothing.  An empty string says
   10078              :          * to print an unnamed NOT NULL, and anything else is a constraint name to
   10079              :          * use.
   10080              :          */
   10081            0 :         if (fout->remoteVersion < 180000)
   10082              :         {
   10083              :                 /*
   10084              :                  * < 18 doesn't have not-null names, so an unnamed constraint is
   10085              :                  * sufficient.
   10086              :                  */
   10087            0 :                 if (PQgetisnull(res, r, i_notnull_name))
   10088            0 :                         tbinfo->notnull_constrs[j] = NULL;
   10089              :                 else
   10090            0 :                         tbinfo->notnull_constrs[j] = "";
   10091            0 :         }
   10092              :         else
   10093              :         {
   10094            0 :                 if (PQgetisnull(res, r, i_notnull_name))
   10095            0 :                         tbinfo->notnull_constrs[j] = NULL;
   10096              :                 else
   10097              :                 {
   10098              :                         /*
   10099              :                          * In binary upgrade of inheritance child tables, must have a
   10100              :                          * constraint name that we can UPDATE later; same if there's a
   10101              :                          * comment on the constraint.
   10102              :                          */
   10103            0 :                         if ((dopt->binary_upgrade &&
   10104            0 :                                  !tbinfo->ispartition &&
   10105            0 :                                  !tbinfo->notnull_islocal) ||
   10106            0 :                                 !PQgetisnull(res, r, i_notnull_comment))
   10107              :                         {
   10108            0 :                                 tbinfo->notnull_constrs[j] =
   10109            0 :                                         pstrdup(PQgetvalue(res, r, i_notnull_name));
   10110            0 :                         }
   10111              :                         else
   10112              :                         {
   10113            0 :                                 char       *default_name;
   10114              : 
   10115              :                                 /* XXX should match ChooseConstraintName better */
   10116            0 :                                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
   10117            0 :                                                                                 tbinfo->attnames[j]);
   10118            0 :                                 if (strcmp(default_name,
   10119            0 :                                                    PQgetvalue(res, r, i_notnull_name)) == 0)
   10120            0 :                                         tbinfo->notnull_constrs[j] = "";
   10121              :                                 else
   10122              :                                 {
   10123            0 :                                         tbinfo->notnull_constrs[j] =
   10124            0 :                                                 pstrdup(PQgetvalue(res, r, i_notnull_name));
   10125              :                                 }
   10126            0 :                                 free(default_name);
   10127            0 :                         }
   10128              :                 }
   10129              :         }
   10130            0 : }
   10131              : 
   10132              : /*
   10133              :  * Test whether a column should be printed as part of table's CREATE TABLE.
   10134              :  * Column number is zero-based.
   10135              :  *
   10136              :  * Normally this is always true, but it's false for dropped columns, as well
   10137              :  * as those that were inherited without any local definition.  (If we print
   10138              :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
   10139              :  * For partitions, it's always true, because we want the partitions to be
   10140              :  * created independently and ATTACH PARTITION used afterwards.
   10141              :  *
   10142              :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
   10143              :  * attisdropped state later, so as to keep control of the physical column
   10144              :  * order.
   10145              :  *
   10146              :  * This function exists because there are scattered nonobvious places that
   10147              :  * must be kept in sync with this decision.
   10148              :  */
   10149              : bool
   10150            0 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
   10151              : {
   10152            0 :         if (dopt->binary_upgrade)
   10153            0 :                 return true;
   10154            0 :         if (tbinfo->attisdropped[colno])
   10155            0 :                 return false;
   10156            0 :         return (tbinfo->attislocal[colno] || tbinfo->ispartition);
   10157            0 : }
   10158              : 
   10159              : 
   10160              : /*
   10161              :  * getTSParsers:
   10162              :  *        get information about all text search parsers in the system catalogs
   10163              :  */
   10164              : void
   10165            0 : getTSParsers(Archive *fout)
   10166              : {
   10167            0 :         PGresult   *res;
   10168            0 :         int                     ntups;
   10169            0 :         int                     i;
   10170            0 :         PQExpBuffer query;
   10171            0 :         TSParserInfo *prsinfo;
   10172            0 :         int                     i_tableoid;
   10173            0 :         int                     i_oid;
   10174            0 :         int                     i_prsname;
   10175            0 :         int                     i_prsnamespace;
   10176            0 :         int                     i_prsstart;
   10177            0 :         int                     i_prstoken;
   10178            0 :         int                     i_prsend;
   10179            0 :         int                     i_prsheadline;
   10180            0 :         int                     i_prslextype;
   10181              : 
   10182            0 :         query = createPQExpBuffer();
   10183              : 
   10184              :         /*
   10185              :          * find all text search objects, including builtin ones; we filter out
   10186              :          * system-defined objects at dump-out time.
   10187              :          */
   10188              : 
   10189            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
   10190              :                                                  "prsstart::oid, prstoken::oid, "
   10191              :                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
   10192              :                                                  "FROM pg_ts_parser");
   10193              : 
   10194            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10195              : 
   10196            0 :         ntups = PQntuples(res);
   10197              : 
   10198            0 :         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
   10199              : 
   10200            0 :         i_tableoid = PQfnumber(res, "tableoid");
   10201            0 :         i_oid = PQfnumber(res, "oid");
   10202            0 :         i_prsname = PQfnumber(res, "prsname");
   10203            0 :         i_prsnamespace = PQfnumber(res, "prsnamespace");
   10204            0 :         i_prsstart = PQfnumber(res, "prsstart");
   10205            0 :         i_prstoken = PQfnumber(res, "prstoken");
   10206            0 :         i_prsend = PQfnumber(res, "prsend");
   10207            0 :         i_prsheadline = PQfnumber(res, "prsheadline");
   10208            0 :         i_prslextype = PQfnumber(res, "prslextype");
   10209              : 
   10210            0 :         for (i = 0; i < ntups; i++)
   10211              :         {
   10212            0 :                 prsinfo[i].dobj.objType = DO_TSPARSER;
   10213            0 :                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10214            0 :                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10215            0 :                 AssignDumpId(&prsinfo[i].dobj);
   10216            0 :                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
   10217            0 :                 prsinfo[i].dobj.namespace =
   10218            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
   10219            0 :                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
   10220            0 :                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
   10221            0 :                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
   10222            0 :                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
   10223            0 :                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
   10224              : 
   10225              :                 /* Decide whether we want to dump it */
   10226            0 :                 selectDumpableObject(&(prsinfo[i].dobj), fout);
   10227            0 :         }
   10228              : 
   10229            0 :         PQclear(res);
   10230              : 
   10231            0 :         destroyPQExpBuffer(query);
   10232            0 : }
   10233              : 
   10234              : /*
   10235              :  * getTSDictionaries:
   10236              :  *        get information about all text search dictionaries in the system catalogs
   10237              :  */
   10238              : void
   10239            0 : getTSDictionaries(Archive *fout)
   10240              : {
   10241            0 :         PGresult   *res;
   10242            0 :         int                     ntups;
   10243            0 :         int                     i;
   10244            0 :         PQExpBuffer query;
   10245            0 :         TSDictInfo *dictinfo;
   10246            0 :         int                     i_tableoid;
   10247            0 :         int                     i_oid;
   10248            0 :         int                     i_dictname;
   10249            0 :         int                     i_dictnamespace;
   10250            0 :         int                     i_dictowner;
   10251            0 :         int                     i_dicttemplate;
   10252            0 :         int                     i_dictinitoption;
   10253              : 
   10254            0 :         query = createPQExpBuffer();
   10255              : 
   10256            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
   10257              :                                                  "dictnamespace, dictowner, "
   10258              :                                                  "dicttemplate, dictinitoption "
   10259              :                                                  "FROM pg_ts_dict");
   10260              : 
   10261            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10262              : 
   10263            0 :         ntups = PQntuples(res);
   10264              : 
   10265            0 :         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
   10266              : 
   10267            0 :         i_tableoid = PQfnumber(res, "tableoid");
   10268            0 :         i_oid = PQfnumber(res, "oid");
   10269            0 :         i_dictname = PQfnumber(res, "dictname");
   10270            0 :         i_dictnamespace = PQfnumber(res, "dictnamespace");
   10271            0 :         i_dictowner = PQfnumber(res, "dictowner");
   10272            0 :         i_dictinitoption = PQfnumber(res, "dictinitoption");
   10273            0 :         i_dicttemplate = PQfnumber(res, "dicttemplate");
   10274              : 
   10275            0 :         for (i = 0; i < ntups; i++)
   10276              :         {
   10277            0 :                 dictinfo[i].dobj.objType = DO_TSDICT;
   10278            0 :                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10279            0 :                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10280            0 :                 AssignDumpId(&dictinfo[i].dobj);
   10281            0 :                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
   10282            0 :                 dictinfo[i].dobj.namespace =
   10283            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
   10284            0 :                 dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
   10285            0 :                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
   10286            0 :                 if (PQgetisnull(res, i, i_dictinitoption))
   10287            0 :                         dictinfo[i].dictinitoption = NULL;
   10288              :                 else
   10289            0 :                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
   10290              : 
   10291              :                 /* Decide whether we want to dump it */
   10292            0 :                 selectDumpableObject(&(dictinfo[i].dobj), fout);
   10293            0 :         }
   10294              : 
   10295            0 :         PQclear(res);
   10296              : 
   10297            0 :         destroyPQExpBuffer(query);
   10298            0 : }
   10299              : 
   10300              : /*
   10301              :  * getTSTemplates:
   10302              :  *        get information about all text search templates in the system catalogs
   10303              :  */
   10304              : void
   10305            0 : getTSTemplates(Archive *fout)
   10306              : {
   10307            0 :         PGresult   *res;
   10308            0 :         int                     ntups;
   10309            0 :         int                     i;
   10310            0 :         PQExpBuffer query;
   10311            0 :         TSTemplateInfo *tmplinfo;
   10312            0 :         int                     i_tableoid;
   10313            0 :         int                     i_oid;
   10314            0 :         int                     i_tmplname;
   10315            0 :         int                     i_tmplnamespace;
   10316            0 :         int                     i_tmplinit;
   10317            0 :         int                     i_tmpllexize;
   10318              : 
   10319            0 :         query = createPQExpBuffer();
   10320              : 
   10321            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
   10322              :                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
   10323              :                                                  "FROM pg_ts_template");
   10324              : 
   10325            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10326              : 
   10327            0 :         ntups = PQntuples(res);
   10328              : 
   10329            0 :         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
   10330              : 
   10331            0 :         i_tableoid = PQfnumber(res, "tableoid");
   10332            0 :         i_oid = PQfnumber(res, "oid");
   10333            0 :         i_tmplname = PQfnumber(res, "tmplname");
   10334            0 :         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
   10335            0 :         i_tmplinit = PQfnumber(res, "tmplinit");
   10336            0 :         i_tmpllexize = PQfnumber(res, "tmpllexize");
   10337              : 
   10338            0 :         for (i = 0; i < ntups; i++)
   10339              :         {
   10340            0 :                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
   10341            0 :                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10342            0 :                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10343            0 :                 AssignDumpId(&tmplinfo[i].dobj);
   10344            0 :                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
   10345            0 :                 tmplinfo[i].dobj.namespace =
   10346            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
   10347            0 :                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
   10348            0 :                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
   10349              : 
   10350              :                 /* Decide whether we want to dump it */
   10351            0 :                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
   10352            0 :         }
   10353              : 
   10354            0 :         PQclear(res);
   10355              : 
   10356            0 :         destroyPQExpBuffer(query);
   10357            0 : }
   10358              : 
   10359              : /*
   10360              :  * getTSConfigurations:
   10361              :  *        get information about all text search configurations
   10362              :  */
   10363              : void
   10364            0 : getTSConfigurations(Archive *fout)
   10365              : {
   10366            0 :         PGresult   *res;
   10367            0 :         int                     ntups;
   10368            0 :         int                     i;
   10369            0 :         PQExpBuffer query;
   10370            0 :         TSConfigInfo *cfginfo;
   10371            0 :         int                     i_tableoid;
   10372            0 :         int                     i_oid;
   10373            0 :         int                     i_cfgname;
   10374            0 :         int                     i_cfgnamespace;
   10375            0 :         int                     i_cfgowner;
   10376            0 :         int                     i_cfgparser;
   10377              : 
   10378            0 :         query = createPQExpBuffer();
   10379              : 
   10380            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
   10381              :                                                  "cfgnamespace, cfgowner, cfgparser "
   10382              :                                                  "FROM pg_ts_config");
   10383              : 
   10384            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10385              : 
   10386            0 :         ntups = PQntuples(res);
   10387              : 
   10388            0 :         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
   10389              : 
   10390            0 :         i_tableoid = PQfnumber(res, "tableoid");
   10391            0 :         i_oid = PQfnumber(res, "oid");
   10392            0 :         i_cfgname = PQfnumber(res, "cfgname");
   10393            0 :         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
   10394            0 :         i_cfgowner = PQfnumber(res, "cfgowner");
   10395            0 :         i_cfgparser = PQfnumber(res, "cfgparser");
   10396              : 
   10397            0 :         for (i = 0; i < ntups; i++)
   10398              :         {
   10399            0 :                 cfginfo[i].dobj.objType = DO_TSCONFIG;
   10400            0 :                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10401            0 :                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10402            0 :                 AssignDumpId(&cfginfo[i].dobj);
   10403            0 :                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
   10404            0 :                 cfginfo[i].dobj.namespace =
   10405            0 :                         findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
   10406            0 :                 cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
   10407            0 :                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
   10408              : 
   10409              :                 /* Decide whether we want to dump it */
   10410            0 :                 selectDumpableObject(&(cfginfo[i].dobj), fout);
   10411            0 :         }
   10412              : 
   10413            0 :         PQclear(res);
   10414              : 
   10415            0 :         destroyPQExpBuffer(query);
   10416            0 : }
   10417              : 
   10418              : /*
   10419              :  * getForeignDataWrappers:
   10420              :  *        get information about all foreign-data wrappers in the system catalogs
   10421              :  */
   10422              : void
   10423            0 : getForeignDataWrappers(Archive *fout)
   10424              : {
   10425            0 :         PGresult   *res;
   10426            0 :         int                     ntups;
   10427            0 :         int                     i;
   10428            0 :         PQExpBuffer query;
   10429            0 :         FdwInfo    *fdwinfo;
   10430            0 :         int                     i_tableoid;
   10431            0 :         int                     i_oid;
   10432            0 :         int                     i_fdwname;
   10433            0 :         int                     i_fdwowner;
   10434            0 :         int                     i_fdwhandler;
   10435            0 :         int                     i_fdwvalidator;
   10436            0 :         int                     i_fdwacl;
   10437            0 :         int                     i_acldefault;
   10438            0 :         int                     i_fdwoptions;
   10439              : 
   10440            0 :         query = createPQExpBuffer();
   10441              : 
   10442            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
   10443              :                                                  "fdwowner, "
   10444              :                                                  "fdwhandler::pg_catalog.regproc, "
   10445              :                                                  "fdwvalidator::pg_catalog.regproc, "
   10446              :                                                  "fdwacl, "
   10447              :                                                  "acldefault('F', fdwowner) AS acldefault, "
   10448              :                                                  "array_to_string(ARRAY("
   10449              :                                                  "SELECT quote_ident(option_name) || ' ' || "
   10450              :                                                  "quote_literal(option_value) "
   10451              :                                                  "FROM pg_options_to_table(fdwoptions) "
   10452              :                                                  "ORDER BY option_name"
   10453              :                                                  "), E',\n    ') AS fdwoptions "
   10454              :                                                  "FROM pg_foreign_data_wrapper");
   10455              : 
   10456            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10457              : 
   10458            0 :         ntups = PQntuples(res);
   10459              : 
   10460            0 :         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
   10461              : 
   10462            0 :         i_tableoid = PQfnumber(res, "tableoid");
   10463            0 :         i_oid = PQfnumber(res, "oid");
   10464            0 :         i_fdwname = PQfnumber(res, "fdwname");
   10465            0 :         i_fdwowner = PQfnumber(res, "fdwowner");
   10466            0 :         i_fdwhandler = PQfnumber(res, "fdwhandler");
   10467            0 :         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
   10468            0 :         i_fdwacl = PQfnumber(res, "fdwacl");
   10469            0 :         i_acldefault = PQfnumber(res, "acldefault");
   10470            0 :         i_fdwoptions = PQfnumber(res, "fdwoptions");
   10471              : 
   10472            0 :         for (i = 0; i < ntups; i++)
   10473              :         {
   10474            0 :                 fdwinfo[i].dobj.objType = DO_FDW;
   10475            0 :                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10476            0 :                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10477            0 :                 AssignDumpId(&fdwinfo[i].dobj);
   10478            0 :                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
   10479            0 :                 fdwinfo[i].dobj.namespace = NULL;
   10480            0 :                 fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
   10481            0 :                 fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10482            0 :                 fdwinfo[i].dacl.privtype = 0;
   10483            0 :                 fdwinfo[i].dacl.initprivs = NULL;
   10484            0 :                 fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
   10485            0 :                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
   10486            0 :                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
   10487            0 :                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
   10488              : 
   10489              :                 /* Decide whether we want to dump it */
   10490            0 :                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
   10491              : 
   10492              :                 /* Mark whether FDW has an ACL */
   10493            0 :                 if (!PQgetisnull(res, i, i_fdwacl))
   10494            0 :                         fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10495            0 :         }
   10496              : 
   10497            0 :         PQclear(res);
   10498              : 
   10499            0 :         destroyPQExpBuffer(query);
   10500            0 : }
   10501              : 
   10502              : /*
   10503              :  * getForeignServers:
   10504              :  *        get information about all foreign servers in the system catalogs
   10505              :  */
   10506              : void
   10507            0 : getForeignServers(Archive *fout)
   10508              : {
   10509            0 :         PGresult   *res;
   10510            0 :         int                     ntups;
   10511            0 :         int                     i;
   10512            0 :         PQExpBuffer query;
   10513            0 :         ForeignServerInfo *srvinfo;
   10514            0 :         int                     i_tableoid;
   10515            0 :         int                     i_oid;
   10516            0 :         int                     i_srvname;
   10517            0 :         int                     i_srvowner;
   10518            0 :         int                     i_srvfdw;
   10519            0 :         int                     i_srvtype;
   10520            0 :         int                     i_srvversion;
   10521            0 :         int                     i_srvacl;
   10522            0 :         int                     i_acldefault;
   10523            0 :         int                     i_srvoptions;
   10524              : 
   10525            0 :         query = createPQExpBuffer();
   10526              : 
   10527            0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
   10528              :                                                  "srvowner, "
   10529              :                                                  "srvfdw, srvtype, srvversion, srvacl, "
   10530              :                                                  "acldefault('S', srvowner) AS acldefault, "
   10531              :                                                  "array_to_string(ARRAY("
   10532              :                                                  "SELECT quote_ident(option_name) || ' ' || "
   10533              :                                                  "quote_literal(option_value) "
   10534              :                                                  "FROM pg_options_to_table(srvoptions) "
   10535              :                                                  "ORDER BY option_name"
   10536              :                                                  "), E',\n    ') AS srvoptions "
   10537              :                                                  "FROM pg_foreign_server");
   10538              : 
   10539            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10540              : 
   10541            0 :         ntups = PQntuples(res);
   10542              : 
   10543            0 :         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
   10544              : 
   10545            0 :         i_tableoid = PQfnumber(res, "tableoid");
   10546            0 :         i_oid = PQfnumber(res, "oid");
   10547            0 :         i_srvname = PQfnumber(res, "srvname");
   10548            0 :         i_srvowner = PQfnumber(res, "srvowner");
   10549            0 :         i_srvfdw = PQfnumber(res, "srvfdw");
   10550            0 :         i_srvtype = PQfnumber(res, "srvtype");
   10551            0 :         i_srvversion = PQfnumber(res, "srvversion");
   10552            0 :         i_srvacl = PQfnumber(res, "srvacl");
   10553            0 :         i_acldefault = PQfnumber(res, "acldefault");
   10554            0 :         i_srvoptions = PQfnumber(res, "srvoptions");
   10555              : 
   10556            0 :         for (i = 0; i < ntups; i++)
   10557              :         {
   10558            0 :                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
   10559            0 :                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10560            0 :                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10561            0 :                 AssignDumpId(&srvinfo[i].dobj);
   10562            0 :                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
   10563            0 :                 srvinfo[i].dobj.namespace = NULL;
   10564            0 :                 srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
   10565            0 :                 srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10566            0 :                 srvinfo[i].dacl.privtype = 0;
   10567            0 :                 srvinfo[i].dacl.initprivs = NULL;
   10568            0 :                 srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
   10569            0 :                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
   10570            0 :                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
   10571            0 :                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
   10572            0 :                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
   10573              : 
   10574              :                 /* Decide whether we want to dump it */
   10575            0 :                 selectDumpableObject(&(srvinfo[i].dobj), fout);
   10576              : 
   10577              :                 /* Servers have user mappings */
   10578            0 :                 srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
   10579              : 
   10580              :                 /* Mark whether server has an ACL */
   10581            0 :                 if (!PQgetisnull(res, i, i_srvacl))
   10582            0 :                         srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10583            0 :         }
   10584              : 
   10585            0 :         PQclear(res);
   10586              : 
   10587            0 :         destroyPQExpBuffer(query);
   10588            0 : }
   10589              : 
   10590              : /*
   10591              :  * getDefaultACLs:
   10592              :  *        get information about all default ACL information in the system catalogs
   10593              :  */
   10594              : void
   10595            0 : getDefaultACLs(Archive *fout)
   10596              : {
   10597            0 :         DumpOptions *dopt = fout->dopt;
   10598            0 :         DefaultACLInfo *daclinfo;
   10599            0 :         PQExpBuffer query;
   10600            0 :         PGresult   *res;
   10601            0 :         int                     i_oid;
   10602            0 :         int                     i_tableoid;
   10603            0 :         int                     i_defaclrole;
   10604            0 :         int                     i_defaclnamespace;
   10605            0 :         int                     i_defaclobjtype;
   10606            0 :         int                     i_defaclacl;
   10607            0 :         int                     i_acldefault;
   10608            0 :         int                     i,
   10609              :                                 ntups;
   10610              : 
   10611            0 :         query = createPQExpBuffer();
   10612              : 
   10613              :         /*
   10614              :          * Global entries (with defaclnamespace=0) replace the hard-wired default
   10615              :          * ACL for their object type.  We should dump them as deltas from the
   10616              :          * default ACL, since that will be used as a starting point for
   10617              :          * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
   10618              :          * non-global entries can only add privileges not revoke them.  We must
   10619              :          * dump those as-is (i.e., as deltas from an empty ACL).
   10620              :          *
   10621              :          * We can use defaclobjtype as the object type for acldefault(), except
   10622              :          * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
   10623              :          * 's'.
   10624              :          */
   10625            0 :         appendPQExpBufferStr(query,
   10626              :                                                  "SELECT oid, tableoid, "
   10627              :                                                  "defaclrole, "
   10628              :                                                  "defaclnamespace, "
   10629              :                                                  "defaclobjtype, "
   10630              :                                                  "defaclacl, "
   10631              :                                                  "CASE WHEN defaclnamespace = 0 THEN "
   10632              :                                                  "acldefault(CASE WHEN defaclobjtype = 'S' "
   10633              :                                                  "THEN 's'::\"char\" ELSE defaclobjtype END, "
   10634              :                                                  "defaclrole) ELSE '{}' END AS acldefault "
   10635              :                                                  "FROM pg_default_acl");
   10636              : 
   10637            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10638              : 
   10639            0 :         ntups = PQntuples(res);
   10640              : 
   10641            0 :         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
   10642              : 
   10643            0 :         i_oid = PQfnumber(res, "oid");
   10644            0 :         i_tableoid = PQfnumber(res, "tableoid");
   10645            0 :         i_defaclrole = PQfnumber(res, "defaclrole");
   10646            0 :         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10647            0 :         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10648            0 :         i_defaclacl = PQfnumber(res, "defaclacl");
   10649            0 :         i_acldefault = PQfnumber(res, "acldefault");
   10650              : 
   10651            0 :         for (i = 0; i < ntups; i++)
   10652              :         {
   10653            0 :                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10654              : 
   10655            0 :                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10656            0 :                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10657            0 :                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10658            0 :                 AssignDumpId(&daclinfo[i].dobj);
   10659              :                 /* cheesy ... is it worth coming up with a better object name? */
   10660            0 :                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10661              : 
   10662            0 :                 if (nspid != InvalidOid)
   10663            0 :                         daclinfo[i].dobj.namespace = findNamespace(nspid);
   10664              :                 else
   10665            0 :                         daclinfo[i].dobj.namespace = NULL;
   10666              : 
   10667            0 :                 daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10668            0 :                 daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10669            0 :                 daclinfo[i].dacl.privtype = 0;
   10670            0 :                 daclinfo[i].dacl.initprivs = NULL;
   10671            0 :                 daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10672            0 :                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10673              : 
   10674              :                 /* Default ACLs are ACLs, of course */
   10675            0 :                 daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10676              : 
   10677              :                 /* Decide whether we want to dump it */
   10678            0 :                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10679            0 :         }
   10680              : 
   10681            0 :         PQclear(res);
   10682              : 
   10683            0 :         destroyPQExpBuffer(query);
   10684            0 : }
   10685              : 
   10686              : /*
   10687              :  * getRoleName -- look up the name of a role, given its OID
   10688              :  *
   10689              :  * In current usage, we don't expect failures, so error out for a bad OID.
   10690              :  */
   10691              : static const char *
   10692            0 : getRoleName(const char *roleoid_str)
   10693              : {
   10694            0 :         Oid                     roleoid = atooid(roleoid_str);
   10695              : 
   10696              :         /*
   10697              :          * Do binary search to find the appropriate item.
   10698              :          */
   10699            0 :         if (nrolenames > 0)
   10700              :         {
   10701            0 :                 RoleNameItem *low = &rolenames[0];
   10702            0 :                 RoleNameItem *high = &rolenames[nrolenames - 1];
   10703              : 
   10704            0 :                 while (low <= high)
   10705              :                 {
   10706            0 :                         RoleNameItem *middle = low + (high - low) / 2;
   10707              : 
   10708            0 :                         if (roleoid < middle->roleoid)
   10709            0 :                                 high = middle - 1;
   10710            0 :                         else if (roleoid > middle->roleoid)
   10711            0 :                                 low = middle + 1;
   10712              :                         else
   10713            0 :                                 return middle->rolename;     /* found a match */
   10714            0 :                 }
   10715            0 :         }
   10716              : 
   10717            0 :         pg_fatal("role with OID %u does not exist", roleoid);
   10718            0 :         return NULL;                            /* keep compiler quiet */
   10719            0 : }
   10720              : 
   10721              : /*
   10722              :  * collectRoleNames --
   10723              :  *
   10724              :  * Construct a table of all known roles.
   10725              :  * The table is sorted by OID for speed in lookup.
   10726              :  */
   10727              : static void
   10728            0 : collectRoleNames(Archive *fout)
   10729              : {
   10730            0 :         PGresult   *res;
   10731            0 :         const char *query;
   10732            0 :         int                     i;
   10733              : 
   10734            0 :         query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10735              : 
   10736            0 :         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10737              : 
   10738            0 :         nrolenames = PQntuples(res);
   10739              : 
   10740            0 :         rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
   10741              : 
   10742            0 :         for (i = 0; i < nrolenames; i++)
   10743              :         {
   10744            0 :                 rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10745            0 :                 rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10746            0 :         }
   10747              : 
   10748            0 :         PQclear(res);
   10749            0 : }
   10750              : 
   10751              : /*
   10752              :  * getAdditionalACLs
   10753              :  *
   10754              :  * We have now created all the DumpableObjects, and collected the ACL data
   10755              :  * that appears in the directly-associated catalog entries.  However, there's
   10756              :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10757              :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10758              :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10759              :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10760              :  * information into the relevant DumpableObjects.
   10761              :  */
   10762              : static void
   10763            0 : getAdditionalACLs(Archive *fout)
   10764              : {
   10765            0 :         PQExpBuffer query = createPQExpBuffer();
   10766            0 :         PGresult   *res;
   10767            0 :         int                     ntups,
   10768              :                                 i;
   10769              : 
   10770              :         /* Check for per-column ACLs */
   10771            0 :         appendPQExpBufferStr(query,
   10772              :                                                  "SELECT DISTINCT attrelid FROM pg_attribute "
   10773              :                                                  "WHERE attacl IS NOT NULL");
   10774              : 
   10775            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10776              : 
   10777            0 :         ntups = PQntuples(res);
   10778            0 :         for (i = 0; i < ntups; i++)
   10779              :         {
   10780            0 :                 Oid                     relid = atooid(PQgetvalue(res, i, 0));
   10781            0 :                 TableInfo  *tblinfo;
   10782              : 
   10783            0 :                 tblinfo = findTableByOid(relid);
   10784              :                 /* OK to ignore tables we haven't got a DumpableObject for */
   10785            0 :                 if (tblinfo)
   10786              :                 {
   10787            0 :                         tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10788            0 :                         tblinfo->hascolumnACLs = true;
   10789            0 :                 }
   10790            0 :         }
   10791            0 :         PQclear(res);
   10792              : 
   10793              :         /* Fetch initial-privileges data */
   10794            0 :         if (fout->remoteVersion >= 90600)
   10795              :         {
   10796            0 :                 printfPQExpBuffer(query,
   10797              :                                                   "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10798              :                                                   "FROM pg_init_privs");
   10799              : 
   10800            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10801              : 
   10802            0 :                 ntups = PQntuples(res);
   10803            0 :                 for (i = 0; i < ntups; i++)
   10804              :                 {
   10805            0 :                         Oid                     objoid = atooid(PQgetvalue(res, i, 0));
   10806            0 :                         Oid                     classoid = atooid(PQgetvalue(res, i, 1));
   10807            0 :                         int                     objsubid = atoi(PQgetvalue(res, i, 2));
   10808            0 :                         char            privtype = *(PQgetvalue(res, i, 3));
   10809            0 :                         char       *initprivs = PQgetvalue(res, i, 4);
   10810            0 :                         CatalogId       objId;
   10811            0 :                         DumpableObject *dobj;
   10812              : 
   10813            0 :                         objId.tableoid = classoid;
   10814            0 :                         objId.oid = objoid;
   10815            0 :                         dobj = findObjectByCatalogId(objId);
   10816              :                         /* OK to ignore entries we haven't got a DumpableObject for */
   10817            0 :                         if (dobj)
   10818              :                         {
   10819              :                                 /* Cope with sub-object initprivs */
   10820            0 :                                 if (objsubid != 0)
   10821              :                                 {
   10822            0 :                                         if (dobj->objType == DO_TABLE)
   10823              :                                         {
   10824              :                                                 /* For a column initprivs, set the table's ACL flags */
   10825            0 :                                                 dobj->components |= DUMP_COMPONENT_ACL;
   10826            0 :                                                 ((TableInfo *) dobj)->hascolumnACLs = true;
   10827            0 :                                         }
   10828              :                                         else
   10829            0 :                                                 pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10830              :                                                                            classoid, objoid, objsubid);
   10831            0 :                                         continue;
   10832              :                                 }
   10833              : 
   10834              :                                 /*
   10835              :                                  * We ignore any pg_init_privs.initprivs entry for the public
   10836              :                                  * schema, as explained in getNamespaces().
   10837              :                                  */
   10838            0 :                                 if (dobj->objType == DO_NAMESPACE &&
   10839            0 :                                         strcmp(dobj->name, "public") == 0)
   10840            0 :                                         continue;
   10841              : 
   10842              :                                 /* Else it had better be of a type we think has ACLs */
   10843            0 :                                 if (dobj->objType == DO_NAMESPACE ||
   10844            0 :                                         dobj->objType == DO_TYPE ||
   10845            0 :                                         dobj->objType == DO_FUNC ||
   10846            0 :                                         dobj->objType == DO_AGG ||
   10847            0 :                                         dobj->objType == DO_TABLE ||
   10848            0 :                                         dobj->objType == DO_PROCLANG ||
   10849            0 :                                         dobj->objType == DO_FDW ||
   10850            0 :                                         dobj->objType == DO_FOREIGN_SERVER)
   10851              :                                 {
   10852            0 :                                         DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10853              : 
   10854            0 :                                         daobj->dacl.privtype = privtype;
   10855            0 :                                         daobj->dacl.initprivs = pstrdup(initprivs);
   10856            0 :                                 }
   10857              :                                 else
   10858            0 :                                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10859              :                                                                    classoid, objoid, objsubid);
   10860            0 :                         }
   10861            0 :                 }
   10862            0 :                 PQclear(res);
   10863            0 :         }
   10864              : 
   10865            0 :         destroyPQExpBuffer(query);
   10866            0 : }
   10867              : 
   10868              : /*
   10869              :  * dumpCommentExtended --
   10870              :  *
   10871              :  * This routine is used to dump any comments associated with the
   10872              :  * object handed to this routine. The routine takes the object type
   10873              :  * and object name (ready to print, except for schema decoration), plus
   10874              :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10875              :  * plus catalog ID and subid which are the lookup key for pg_description,
   10876              :  * plus the dump ID for the object (for setting a dependency).
   10877              :  * If a matching pg_description entry is found, it is dumped.
   10878              :  *
   10879              :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10880              :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10881              :  * but it doesn't seem worth complicating the API for all callers to make
   10882              :  * it cleaner.
   10883              :  *
   10884              :  * Note: although this routine takes a dumpId for dependency purposes,
   10885              :  * that purpose is just to mark the dependency in the emitted dump file
   10886              :  * for possible future use by pg_restore.  We do NOT use it for determining
   10887              :  * ordering of the comment in the dump file, because this routine is called
   10888              :  * after dependency sorting occurs.  This routine should be called just after
   10889              :  * calling ArchiveEntry() for the specified object.
   10890              :  */
   10891              : static void
   10892            0 : dumpCommentExtended(Archive *fout, const char *type,
   10893              :                                         const char *name, const char *namespace,
   10894              :                                         const char *owner, CatalogId catalogId,
   10895              :                                         int subid, DumpId dumpId,
   10896              :                                         const char *initdb_comment)
   10897              : {
   10898            0 :         DumpOptions *dopt = fout->dopt;
   10899            0 :         CommentItem *comments;
   10900            0 :         int                     ncomments;
   10901              : 
   10902              :         /* do nothing, if --no-comments is supplied */
   10903            0 :         if (dopt->no_comments)
   10904            0 :                 return;
   10905              : 
   10906              :         /* Comments are schema not data ... except LO comments are data */
   10907            0 :         if (strcmp(type, "LARGE OBJECT") != 0)
   10908              :         {
   10909            0 :                 if (!dopt->dumpSchema)
   10910            0 :                         return;
   10911            0 :         }
   10912              :         else
   10913              :         {
   10914              :                 /* We do dump LO comments in binary-upgrade mode */
   10915            0 :                 if (!dopt->dumpData && !dopt->binary_upgrade)
   10916            0 :                         return;
   10917              :         }
   10918              : 
   10919              :         /* Search for comments associated with catalogId, using table */
   10920            0 :         ncomments = findComments(catalogId.tableoid, catalogId.oid,
   10921              :                                                          &comments);
   10922              : 
   10923              :         /* Is there one matching the subid? */
   10924            0 :         while (ncomments > 0)
   10925              :         {
   10926            0 :                 if (comments->objsubid == subid)
   10927            0 :                         break;
   10928            0 :                 comments++;
   10929            0 :                 ncomments--;
   10930              :         }
   10931              : 
   10932            0 :         if (initdb_comment != NULL)
   10933              :         {
   10934              :                 static CommentItem empty_comment = {.descr = ""};
   10935              : 
   10936              :                 /*
   10937              :                  * initdb creates this object with a comment.  Skip dumping the
   10938              :                  * initdb-provided comment, which would complicate matters for
   10939              :                  * non-superuser use of pg_dump.  When the DBA has removed initdb's
   10940              :                  * comment, replicate that.
   10941              :                  */
   10942            0 :                 if (ncomments == 0)
   10943              :                 {
   10944            0 :                         comments = &empty_comment;
   10945            0 :                         ncomments = 1;
   10946            0 :                 }
   10947            0 :                 else if (strcmp(comments->descr, initdb_comment) == 0)
   10948            0 :                         ncomments = 0;
   10949            0 :         }
   10950              : 
   10951              :         /* If a comment exists, build COMMENT ON statement */
   10952            0 :         if (ncomments > 0)
   10953              :         {
   10954            0 :                 PQExpBuffer query = createPQExpBuffer();
   10955            0 :                 PQExpBuffer tag = createPQExpBuffer();
   10956              : 
   10957            0 :                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
   10958            0 :                 if (namespace && *namespace)
   10959            0 :                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
   10960            0 :                 appendPQExpBuffer(query, "%s IS ", name);
   10961            0 :                 appendStringLiteralAH(query, comments->descr, fout);
   10962            0 :                 appendPQExpBufferStr(query, ";\n");
   10963              : 
   10964            0 :                 appendPQExpBuffer(tag, "%s %s", type, name);
   10965              : 
   10966              :                 /*
   10967              :                  * We mark comments as SECTION_NONE because they really belong in the
   10968              :                  * same section as their parent, whether that is pre-data or
   10969              :                  * post-data.
   10970              :                  */
   10971            0 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10972            0 :                                          ARCHIVE_OPTS(.tag = tag->data,
   10973              :                                                                   .namespace = namespace,
   10974              :                                                                   .owner = owner,
   10975              :                                                                   .description = "COMMENT",
   10976              :                                                                   .section = SECTION_NONE,
   10977              :                                                                   .createStmt = query->data,
   10978              :                                                                   .deps = &dumpId,
   10979              :                                                                   .nDeps = 1));
   10980              : 
   10981            0 :                 destroyPQExpBuffer(query);
   10982            0 :                 destroyPQExpBuffer(tag);
   10983            0 :         }
   10984            0 : }
   10985              : 
   10986              : /*
   10987              :  * dumpComment --
   10988              :  *
   10989              :  * Typical simplification of the above function.
   10990              :  */
   10991              : static inline void
   10992            0 : dumpComment(Archive *fout, const char *type,
   10993              :                         const char *name, const char *namespace,
   10994              :                         const char *owner, CatalogId catalogId,
   10995              :                         int subid, DumpId dumpId)
   10996              : {
   10997            0 :         dumpCommentExtended(fout, type, name, namespace, owner,
   10998            0 :                                                 catalogId, subid, dumpId, NULL);
   10999            0 : }
   11000              : 
   11001              : /*
   11002              :  * appendNamedArgument --
   11003              :  *
   11004              :  * Convenience routine for constructing parameters of the form:
   11005              :  * 'paraname', 'value'::type
   11006              :  */
   11007              : static void
   11008            0 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   11009              :                                         const char *argtype, const char *argval)
   11010              : {
   11011            0 :         appendPQExpBufferStr(out, ",\n\t");
   11012              : 
   11013            0 :         appendStringLiteralAH(out, argname, fout);
   11014            0 :         appendPQExpBufferStr(out, ", ");
   11015              : 
   11016            0 :         appendStringLiteralAH(out, argval, fout);
   11017            0 :         appendPQExpBuffer(out, "::%s", argtype);
   11018            0 : }
   11019              : 
   11020              : /*
   11021              :  * fetchAttributeStats --
   11022              :  *
   11023              :  * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
   11024              :  */
   11025              : static PGresult *
   11026            0 : fetchAttributeStats(Archive *fout)
   11027              : {
   11028            0 :         ArchiveHandle *AH = (ArchiveHandle *) fout;
   11029            0 :         PQExpBuffer nspnames = createPQExpBuffer();
   11030            0 :         PQExpBuffer relnames = createPQExpBuffer();
   11031            0 :         int                     count = 0;
   11032            0 :         PGresult   *res = NULL;
   11033              :         static TocEntry *te;
   11034              :         static bool restarted;
   11035            0 :         int                     max_rels = MAX_ATTR_STATS_RELS;
   11036              : 
   11037              :         /*
   11038              :          * Our query for retrieving statistics for multiple relations uses WITH
   11039              :          * ORDINALITY and multi-argument UNNEST(), both of which were introduced
   11040              :          * in v9.4.  For older versions, we resort to gathering statistics for a
   11041              :          * single relation at a time.
   11042              :          */
   11043            0 :         if (fout->remoteVersion < 90400)
   11044            0 :                 max_rels = 1;
   11045              : 
   11046              :         /* If we're just starting, set our TOC pointer. */
   11047            0 :         if (!te)
   11048            0 :                 te = AH->toc->next;
   11049              : 
   11050              :         /*
   11051              :          * We can't easily avoid a second TOC scan for the tar format because it
   11052              :          * writes restore.sql separately, which means we must execute the queries
   11053              :          * twice.  This feels risky, but there is no known reason it should
   11054              :          * generate different output than the first pass.  Even if it does, the
   11055              :          * worst-case scenario is that restore.sql might have different statistics
   11056              :          * data than the archive.
   11057              :          */
   11058            0 :         if (!restarted && te == AH->toc && AH->format == archTar)
   11059              :         {
   11060            0 :                 te = AH->toc->next;
   11061            0 :                 restarted = true;
   11062            0 :         }
   11063              : 
   11064            0 :         appendPQExpBufferChar(nspnames, '{');
   11065            0 :         appendPQExpBufferChar(relnames, '{');
   11066              : 
   11067              :         /*
   11068              :          * Scan the TOC for the next set of relevant stats entries.  We assume
   11069              :          * that statistics are dumped in the order they are listed in the TOC.
   11070              :          * This is perhaps not the sturdiest assumption, so we verify it matches
   11071              :          * reality in dumpRelationStats_dumper().
   11072              :          */
   11073            0 :         for (; te != AH->toc && count < max_rels; te = te->next)
   11074              :         {
   11075            0 :                 if ((te->reqs & REQ_STATS) != 0 &&
   11076            0 :                         strcmp(te->desc, "STATISTICS DATA") == 0)
   11077              :                 {
   11078            0 :                         appendPGArray(nspnames, te->namespace);
   11079            0 :                         appendPGArray(relnames, te->tag);
   11080            0 :                         count++;
   11081            0 :                 }
   11082            0 :         }
   11083              : 
   11084            0 :         appendPQExpBufferChar(nspnames, '}');
   11085            0 :         appendPQExpBufferChar(relnames, '}');
   11086              : 
   11087              :         /* Execute the query for the next batch of relations. */
   11088            0 :         if (count > 0)
   11089              :         {
   11090            0 :                 PQExpBuffer query = createPQExpBuffer();
   11091              : 
   11092            0 :                 appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
   11093            0 :                 appendStringLiteralAH(query, nspnames->data, fout);
   11094            0 :                 appendPQExpBufferStr(query, "::pg_catalog.name[],");
   11095            0 :                 appendStringLiteralAH(query, relnames->data, fout);
   11096            0 :                 appendPQExpBufferStr(query, "::pg_catalog.name[])");
   11097            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11098            0 :                 destroyPQExpBuffer(query);
   11099            0 :         }
   11100              : 
   11101            0 :         destroyPQExpBuffer(nspnames);
   11102            0 :         destroyPQExpBuffer(relnames);
   11103            0 :         return res;
   11104            0 : }
   11105              : 
   11106              : /*
   11107              :  * dumpRelationStats_dumper --
   11108              :  *
   11109              :  * Generate command to import stats into the relation on the new database.
   11110              :  * This routine is called by the Archiver when it wants the statistics to be
   11111              :  * dumped.
   11112              :  */
   11113              : static char *
   11114            0 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
   11115              : {
   11116            0 :         const RelStatsInfo *rsinfo = userArg;
   11117              :         static PGresult *res;
   11118              :         static int      rownum;
   11119            0 :         PQExpBuffer query;
   11120            0 :         PQExpBufferData out_data;
   11121            0 :         PQExpBuffer out = &out_data;
   11122            0 :         int                     i_schemaname;
   11123            0 :         int                     i_tablename;
   11124            0 :         int                     i_attname;
   11125            0 :         int                     i_inherited;
   11126            0 :         int                     i_null_frac;
   11127            0 :         int                     i_avg_width;
   11128            0 :         int                     i_n_distinct;
   11129            0 :         int                     i_most_common_vals;
   11130            0 :         int                     i_most_common_freqs;
   11131            0 :         int                     i_histogram_bounds;
   11132            0 :         int                     i_correlation;
   11133            0 :         int                     i_most_common_elems;
   11134            0 :         int                     i_most_common_elem_freqs;
   11135            0 :         int                     i_elem_count_histogram;
   11136            0 :         int                     i_range_length_histogram;
   11137            0 :         int                     i_range_empty_frac;
   11138            0 :         int                     i_range_bounds_histogram;
   11139              :         static TocEntry *expected_te;
   11140              : 
   11141              :         /*
   11142              :          * fetchAttributeStats() assumes that the statistics are dumped in the
   11143              :          * order they are listed in the TOC.  We verify that here for safety.
   11144              :          */
   11145            0 :         if (!expected_te)
   11146            0 :                 expected_te = ((ArchiveHandle *) fout)->toc;
   11147              : 
   11148            0 :         expected_te = expected_te->next;
   11149            0 :         while ((expected_te->reqs & REQ_STATS) == 0 ||
   11150            0 :                    strcmp(expected_te->desc, "STATISTICS DATA") != 0)
   11151            0 :                 expected_te = expected_te->next;
   11152              : 
   11153            0 :         if (te != expected_te)
   11154            0 :                 pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
   11155              :                                  te->dumpId, te->desc, te->tag,
   11156              :                                  expected_te->dumpId, expected_te->desc, expected_te->tag);
   11157              : 
   11158            0 :         query = createPQExpBuffer();
   11159            0 :         if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
   11160              :         {
   11161            0 :                 appendPQExpBufferStr(query,
   11162              :                                                          "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n"
   11163              :                                                          "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
   11164              :                                                          "s.null_frac, s.avg_width, s.n_distinct, "
   11165              :                                                          "s.most_common_vals, s.most_common_freqs, "
   11166              :                                                          "s.histogram_bounds, s.correlation, "
   11167              :                                                          "s.most_common_elems, s.most_common_elem_freqs, "
   11168              :                                                          "s.elem_count_histogram, ");
   11169              : 
   11170            0 :                 if (fout->remoteVersion >= 170000)
   11171            0 :                         appendPQExpBufferStr(query,
   11172              :                                                                  "s.range_length_histogram, "
   11173              :                                                                  "s.range_empty_frac, "
   11174              :                                                                  "s.range_bounds_histogram ");
   11175              :                 else
   11176            0 :                         appendPQExpBufferStr(query,
   11177              :                                                                  "NULL AS range_length_histogram,"
   11178              :                                                                  "NULL AS range_empty_frac,"
   11179              :                                                                  "NULL AS range_bounds_histogram ");
   11180              : 
   11181              :                 /*
   11182              :                  * The results must be in the order of the relations supplied in the
   11183              :                  * parameters to ensure we remain in sync as we walk through the TOC.
   11184              :                  * The redundant filter clause on s.tablename = ANY(...) seems
   11185              :                  * sufficient to convince the planner to use
   11186              :                  * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
   11187              :                  * This may not work for all versions.
   11188              :                  *
   11189              :                  * Our query for retrieving statistics for multiple relations uses
   11190              :                  * WITH ORDINALITY and multi-argument UNNEST(), both of which were
   11191              :                  * introduced in v9.4.  For older versions, we resort to gathering
   11192              :                  * statistics for a single relation at a time.
   11193              :                  */
   11194            0 :                 if (fout->remoteVersion >= 90400)
   11195            0 :                         appendPQExpBufferStr(query,
   11196              :                                                                  "FROM pg_catalog.pg_stats s "
   11197              :                                                                  "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
   11198              :                                                                  "ON s.schemaname = u.schemaname "
   11199              :                                                                  "AND s.tablename = u.tablename "
   11200              :                                                                  "WHERE s.tablename = ANY($2) "
   11201              :                                                                  "ORDER BY u.ord, s.attname, s.inherited");
   11202              :                 else
   11203            0 :                         appendPQExpBufferStr(query,
   11204              :                                                                  "FROM pg_catalog.pg_stats s "
   11205              :                                                                  "WHERE s.schemaname = $1[1] "
   11206              :                                                                  "AND s.tablename = $2[1] "
   11207              :                                                                  "ORDER BY s.attname, s.inherited");
   11208              : 
   11209            0 :                 ExecuteSqlStatement(fout, query->data);
   11210              : 
   11211            0 :                 fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
   11212            0 :                 resetPQExpBuffer(query);
   11213            0 :         }
   11214              : 
   11215            0 :         initPQExpBuffer(out);
   11216              : 
   11217              :         /* restore relation stats */
   11218            0 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   11219            0 :         appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11220            0 :                                           fout->remoteVersion);
   11221            0 :         appendPQExpBufferStr(out, "\t'schemaname', ");
   11222            0 :         appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11223            0 :         appendPQExpBufferStr(out, ",\n");
   11224            0 :         appendPQExpBufferStr(out, "\t'relname', ");
   11225            0 :         appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11226            0 :         appendPQExpBufferStr(out, ",\n");
   11227            0 :         appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
   11228              : 
   11229              :         /*
   11230              :          * Before v14, a reltuples value of 0 was ambiguous: it could either mean
   11231              :          * the relation is empty, or it could mean that it hadn't yet been
   11232              :          * vacuumed or analyzed.  (Newer versions use -1 for the latter case.)
   11233              :          * This ambiguity allegedly can cause the planner to choose inefficient
   11234              :          * plans after restoring to v18 or newer.  To deal with this, let's just
   11235              :          * set reltuples to -1 in that case.
   11236              :          */
   11237            0 :         if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
   11238            0 :                 appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
   11239              :         else
   11240            0 :                 appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
   11241              : 
   11242            0 :         appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
   11243            0 :                                           rsinfo->relallvisible);
   11244              : 
   11245            0 :         if (fout->remoteVersion >= 180000)
   11246            0 :                 appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
   11247              : 
   11248            0 :         appendPQExpBufferStr(out, "\n);\n");
   11249              : 
   11250              :         /* Fetch the next batch of attribute statistics if needed. */
   11251            0 :         if (rownum >= PQntuples(res))
   11252              :         {
   11253            0 :                 PQclear(res);
   11254            0 :                 res = fetchAttributeStats(fout);
   11255            0 :                 rownum = 0;
   11256            0 :         }
   11257              : 
   11258            0 :         i_schemaname = PQfnumber(res, "schemaname");
   11259            0 :         i_tablename = PQfnumber(res, "tablename");
   11260            0 :         i_attname = PQfnumber(res, "attname");
   11261            0 :         i_inherited = PQfnumber(res, "inherited");
   11262            0 :         i_null_frac = PQfnumber(res, "null_frac");
   11263            0 :         i_avg_width = PQfnumber(res, "avg_width");
   11264            0 :         i_n_distinct = PQfnumber(res, "n_distinct");
   11265            0 :         i_most_common_vals = PQfnumber(res, "most_common_vals");
   11266            0 :         i_most_common_freqs = PQfnumber(res, "most_common_freqs");
   11267            0 :         i_histogram_bounds = PQfnumber(res, "histogram_bounds");
   11268            0 :         i_correlation = PQfnumber(res, "correlation");
   11269            0 :         i_most_common_elems = PQfnumber(res, "most_common_elems");
   11270            0 :         i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
   11271            0 :         i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
   11272            0 :         i_range_length_histogram = PQfnumber(res, "range_length_histogram");
   11273            0 :         i_range_empty_frac = PQfnumber(res, "range_empty_frac");
   11274            0 :         i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
   11275              : 
   11276              :         /* restore attribute stats */
   11277            0 :         for (; rownum < PQntuples(res); rownum++)
   11278              :         {
   11279            0 :                 const char *attname;
   11280              : 
   11281              :                 /* Stop if the next stat row in our cache isn't for this relation. */
   11282            0 :                 if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
   11283            0 :                         strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
   11284            0 :                         break;
   11285              : 
   11286            0 :                 appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   11287            0 :                 appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11288            0 :                                                   fout->remoteVersion);
   11289            0 :                 appendPQExpBufferStr(out, "\t'schemaname', ");
   11290            0 :                 appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11291            0 :                 appendPQExpBufferStr(out, ",\n\t'relname', ");
   11292            0 :                 appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11293              : 
   11294            0 :                 if (PQgetisnull(res, rownum, i_attname))
   11295            0 :                         pg_fatal("unexpected null attname");
   11296            0 :                 attname = PQgetvalue(res, rownum, i_attname);
   11297              : 
   11298              :                 /*
   11299              :                  * Indexes look up attname in indAttNames to derive attnum, all others
   11300              :                  * use attname directly.  We must specify attnum for indexes, since
   11301              :                  * their attnames are not necessarily stable across dump/reload.
   11302              :                  */
   11303            0 :                 if (rsinfo->nindAttNames == 0)
   11304              :                 {
   11305            0 :                         appendPQExpBufferStr(out, ",\n\t'attname', ");
   11306            0 :                         appendStringLiteralAH(out, attname, fout);
   11307            0 :                 }
   11308              :                 else
   11309              :                 {
   11310            0 :                         bool            found = false;
   11311              : 
   11312            0 :                         for (int i = 0; i < rsinfo->nindAttNames; i++)
   11313              :                         {
   11314            0 :                                 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
   11315              :                                 {
   11316            0 :                                         appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
   11317            0 :                                                                           i + 1);
   11318            0 :                                         found = true;
   11319            0 :                                         break;
   11320              :                                 }
   11321            0 :                         }
   11322              : 
   11323            0 :                         if (!found)
   11324            0 :                                 pg_fatal("could not find index attname \"%s\"", attname);
   11325            0 :                 }
   11326              : 
   11327            0 :                 if (!PQgetisnull(res, rownum, i_inherited))
   11328            0 :                         appendNamedArgument(out, fout, "inherited", "boolean",
   11329            0 :                                                                 PQgetvalue(res, rownum, i_inherited));
   11330            0 :                 if (!PQgetisnull(res, rownum, i_null_frac))
   11331            0 :                         appendNamedArgument(out, fout, "null_frac", "real",
   11332            0 :                                                                 PQgetvalue(res, rownum, i_null_frac));
   11333            0 :                 if (!PQgetisnull(res, rownum, i_avg_width))
   11334            0 :                         appendNamedArgument(out, fout, "avg_width", "integer",
   11335            0 :                                                                 PQgetvalue(res, rownum, i_avg_width));
   11336            0 :                 if (!PQgetisnull(res, rownum, i_n_distinct))
   11337            0 :                         appendNamedArgument(out, fout, "n_distinct", "real",
   11338            0 :                                                                 PQgetvalue(res, rownum, i_n_distinct));
   11339            0 :                 if (!PQgetisnull(res, rownum, i_most_common_vals))
   11340            0 :                         appendNamedArgument(out, fout, "most_common_vals", "text",
   11341            0 :                                                                 PQgetvalue(res, rownum, i_most_common_vals));
   11342            0 :                 if (!PQgetisnull(res, rownum, i_most_common_freqs))
   11343            0 :                         appendNamedArgument(out, fout, "most_common_freqs", "real[]",
   11344            0 :                                                                 PQgetvalue(res, rownum, i_most_common_freqs));
   11345            0 :                 if (!PQgetisnull(res, rownum, i_histogram_bounds))
   11346            0 :                         appendNamedArgument(out, fout, "histogram_bounds", "text",
   11347            0 :                                                                 PQgetvalue(res, rownum, i_histogram_bounds));
   11348            0 :                 if (!PQgetisnull(res, rownum, i_correlation))
   11349            0 :                         appendNamedArgument(out, fout, "correlation", "real",
   11350            0 :                                                                 PQgetvalue(res, rownum, i_correlation));
   11351            0 :                 if (!PQgetisnull(res, rownum, i_most_common_elems))
   11352            0 :                         appendNamedArgument(out, fout, "most_common_elems", "text",
   11353            0 :                                                                 PQgetvalue(res, rownum, i_most_common_elems));
   11354            0 :                 if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
   11355            0 :                         appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
   11356            0 :                                                                 PQgetvalue(res, rownum, i_most_common_elem_freqs));
   11357            0 :                 if (!PQgetisnull(res, rownum, i_elem_count_histogram))
   11358            0 :                         appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
   11359            0 :                                                                 PQgetvalue(res, rownum, i_elem_count_histogram));
   11360            0 :                 if (fout->remoteVersion >= 170000)
   11361              :                 {
   11362            0 :                         if (!PQgetisnull(res, rownum, i_range_length_histogram))
   11363            0 :                                 appendNamedArgument(out, fout, "range_length_histogram", "text",
   11364            0 :                                                                         PQgetvalue(res, rownum, i_range_length_histogram));
   11365            0 :                         if (!PQgetisnull(res, rownum, i_range_empty_frac))
   11366            0 :                                 appendNamedArgument(out, fout, "range_empty_frac", "real",
   11367            0 :                                                                         PQgetvalue(res, rownum, i_range_empty_frac));
   11368            0 :                         if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
   11369            0 :                                 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
   11370            0 :                                                                         PQgetvalue(res, rownum, i_range_bounds_histogram));
   11371            0 :                 }
   11372            0 :                 appendPQExpBufferStr(out, "\n);\n");
   11373            0 :         }
   11374              : 
   11375            0 :         destroyPQExpBuffer(query);
   11376            0 :         return out->data;
   11377            0 : }
   11378              : 
   11379              : /*
   11380              :  * dumpRelationStats --
   11381              :  *
   11382              :  * Make an ArchiveEntry for the relation statistics.  The Archiver will take
   11383              :  * care of gathering the statistics and generating the restore commands when
   11384              :  * they are needed.
   11385              :  */
   11386              : static void
   11387            0 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   11388              : {
   11389            0 :         const DumpableObject *dobj = &rsinfo->dobj;
   11390              : 
   11391              :         /* nothing to do if we are not dumping statistics */
   11392            0 :         if (!fout->dopt->dumpStatistics)
   11393            0 :                 return;
   11394              : 
   11395            0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11396            0 :                                  ARCHIVE_OPTS(.tag = dobj->name,
   11397              :                                                           .namespace = dobj->namespace->dobj.name,
   11398              :                                                           .description = "STATISTICS DATA",
   11399              :                                                           .section = rsinfo->section,
   11400              :                                                           .defnFn = dumpRelationStats_dumper,
   11401              :                                                           .defnArg = rsinfo,
   11402              :                                                           .deps = dobj->dependencies,
   11403              :                                                           .nDeps = dobj->nDeps));
   11404            0 : }
   11405              : 
   11406              : /*
   11407              :  * dumpTableComment --
   11408              :  *
   11409              :  * As above, but dump comments for both the specified table (or view)
   11410              :  * and its columns.
   11411              :  */
   11412              : static void
   11413            0 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   11414              :                                  const char *reltypename)
   11415              : {
   11416            0 :         DumpOptions *dopt = fout->dopt;
   11417            0 :         CommentItem *comments;
   11418            0 :         int                     ncomments;
   11419            0 :         PQExpBuffer query;
   11420            0 :         PQExpBuffer tag;
   11421              : 
   11422              :         /* do nothing, if --no-comments is supplied */
   11423            0 :         if (dopt->no_comments)
   11424            0 :                 return;
   11425              : 
   11426              :         /* Comments are SCHEMA not data */
   11427            0 :         if (!dopt->dumpSchema)
   11428            0 :                 return;
   11429              : 
   11430              :         /* Search for comments associated with relation, using table */
   11431            0 :         ncomments = findComments(tbinfo->dobj.catId.tableoid,
   11432            0 :                                                          tbinfo->dobj.catId.oid,
   11433              :                                                          &comments);
   11434              : 
   11435              :         /* If comments exist, build COMMENT ON statements */
   11436            0 :         if (ncomments <= 0)
   11437            0 :                 return;
   11438              : 
   11439            0 :         query = createPQExpBuffer();
   11440            0 :         tag = createPQExpBuffer();
   11441              : 
   11442            0 :         while (ncomments > 0)
   11443              :         {
   11444            0 :                 const char *descr = comments->descr;
   11445            0 :                 int                     objsubid = comments->objsubid;
   11446              : 
   11447            0 :                 if (objsubid == 0)
   11448              :                 {
   11449            0 :                         resetPQExpBuffer(tag);
   11450            0 :                         appendPQExpBuffer(tag, "%s %s", reltypename,
   11451            0 :                                                           fmtId(tbinfo->dobj.name));
   11452              : 
   11453            0 :                         resetPQExpBuffer(query);
   11454            0 :                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   11455            0 :                                                           fmtQualifiedDumpable(tbinfo));
   11456            0 :                         appendStringLiteralAH(query, descr, fout);
   11457            0 :                         appendPQExpBufferStr(query, ";\n");
   11458              : 
   11459            0 :                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11460            0 :                                                  ARCHIVE_OPTS(.tag = tag->data,
   11461              :                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   11462              :                                                                           .owner = tbinfo->rolname,
   11463              :                                                                           .description = "COMMENT",
   11464              :                                                                           .section = SECTION_NONE,
   11465              :                                                                           .createStmt = query->data,
   11466              :                                                                           .deps = &(tbinfo->dobj.dumpId),
   11467              :                                                                           .nDeps = 1));
   11468            0 :                 }
   11469            0 :                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   11470              :                 {
   11471            0 :                         resetPQExpBuffer(tag);
   11472            0 :                         appendPQExpBuffer(tag, "COLUMN %s.",
   11473            0 :                                                           fmtId(tbinfo->dobj.name));
   11474            0 :                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   11475              : 
   11476            0 :                         resetPQExpBuffer(query);
   11477            0 :                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   11478            0 :                                                           fmtQualifiedDumpable(tbinfo));
   11479            0 :                         appendPQExpBuffer(query, "%s IS ",
   11480            0 :                                                           fmtId(tbinfo->attnames[objsubid - 1]));
   11481            0 :                         appendStringLiteralAH(query, descr, fout);
   11482            0 :                         appendPQExpBufferStr(query, ";\n");
   11483              : 
   11484            0 :                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11485            0 :                                                  ARCHIVE_OPTS(.tag = tag->data,
   11486              :                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   11487              :                                                                           .owner = tbinfo->rolname,
   11488              :                                                                           .description = "COMMENT",
   11489              :                                                                           .section = SECTION_NONE,
   11490              :                                                                           .createStmt = query->data,
   11491              :                                                                           .deps = &(tbinfo->dobj.dumpId),
   11492              :                                                                           .nDeps = 1));
   11493            0 :                 }
   11494              : 
   11495            0 :                 comments++;
   11496            0 :                 ncomments--;
   11497            0 :         }
   11498              : 
   11499            0 :         destroyPQExpBuffer(query);
   11500            0 :         destroyPQExpBuffer(tag);
   11501            0 : }
   11502              : 
   11503              : /*
   11504              :  * findComments --
   11505              :  *
   11506              :  * Find the comment(s), if any, associated with the given object.  All the
   11507              :  * objsubid values associated with the given classoid/objoid are found with
   11508              :  * one search.
   11509              :  */
   11510              : static int
   11511            0 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   11512              : {
   11513            0 :         CommentItem *middle = NULL;
   11514            0 :         CommentItem *low;
   11515            0 :         CommentItem *high;
   11516            0 :         int                     nmatch;
   11517              : 
   11518              :         /*
   11519              :          * Do binary search to find some item matching the object.
   11520              :          */
   11521            0 :         low = &comments[0];
   11522            0 :         high = &comments[ncomments - 1];
   11523            0 :         while (low <= high)
   11524              :         {
   11525            0 :                 middle = low + (high - low) / 2;
   11526              : 
   11527            0 :                 if (classoid < middle->classoid)
   11528            0 :                         high = middle - 1;
   11529            0 :                 else if (classoid > middle->classoid)
   11530            0 :                         low = middle + 1;
   11531            0 :                 else if (objoid < middle->objoid)
   11532            0 :                         high = middle - 1;
   11533            0 :                 else if (objoid > middle->objoid)
   11534            0 :                         low = middle + 1;
   11535              :                 else
   11536            0 :                         break;                          /* found a match */
   11537              :         }
   11538              : 
   11539            0 :         if (low > high)                              /* no matches */
   11540              :         {
   11541            0 :                 *items = NULL;
   11542            0 :                 return 0;
   11543              :         }
   11544              : 
   11545              :         /*
   11546              :          * Now determine how many items match the object.  The search loop
   11547              :          * invariant still holds: only items between low and high inclusive could
   11548              :          * match.
   11549              :          */
   11550            0 :         nmatch = 1;
   11551            0 :         while (middle > low)
   11552              :         {
   11553            0 :                 if (classoid != middle[-1].classoid ||
   11554            0 :                         objoid != middle[-1].objoid)
   11555            0 :                         break;
   11556            0 :                 middle--;
   11557            0 :                 nmatch++;
   11558              :         }
   11559              : 
   11560            0 :         *items = middle;
   11561              : 
   11562            0 :         middle += nmatch;
   11563            0 :         while (middle <= high)
   11564              :         {
   11565            0 :                 if (classoid != middle->classoid ||
   11566            0 :                         objoid != middle->objoid)
   11567            0 :                         break;
   11568            0 :                 middle++;
   11569            0 :                 nmatch++;
   11570              :         }
   11571              : 
   11572            0 :         return nmatch;
   11573            0 : }
   11574              : 
   11575              : /*
   11576              :  * collectComments --
   11577              :  *
   11578              :  * Construct a table of all comments available for database objects;
   11579              :  * also set the has-comment component flag for each relevant object.
   11580              :  *
   11581              :  * We used to do per-object queries for the comments, but it's much faster
   11582              :  * to pull them all over at once, and on most databases the memory cost
   11583              :  * isn't high.
   11584              :  *
   11585              :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   11586              :  */
   11587              : static void
   11588            0 : collectComments(Archive *fout)
   11589              : {
   11590            0 :         PGresult   *res;
   11591            0 :         PQExpBuffer query;
   11592            0 :         int                     i_description;
   11593            0 :         int                     i_classoid;
   11594            0 :         int                     i_objoid;
   11595            0 :         int                     i_objsubid;
   11596            0 :         int                     ntups;
   11597            0 :         int                     i;
   11598            0 :         DumpableObject *dobj;
   11599              : 
   11600            0 :         query = createPQExpBuffer();
   11601              : 
   11602            0 :         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   11603              :                                                  "FROM pg_catalog.pg_description "
   11604              :                                                  "ORDER BY classoid, objoid, objsubid");
   11605              : 
   11606            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11607              : 
   11608              :         /* Construct lookup table containing OIDs in numeric form */
   11609              : 
   11610            0 :         i_description = PQfnumber(res, "description");
   11611            0 :         i_classoid = PQfnumber(res, "classoid");
   11612            0 :         i_objoid = PQfnumber(res, "objoid");
   11613            0 :         i_objsubid = PQfnumber(res, "objsubid");
   11614              : 
   11615            0 :         ntups = PQntuples(res);
   11616              : 
   11617            0 :         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
   11618            0 :         ncomments = 0;
   11619            0 :         dobj = NULL;
   11620              : 
   11621            0 :         for (i = 0; i < ntups; i++)
   11622              :         {
   11623            0 :                 CatalogId       objId;
   11624            0 :                 int                     subid;
   11625              : 
   11626            0 :                 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   11627            0 :                 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   11628            0 :                 subid = atoi(PQgetvalue(res, i, i_objsubid));
   11629              : 
   11630              :                 /* We needn't remember comments that don't match any dumpable object */
   11631            0 :                 if (dobj == NULL ||
   11632            0 :                         dobj->catId.tableoid != objId.tableoid ||
   11633            0 :                         dobj->catId.oid != objId.oid)
   11634            0 :                         dobj = findObjectByCatalogId(objId);
   11635            0 :                 if (dobj == NULL)
   11636            0 :                         continue;
   11637              : 
   11638              :                 /*
   11639              :                  * Comments on columns of composite types are linked to the type's
   11640              :                  * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   11641              :                  * in the type's own DumpableObject.
   11642              :                  */
   11643            0 :                 if (subid != 0 && dobj->objType == DO_TABLE &&
   11644            0 :                         ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   11645              :                 {
   11646            0 :                         TypeInfo   *cTypeInfo;
   11647              : 
   11648            0 :                         cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   11649            0 :                         if (cTypeInfo)
   11650            0 :                                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   11651            0 :                 }
   11652              :                 else
   11653            0 :                         dobj->components |= DUMP_COMPONENT_COMMENT;
   11654              : 
   11655            0 :                 comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   11656            0 :                 comments[ncomments].classoid = objId.tableoid;
   11657            0 :                 comments[ncomments].objoid = objId.oid;
   11658            0 :                 comments[ncomments].objsubid = subid;
   11659            0 :                 ncomments++;
   11660            0 :         }
   11661              : 
   11662            0 :         PQclear(res);
   11663            0 :         destroyPQExpBuffer(query);
   11664            0 : }
   11665              : 
   11666              : /*
   11667              :  * dumpDumpableObject
   11668              :  *
   11669              :  * This routine and its subsidiaries are responsible for creating
   11670              :  * ArchiveEntries (TOC objects) for each object to be dumped.
   11671              :  */
   11672              : static void
   11673            0 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   11674              : {
   11675              :         /*
   11676              :          * Clear any dump-request bits for components that don't exist for this
   11677              :          * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   11678              :          * request for every kind of object.)
   11679              :          */
   11680            0 :         dobj->dump &= dobj->components;
   11681              : 
   11682              :         /* Now, short-circuit if there's nothing to be done here. */
   11683            0 :         if (dobj->dump == 0)
   11684            0 :                 return;
   11685              : 
   11686            0 :         switch (dobj->objType)
   11687              :         {
   11688              :                 case DO_NAMESPACE:
   11689            0 :                         dumpNamespace(fout, (const NamespaceInfo *) dobj);
   11690            0 :                         break;
   11691              :                 case DO_EXTENSION:
   11692            0 :                         dumpExtension(fout, (const ExtensionInfo *) dobj);
   11693            0 :                         break;
   11694              :                 case DO_TYPE:
   11695            0 :                         dumpType(fout, (const TypeInfo *) dobj);
   11696            0 :                         break;
   11697              :                 case DO_SHELL_TYPE:
   11698            0 :                         dumpShellType(fout, (const ShellTypeInfo *) dobj);
   11699            0 :                         break;
   11700              :                 case DO_FUNC:
   11701            0 :                         dumpFunc(fout, (const FuncInfo *) dobj);
   11702            0 :                         break;
   11703              :                 case DO_AGG:
   11704            0 :                         dumpAgg(fout, (const AggInfo *) dobj);
   11705            0 :                         break;
   11706              :                 case DO_OPERATOR:
   11707            0 :                         dumpOpr(fout, (const OprInfo *) dobj);
   11708            0 :                         break;
   11709              :                 case DO_ACCESS_METHOD:
   11710            0 :                         dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   11711            0 :                         break;
   11712              :                 case DO_OPCLASS:
   11713            0 :                         dumpOpclass(fout, (const OpclassInfo *) dobj);
   11714            0 :                         break;
   11715              :                 case DO_OPFAMILY:
   11716            0 :                         dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   11717            0 :                         break;
   11718              :                 case DO_COLLATION:
   11719            0 :                         dumpCollation(fout, (const CollInfo *) dobj);
   11720            0 :                         break;
   11721              :                 case DO_CONVERSION:
   11722            0 :                         dumpConversion(fout, (const ConvInfo *) dobj);
   11723            0 :                         break;
   11724              :                 case DO_TABLE:
   11725            0 :                         dumpTable(fout, (const TableInfo *) dobj);
   11726            0 :                         break;
   11727              :                 case DO_TABLE_ATTACH:
   11728            0 :                         dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   11729            0 :                         break;
   11730              :                 case DO_ATTRDEF:
   11731            0 :                         dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11732            0 :                         break;
   11733              :                 case DO_INDEX:
   11734            0 :                         dumpIndex(fout, (const IndxInfo *) dobj);
   11735            0 :                         break;
   11736              :                 case DO_INDEX_ATTACH:
   11737            0 :                         dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11738            0 :                         break;
   11739              :                 case DO_STATSEXT:
   11740            0 :                         dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11741            0 :                         break;
   11742              :                 case DO_REFRESH_MATVIEW:
   11743            0 :                         refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11744            0 :                         break;
   11745              :                 case DO_RULE:
   11746            0 :                         dumpRule(fout, (const RuleInfo *) dobj);
   11747            0 :                         break;
   11748              :                 case DO_TRIGGER:
   11749            0 :                         dumpTrigger(fout, (const TriggerInfo *) dobj);
   11750            0 :                         break;
   11751              :                 case DO_EVENT_TRIGGER:
   11752            0 :                         dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11753            0 :                         break;
   11754              :                 case DO_CONSTRAINT:
   11755            0 :                         dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11756            0 :                         break;
   11757              :                 case DO_FK_CONSTRAINT:
   11758            0 :                         dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11759            0 :                         break;
   11760              :                 case DO_PROCLANG:
   11761            0 :                         dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11762            0 :                         break;
   11763              :                 case DO_CAST:
   11764            0 :                         dumpCast(fout, (const CastInfo *) dobj);
   11765            0 :                         break;
   11766              :                 case DO_TRANSFORM:
   11767            0 :                         dumpTransform(fout, (const TransformInfo *) dobj);
   11768            0 :                         break;
   11769              :                 case DO_SEQUENCE_SET:
   11770            0 :                         dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11771            0 :                         break;
   11772              :                 case DO_TABLE_DATA:
   11773            0 :                         dumpTableData(fout, (const TableDataInfo *) dobj);
   11774            0 :                         break;
   11775              :                 case DO_DUMMY_TYPE:
   11776              :                         /* table rowtypes and array types are never dumped separately */
   11777              :                         break;
   11778              :                 case DO_TSPARSER:
   11779            0 :                         dumpTSParser(fout, (const TSParserInfo *) dobj);
   11780            0 :                         break;
   11781              :                 case DO_TSDICT:
   11782            0 :                         dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11783            0 :                         break;
   11784              :                 case DO_TSTEMPLATE:
   11785            0 :                         dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11786            0 :                         break;
   11787              :                 case DO_TSCONFIG:
   11788            0 :                         dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11789            0 :                         break;
   11790              :                 case DO_FDW:
   11791            0 :                         dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11792            0 :                         break;
   11793              :                 case DO_FOREIGN_SERVER:
   11794            0 :                         dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11795            0 :                         break;
   11796              :                 case DO_DEFAULT_ACL:
   11797            0 :                         dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11798            0 :                         break;
   11799              :                 case DO_LARGE_OBJECT:
   11800            0 :                         dumpLO(fout, (const LoInfo *) dobj);
   11801            0 :                         break;
   11802              :                 case DO_LARGE_OBJECT_DATA:
   11803            0 :                         if (dobj->dump & DUMP_COMPONENT_DATA)
   11804              :                         {
   11805            0 :                                 LoInfo     *loinfo;
   11806            0 :                                 TocEntry   *te;
   11807              : 
   11808            0 :                                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11809            0 :                                 if (loinfo == NULL)
   11810            0 :                                         pg_fatal("missing metadata for large objects \"%s\"",
   11811              :                                                          dobj->name);
   11812              : 
   11813            0 :                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11814            0 :                                                                   ARCHIVE_OPTS(.tag = dobj->name,
   11815              :                                                                                            .owner = loinfo->rolname,
   11816              :                                                                                            .description = "BLOBS",
   11817              :                                                                                            .section = SECTION_DATA,
   11818              :                                                                                            .deps = dobj->dependencies,
   11819              :                                                                                            .nDeps = dobj->nDeps,
   11820              :                                                                                            .dumpFn = dumpLOs,
   11821              :                                                                                            .dumpArg = loinfo));
   11822              : 
   11823              :                                 /*
   11824              :                                  * Set the TocEntry's dataLength in case we are doing a
   11825              :                                  * parallel dump and want to order dump jobs by table size.
   11826              :                                  * (We need some size estimate for every TocEntry with a
   11827              :                                  * DataDumper function.)  We don't currently have any cheap
   11828              :                                  * way to estimate the size of LOs, but fortunately it doesn't
   11829              :                                  * matter too much as long as we get large batches of LOs
   11830              :                                  * processed reasonably early.  Assume 8K per blob.
   11831              :                                  */
   11832            0 :                                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11833            0 :                         }
   11834            0 :                         break;
   11835              :                 case DO_POLICY:
   11836            0 :                         dumpPolicy(fout, (const PolicyInfo *) dobj);
   11837            0 :                         break;
   11838              :                 case DO_PUBLICATION:
   11839            0 :                         dumpPublication(fout, (const PublicationInfo *) dobj);
   11840            0 :                         break;
   11841              :                 case DO_PUBLICATION_REL:
   11842            0 :                         dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11843            0 :                         break;
   11844              :                 case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11845            0 :                         dumpPublicationNamespace(fout,
   11846            0 :                                                                          (const PublicationSchemaInfo *) dobj);
   11847            0 :                         break;
   11848              :                 case DO_SUBSCRIPTION:
   11849            0 :                         dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11850            0 :                         break;
   11851              :                 case DO_SUBSCRIPTION_REL:
   11852            0 :                         dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   11853            0 :                         break;
   11854              :                 case DO_REL_STATS:
   11855            0 :                         dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   11856            0 :                         break;
   11857              :                 case DO_PRE_DATA_BOUNDARY:
   11858              :                 case DO_POST_DATA_BOUNDARY:
   11859              :                         /* never dumped, nothing to do */
   11860            0 :                         break;
   11861              :         }
   11862            0 : }
   11863              : 
   11864              : /*
   11865              :  * dumpNamespace
   11866              :  *        writes out to fout the queries to recreate a user-defined namespace
   11867              :  */
   11868              : static void
   11869            0 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   11870              : {
   11871            0 :         DumpOptions *dopt = fout->dopt;
   11872            0 :         PQExpBuffer q;
   11873            0 :         PQExpBuffer delq;
   11874            0 :         char       *qnspname;
   11875              : 
   11876              :         /* Do nothing if not dumping schema */
   11877            0 :         if (!dopt->dumpSchema)
   11878            0 :                 return;
   11879              : 
   11880            0 :         q = createPQExpBuffer();
   11881            0 :         delq = createPQExpBuffer();
   11882              : 
   11883            0 :         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   11884              : 
   11885            0 :         if (nspinfo->create)
   11886              :         {
   11887            0 :                 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   11888            0 :                 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   11889            0 :         }
   11890              :         else
   11891              :         {
   11892              :                 /* see selectDumpableNamespace() */
   11893            0 :                 appendPQExpBufferStr(delq,
   11894              :                                                          "-- *not* dropping schema, since initdb creates it\n");
   11895            0 :                 appendPQExpBufferStr(q,
   11896              :                                                          "-- *not* creating schema, since initdb creates it\n");
   11897              :         }
   11898              : 
   11899            0 :         if (dopt->binary_upgrade)
   11900            0 :                 binary_upgrade_extension_member(q, &nspinfo->dobj,
   11901            0 :                                                                                 "SCHEMA", qnspname, NULL);
   11902              : 
   11903            0 :         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11904            0 :                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   11905            0 :                                          ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   11906              :                                                                   .owner = nspinfo->rolname,
   11907              :                                                                   .description = "SCHEMA",
   11908              :                                                                   .section = SECTION_PRE_DATA,
   11909              :                                                                   .createStmt = q->data,
   11910              :                                                                   .dropStmt = delq->data));
   11911              : 
   11912              :         /* Dump Schema Comments and Security Labels */
   11913            0 :         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11914              :         {
   11915            0 :                 const char *initdb_comment = NULL;
   11916              : 
   11917            0 :                 if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   11918            0 :                         initdb_comment = "standard public schema";
   11919            0 :                 dumpCommentExtended(fout, "SCHEMA", qnspname,
   11920            0 :                                                         NULL, nspinfo->rolname,
   11921            0 :                                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   11922            0 :                                                         initdb_comment);
   11923            0 :         }
   11924              : 
   11925            0 :         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11926            0 :                 dumpSecLabel(fout, "SCHEMA", qnspname,
   11927            0 :                                          NULL, nspinfo->rolname,
   11928            0 :                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   11929              : 
   11930            0 :         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11931            0 :                 dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   11932            0 :                                 qnspname, NULL, NULL,
   11933            0 :                                 NULL, nspinfo->rolname, &nspinfo->dacl);
   11934              : 
   11935            0 :         free(qnspname);
   11936              : 
   11937            0 :         destroyPQExpBuffer(q);
   11938            0 :         destroyPQExpBuffer(delq);
   11939            0 : }
   11940              : 
   11941              : /*
   11942              :  * dumpExtension
   11943              :  *        writes out to fout the queries to recreate an extension
   11944              :  */
   11945              : static void
   11946            0 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   11947              : {
   11948            0 :         DumpOptions *dopt = fout->dopt;
   11949            0 :         PQExpBuffer q;
   11950            0 :         PQExpBuffer delq;
   11951            0 :         char       *qextname;
   11952              : 
   11953              :         /* Do nothing if not dumping schema */
   11954            0 :         if (!dopt->dumpSchema)
   11955            0 :                 return;
   11956              : 
   11957            0 :         q = createPQExpBuffer();
   11958            0 :         delq = createPQExpBuffer();
   11959              : 
   11960            0 :         qextname = pg_strdup(fmtId(extinfo->dobj.name));
   11961              : 
   11962            0 :         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   11963              : 
   11964            0 :         if (!dopt->binary_upgrade)
   11965              :         {
   11966              :                 /*
   11967              :                  * In a regular dump, we simply create the extension, intentionally
   11968              :                  * not specifying a version, so that the destination installation's
   11969              :                  * default version is used.
   11970              :                  *
   11971              :                  * Use of IF NOT EXISTS here is unlike our behavior for other object
   11972              :                  * types; but there are various scenarios in which it's convenient to
   11973              :                  * manually create the desired extension before restoring, so we
   11974              :                  * prefer to allow it to exist already.
   11975              :                  */
   11976            0 :                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   11977            0 :                                                   qextname, fmtId(extinfo->namespace));
   11978            0 :         }
   11979              :         else
   11980              :         {
   11981              :                 /*
   11982              :                  * In binary-upgrade mode, it's critical to reproduce the state of the
   11983              :                  * database exactly, so our procedure is to create an empty extension,
   11984              :                  * restore all the contained objects normally, and add them to the
   11985              :                  * extension one by one.  This function performs just the first of
   11986              :                  * those steps.  binary_upgrade_extension_member() takes care of
   11987              :                  * adding member objects as they're created.
   11988              :                  */
   11989            0 :                 int                     i;
   11990            0 :                 int                     n;
   11991              : 
   11992            0 :                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   11993              : 
   11994              :                 /*
   11995              :                  * We unconditionally create the extension, so we must drop it if it
   11996              :                  * exists.  This could happen if the user deleted 'plpgsql' and then
   11997              :                  * readded it, causing its oid to be greater than g_last_builtin_oid.
   11998              :                  */
   11999            0 :                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   12000              : 
   12001            0 :                 appendPQExpBufferStr(q,
   12002              :                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   12003            0 :                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
   12004            0 :                 appendPQExpBufferStr(q, ", ");
   12005            0 :                 appendStringLiteralAH(q, extinfo->namespace, fout);
   12006            0 :                 appendPQExpBufferStr(q, ", ");
   12007            0 :                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   12008            0 :                 appendStringLiteralAH(q, extinfo->extversion, fout);
   12009            0 :                 appendPQExpBufferStr(q, ", ");
   12010              : 
   12011              :                 /*
   12012              :                  * Note that we're pushing extconfig (an OID array) back into
   12013              :                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   12014              :                  * preserved in binary upgrade.
   12015              :                  */
   12016            0 :                 if (strlen(extinfo->extconfig) > 2)
   12017            0 :                         appendStringLiteralAH(q, extinfo->extconfig, fout);
   12018              :                 else
   12019            0 :                         appendPQExpBufferStr(q, "NULL");
   12020            0 :                 appendPQExpBufferStr(q, ", ");
   12021            0 :                 if (strlen(extinfo->extcondition) > 2)
   12022            0 :                         appendStringLiteralAH(q, extinfo->extcondition, fout);
   12023              :                 else
   12024            0 :                         appendPQExpBufferStr(q, "NULL");
   12025            0 :                 appendPQExpBufferStr(q, ", ");
   12026            0 :                 appendPQExpBufferStr(q, "ARRAY[");
   12027            0 :                 n = 0;
   12028            0 :                 for (i = 0; i < extinfo->dobj.nDeps; i++)
   12029              :                 {
   12030            0 :                         DumpableObject *extobj;
   12031              : 
   12032            0 :                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   12033            0 :                         if (extobj && extobj->objType == DO_EXTENSION)
   12034              :                         {
   12035            0 :                                 if (n++ > 0)
   12036            0 :                                         appendPQExpBufferChar(q, ',');
   12037            0 :                                 appendStringLiteralAH(q, extobj->name, fout);
   12038            0 :                         }
   12039            0 :                 }
   12040            0 :                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   12041            0 :                 appendPQExpBufferStr(q, ");\n");
   12042            0 :         }
   12043              : 
   12044            0 :         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12045            0 :                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   12046            0 :                                          ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   12047              :                                                                   .description = "EXTENSION",
   12048              :                                                                   .section = SECTION_PRE_DATA,
   12049              :                                                                   .createStmt = q->data,
   12050              :                                                                   .dropStmt = delq->data));
   12051              : 
   12052              :         /* Dump Extension Comments */
   12053            0 :         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12054            0 :                 dumpComment(fout, "EXTENSION", qextname,
   12055              :                                         NULL, "",
   12056            0 :                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   12057              : 
   12058            0 :         free(qextname);
   12059              : 
   12060            0 :         destroyPQExpBuffer(q);
   12061            0 :         destroyPQExpBuffer(delq);
   12062            0 : }
   12063              : 
   12064              : /*
   12065              :  * dumpType
   12066              :  *        writes out to fout the queries to recreate a user-defined type
   12067              :  */
   12068              : static void
   12069            0 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   12070              : {
   12071            0 :         DumpOptions *dopt = fout->dopt;
   12072              : 
   12073              :         /* Do nothing if not dumping schema */
   12074            0 :         if (!dopt->dumpSchema)
   12075            0 :                 return;
   12076              : 
   12077              :         /* Dump out in proper style */
   12078            0 :         if (tyinfo->typtype == TYPTYPE_BASE)
   12079            0 :                 dumpBaseType(fout, tyinfo);
   12080            0 :         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   12081            0 :                 dumpDomain(fout, tyinfo);
   12082            0 :         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   12083            0 :                 dumpCompositeType(fout, tyinfo);
   12084            0 :         else if (tyinfo->typtype == TYPTYPE_ENUM)
   12085            0 :                 dumpEnumType(fout, tyinfo);
   12086            0 :         else if (tyinfo->typtype == TYPTYPE_RANGE)
   12087            0 :                 dumpRangeType(fout, tyinfo);
   12088            0 :         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   12089            0 :                 dumpUndefinedType(fout, tyinfo);
   12090              :         else
   12091            0 :                 pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   12092              :                                            tyinfo->dobj.name);
   12093            0 : }
   12094              : 
   12095              : /*
   12096              :  * dumpEnumType
   12097              :  *        writes out to fout the queries to recreate a user-defined enum type
   12098              :  */
   12099              : static void
   12100            0 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   12101              : {
   12102            0 :         DumpOptions *dopt = fout->dopt;
   12103            0 :         PQExpBuffer q = createPQExpBuffer();
   12104            0 :         PQExpBuffer delq = createPQExpBuffer();
   12105            0 :         PQExpBuffer query = createPQExpBuffer();
   12106            0 :         PGresult   *res;
   12107            0 :         int                     num,
   12108              :                                 i;
   12109            0 :         Oid                     enum_oid;
   12110            0 :         char       *qtypname;
   12111            0 :         char       *qualtypname;
   12112            0 :         char       *label;
   12113            0 :         int                     i_enumlabel;
   12114            0 :         int                     i_oid;
   12115              : 
   12116            0 :         if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   12117              :         {
   12118              :                 /* Set up query for enum-specific details */
   12119            0 :                 appendPQExpBufferStr(query,
   12120              :                                                          "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   12121              :                                                          "SELECT oid, enumlabel "
   12122              :                                                          "FROM pg_catalog.pg_enum "
   12123              :                                                          "WHERE enumtypid = $1 "
   12124              :                                                          "ORDER BY enumsortorder");
   12125              : 
   12126            0 :                 ExecuteSqlStatement(fout, query->data);
   12127              : 
   12128            0 :                 fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   12129            0 :         }
   12130              : 
   12131            0 :         printfPQExpBuffer(query,
   12132              :                                           "EXECUTE dumpEnumType('%u')",
   12133            0 :                                           tyinfo->dobj.catId.oid);
   12134              : 
   12135            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12136              : 
   12137            0 :         num = PQntuples(res);
   12138              : 
   12139            0 :         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12140            0 :         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12141              : 
   12142              :         /*
   12143              :          * CASCADE shouldn't be required here as for normal types since the I/O
   12144              :          * functions are generic and do not get dropped.
   12145              :          */
   12146            0 :         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12147              : 
   12148            0 :         if (dopt->binary_upgrade)
   12149            0 :                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12150            0 :                                                                                                  tyinfo->dobj.catId.oid,
   12151              :                                                                                                  false, false);
   12152              : 
   12153            0 :         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   12154            0 :                                           qualtypname);
   12155              : 
   12156            0 :         if (!dopt->binary_upgrade)
   12157              :         {
   12158            0 :                 i_enumlabel = PQfnumber(res, "enumlabel");
   12159              : 
   12160              :                 /* Labels with server-assigned oids */
   12161            0 :                 for (i = 0; i < num; i++)
   12162              :                 {
   12163            0 :                         label = PQgetvalue(res, i, i_enumlabel);
   12164            0 :                         if (i > 0)
   12165            0 :                                 appendPQExpBufferChar(q, ',');
   12166            0 :                         appendPQExpBufferStr(q, "\n    ");
   12167            0 :                         appendStringLiteralAH(q, label, fout);
   12168            0 :                 }
   12169            0 :         }
   12170              : 
   12171            0 :         appendPQExpBufferStr(q, "\n);\n");
   12172              : 
   12173            0 :         if (dopt->binary_upgrade)
   12174              :         {
   12175            0 :                 i_oid = PQfnumber(res, "oid");
   12176            0 :                 i_enumlabel = PQfnumber(res, "enumlabel");
   12177              : 
   12178              :                 /* Labels with dump-assigned (preserved) oids */
   12179            0 :                 for (i = 0; i < num; i++)
   12180              :                 {
   12181            0 :                         enum_oid = atooid(PQgetvalue(res, i, i_oid));
   12182            0 :                         label = PQgetvalue(res, i, i_enumlabel);
   12183              : 
   12184            0 :                         if (i == 0)
   12185            0 :                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   12186            0 :                         appendPQExpBuffer(q,
   12187              :                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   12188            0 :                                                           enum_oid);
   12189            0 :                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   12190            0 :                         appendStringLiteralAH(q, label, fout);
   12191            0 :                         appendPQExpBufferStr(q, ";\n\n");
   12192            0 :                 }
   12193            0 :         }
   12194              : 
   12195            0 :         if (dopt->binary_upgrade)
   12196            0 :                 binary_upgrade_extension_member(q, &tyinfo->dobj,
   12197            0 :                                                                                 "TYPE", qtypname,
   12198            0 :                                                                                 tyinfo->dobj.namespace->dobj.name);
   12199              : 
   12200            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12201            0 :                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12202            0 :                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12203              :                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12204              :                                                                   .owner = tyinfo->rolname,
   12205              :                                                                   .description = "TYPE",
   12206              :                                                                   .section = SECTION_PRE_DATA,
   12207              :                                                                   .createStmt = q->data,
   12208              :                                                                   .dropStmt = delq->data));
   12209              : 
   12210              :         /* Dump Type Comments and Security Labels */
   12211            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12212            0 :                 dumpComment(fout, "TYPE", qtypname,
   12213            0 :                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12214            0 :                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12215              : 
   12216            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12217            0 :                 dumpSecLabel(fout, "TYPE", qtypname,
   12218            0 :                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12219            0 :                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12220              : 
   12221            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12222            0 :                 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12223            0 :                                 qtypname, NULL,
   12224            0 :                                 tyinfo->dobj.namespace->dobj.name,
   12225            0 :                                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12226              : 
   12227            0 :         PQclear(res);
   12228            0 :         destroyPQExpBuffer(q);
   12229            0 :         destroyPQExpBuffer(delq);
   12230            0 :         destroyPQExpBuffer(query);
   12231            0 :         free(qtypname);
   12232            0 :         free(qualtypname);
   12233            0 : }
   12234              : 
   12235              : /*
   12236              :  * dumpRangeType
   12237              :  *        writes out to fout the queries to recreate a user-defined range type
   12238              :  */
   12239              : static void
   12240            0 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   12241              : {
   12242            0 :         DumpOptions *dopt = fout->dopt;
   12243            0 :         PQExpBuffer q = createPQExpBuffer();
   12244            0 :         PQExpBuffer delq = createPQExpBuffer();
   12245            0 :         PQExpBuffer query = createPQExpBuffer();
   12246            0 :         PGresult   *res;
   12247            0 :         Oid                     collationOid;
   12248            0 :         char       *qtypname;
   12249            0 :         char       *qualtypname;
   12250            0 :         char       *procname;
   12251              : 
   12252            0 :         if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   12253              :         {
   12254              :                 /* Set up query for range-specific details */
   12255            0 :                 appendPQExpBufferStr(query,
   12256              :                                                          "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   12257              : 
   12258            0 :                 appendPQExpBufferStr(query,
   12259              :                                                          "SELECT ");
   12260              : 
   12261            0 :                 if (fout->remoteVersion >= 140000)
   12262            0 :                         appendPQExpBufferStr(query,
   12263              :                                                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   12264              :                 else
   12265            0 :                         appendPQExpBufferStr(query,
   12266              :                                                                  "NULL AS rngmultitype, ");
   12267              : 
   12268            0 :                 appendPQExpBufferStr(query,
   12269              :                                                          "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   12270              :                                                          "opc.opcname AS opcname, "
   12271              :                                                          "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   12272              :                                                          "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   12273              :                                                          "opc.opcdefault, "
   12274              :                                                          "CASE WHEN rngcollation = st.typcollation THEN 0 "
   12275              :                                                          "     ELSE rngcollation END AS collation, "
   12276              :                                                          "rngcanonical, rngsubdiff "
   12277              :                                                          "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   12278              :                                                          "     pg_catalog.pg_opclass opc "
   12279              :                                                          "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   12280              :                                                          "rngtypid = $1");
   12281              : 
   12282            0 :                 ExecuteSqlStatement(fout, query->data);
   12283              : 
   12284            0 :                 fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   12285            0 :         }
   12286              : 
   12287            0 :         printfPQExpBuffer(query,
   12288              :                                           "EXECUTE dumpRangeType('%u')",
   12289            0 :                                           tyinfo->dobj.catId.oid);
   12290              : 
   12291            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12292              : 
   12293            0 :         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12294            0 :         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12295              : 
   12296              :         /*
   12297              :          * CASCADE shouldn't be required here as for normal types since the I/O
   12298              :          * functions are generic and do not get dropped.
   12299              :          */
   12300            0 :         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12301              : 
   12302            0 :         if (dopt->binary_upgrade)
   12303            0 :                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12304            0 :                                                                                                  tyinfo->dobj.catId.oid,
   12305              :                                                                                                  false, true);
   12306              : 
   12307            0 :         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   12308            0 :                                           qualtypname);
   12309              : 
   12310            0 :         appendPQExpBuffer(q, "\n    subtype = %s",
   12311            0 :                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   12312              : 
   12313            0 :         if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   12314            0 :                 appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   12315            0 :                                                   PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   12316              : 
   12317              :         /* print subtype_opclass only if not default for subtype */
   12318            0 :         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   12319              :         {
   12320            0 :                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   12321            0 :                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   12322              : 
   12323            0 :                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   12324            0 :                                                   fmtId(nspname));
   12325            0 :                 appendPQExpBufferStr(q, fmtId(opcname));
   12326            0 :         }
   12327              : 
   12328            0 :         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   12329            0 :         if (OidIsValid(collationOid))
   12330              :         {
   12331            0 :                 CollInfo   *coll = findCollationByOid(collationOid);
   12332              : 
   12333            0 :                 if (coll)
   12334            0 :                         appendPQExpBuffer(q, ",\n    collation = %s",
   12335            0 :                                                           fmtQualifiedDumpable(coll));
   12336            0 :         }
   12337              : 
   12338            0 :         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   12339            0 :         if (strcmp(procname, "-") != 0)
   12340            0 :                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   12341              : 
   12342            0 :         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   12343            0 :         if (strcmp(procname, "-") != 0)
   12344            0 :                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   12345              : 
   12346            0 :         appendPQExpBufferStr(q, "\n);\n");
   12347              : 
   12348            0 :         if (dopt->binary_upgrade)
   12349            0 :                 binary_upgrade_extension_member(q, &tyinfo->dobj,
   12350            0 :                                                                                 "TYPE", qtypname,
   12351            0 :                                                                                 tyinfo->dobj.namespace->dobj.name);
   12352              : 
   12353            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12354            0 :                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12355            0 :                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12356              :                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12357              :                                                                   .owner = tyinfo->rolname,
   12358              :                                                                   .description = "TYPE",
   12359              :                                                                   .section = SECTION_PRE_DATA,
   12360              :                                                                   .createStmt = q->data,
   12361              :                                                                   .dropStmt = delq->data));
   12362              : 
   12363              :         /* Dump Type Comments and Security Labels */
   12364            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12365            0 :                 dumpComment(fout, "TYPE", qtypname,
   12366            0 :                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12367            0 :                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12368              : 
   12369            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12370            0 :                 dumpSecLabel(fout, "TYPE", qtypname,
   12371            0 :                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12372            0 :                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12373              : 
   12374            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12375            0 :                 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12376            0 :                                 qtypname, NULL,
   12377            0 :                                 tyinfo->dobj.namespace->dobj.name,
   12378            0 :                                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12379              : 
   12380            0 :         PQclear(res);
   12381            0 :         destroyPQExpBuffer(q);
   12382            0 :         destroyPQExpBuffer(delq);
   12383            0 :         destroyPQExpBuffer(query);
   12384            0 :         free(qtypname);
   12385            0 :         free(qualtypname);
   12386            0 : }
   12387              : 
   12388              : /*
   12389              :  * dumpUndefinedType
   12390              :  *        writes out to fout the queries to recreate a !typisdefined type
   12391              :  *
   12392              :  * This is a shell type, but we use different terminology to distinguish
   12393              :  * this case from where we have to emit a shell type definition to break
   12394              :  * circular dependencies.  An undefined type shouldn't ever have anything
   12395              :  * depending on it.
   12396              :  */
   12397              : static void
   12398            0 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   12399              : {
   12400            0 :         DumpOptions *dopt = fout->dopt;
   12401            0 :         PQExpBuffer q = createPQExpBuffer();
   12402            0 :         PQExpBuffer delq = createPQExpBuffer();
   12403            0 :         char       *qtypname;
   12404            0 :         char       *qualtypname;
   12405              : 
   12406            0 :         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12407            0 :         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12408              : 
   12409            0 :         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12410              : 
   12411            0 :         if (dopt->binary_upgrade)
   12412            0 :                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12413            0 :                                                                                                  tyinfo->dobj.catId.oid,
   12414              :                                                                                                  false, false);
   12415              : 
   12416            0 :         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12417            0 :                                           qualtypname);
   12418              : 
   12419            0 :         if (dopt->binary_upgrade)
   12420            0 :                 binary_upgrade_extension_member(q, &tyinfo->dobj,
   12421            0 :                                                                                 "TYPE", qtypname,
   12422            0 :                                                                                 tyinfo->dobj.namespace->dobj.name);
   12423              : 
   12424            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12425            0 :                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12426            0 :                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12427              :                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12428              :                                                                   .owner = tyinfo->rolname,
   12429              :                                                                   .description = "TYPE",
   12430              :                                                                   .section = SECTION_PRE_DATA,
   12431              :                                                                   .createStmt = q->data,
   12432              :                                                                   .dropStmt = delq->data));
   12433              : 
   12434              :         /* Dump Type Comments and Security Labels */
   12435            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12436            0 :                 dumpComment(fout, "TYPE", qtypname,
   12437            0 :                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12438            0 :                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12439              : 
   12440            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12441            0 :                 dumpSecLabel(fout, "TYPE", qtypname,
   12442            0 :                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12443            0 :                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12444              : 
   12445            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12446            0 :                 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12447            0 :                                 qtypname, NULL,
   12448            0 :                                 tyinfo->dobj.namespace->dobj.name,
   12449            0 :                                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12450              : 
   12451            0 :         destroyPQExpBuffer(q);
   12452            0 :         destroyPQExpBuffer(delq);
   12453            0 :         free(qtypname);
   12454            0 :         free(qualtypname);
   12455            0 : }
   12456              : 
   12457              : /*
   12458              :  * dumpBaseType
   12459              :  *        writes out to fout the queries to recreate a user-defined base type
   12460              :  */
   12461              : static void
   12462            0 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   12463              : {
   12464            0 :         DumpOptions *dopt = fout->dopt;
   12465            0 :         PQExpBuffer q = createPQExpBuffer();
   12466            0 :         PQExpBuffer delq = createPQExpBuffer();
   12467            0 :         PQExpBuffer query = createPQExpBuffer();
   12468            0 :         PGresult   *res;
   12469            0 :         char       *qtypname;
   12470            0 :         char       *qualtypname;
   12471            0 :         char       *typlen;
   12472            0 :         char       *typinput;
   12473            0 :         char       *typoutput;
   12474            0 :         char       *typreceive;
   12475            0 :         char       *typsend;
   12476            0 :         char       *typmodin;
   12477            0 :         char       *typmodout;
   12478            0 :         char       *typanalyze;
   12479            0 :         char       *typsubscript;
   12480            0 :         Oid                     typreceiveoid;
   12481            0 :         Oid                     typsendoid;
   12482            0 :         Oid                     typmodinoid;
   12483            0 :         Oid                     typmodoutoid;
   12484            0 :         Oid                     typanalyzeoid;
   12485            0 :         Oid                     typsubscriptoid;
   12486            0 :         char       *typcategory;
   12487            0 :         char       *typispreferred;
   12488            0 :         char       *typdelim;
   12489            0 :         char       *typbyval;
   12490            0 :         char       *typalign;
   12491            0 :         char       *typstorage;
   12492            0 :         char       *typcollatable;
   12493            0 :         char       *typdefault;
   12494            0 :         bool            typdefault_is_literal = false;
   12495              : 
   12496            0 :         if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   12497              :         {
   12498              :                 /* Set up query for type-specific details */
   12499            0 :                 appendPQExpBufferStr(query,
   12500              :                                                          "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   12501              :                                                          "SELECT typlen, "
   12502              :                                                          "typinput, typoutput, typreceive, typsend, "
   12503              :                                                          "typreceive::pg_catalog.oid AS typreceiveoid, "
   12504              :                                                          "typsend::pg_catalog.oid AS typsendoid, "
   12505              :                                                          "typanalyze, "
   12506              :                                                          "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   12507              :                                                          "typdelim, typbyval, typalign, typstorage, "
   12508              :                                                          "typmodin, typmodout, "
   12509              :                                                          "typmodin::pg_catalog.oid AS typmodinoid, "
   12510              :                                                          "typmodout::pg_catalog.oid AS typmodoutoid, "
   12511              :                                                          "typcategory, typispreferred, "
   12512              :                                                          "(typcollation <> 0) AS typcollatable, "
   12513              :                                                          "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   12514              : 
   12515            0 :                 if (fout->remoteVersion >= 140000)
   12516            0 :                         appendPQExpBufferStr(query,
   12517              :                                                                  "typsubscript, "
   12518              :                                                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   12519              :                 else
   12520            0 :                         appendPQExpBufferStr(query,
   12521              :                                                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   12522              : 
   12523            0 :                 appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   12524              :                                                          "WHERE oid = $1");
   12525              : 
   12526            0 :                 ExecuteSqlStatement(fout, query->data);
   12527              : 
   12528            0 :                 fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   12529            0 :         }
   12530              : 
   12531            0 :         printfPQExpBuffer(query,
   12532              :                                           "EXECUTE dumpBaseType('%u')",
   12533            0 :                                           tyinfo->dobj.catId.oid);
   12534              : 
   12535            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12536              : 
   12537            0 :         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   12538            0 :         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   12539            0 :         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   12540            0 :         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   12541            0 :         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   12542            0 :         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   12543            0 :         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   12544            0 :         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   12545            0 :         typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   12546            0 :         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   12547            0 :         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   12548            0 :         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   12549            0 :         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   12550            0 :         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   12551            0 :         typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   12552            0 :         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   12553            0 :         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   12554            0 :         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   12555            0 :         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   12556            0 :         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   12557            0 :         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   12558            0 :         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   12559            0 :         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12560            0 :                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12561            0 :         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12562              :         {
   12563            0 :                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12564            0 :                 typdefault_is_literal = true;   /* it needs quotes */
   12565            0 :         }
   12566              :         else
   12567            0 :                 typdefault = NULL;
   12568              : 
   12569            0 :         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12570            0 :         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12571              : 
   12572              :         /*
   12573              :          * The reason we include CASCADE is that the circular dependency between
   12574              :          * the type and its I/O functions makes it impossible to drop the type any
   12575              :          * other way.
   12576              :          */
   12577            0 :         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   12578              : 
   12579              :         /*
   12580              :          * We might already have a shell type, but setting pg_type_oid is
   12581              :          * harmless, and in any case we'd better set the array type OID.
   12582              :          */
   12583            0 :         if (dopt->binary_upgrade)
   12584            0 :                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12585            0 :                                                                                                  tyinfo->dobj.catId.oid,
   12586              :                                                                                                  false, false);
   12587              : 
   12588            0 :         appendPQExpBuffer(q,
   12589              :                                           "CREATE TYPE %s (\n"
   12590              :                                           "    INTERNALLENGTH = %s",
   12591            0 :                                           qualtypname,
   12592            0 :                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   12593              : 
   12594              :         /* regproc result is sufficiently quoted already */
   12595            0 :         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   12596            0 :         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   12597            0 :         if (OidIsValid(typreceiveoid))
   12598            0 :                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   12599            0 :         if (OidIsValid(typsendoid))
   12600            0 :                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   12601            0 :         if (OidIsValid(typmodinoid))
   12602            0 :                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   12603            0 :         if (OidIsValid(typmodoutoid))
   12604            0 :                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   12605            0 :         if (OidIsValid(typanalyzeoid))
   12606            0 :                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   12607              : 
   12608            0 :         if (strcmp(typcollatable, "t") == 0)
   12609            0 :                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   12610              : 
   12611            0 :         if (typdefault != NULL)
   12612              :         {
   12613            0 :                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   12614            0 :                 if (typdefault_is_literal)
   12615            0 :                         appendStringLiteralAH(q, typdefault, fout);
   12616              :                 else
   12617            0 :                         appendPQExpBufferStr(q, typdefault);
   12618            0 :         }
   12619              : 
   12620            0 :         if (OidIsValid(typsubscriptoid))
   12621            0 :                 appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   12622              : 
   12623            0 :         if (OidIsValid(tyinfo->typelem))
   12624            0 :                 appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   12625            0 :                                                   getFormattedTypeName(fout, tyinfo->typelem,
   12626              :                                                                                            zeroIsError));
   12627              : 
   12628            0 :         if (strcmp(typcategory, "U") != 0)
   12629              :         {
   12630            0 :                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   12631            0 :                 appendStringLiteralAH(q, typcategory, fout);
   12632            0 :         }
   12633              : 
   12634            0 :         if (strcmp(typispreferred, "t") == 0)
   12635            0 :                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   12636              : 
   12637            0 :         if (typdelim && strcmp(typdelim, ",") != 0)
   12638              :         {
   12639            0 :                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   12640            0 :                 appendStringLiteralAH(q, typdelim, fout);
   12641            0 :         }
   12642              : 
   12643            0 :         if (*typalign == TYPALIGN_CHAR)
   12644            0 :                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   12645            0 :         else if (*typalign == TYPALIGN_SHORT)
   12646            0 :                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   12647            0 :         else if (*typalign == TYPALIGN_INT)
   12648            0 :                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   12649            0 :         else if (*typalign == TYPALIGN_DOUBLE)
   12650            0 :                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   12651              : 
   12652            0 :         if (*typstorage == TYPSTORAGE_PLAIN)
   12653            0 :                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   12654            0 :         else if (*typstorage == TYPSTORAGE_EXTERNAL)
   12655            0 :                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
   12656            0 :         else if (*typstorage == TYPSTORAGE_EXTENDED)
   12657            0 :                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   12658            0 :         else if (*typstorage == TYPSTORAGE_MAIN)
   12659            0 :                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
   12660              : 
   12661            0 :         if (strcmp(typbyval, "t") == 0)
   12662            0 :                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   12663              : 
   12664            0 :         appendPQExpBufferStr(q, "\n);\n");
   12665              : 
   12666            0 :         if (dopt->binary_upgrade)
   12667            0 :                 binary_upgrade_extension_member(q, &tyinfo->dobj,
   12668            0 :                                                                                 "TYPE", qtypname,
   12669            0 :                                                                                 tyinfo->dobj.namespace->dobj.name);
   12670              : 
   12671            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12672            0 :                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12673            0 :                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12674              :                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12675              :                                                                   .owner = tyinfo->rolname,
   12676              :                                                                   .description = "TYPE",
   12677              :                                                                   .section = SECTION_PRE_DATA,
   12678              :                                                                   .createStmt = q->data,
   12679              :                                                                   .dropStmt = delq->data));
   12680              : 
   12681              :         /* Dump Type Comments and Security Labels */
   12682            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12683            0 :                 dumpComment(fout, "TYPE", qtypname,
   12684            0 :                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12685            0 :                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12686              : 
   12687            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12688            0 :                 dumpSecLabel(fout, "TYPE", qtypname,
   12689            0 :                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12690            0 :                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12691              : 
   12692            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12693            0 :                 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12694            0 :                                 qtypname, NULL,
   12695            0 :                                 tyinfo->dobj.namespace->dobj.name,
   12696            0 :                                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12697              : 
   12698            0 :         PQclear(res);
   12699            0 :         destroyPQExpBuffer(q);
   12700            0 :         destroyPQExpBuffer(delq);
   12701            0 :         destroyPQExpBuffer(query);
   12702            0 :         free(qtypname);
   12703            0 :         free(qualtypname);
   12704            0 : }
   12705              : 
   12706              : /*
   12707              :  * dumpDomain
   12708              :  *        writes out to fout the queries to recreate a user-defined domain
   12709              :  */
   12710              : static void
   12711            0 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   12712              : {
   12713            0 :         DumpOptions *dopt = fout->dopt;
   12714            0 :         PQExpBuffer q = createPQExpBuffer();
   12715            0 :         PQExpBuffer delq = createPQExpBuffer();
   12716            0 :         PQExpBuffer query = createPQExpBuffer();
   12717            0 :         PGresult   *res;
   12718            0 :         int                     i;
   12719            0 :         char       *qtypname;
   12720            0 :         char       *qualtypname;
   12721            0 :         char       *typnotnull;
   12722            0 :         char       *typdefn;
   12723            0 :         char       *typdefault;
   12724            0 :         Oid                     typcollation;
   12725            0 :         bool            typdefault_is_literal = false;
   12726              : 
   12727            0 :         if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12728              :         {
   12729              :                 /* Set up query for domain-specific details */
   12730            0 :                 appendPQExpBufferStr(query,
   12731              :                                                          "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12732              : 
   12733            0 :                 appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   12734              :                                                          "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   12735              :                                                          "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   12736              :                                                          "t.typdefault, "
   12737              :                                                          "CASE WHEN t.typcollation <> u.typcollation "
   12738              :                                                          "THEN t.typcollation ELSE 0 END AS typcollation "
   12739              :                                                          "FROM pg_catalog.pg_type t "
   12740              :                                                          "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   12741              :                                                          "WHERE t.oid = $1");
   12742              : 
   12743            0 :                 ExecuteSqlStatement(fout, query->data);
   12744              : 
   12745            0 :                 fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12746            0 :         }
   12747              : 
   12748            0 :         printfPQExpBuffer(query,
   12749              :                                           "EXECUTE dumpDomain('%u')",
   12750            0 :                                           tyinfo->dobj.catId.oid);
   12751              : 
   12752            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12753              : 
   12754            0 :         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12755            0 :         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12756            0 :         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12757            0 :                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12758            0 :         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12759              :         {
   12760            0 :                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12761            0 :                 typdefault_is_literal = true;   /* it needs quotes */
   12762            0 :         }
   12763              :         else
   12764            0 :                 typdefault = NULL;
   12765            0 :         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12766              : 
   12767            0 :         if (dopt->binary_upgrade)
   12768            0 :                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12769            0 :                                                                                                  tyinfo->dobj.catId.oid,
   12770              :                                                                                                  true,  /* force array type */
   12771              :                                                                                                  false);        /* force multirange type */
   12772              : 
   12773            0 :         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12774            0 :         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12775              : 
   12776            0 :         appendPQExpBuffer(q,
   12777              :                                           "CREATE DOMAIN %s AS %s",
   12778            0 :                                           qualtypname,
   12779            0 :                                           typdefn);
   12780              : 
   12781              :         /* Print collation only if different from base type's collation */
   12782            0 :         if (OidIsValid(typcollation))
   12783              :         {
   12784            0 :                 CollInfo   *coll;
   12785              : 
   12786            0 :                 coll = findCollationByOid(typcollation);
   12787            0 :                 if (coll)
   12788            0 :                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   12789            0 :         }
   12790              : 
   12791              :         /*
   12792              :          * Print a not-null constraint if there's one.  In servers older than 17
   12793              :          * these don't have names, so just print it unadorned; in newer ones they
   12794              :          * do, but most of the time it's going to be the standard generated one,
   12795              :          * so omit the name in that case also.
   12796              :          */
   12797            0 :         if (typnotnull[0] == 't')
   12798              :         {
   12799            0 :                 if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
   12800            0 :                         appendPQExpBufferStr(q, " NOT NULL");
   12801              :                 else
   12802              :                 {
   12803            0 :                         ConstraintInfo *notnull = tyinfo->notnull;
   12804              : 
   12805            0 :                         if (!notnull->separate)
   12806              :                         {
   12807            0 :                                 char       *default_name;
   12808              : 
   12809              :                                 /* XXX should match ChooseConstraintName better */
   12810            0 :                                 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
   12811              : 
   12812            0 :                                 if (strcmp(default_name, notnull->dobj.name) == 0)
   12813            0 :                                         appendPQExpBufferStr(q, " NOT NULL");
   12814              :                                 else
   12815            0 :                                         appendPQExpBuffer(q, " CONSTRAINT %s %s",
   12816            0 :                                                                           fmtId(notnull->dobj.name), notnull->condef);
   12817            0 :                                 free(default_name);
   12818            0 :                         }
   12819            0 :                 }
   12820            0 :         }
   12821              : 
   12822            0 :         if (typdefault != NULL)
   12823              :         {
   12824            0 :                 appendPQExpBufferStr(q, " DEFAULT ");
   12825            0 :                 if (typdefault_is_literal)
   12826            0 :                         appendStringLiteralAH(q, typdefault, fout);
   12827              :                 else
   12828            0 :                         appendPQExpBufferStr(q, typdefault);
   12829            0 :         }
   12830              : 
   12831            0 :         PQclear(res);
   12832              : 
   12833              :         /*
   12834              :          * Add any CHECK constraints for the domain
   12835              :          */
   12836            0 :         for (i = 0; i < tyinfo->nDomChecks; i++)
   12837              :         {
   12838            0 :                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12839              : 
   12840            0 :                 if (!domcheck->separate && domcheck->contype == 'c')
   12841            0 :                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12842            0 :                                                           fmtId(domcheck->dobj.name), domcheck->condef);
   12843            0 :         }
   12844              : 
   12845            0 :         appendPQExpBufferStr(q, ";\n");
   12846              : 
   12847            0 :         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12848              : 
   12849            0 :         if (dopt->binary_upgrade)
   12850            0 :                 binary_upgrade_extension_member(q, &tyinfo->dobj,
   12851            0 :                                                                                 "DOMAIN", qtypname,
   12852            0 :                                                                                 tyinfo->dobj.namespace->dobj.name);
   12853              : 
   12854            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12855            0 :                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12856            0 :                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12857              :                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12858              :                                                                   .owner = tyinfo->rolname,
   12859              :                                                                   .description = "DOMAIN",
   12860              :                                                                   .section = SECTION_PRE_DATA,
   12861              :                                                                   .createStmt = q->data,
   12862              :                                                                   .dropStmt = delq->data));
   12863              : 
   12864              :         /* Dump Domain Comments and Security Labels */
   12865            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12866            0 :                 dumpComment(fout, "DOMAIN", qtypname,
   12867            0 :                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12868            0 :                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12869              : 
   12870            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12871            0 :                 dumpSecLabel(fout, "DOMAIN", qtypname,
   12872            0 :                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12873            0 :                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12874              : 
   12875            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12876            0 :                 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12877            0 :                                 qtypname, NULL,
   12878            0 :                                 tyinfo->dobj.namespace->dobj.name,
   12879            0 :                                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12880              : 
   12881              :         /* Dump any per-constraint comments */
   12882            0 :         for (i = 0; i < tyinfo->nDomChecks; i++)
   12883              :         {
   12884            0 :                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12885            0 :                 PQExpBuffer conprefix;
   12886              : 
   12887              :                 /* but only if the constraint itself was dumped here */
   12888            0 :                 if (domcheck->separate)
   12889            0 :                         continue;
   12890              : 
   12891            0 :                 conprefix = createPQExpBuffer();
   12892            0 :                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12893            0 :                                                   fmtId(domcheck->dobj.name));
   12894              : 
   12895            0 :                 if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   12896            0 :                         dumpComment(fout, conprefix->data, qtypname,
   12897            0 :                                                 tyinfo->dobj.namespace->dobj.name,
   12898            0 :                                                 tyinfo->rolname,
   12899            0 :                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   12900              : 
   12901            0 :                 destroyPQExpBuffer(conprefix);
   12902            0 :         }
   12903              : 
   12904              :         /*
   12905              :          * And a comment on the not-null constraint, if there's one -- but only if
   12906              :          * the constraint itself was dumped here
   12907              :          */
   12908            0 :         if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
   12909              :         {
   12910            0 :                 PQExpBuffer conprefix = createPQExpBuffer();
   12911              : 
   12912            0 :                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12913            0 :                                                   fmtId(tyinfo->notnull->dobj.name));
   12914              : 
   12915            0 :                 if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
   12916            0 :                         dumpComment(fout, conprefix->data, qtypname,
   12917            0 :                                                 tyinfo->dobj.namespace->dobj.name,
   12918            0 :                                                 tyinfo->rolname,
   12919            0 :                                                 tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
   12920            0 :                 destroyPQExpBuffer(conprefix);
   12921            0 :         }
   12922              : 
   12923            0 :         destroyPQExpBuffer(q);
   12924            0 :         destroyPQExpBuffer(delq);
   12925            0 :         destroyPQExpBuffer(query);
   12926            0 :         free(qtypname);
   12927            0 :         free(qualtypname);
   12928            0 : }
   12929              : 
   12930              : /*
   12931              :  * dumpCompositeType
   12932              :  *        writes out to fout the queries to recreate a user-defined stand-alone
   12933              :  *        composite type
   12934              :  */
   12935              : static void
   12936            0 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   12937              : {
   12938            0 :         DumpOptions *dopt = fout->dopt;
   12939            0 :         PQExpBuffer q = createPQExpBuffer();
   12940            0 :         PQExpBuffer dropped = createPQExpBuffer();
   12941            0 :         PQExpBuffer delq = createPQExpBuffer();
   12942            0 :         PQExpBuffer query = createPQExpBuffer();
   12943            0 :         PGresult   *res;
   12944            0 :         char       *qtypname;
   12945            0 :         char       *qualtypname;
   12946            0 :         int                     ntups;
   12947            0 :         int                     i_attname;
   12948            0 :         int                     i_atttypdefn;
   12949            0 :         int                     i_attlen;
   12950            0 :         int                     i_attalign;
   12951            0 :         int                     i_attisdropped;
   12952            0 :         int                     i_attcollation;
   12953            0 :         int                     i;
   12954            0 :         int                     actual_atts;
   12955              : 
   12956            0 :         if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   12957              :         {
   12958              :                 /*
   12959              :                  * Set up query for type-specific details.
   12960              :                  *
   12961              :                  * Since we only want to dump COLLATE clauses for attributes whose
   12962              :                  * collation is different from their type's default, we use a CASE
   12963              :                  * here to suppress uninteresting attcollations cheaply.  atttypid
   12964              :                  * will be 0 for dropped columns; collation does not matter for those.
   12965              :                  */
   12966            0 :                 appendPQExpBufferStr(query,
   12967              :                                                          "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   12968              :                                                          "SELECT a.attname, a.attnum, "
   12969              :                                                          "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   12970              :                                                          "a.attlen, a.attalign, a.attisdropped, "
   12971              :                                                          "CASE WHEN a.attcollation <> at.typcollation "
   12972              :                                                          "THEN a.attcollation ELSE 0 END AS attcollation "
   12973              :                                                          "FROM pg_catalog.pg_type ct "
   12974              :                                                          "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   12975              :                                                          "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   12976              :                                                          "WHERE ct.oid = $1 "
   12977              :                                                          "ORDER BY a.attnum");
   12978              : 
   12979            0 :                 ExecuteSqlStatement(fout, query->data);
   12980              : 
   12981            0 :                 fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   12982            0 :         }
   12983              : 
   12984            0 :         printfPQExpBuffer(query,
   12985              :                                           "EXECUTE dumpCompositeType('%u')",
   12986            0 :                                           tyinfo->dobj.catId.oid);
   12987              : 
   12988            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12989              : 
   12990            0 :         ntups = PQntuples(res);
   12991              : 
   12992            0 :         i_attname = PQfnumber(res, "attname");
   12993            0 :         i_atttypdefn = PQfnumber(res, "atttypdefn");
   12994            0 :         i_attlen = PQfnumber(res, "attlen");
   12995            0 :         i_attalign = PQfnumber(res, "attalign");
   12996            0 :         i_attisdropped = PQfnumber(res, "attisdropped");
   12997            0 :         i_attcollation = PQfnumber(res, "attcollation");
   12998              : 
   12999            0 :         if (dopt->binary_upgrade)
   13000              :         {
   13001            0 :                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13002            0 :                                                                                                  tyinfo->dobj.catId.oid,
   13003              :                                                                                                  false, false);
   13004            0 :                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   13005            0 :         }
   13006              : 
   13007            0 :         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   13008            0 :         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   13009              : 
   13010            0 :         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   13011            0 :                                           qualtypname);
   13012              : 
   13013            0 :         actual_atts = 0;
   13014            0 :         for (i = 0; i < ntups; i++)
   13015              :         {
   13016            0 :                 char       *attname;
   13017            0 :                 char       *atttypdefn;
   13018            0 :                 char       *attlen;
   13019            0 :                 char       *attalign;
   13020            0 :                 bool            attisdropped;
   13021            0 :                 Oid                     attcollation;
   13022              : 
   13023            0 :                 attname = PQgetvalue(res, i, i_attname);
   13024            0 :                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   13025            0 :                 attlen = PQgetvalue(res, i, i_attlen);
   13026            0 :                 attalign = PQgetvalue(res, i, i_attalign);
   13027            0 :                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   13028            0 :                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   13029              : 
   13030            0 :                 if (attisdropped && !dopt->binary_upgrade)
   13031            0 :                         continue;
   13032              : 
   13033              :                 /* Format properly if not first attr */
   13034            0 :                 if (actual_atts++ > 0)
   13035            0 :                         appendPQExpBufferChar(q, ',');
   13036            0 :                 appendPQExpBufferStr(q, "\n\t");
   13037              : 
   13038            0 :                 if (!attisdropped)
   13039              :                 {
   13040            0 :                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   13041              : 
   13042              :                         /* Add collation if not default for the column type */
   13043            0 :                         if (OidIsValid(attcollation))
   13044              :                         {
   13045            0 :                                 CollInfo   *coll;
   13046              : 
   13047            0 :                                 coll = findCollationByOid(attcollation);
   13048            0 :                                 if (coll)
   13049            0 :                                         appendPQExpBuffer(q, " COLLATE %s",
   13050            0 :                                                                           fmtQualifiedDumpable(coll));
   13051            0 :                         }
   13052            0 :                 }
   13053              :                 else
   13054              :                 {
   13055              :                         /*
   13056              :                          * This is a dropped attribute and we're in binary_upgrade mode.
   13057              :                          * Insert a placeholder for it in the CREATE TYPE command, and set
   13058              :                          * length and alignment with direct UPDATE to the catalogs
   13059              :                          * afterwards. See similar code in dumpTableSchema().
   13060              :                          */
   13061            0 :                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   13062              : 
   13063              :                         /* stash separately for insertion after the CREATE TYPE */
   13064            0 :                         appendPQExpBufferStr(dropped,
   13065              :                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
   13066            0 :                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   13067              :                                                           "SET attlen = %s, "
   13068              :                                                           "attalign = '%s', attbyval = false\n"
   13069            0 :                                                           "WHERE attname = ", attlen, attalign);
   13070            0 :                         appendStringLiteralAH(dropped, attname, fout);
   13071            0 :                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   13072            0 :                         appendStringLiteralAH(dropped, qualtypname, fout);
   13073            0 :                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   13074              : 
   13075            0 :                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   13076            0 :                                                           qualtypname);
   13077            0 :                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   13078            0 :                                                           fmtId(attname));
   13079              :                 }
   13080            0 :         }
   13081            0 :         appendPQExpBufferStr(q, "\n);\n");
   13082            0 :         appendPQExpBufferStr(q, dropped->data);
   13083              : 
   13084            0 :         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   13085              : 
   13086            0 :         if (dopt->binary_upgrade)
   13087            0 :                 binary_upgrade_extension_member(q, &tyinfo->dobj,
   13088            0 :                                                                                 "TYPE", qtypname,
   13089            0 :                                                                                 tyinfo->dobj.namespace->dobj.name);
   13090              : 
   13091            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13092            0 :                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   13093            0 :                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   13094              :                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   13095              :                                                                   .owner = tyinfo->rolname,
   13096              :                                                                   .description = "TYPE",
   13097              :                                                                   .section = SECTION_PRE_DATA,
   13098              :                                                                   .createStmt = q->data,
   13099              :                                                                   .dropStmt = delq->data));
   13100              : 
   13101              : 
   13102              :         /* Dump Type Comments and Security Labels */
   13103            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13104            0 :                 dumpComment(fout, "TYPE", qtypname,
   13105            0 :                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13106            0 :                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13107              : 
   13108            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13109            0 :                 dumpSecLabel(fout, "TYPE", qtypname,
   13110            0 :                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13111            0 :                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13112              : 
   13113            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   13114            0 :                 dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   13115            0 :                                 qtypname, NULL,
   13116            0 :                                 tyinfo->dobj.namespace->dobj.name,
   13117            0 :                                 NULL, tyinfo->rolname, &tyinfo->dacl);
   13118              : 
   13119              :         /* Dump any per-column comments */
   13120            0 :         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13121            0 :                 dumpCompositeTypeColComments(fout, tyinfo, res);
   13122              : 
   13123            0 :         PQclear(res);
   13124            0 :         destroyPQExpBuffer(q);
   13125            0 :         destroyPQExpBuffer(dropped);
   13126            0 :         destroyPQExpBuffer(delq);
   13127            0 :         destroyPQExpBuffer(query);
   13128            0 :         free(qtypname);
   13129            0 :         free(qualtypname);
   13130            0 : }
   13131              : 
   13132              : /*
   13133              :  * dumpCompositeTypeColComments
   13134              :  *        writes out to fout the queries to recreate comments on the columns of
   13135              :  *        a user-defined stand-alone composite type.
   13136              :  *
   13137              :  * The caller has already made a query to collect the names and attnums
   13138              :  * of the type's columns, so we just pass that result into here rather
   13139              :  * than reading them again.
   13140              :  */
   13141              : static void
   13142            0 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   13143              :                                                          PGresult *res)
   13144              : {
   13145            0 :         CommentItem *comments;
   13146            0 :         int                     ncomments;
   13147            0 :         PQExpBuffer query;
   13148            0 :         PQExpBuffer target;
   13149            0 :         int                     i;
   13150            0 :         int                     ntups;
   13151            0 :         int                     i_attname;
   13152            0 :         int                     i_attnum;
   13153            0 :         int                     i_attisdropped;
   13154              : 
   13155              :         /* do nothing, if --no-comments is supplied */
   13156            0 :         if (fout->dopt->no_comments)
   13157            0 :                 return;
   13158              : 
   13159              :         /* Search for comments associated with type's pg_class OID */
   13160            0 :         ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   13161              :                                                          &comments);
   13162              : 
   13163              :         /* If no comments exist, we're done */
   13164            0 :         if (ncomments <= 0)
   13165            0 :                 return;
   13166              : 
   13167              :         /* Build COMMENT ON statements */
   13168            0 :         query = createPQExpBuffer();
   13169            0 :         target = createPQExpBuffer();
   13170              : 
   13171            0 :         ntups = PQntuples(res);
   13172            0 :         i_attnum = PQfnumber(res, "attnum");
   13173            0 :         i_attname = PQfnumber(res, "attname");
   13174            0 :         i_attisdropped = PQfnumber(res, "attisdropped");
   13175            0 :         while (ncomments > 0)
   13176              :         {
   13177            0 :                 const char *attname;
   13178              : 
   13179            0 :                 attname = NULL;
   13180            0 :                 for (i = 0; i < ntups; i++)
   13181              :                 {
   13182            0 :                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   13183            0 :                                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   13184              :                         {
   13185            0 :                                 attname = PQgetvalue(res, i, i_attname);
   13186            0 :                                 break;
   13187              :                         }
   13188            0 :                 }
   13189            0 :                 if (attname)                    /* just in case we don't find it */
   13190              :                 {
   13191            0 :                         const char *descr = comments->descr;
   13192              : 
   13193            0 :                         resetPQExpBuffer(target);
   13194            0 :                         appendPQExpBuffer(target, "COLUMN %s.",
   13195            0 :                                                           fmtId(tyinfo->dobj.name));
   13196            0 :                         appendPQExpBufferStr(target, fmtId(attname));
   13197              : 
   13198            0 :                         resetPQExpBuffer(query);
   13199            0 :                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   13200            0 :                                                           fmtQualifiedDumpable(tyinfo));
   13201            0 :                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   13202            0 :                         appendStringLiteralAH(query, descr, fout);
   13203            0 :                         appendPQExpBufferStr(query, ";\n");
   13204              : 
   13205            0 :                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   13206            0 :                                                  ARCHIVE_OPTS(.tag = target->data,
   13207              :                                                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   13208              :                                                                           .owner = tyinfo->rolname,
   13209              :                                                                           .description = "COMMENT",
   13210              :                                                                           .section = SECTION_NONE,
   13211              :                                                                           .createStmt = query->data,
   13212              :                                                                           .deps = &(tyinfo->dobj.dumpId),
   13213              :                                                                           .nDeps = 1));
   13214            0 :                 }
   13215              : 
   13216            0 :                 comments++;
   13217            0 :                 ncomments--;
   13218            0 :         }
   13219              : 
   13220            0 :         destroyPQExpBuffer(query);
   13221            0 :         destroyPQExpBuffer(target);
   13222            0 : }
   13223              : 
   13224              : /*
   13225              :  * dumpShellType
   13226              :  *        writes out to fout the queries to create a shell type
   13227              :  *
   13228              :  * We dump a shell definition in advance of the I/O functions for the type.
   13229              :  */
   13230              : static void
   13231            0 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   13232              : {
   13233            0 :         DumpOptions *dopt = fout->dopt;
   13234            0 :         PQExpBuffer q;
   13235              : 
   13236              :         /* Do nothing if not dumping schema */
   13237            0 :         if (!dopt->dumpSchema)
   13238            0 :                 return;
   13239              : 
   13240            0 :         q = createPQExpBuffer();
   13241              : 
   13242              :         /*
   13243              :          * Note the lack of a DROP command for the shell type; any required DROP
   13244              :          * is driven off the base type entry, instead.  This interacts with
   13245              :          * _printTocEntry()'s use of the presence of a DROP command to decide
   13246              :          * whether an entry needs an ALTER OWNER command.  We don't want to alter
   13247              :          * the shell type's owner immediately on creation; that should happen only
   13248              :          * after it's filled in, otherwise the backend complains.
   13249              :          */
   13250              : 
   13251            0 :         if (dopt->binary_upgrade)
   13252            0 :                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13253            0 :                                                                                                  stinfo->baseType->dobj.catId.oid,
   13254              :                                                                                                  false, false);
   13255              : 
   13256            0 :         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   13257            0 :                                           fmtQualifiedDumpable(stinfo));
   13258              : 
   13259            0 :         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13260            0 :                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   13261            0 :                                          ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   13262              :                                                                   .namespace = stinfo->dobj.namespace->dobj.name,
   13263              :                                                                   .owner = stinfo->baseType->rolname,
   13264              :                                                                   .description = "SHELL TYPE",
   13265              :                                                                   .section = SECTION_PRE_DATA,
   13266              :                                                                   .createStmt = q->data));
   13267              : 
   13268            0 :         destroyPQExpBuffer(q);
   13269            0 : }
   13270              : 
   13271              : /*
   13272              :  * dumpProcLang
   13273              :  *                writes out to fout the queries to recreate a user-defined
   13274              :  *                procedural language
   13275              :  */
   13276              : static void
   13277            0 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   13278              : {
   13279            0 :         DumpOptions *dopt = fout->dopt;
   13280            0 :         PQExpBuffer defqry;
   13281            0 :         PQExpBuffer delqry;
   13282            0 :         bool            useParams;
   13283            0 :         char       *qlanname;
   13284            0 :         FuncInfo   *funcInfo;
   13285            0 :         FuncInfo   *inlineInfo = NULL;
   13286            0 :         FuncInfo   *validatorInfo = NULL;
   13287              : 
   13288              :         /* Do nothing if not dumping schema */
   13289            0 :         if (!dopt->dumpSchema)
   13290            0 :                 return;
   13291              : 
   13292              :         /*
   13293              :          * Try to find the support function(s).  It is not an error if we don't
   13294              :          * find them --- if the functions are in the pg_catalog schema, as is
   13295              :          * standard in 8.1 and up, then we won't have loaded them. (In this case
   13296              :          * we will emit a parameterless CREATE LANGUAGE command, which will
   13297              :          * require PL template knowledge in the backend to reload.)
   13298              :          */
   13299              : 
   13300            0 :         funcInfo = findFuncByOid(plang->lanplcallfoid);
   13301            0 :         if (funcInfo != NULL && !funcInfo->dobj.dump)
   13302            0 :                 funcInfo = NULL;                /* treat not-dumped same as not-found */
   13303              : 
   13304            0 :         if (OidIsValid(plang->laninline))
   13305              :         {
   13306            0 :                 inlineInfo = findFuncByOid(plang->laninline);
   13307            0 :                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   13308            0 :                         inlineInfo = NULL;
   13309            0 :         }
   13310              : 
   13311            0 :         if (OidIsValid(plang->lanvalidator))
   13312              :         {
   13313            0 :                 validatorInfo = findFuncByOid(plang->lanvalidator);
   13314            0 :                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   13315            0 :                         validatorInfo = NULL;
   13316            0 :         }
   13317              : 
   13318              :         /*
   13319              :          * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   13320              :          * parameters.  Otherwise, we'll write a parameterless command, which will
   13321              :          * be interpreted as CREATE EXTENSION.
   13322              :          */
   13323            0 :         useParams = (funcInfo != NULL &&
   13324            0 :                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   13325            0 :                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   13326              : 
   13327            0 :         defqry = createPQExpBuffer();
   13328            0 :         delqry = createPQExpBuffer();
   13329              : 
   13330            0 :         qlanname = pg_strdup(fmtId(plang->dobj.name));
   13331              : 
   13332            0 :         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   13333            0 :                                           qlanname);
   13334              : 
   13335            0 :         if (useParams)
   13336              :         {
   13337            0 :                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   13338            0 :                                                   plang->lanpltrusted ? "TRUSTED " : "",
   13339            0 :                                                   qlanname);
   13340            0 :                 appendPQExpBuffer(defqry, " HANDLER %s",
   13341            0 :                                                   fmtQualifiedDumpable(funcInfo));
   13342            0 :                 if (OidIsValid(plang->laninline))
   13343            0 :                         appendPQExpBuffer(defqry, " INLINE %s",
   13344            0 :                                                           fmtQualifiedDumpable(inlineInfo));
   13345            0 :                 if (OidIsValid(plang->lanvalidator))
   13346            0 :                         appendPQExpBuffer(defqry, " VALIDATOR %s",
   13347            0 :                                                           fmtQualifiedDumpable(validatorInfo));
   13348            0 :         }
   13349              :         else
   13350              :         {
   13351              :                 /*
   13352              :                  * If not dumping parameters, then use CREATE OR REPLACE so that the
   13353              :                  * command will not fail if the language is preinstalled in the target
   13354              :                  * database.
   13355              :                  *
   13356              :                  * Modern servers will interpret this as CREATE EXTENSION IF NOT
   13357              :                  * EXISTS; perhaps we should emit that instead?  But it might just add
   13358              :                  * confusion.
   13359              :                  */
   13360            0 :                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   13361            0 :                                                   qlanname);
   13362              :         }
   13363            0 :         appendPQExpBufferStr(defqry, ";\n");
   13364              : 
   13365            0 :         if (dopt->binary_upgrade)
   13366            0 :                 binary_upgrade_extension_member(defqry, &plang->dobj,
   13367            0 :                                                                                 "LANGUAGE", qlanname, NULL);
   13368              : 
   13369            0 :         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13370            0 :                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   13371            0 :                                          ARCHIVE_OPTS(.tag = plang->dobj.name,
   13372              :                                                                   .owner = plang->lanowner,
   13373              :                                                                   .description = "PROCEDURAL LANGUAGE",
   13374              :                                                                   .section = SECTION_PRE_DATA,
   13375              :                                                                   .createStmt = defqry->data,
   13376              :                                                                   .dropStmt = delqry->data,
   13377              :                                                                   ));
   13378              : 
   13379              :         /* Dump Proc Lang Comments and Security Labels */
   13380            0 :         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   13381            0 :                 dumpComment(fout, "LANGUAGE", qlanname,
   13382            0 :                                         NULL, plang->lanowner,
   13383            0 :                                         plang->dobj.catId, 0, plang->dobj.dumpId);
   13384              : 
   13385            0 :         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13386            0 :                 dumpSecLabel(fout, "LANGUAGE", qlanname,
   13387            0 :                                          NULL, plang->lanowner,
   13388            0 :                                          plang->dobj.catId, 0, plang->dobj.dumpId);
   13389              : 
   13390            0 :         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   13391            0 :                 dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   13392            0 :                                 qlanname, NULL, NULL,
   13393            0 :                                 NULL, plang->lanowner, &plang->dacl);
   13394              : 
   13395            0 :         free(qlanname);
   13396              : 
   13397            0 :         destroyPQExpBuffer(defqry);
   13398            0 :         destroyPQExpBuffer(delqry);
   13399            0 : }
   13400              : 
   13401              : /*
   13402              :  * format_function_arguments: generate function name and argument list
   13403              :  *
   13404              :  * This is used when we can rely on pg_get_function_arguments to format
   13405              :  * the argument list.  Note, however, that pg_get_function_arguments
   13406              :  * does not special-case zero-argument aggregates.
   13407              :  */
   13408              : static char *
   13409            0 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   13410              : {
   13411            0 :         PQExpBufferData fn;
   13412              : 
   13413            0 :         initPQExpBuffer(&fn);
   13414            0 :         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   13415            0 :         if (is_agg && finfo->nargs == 0)
   13416            0 :                 appendPQExpBufferStr(&fn, "(*)");
   13417              :         else
   13418            0 :                 appendPQExpBuffer(&fn, "(%s)", funcargs);
   13419            0 :         return fn.data;
   13420            0 : }
   13421              : 
   13422              : /*
   13423              :  * format_function_signature: generate function name and argument list
   13424              :  *
   13425              :  * Only a minimal list of input argument types is generated; this is
   13426              :  * sufficient to reference the function, but not to define it.
   13427              :  *
   13428              :  * If honor_quotes is false then the function name is never quoted.
   13429              :  * This is appropriate for use in TOC tags, but not in SQL commands.
   13430              :  */
   13431              : static char *
   13432            0 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   13433              : {
   13434            0 :         PQExpBufferData fn;
   13435            0 :         int                     j;
   13436              : 
   13437            0 :         initPQExpBuffer(&fn);
   13438            0 :         if (honor_quotes)
   13439            0 :                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   13440              :         else
   13441            0 :                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   13442            0 :         for (j = 0; j < finfo->nargs; j++)
   13443              :         {
   13444            0 :                 if (j > 0)
   13445            0 :                         appendPQExpBufferStr(&fn, ", ");
   13446              : 
   13447            0 :                 appendPQExpBufferStr(&fn,
   13448            0 :                                                          getFormattedTypeName(fout, finfo->argtypes[j],
   13449              :                                                                                                   zeroIsError));
   13450            0 :         }
   13451            0 :         appendPQExpBufferChar(&fn, ')');
   13452            0 :         return fn.data;
   13453            0 : }
   13454              : 
   13455              : 
   13456              : /*
   13457              :  * dumpFunc:
   13458              :  *        dump out one function
   13459              :  */
   13460              : static void
   13461            0 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   13462              : {
   13463            0 :         DumpOptions *dopt = fout->dopt;
   13464            0 :         PQExpBuffer query;
   13465            0 :         PQExpBuffer q;
   13466            0 :         PQExpBuffer delqry;
   13467            0 :         PQExpBuffer asPart;
   13468            0 :         PGresult   *res;
   13469            0 :         char       *funcsig;            /* identity signature */
   13470            0 :         char       *funcfullsig = NULL; /* full signature */
   13471            0 :         char       *funcsig_tag;
   13472            0 :         char       *qual_funcsig;
   13473            0 :         char       *proretset;
   13474            0 :         char       *prosrc;
   13475            0 :         char       *probin;
   13476            0 :         char       *prosqlbody;
   13477            0 :         char       *funcargs;
   13478            0 :         char       *funciargs;
   13479            0 :         char       *funcresult;
   13480            0 :         char       *protrftypes;
   13481            0 :         char       *prokind;
   13482            0 :         char       *provolatile;
   13483            0 :         char       *proisstrict;
   13484            0 :         char       *prosecdef;
   13485            0 :         char       *proleakproof;
   13486            0 :         char       *proconfig;
   13487            0 :         char       *procost;
   13488            0 :         char       *prorows;
   13489            0 :         char       *prosupport;
   13490            0 :         char       *proparallel;
   13491            0 :         char       *lanname;
   13492            0 :         char      **configitems = NULL;
   13493            0 :         int                     nconfigitems = 0;
   13494            0 :         const char *keyword;
   13495              : 
   13496              :         /* Do nothing if not dumping schema */
   13497            0 :         if (!dopt->dumpSchema)
   13498            0 :                 return;
   13499              : 
   13500            0 :         query = createPQExpBuffer();
   13501            0 :         q = createPQExpBuffer();
   13502            0 :         delqry = createPQExpBuffer();
   13503            0 :         asPart = createPQExpBuffer();
   13504              : 
   13505            0 :         if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   13506              :         {
   13507              :                 /* Set up query for function-specific details */
   13508            0 :                 appendPQExpBufferStr(query,
   13509              :                                                          "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   13510              : 
   13511            0 :                 appendPQExpBufferStr(query,
   13512              :                                                          "SELECT\n"
   13513              :                                                          "proretset,\n"
   13514              :                                                          "prosrc,\n"
   13515              :                                                          "probin,\n"
   13516              :                                                          "provolatile,\n"
   13517              :                                                          "proisstrict,\n"
   13518              :                                                          "prosecdef,\n"
   13519              :                                                          "lanname,\n"
   13520              :                                                          "proconfig,\n"
   13521              :                                                          "procost,\n"
   13522              :                                                          "prorows,\n"
   13523              :                                                          "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   13524              :                                                          "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   13525              :                                                          "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   13526              :                                                          "proleakproof,\n");
   13527              : 
   13528            0 :                 if (fout->remoteVersion >= 90500)
   13529            0 :                         appendPQExpBufferStr(query,
   13530              :                                                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   13531              :                 else
   13532            0 :                         appendPQExpBufferStr(query,
   13533              :                                                                  "NULL AS protrftypes,\n");
   13534              : 
   13535            0 :                 if (fout->remoteVersion >= 90600)
   13536            0 :                         appendPQExpBufferStr(query,
   13537              :                                                                  "proparallel,\n");
   13538              :                 else
   13539            0 :                         appendPQExpBufferStr(query,
   13540              :                                                                  "'u' AS proparallel,\n");
   13541              : 
   13542            0 :                 if (fout->remoteVersion >= 110000)
   13543            0 :                         appendPQExpBufferStr(query,
   13544              :                                                                  "prokind,\n");
   13545              :                 else
   13546            0 :                         appendPQExpBufferStr(query,
   13547              :                                                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   13548              : 
   13549            0 :                 if (fout->remoteVersion >= 120000)
   13550            0 :                         appendPQExpBufferStr(query,
   13551              :                                                                  "prosupport,\n");
   13552              :                 else
   13553            0 :                         appendPQExpBufferStr(query,
   13554              :                                                                  "'-' AS prosupport,\n");
   13555              : 
   13556            0 :                 if (fout->remoteVersion >= 140000)
   13557            0 :                         appendPQExpBufferStr(query,
   13558              :                                                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   13559              :                 else
   13560            0 :                         appendPQExpBufferStr(query,
   13561              :                                                                  "NULL AS prosqlbody\n");
   13562              : 
   13563            0 :                 appendPQExpBufferStr(query,
   13564              :                                                          "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   13565              :                                                          "WHERE p.oid = $1 "
   13566              :                                                          "AND l.oid = p.prolang");
   13567              : 
   13568            0 :                 ExecuteSqlStatement(fout, query->data);
   13569              : 
   13570            0 :                 fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   13571            0 :         }
   13572              : 
   13573            0 :         printfPQExpBuffer(query,
   13574              :                                           "EXECUTE dumpFunc('%u')",
   13575            0 :                                           finfo->dobj.catId.oid);
   13576              : 
   13577            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13578              : 
   13579            0 :         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   13580            0 :         if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   13581              :         {
   13582            0 :                 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   13583            0 :                 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   13584            0 :                 prosqlbody = NULL;
   13585            0 :         }
   13586              :         else
   13587              :         {
   13588            0 :                 prosrc = NULL;
   13589            0 :                 probin = NULL;
   13590            0 :                 prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   13591              :         }
   13592            0 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   13593            0 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   13594            0 :         funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   13595            0 :         protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   13596            0 :         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   13597            0 :         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   13598            0 :         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   13599            0 :         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   13600            0 :         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   13601            0 :         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   13602            0 :         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   13603            0 :         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   13604            0 :         prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   13605            0 :         proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   13606            0 :         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   13607              : 
   13608              :         /*
   13609              :          * See backend/commands/functioncmds.c for details of how the 'AS' clause
   13610              :          * is used.
   13611              :          */
   13612            0 :         if (prosqlbody)
   13613              :         {
   13614            0 :                 appendPQExpBufferStr(asPart, prosqlbody);
   13615            0 :         }
   13616            0 :         else if (probin[0] != '\0')
   13617              :         {
   13618            0 :                 appendPQExpBufferStr(asPart, "AS ");
   13619            0 :                 appendStringLiteralAH(asPart, probin, fout);
   13620            0 :                 if (prosrc[0] != '\0')
   13621              :                 {
   13622            0 :                         appendPQExpBufferStr(asPart, ", ");
   13623              : 
   13624              :                         /*
   13625              :                          * where we have bin, use dollar quoting if allowed and src
   13626              :                          * contains quote or backslash; else use regular quoting.
   13627              :                          */
   13628            0 :                         if (dopt->disable_dollar_quoting ||
   13629            0 :                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   13630            0 :                                 appendStringLiteralAH(asPart, prosrc, fout);
   13631              :                         else
   13632            0 :                                 appendStringLiteralDQ(asPart, prosrc, NULL);
   13633            0 :                 }
   13634            0 :         }
   13635              :         else
   13636              :         {
   13637            0 :                 appendPQExpBufferStr(asPart, "AS ");
   13638              :                 /* with no bin, dollar quote src unconditionally if allowed */
   13639            0 :                 if (dopt->disable_dollar_quoting)
   13640            0 :                         appendStringLiteralAH(asPart, prosrc, fout);
   13641              :                 else
   13642            0 :                         appendStringLiteralDQ(asPart, prosrc, NULL);
   13643              :         }
   13644              : 
   13645            0 :         if (*proconfig)
   13646              :         {
   13647            0 :                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   13648            0 :                         pg_fatal("could not parse %s array", "proconfig");
   13649            0 :         }
   13650              :         else
   13651              :         {
   13652            0 :                 configitems = NULL;
   13653            0 :                 nconfigitems = 0;
   13654              :         }
   13655              : 
   13656            0 :         funcfullsig = format_function_arguments(finfo, funcargs, false);
   13657            0 :         funcsig = format_function_arguments(finfo, funciargs, false);
   13658              : 
   13659            0 :         funcsig_tag = format_function_signature(fout, finfo, false);
   13660              : 
   13661            0 :         qual_funcsig = psprintf("%s.%s",
   13662            0 :                                                         fmtId(finfo->dobj.namespace->dobj.name),
   13663            0 :                                                         funcsig);
   13664              : 
   13665            0 :         if (prokind[0] == PROKIND_PROCEDURE)
   13666            0 :                 keyword = "PROCEDURE";
   13667              :         else
   13668            0 :                 keyword = "FUNCTION"; /* works for window functions too */
   13669              : 
   13670            0 :         appendPQExpBuffer(delqry, "DROP %s %s;\n",
   13671            0 :                                           keyword, qual_funcsig);
   13672              : 
   13673            0 :         appendPQExpBuffer(q, "CREATE %s %s.%s",
   13674            0 :                                           keyword,
   13675            0 :                                           fmtId(finfo->dobj.namespace->dobj.name),
   13676            0 :                                           funcfullsig ? funcfullsig :
   13677            0 :                                           funcsig);
   13678              : 
   13679            0 :         if (prokind[0] == PROKIND_PROCEDURE)
   13680              :                  /* no result type to output */ ;
   13681            0 :         else if (funcresult)
   13682            0 :                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
   13683              :         else
   13684            0 :                 appendPQExpBuffer(q, " RETURNS %s%s",
   13685            0 :                                                   (proretset[0] == 't') ? "SETOF " : "",
   13686            0 :                                                   getFormattedTypeName(fout, finfo->prorettype,
   13687              :                                                                                            zeroIsError));
   13688              : 
   13689            0 :         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   13690              : 
   13691            0 :         if (*protrftypes)
   13692              :         {
   13693            0 :                 Oid                *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
   13694            0 :                 int                     i;
   13695              : 
   13696            0 :                 appendPQExpBufferStr(q, " TRANSFORM ");
   13697            0 :                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   13698            0 :                 for (i = 0; typeids[i]; i++)
   13699              :                 {
   13700            0 :                         if (i != 0)
   13701            0 :                                 appendPQExpBufferStr(q, ", ");
   13702            0 :                         appendPQExpBuffer(q, "FOR TYPE %s",
   13703            0 :                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
   13704            0 :                 }
   13705              : 
   13706            0 :                 free(typeids);
   13707            0 :         }
   13708              : 
   13709            0 :         if (prokind[0] == PROKIND_WINDOW)
   13710            0 :                 appendPQExpBufferStr(q, " WINDOW");
   13711              : 
   13712            0 :         if (provolatile[0] != PROVOLATILE_VOLATILE)
   13713              :         {
   13714            0 :                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   13715            0 :                         appendPQExpBufferStr(q, " IMMUTABLE");
   13716            0 :                 else if (provolatile[0] == PROVOLATILE_STABLE)
   13717            0 :                         appendPQExpBufferStr(q, " STABLE");
   13718            0 :                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
   13719            0 :                         pg_fatal("unrecognized provolatile value for function \"%s\"",
   13720              :                                          finfo->dobj.name);
   13721            0 :         }
   13722              : 
   13723            0 :         if (proisstrict[0] == 't')
   13724            0 :                 appendPQExpBufferStr(q, " STRICT");
   13725              : 
   13726            0 :         if (prosecdef[0] == 't')
   13727            0 :                 appendPQExpBufferStr(q, " SECURITY DEFINER");
   13728              : 
   13729            0 :         if (proleakproof[0] == 't')
   13730            0 :                 appendPQExpBufferStr(q, " LEAKPROOF");
   13731              : 
   13732              :         /*
   13733              :          * COST and ROWS are emitted only if present and not default, so as not to
   13734              :          * break backwards-compatibility of the dump without need.  Keep this code
   13735              :          * in sync with the defaults in functioncmds.c.
   13736              :          */
   13737            0 :         if (strcmp(procost, "0") != 0)
   13738              :         {
   13739            0 :                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   13740              :                 {
   13741              :                         /* default cost is 1 */
   13742            0 :                         if (strcmp(procost, "1") != 0)
   13743            0 :                                 appendPQExpBuffer(q, " COST %s", procost);
   13744            0 :                 }
   13745              :                 else
   13746              :                 {
   13747              :                         /* default cost is 100 */
   13748            0 :                         if (strcmp(procost, "100") != 0)
   13749            0 :                                 appendPQExpBuffer(q, " COST %s", procost);
   13750              :                 }
   13751            0 :         }
   13752            0 :         if (proretset[0] == 't' &&
   13753            0 :                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   13754            0 :                 appendPQExpBuffer(q, " ROWS %s", prorows);
   13755              : 
   13756            0 :         if (strcmp(prosupport, "-") != 0)
   13757              :         {
   13758              :                 /* We rely on regprocout to provide quoting and qualification */
   13759            0 :                 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   13760            0 :         }
   13761              : 
   13762            0 :         if (proparallel[0] != PROPARALLEL_UNSAFE)
   13763              :         {
   13764            0 :                 if (proparallel[0] == PROPARALLEL_SAFE)
   13765            0 :                         appendPQExpBufferStr(q, " PARALLEL SAFE");
   13766            0 :                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   13767            0 :                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   13768            0 :                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
   13769            0 :                         pg_fatal("unrecognized proparallel value for function \"%s\"",
   13770              :                                          finfo->dobj.name);
   13771            0 :         }
   13772              : 
   13773            0 :         for (int i = 0; i < nconfigitems; i++)
   13774              :         {
   13775              :                 /* we feel free to scribble on configitems[] here */
   13776            0 :                 char       *configitem = configitems[i];
   13777            0 :                 char       *pos;
   13778              : 
   13779            0 :                 pos = strchr(configitem, '=');
   13780            0 :                 if (pos == NULL)
   13781            0 :                         continue;
   13782            0 :                 *pos++ = '\0';
   13783            0 :                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   13784              : 
   13785              :                 /*
   13786              :                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   13787              :                  * by flatten_set_variable_args() before they were put into the
   13788              :                  * proconfig array.  However, because the quoting rules used there
   13789              :                  * aren't exactly like SQL's, we have to break the list value apart
   13790              :                  * and then quote the elements as string literals.  (The elements may
   13791              :                  * be double-quoted as-is, but we can't just feed them to the SQL
   13792              :                  * parser; it would do the wrong thing with elements that are
   13793              :                  * zero-length or longer than NAMEDATALEN.)  Also, we need a special
   13794              :                  * case for empty lists.
   13795              :                  *
   13796              :                  * Variables that are not so marked should just be emitted as simple
   13797              :                  * string literals.  If the variable is not known to
   13798              :                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   13799              :                  * to use GUC_LIST_QUOTE for extension variables.
   13800              :                  */
   13801            0 :                 if (variable_is_guc_list_quote(configitem))
   13802              :                 {
   13803            0 :                         char      **namelist;
   13804            0 :                         char      **nameptr;
   13805              : 
   13806              :                         /* Parse string into list of identifiers */
   13807              :                         /* this shouldn't fail really */
   13808            0 :                         if (SplitGUCList(pos, ',', &namelist))
   13809              :                         {
   13810              :                                 /* Special case: represent an empty list as NULL */
   13811            0 :                                 if (*namelist == NULL)
   13812            0 :                                         appendPQExpBufferStr(q, "NULL");
   13813            0 :                                 for (nameptr = namelist; *nameptr; nameptr++)
   13814              :                                 {
   13815            0 :                                         if (nameptr != namelist)
   13816            0 :                                                 appendPQExpBufferStr(q, ", ");
   13817            0 :                                         appendStringLiteralAH(q, *nameptr, fout);
   13818            0 :                                 }
   13819            0 :                         }
   13820            0 :                         pg_free(namelist);
   13821            0 :                 }
   13822              :                 else
   13823            0 :                         appendStringLiteralAH(q, pos, fout);
   13824            0 :         }
   13825              : 
   13826            0 :         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13827              : 
   13828            0 :         append_depends_on_extension(fout, q, &finfo->dobj,
   13829            0 :                                                                 "pg_catalog.pg_proc", keyword,
   13830            0 :                                                                 qual_funcsig);
   13831              : 
   13832            0 :         if (dopt->binary_upgrade)
   13833            0 :                 binary_upgrade_extension_member(q, &finfo->dobj,
   13834            0 :                                                                                 keyword, funcsig,
   13835            0 :                                                                                 finfo->dobj.namespace->dobj.name);
   13836              : 
   13837            0 :         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13838            0 :                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13839            0 :                                          ARCHIVE_OPTS(.tag = funcsig_tag,
   13840              :                                                                   .namespace = finfo->dobj.namespace->dobj.name,
   13841              :                                                                   .owner = finfo->rolname,
   13842              :                                                                   .description = keyword,
   13843              :                                                                   .section = finfo->postponed_def ?
   13844              :                                                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   13845              :                                                                   .createStmt = q->data,
   13846              :                                                                   .dropStmt = delqry->data));
   13847              : 
   13848              :         /* Dump Function Comments and Security Labels */
   13849            0 :         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13850            0 :                 dumpComment(fout, keyword, funcsig,
   13851            0 :                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
   13852            0 :                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13853              : 
   13854            0 :         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13855            0 :                 dumpSecLabel(fout, keyword, funcsig,
   13856            0 :                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
   13857            0 :                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13858              : 
   13859            0 :         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   13860            0 :                 dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   13861            0 :                                 funcsig, NULL,
   13862            0 :                                 finfo->dobj.namespace->dobj.name,
   13863            0 :                                 NULL, finfo->rolname, &finfo->dacl);
   13864              : 
   13865            0 :         PQclear(res);
   13866              : 
   13867            0 :         destroyPQExpBuffer(query);
   13868            0 :         destroyPQExpBuffer(q);
   13869            0 :         destroyPQExpBuffer(delqry);
   13870            0 :         destroyPQExpBuffer(asPart);
   13871            0 :         free(funcsig);
   13872            0 :         free(funcfullsig);
   13873            0 :         free(funcsig_tag);
   13874            0 :         free(qual_funcsig);
   13875            0 :         free(configitems);
   13876            0 : }
   13877              : 
   13878              : 
   13879              : /*
   13880              :  * Dump a user-defined cast
   13881              :  */
   13882              : static void
   13883            0 : dumpCast(Archive *fout, const CastInfo *cast)
   13884              : {
   13885            0 :         DumpOptions *dopt = fout->dopt;
   13886            0 :         PQExpBuffer defqry;
   13887            0 :         PQExpBuffer delqry;
   13888            0 :         PQExpBuffer labelq;
   13889            0 :         PQExpBuffer castargs;
   13890            0 :         FuncInfo   *funcInfo = NULL;
   13891            0 :         const char *sourceType;
   13892            0 :         const char *targetType;
   13893              : 
   13894              :         /* Do nothing if not dumping schema */
   13895            0 :         if (!dopt->dumpSchema)
   13896            0 :                 return;
   13897              : 
   13898              :         /* Cannot dump if we don't have the cast function's info */
   13899            0 :         if (OidIsValid(cast->castfunc))
   13900              :         {
   13901            0 :                 funcInfo = findFuncByOid(cast->castfunc);
   13902            0 :                 if (funcInfo == NULL)
   13903            0 :                         pg_fatal("could not find function definition for function with OID %u",
   13904              :                                          cast->castfunc);
   13905            0 :         }
   13906              : 
   13907            0 :         defqry = createPQExpBuffer();
   13908            0 :         delqry = createPQExpBuffer();
   13909            0 :         labelq = createPQExpBuffer();
   13910            0 :         castargs = createPQExpBuffer();
   13911              : 
   13912            0 :         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   13913            0 :         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   13914            0 :         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   13915            0 :                                           sourceType, targetType);
   13916              : 
   13917            0 :         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   13918            0 :                                           sourceType, targetType);
   13919              : 
   13920            0 :         switch (cast->castmethod)
   13921              :         {
   13922              :                 case COERCION_METHOD_BINARY:
   13923            0 :                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   13924            0 :                         break;
   13925              :                 case COERCION_METHOD_INOUT:
   13926            0 :                         appendPQExpBufferStr(defqry, "WITH INOUT");
   13927            0 :                         break;
   13928              :                 case COERCION_METHOD_FUNCTION:
   13929            0 :                         if (funcInfo)
   13930              :                         {
   13931            0 :                                 char       *fsig = format_function_signature(fout, funcInfo, true);
   13932              : 
   13933              :                                 /*
   13934              :                                  * Always qualify the function name (format_function_signature
   13935              :                                  * won't qualify it).
   13936              :                                  */
   13937            0 :                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   13938            0 :                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   13939            0 :                                 free(fsig);
   13940            0 :                         }
   13941              :                         else
   13942            0 :                                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   13943            0 :                         break;
   13944              :                 default:
   13945            0 :                         pg_log_warning("bogus value in pg_cast.castmethod field");
   13946            0 :         }
   13947              : 
   13948            0 :         if (cast->castcontext == 'a')
   13949            0 :                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   13950            0 :         else if (cast->castcontext == 'i')
   13951            0 :                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
   13952            0 :         appendPQExpBufferStr(defqry, ";\n");
   13953              : 
   13954            0 :         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   13955            0 :                                           sourceType, targetType);
   13956              : 
   13957            0 :         appendPQExpBuffer(castargs, "(%s AS %s)",
   13958            0 :                                           sourceType, targetType);
   13959              : 
   13960            0 :         if (dopt->binary_upgrade)
   13961            0 :                 binary_upgrade_extension_member(defqry, &cast->dobj,
   13962            0 :                                                                                 "CAST", castargs->data, NULL);
   13963              : 
   13964            0 :         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13965            0 :                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   13966            0 :                                          ARCHIVE_OPTS(.tag = labelq->data,
   13967              :                                                                   .description = "CAST",
   13968              :                                                                   .section = SECTION_PRE_DATA,
   13969              :                                                                   .createStmt = defqry->data,
   13970              :                                                                   .dropStmt = delqry->data));
   13971              : 
   13972              :         /* Dump Cast Comments */
   13973            0 :         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   13974            0 :                 dumpComment(fout, "CAST", castargs->data,
   13975              :                                         NULL, "",
   13976            0 :                                         cast->dobj.catId, 0, cast->dobj.dumpId);
   13977              : 
   13978            0 :         destroyPQExpBuffer(defqry);
   13979            0 :         destroyPQExpBuffer(delqry);
   13980            0 :         destroyPQExpBuffer(labelq);
   13981            0 :         destroyPQExpBuffer(castargs);
   13982            0 : }
   13983              : 
   13984              : /*
   13985              :  * Dump a transform
   13986              :  */
   13987              : static void
   13988            0 : dumpTransform(Archive *fout, const TransformInfo *transform)
   13989              : {
   13990            0 :         DumpOptions *dopt = fout->dopt;
   13991            0 :         PQExpBuffer defqry;
   13992            0 :         PQExpBuffer delqry;
   13993            0 :         PQExpBuffer labelq;
   13994            0 :         PQExpBuffer transformargs;
   13995            0 :         FuncInfo   *fromsqlFuncInfo = NULL;
   13996            0 :         FuncInfo   *tosqlFuncInfo = NULL;
   13997            0 :         char       *lanname;
   13998            0 :         const char *transformType;
   13999              : 
   14000              :         /* Do nothing if not dumping schema */
   14001            0 :         if (!dopt->dumpSchema)
   14002            0 :                 return;
   14003              : 
   14004              :         /* Cannot dump if we don't have the transform functions' info */
   14005            0 :         if (OidIsValid(transform->trffromsql))
   14006              :         {
   14007            0 :                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   14008            0 :                 if (fromsqlFuncInfo == NULL)
   14009            0 :                         pg_fatal("could not find function definition for function with OID %u",
   14010              :                                          transform->trffromsql);
   14011            0 :         }
   14012            0 :         if (OidIsValid(transform->trftosql))
   14013              :         {
   14014            0 :                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
   14015            0 :                 if (tosqlFuncInfo == NULL)
   14016            0 :                         pg_fatal("could not find function definition for function with OID %u",
   14017              :                                          transform->trftosql);
   14018            0 :         }
   14019              : 
   14020            0 :         defqry = createPQExpBuffer();
   14021            0 :         delqry = createPQExpBuffer();
   14022            0 :         labelq = createPQExpBuffer();
   14023            0 :         transformargs = createPQExpBuffer();
   14024              : 
   14025            0 :         lanname = get_language_name(fout, transform->trflang);
   14026            0 :         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   14027              : 
   14028            0 :         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   14029            0 :                                           transformType, lanname);
   14030              : 
   14031            0 :         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   14032            0 :                                           transformType, lanname);
   14033              : 
   14034            0 :         if (!transform->trffromsql && !transform->trftosql)
   14035            0 :                 pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   14036              : 
   14037            0 :         if (transform->trffromsql)
   14038              :         {
   14039            0 :                 if (fromsqlFuncInfo)
   14040              :                 {
   14041            0 :                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   14042              : 
   14043              :                         /*
   14044              :                          * Always qualify the function name (format_function_signature
   14045              :                          * won't qualify it).
   14046              :                          */
   14047            0 :                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   14048            0 :                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14049            0 :                         free(fsig);
   14050            0 :                 }
   14051              :                 else
   14052            0 :                         pg_log_warning("bogus value in pg_transform.trffromsql field");
   14053            0 :         }
   14054              : 
   14055            0 :         if (transform->trftosql)
   14056              :         {
   14057            0 :                 if (transform->trffromsql)
   14058            0 :                         appendPQExpBufferStr(defqry, ", ");
   14059              : 
   14060            0 :                 if (tosqlFuncInfo)
   14061              :                 {
   14062            0 :                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   14063              : 
   14064              :                         /*
   14065              :                          * Always qualify the function name (format_function_signature
   14066              :                          * won't qualify it).
   14067              :                          */
   14068            0 :                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   14069            0 :                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14070            0 :                         free(fsig);
   14071            0 :                 }
   14072              :                 else
   14073            0 :                         pg_log_warning("bogus value in pg_transform.trftosql field");
   14074            0 :         }
   14075              : 
   14076            0 :         appendPQExpBufferStr(defqry, ");\n");
   14077              : 
   14078            0 :         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   14079            0 :                                           transformType, lanname);
   14080              : 
   14081            0 :         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   14082            0 :                                           transformType, lanname);
   14083              : 
   14084            0 :         if (dopt->binary_upgrade)
   14085            0 :                 binary_upgrade_extension_member(defqry, &transform->dobj,
   14086            0 :                                                                                 "TRANSFORM", transformargs->data, NULL);
   14087              : 
   14088            0 :         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14089            0 :                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   14090            0 :                                          ARCHIVE_OPTS(.tag = labelq->data,
   14091              :                                                                   .description = "TRANSFORM",
   14092              :                                                                   .section = SECTION_PRE_DATA,
   14093              :                                                                   .createStmt = defqry->data,
   14094              :                                                                   .dropStmt = delqry->data,
   14095              :                                                                   .deps = transform->dobj.dependencies,
   14096              :                                                                   .nDeps = transform->dobj.nDeps));
   14097              : 
   14098              :         /* Dump Transform Comments */
   14099            0 :         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   14100            0 :                 dumpComment(fout, "TRANSFORM", transformargs->data,
   14101              :                                         NULL, "",
   14102            0 :                                         transform->dobj.catId, 0, transform->dobj.dumpId);
   14103              : 
   14104            0 :         free(lanname);
   14105            0 :         destroyPQExpBuffer(defqry);
   14106            0 :         destroyPQExpBuffer(delqry);
   14107            0 :         destroyPQExpBuffer(labelq);
   14108            0 :         destroyPQExpBuffer(transformargs);
   14109            0 : }
   14110              : 
   14111              : 
   14112              : /*
   14113              :  * dumpOpr
   14114              :  *        write out a single operator definition
   14115              :  */
   14116              : static void
   14117            0 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   14118              : {
   14119            0 :         DumpOptions *dopt = fout->dopt;
   14120            0 :         PQExpBuffer query;
   14121            0 :         PQExpBuffer q;
   14122            0 :         PQExpBuffer delq;
   14123            0 :         PQExpBuffer oprid;
   14124            0 :         PQExpBuffer details;
   14125            0 :         PGresult   *res;
   14126            0 :         int                     i_oprkind;
   14127            0 :         int                     i_oprcode;
   14128            0 :         int                     i_oprleft;
   14129            0 :         int                     i_oprright;
   14130            0 :         int                     i_oprcom;
   14131            0 :         int                     i_oprnegate;
   14132            0 :         int                     i_oprrest;
   14133            0 :         int                     i_oprjoin;
   14134            0 :         int                     i_oprcanmerge;
   14135            0 :         int                     i_oprcanhash;
   14136            0 :         char       *oprkind;
   14137            0 :         char       *oprcode;
   14138            0 :         char       *oprleft;
   14139            0 :         char       *oprright;
   14140            0 :         char       *oprcom;
   14141            0 :         char       *oprnegate;
   14142            0 :         char       *oprrest;
   14143            0 :         char       *oprjoin;
   14144            0 :         char       *oprcanmerge;
   14145            0 :         char       *oprcanhash;
   14146            0 :         char       *oprregproc;
   14147            0 :         char       *oprref;
   14148              : 
   14149              :         /* Do nothing if not dumping schema */
   14150            0 :         if (!dopt->dumpSchema)
   14151            0 :                 return;
   14152              : 
   14153              :         /*
   14154              :          * some operators are invalid because they were the result of user
   14155              :          * defining operators before commutators exist
   14156              :          */
   14157            0 :         if (!OidIsValid(oprinfo->oprcode))
   14158            0 :                 return;
   14159              : 
   14160            0 :         query = createPQExpBuffer();
   14161            0 :         q = createPQExpBuffer();
   14162            0 :         delq = createPQExpBuffer();
   14163            0 :         oprid = createPQExpBuffer();
   14164            0 :         details = createPQExpBuffer();
   14165              : 
   14166            0 :         if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   14167              :         {
   14168              :                 /* Set up query for operator-specific details */
   14169            0 :                 appendPQExpBufferStr(query,
   14170              :                                                          "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   14171              :                                                          "SELECT oprkind, "
   14172              :                                                          "oprcode::pg_catalog.regprocedure, "
   14173              :                                                          "oprleft::pg_catalog.regtype, "
   14174              :                                                          "oprright::pg_catalog.regtype, "
   14175              :                                                          "oprcom, "
   14176              :                                                          "oprnegate, "
   14177              :                                                          "oprrest::pg_catalog.regprocedure, "
   14178              :                                                          "oprjoin::pg_catalog.regprocedure, "
   14179              :                                                          "oprcanmerge, oprcanhash "
   14180              :                                                          "FROM pg_catalog.pg_operator "
   14181              :                                                          "WHERE oid = $1");
   14182              : 
   14183            0 :                 ExecuteSqlStatement(fout, query->data);
   14184              : 
   14185            0 :                 fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   14186            0 :         }
   14187              : 
   14188            0 :         printfPQExpBuffer(query,
   14189              :                                           "EXECUTE dumpOpr('%u')",
   14190            0 :                                           oprinfo->dobj.catId.oid);
   14191              : 
   14192            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14193              : 
   14194            0 :         i_oprkind = PQfnumber(res, "oprkind");
   14195            0 :         i_oprcode = PQfnumber(res, "oprcode");
   14196            0 :         i_oprleft = PQfnumber(res, "oprleft");
   14197            0 :         i_oprright = PQfnumber(res, "oprright");
   14198            0 :         i_oprcom = PQfnumber(res, "oprcom");
   14199            0 :         i_oprnegate = PQfnumber(res, "oprnegate");
   14200            0 :         i_oprrest = PQfnumber(res, "oprrest");
   14201            0 :         i_oprjoin = PQfnumber(res, "oprjoin");
   14202            0 :         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   14203            0 :         i_oprcanhash = PQfnumber(res, "oprcanhash");
   14204              : 
   14205            0 :         oprkind = PQgetvalue(res, 0, i_oprkind);
   14206            0 :         oprcode = PQgetvalue(res, 0, i_oprcode);
   14207            0 :         oprleft = PQgetvalue(res, 0, i_oprleft);
   14208            0 :         oprright = PQgetvalue(res, 0, i_oprright);
   14209            0 :         oprcom = PQgetvalue(res, 0, i_oprcom);
   14210            0 :         oprnegate = PQgetvalue(res, 0, i_oprnegate);
   14211            0 :         oprrest = PQgetvalue(res, 0, i_oprrest);
   14212            0 :         oprjoin = PQgetvalue(res, 0, i_oprjoin);
   14213            0 :         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   14214            0 :         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   14215              : 
   14216              :         /* In PG14 upwards postfix operator support does not exist anymore. */
   14217            0 :         if (strcmp(oprkind, "r") == 0)
   14218            0 :                 pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   14219              :                                            oprcode);
   14220              : 
   14221            0 :         oprregproc = convertRegProcReference(oprcode);
   14222            0 :         if (oprregproc)
   14223              :         {
   14224            0 :                 appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   14225            0 :                 free(oprregproc);
   14226            0 :         }
   14227              : 
   14228            0 :         appendPQExpBuffer(oprid, "%s (",
   14229            0 :                                           oprinfo->dobj.name);
   14230              : 
   14231              :         /*
   14232              :          * right unary means there's a left arg and left unary means there's a
   14233              :          * right arg.  (Although the "r" case is dead code for PG14 and later,
   14234              :          * continue to support it in case we're dumping from an old server.)
   14235              :          */
   14236            0 :         if (strcmp(oprkind, "r") == 0 ||
   14237            0 :                 strcmp(oprkind, "b") == 0)
   14238              :         {
   14239            0 :                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   14240            0 :                 appendPQExpBufferStr(oprid, oprleft);
   14241            0 :         }
   14242              :         else
   14243            0 :                 appendPQExpBufferStr(oprid, "NONE");
   14244              : 
   14245            0 :         if (strcmp(oprkind, "l") == 0 ||
   14246            0 :                 strcmp(oprkind, "b") == 0)
   14247              :         {
   14248            0 :                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   14249            0 :                 appendPQExpBuffer(oprid, ", %s)", oprright);
   14250            0 :         }
   14251              :         else
   14252            0 :                 appendPQExpBufferStr(oprid, ", NONE)");
   14253              : 
   14254            0 :         oprref = getFormattedOperatorName(oprcom);
   14255            0 :         if (oprref)
   14256              :         {
   14257            0 :                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   14258            0 :                 free(oprref);
   14259            0 :         }
   14260              : 
   14261            0 :         oprref = getFormattedOperatorName(oprnegate);
   14262            0 :         if (oprref)
   14263              :         {
   14264            0 :                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   14265            0 :                 free(oprref);
   14266            0 :         }
   14267              : 
   14268            0 :         if (strcmp(oprcanmerge, "t") == 0)
   14269            0 :                 appendPQExpBufferStr(details, ",\n    MERGES");
   14270              : 
   14271            0 :         if (strcmp(oprcanhash, "t") == 0)
   14272            0 :                 appendPQExpBufferStr(details, ",\n    HASHES");
   14273              : 
   14274            0 :         oprregproc = convertRegProcReference(oprrest);
   14275            0 :         if (oprregproc)
   14276              :         {
   14277            0 :                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   14278            0 :                 free(oprregproc);
   14279            0 :         }
   14280              : 
   14281            0 :         oprregproc = convertRegProcReference(oprjoin);
   14282            0 :         if (oprregproc)
   14283              :         {
   14284            0 :                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   14285            0 :                 free(oprregproc);
   14286            0 :         }
   14287              : 
   14288            0 :         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   14289            0 :                                           fmtId(oprinfo->dobj.namespace->dobj.name),
   14290            0 :                                           oprid->data);
   14291              : 
   14292            0 :         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   14293            0 :                                           fmtId(oprinfo->dobj.namespace->dobj.name),
   14294            0 :                                           oprinfo->dobj.name, details->data);
   14295              : 
   14296            0 :         if (dopt->binary_upgrade)
   14297            0 :                 binary_upgrade_extension_member(q, &oprinfo->dobj,
   14298            0 :                                                                                 "OPERATOR", oprid->data,
   14299            0 :                                                                                 oprinfo->dobj.namespace->dobj.name);
   14300              : 
   14301            0 :         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14302            0 :                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   14303            0 :                                          ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   14304              :                                                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   14305              :                                                                   .owner = oprinfo->rolname,
   14306              :                                                                   .description = "OPERATOR",
   14307              :                                                                   .section = SECTION_PRE_DATA,
   14308              :                                                                   .createStmt = q->data,
   14309              :                                                                   .dropStmt = delq->data));
   14310              : 
   14311              :         /* Dump Operator Comments */
   14312            0 :         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14313            0 :                 dumpComment(fout, "OPERATOR", oprid->data,
   14314            0 :                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   14315            0 :                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   14316              : 
   14317            0 :         PQclear(res);
   14318              : 
   14319            0 :         destroyPQExpBuffer(query);
   14320            0 :         destroyPQExpBuffer(q);
   14321            0 :         destroyPQExpBuffer(delq);
   14322            0 :         destroyPQExpBuffer(oprid);
   14323            0 :         destroyPQExpBuffer(details);
   14324            0 : }
   14325              : 
   14326              : /*
   14327              :  * Convert a function reference obtained from pg_operator
   14328              :  *
   14329              :  * Returns allocated string of what to print, or NULL if function references
   14330              :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   14331              :  *
   14332              :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   14333              :  * part.
   14334              :  */
   14335              : static char *
   14336            0 : convertRegProcReference(const char *proc)
   14337              : {
   14338            0 :         char       *name;
   14339            0 :         char       *paren;
   14340            0 :         bool            inquote;
   14341              : 
   14342              :         /* In all cases "-" means a null reference */
   14343            0 :         if (strcmp(proc, "-") == 0)
   14344            0 :                 return NULL;
   14345              : 
   14346            0 :         name = pg_strdup(proc);
   14347              :         /* find non-double-quoted left paren */
   14348            0 :         inquote = false;
   14349            0 :         for (paren = name; *paren; paren++)
   14350              :         {
   14351            0 :                 if (*paren == '(' && !inquote)
   14352              :                 {
   14353            0 :                         *paren = '\0';
   14354            0 :                         break;
   14355              :                 }
   14356            0 :                 if (*paren == '"')
   14357            0 :                         inquote = !inquote;
   14358            0 :         }
   14359            0 :         return name;
   14360            0 : }
   14361              : 
   14362              : /*
   14363              :  * getFormattedOperatorName - retrieve the operator name for the
   14364              :  * given operator OID (presented in string form).
   14365              :  *
   14366              :  * Returns an allocated string, or NULL if the given OID is invalid.
   14367              :  * Caller is responsible for free'ing result string.
   14368              :  *
   14369              :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   14370              :  * useful in commands where the operator's argument types can be inferred from
   14371              :  * context.  We always schema-qualify the name, though.  The predecessor to
   14372              :  * this code tried to skip the schema qualification if possible, but that led
   14373              :  * to wrong results in corner cases, such as if an operator and its negator
   14374              :  * are in different schemas.
   14375              :  */
   14376              : static char *
   14377            0 : getFormattedOperatorName(const char *oproid)
   14378              : {
   14379            0 :         OprInfo    *oprInfo;
   14380              : 
   14381              :         /* In all cases "0" means a null reference */
   14382            0 :         if (strcmp(oproid, "0") == 0)
   14383            0 :                 return NULL;
   14384              : 
   14385            0 :         oprInfo = findOprByOid(atooid(oproid));
   14386            0 :         if (oprInfo == NULL)
   14387              :         {
   14388            0 :                 pg_log_warning("could not find operator with OID %s",
   14389              :                                            oproid);
   14390            0 :                 return NULL;
   14391              :         }
   14392              : 
   14393            0 :         return psprintf("OPERATOR(%s.%s)",
   14394            0 :                                         fmtId(oprInfo->dobj.namespace->dobj.name),
   14395            0 :                                         oprInfo->dobj.name);
   14396            0 : }
   14397              : 
   14398              : /*
   14399              :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   14400              :  *
   14401              :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   14402              :  * argument lists of these functions are predetermined.  Note that the
   14403              :  * caller should ensure we are in the proper schema, because the results
   14404              :  * are search path dependent!
   14405              :  */
   14406              : static char *
   14407            0 : convertTSFunction(Archive *fout, Oid funcOid)
   14408              : {
   14409            0 :         char       *result;
   14410            0 :         char            query[128];
   14411            0 :         PGresult   *res;
   14412              : 
   14413            0 :         snprintf(query, sizeof(query),
   14414            0 :                          "SELECT '%u'::pg_catalog.regproc", funcOid);
   14415            0 :         res = ExecuteSqlQueryForSingleRow(fout, query);
   14416              : 
   14417            0 :         result = pg_strdup(PQgetvalue(res, 0, 0));
   14418              : 
   14419            0 :         PQclear(res);
   14420              : 
   14421            0 :         return result;
   14422            0 : }
   14423              : 
   14424              : /*
   14425              :  * dumpAccessMethod
   14426              :  *        write out a single access method definition
   14427              :  */
   14428              : static void
   14429            0 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   14430              : {
   14431            0 :         DumpOptions *dopt = fout->dopt;
   14432            0 :         PQExpBuffer q;
   14433            0 :         PQExpBuffer delq;
   14434            0 :         char       *qamname;
   14435              : 
   14436              :         /* Do nothing if not dumping schema */
   14437            0 :         if (!dopt->dumpSchema)
   14438            0 :                 return;
   14439              : 
   14440            0 :         q = createPQExpBuffer();
   14441            0 :         delq = createPQExpBuffer();
   14442              : 
   14443            0 :         qamname = pg_strdup(fmtId(aminfo->dobj.name));
   14444              : 
   14445            0 :         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   14446              : 
   14447            0 :         switch (aminfo->amtype)
   14448              :         {
   14449              :                 case AMTYPE_INDEX:
   14450            0 :                         appendPQExpBufferStr(q, "TYPE INDEX ");
   14451            0 :                         break;
   14452              :                 case AMTYPE_TABLE:
   14453            0 :                         appendPQExpBufferStr(q, "TYPE TABLE ");
   14454            0 :                         break;
   14455              :                 default:
   14456            0 :                         pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   14457              :                                                    aminfo->amtype, qamname);
   14458            0 :                         destroyPQExpBuffer(q);
   14459            0 :                         destroyPQExpBuffer(delq);
   14460            0 :                         free(qamname);
   14461            0 :                         return;
   14462              :         }
   14463              : 
   14464            0 :         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   14465              : 
   14466            0 :         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   14467            0 :                                           qamname);
   14468              : 
   14469            0 :         if (dopt->binary_upgrade)
   14470            0 :                 binary_upgrade_extension_member(q, &aminfo->dobj,
   14471            0 :                                                                                 "ACCESS METHOD", qamname, NULL);
   14472              : 
   14473            0 :         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14474            0 :                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   14475            0 :                                          ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   14476              :                                                                   .description = "ACCESS METHOD",
   14477              :                                                                   .section = SECTION_PRE_DATA,
   14478              :                                                                   .createStmt = q->data,
   14479              :                                                                   .dropStmt = delq->data));
   14480              : 
   14481              :         /* Dump Access Method Comments */
   14482            0 :         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14483            0 :                 dumpComment(fout, "ACCESS METHOD", qamname,
   14484              :                                         NULL, "",
   14485            0 :                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   14486              : 
   14487            0 :         destroyPQExpBuffer(q);
   14488            0 :         destroyPQExpBuffer(delq);
   14489            0 :         free(qamname);
   14490            0 : }
   14491              : 
   14492              : /*
   14493              :  * dumpOpclass
   14494              :  *        write out a single operator class definition
   14495              :  */
   14496              : static void
   14497            0 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   14498              : {
   14499            0 :         DumpOptions *dopt = fout->dopt;
   14500            0 :         PQExpBuffer query;
   14501            0 :         PQExpBuffer q;
   14502            0 :         PQExpBuffer delq;
   14503            0 :         PQExpBuffer nameusing;
   14504            0 :         PGresult   *res;
   14505            0 :         int                     ntups;
   14506            0 :         int                     i_opcintype;
   14507            0 :         int                     i_opckeytype;
   14508            0 :         int                     i_opcdefault;
   14509            0 :         int                     i_opcfamily;
   14510            0 :         int                     i_opcfamilyname;
   14511            0 :         int                     i_opcfamilynsp;
   14512            0 :         int                     i_amname;
   14513            0 :         int                     i_amopstrategy;
   14514            0 :         int                     i_amopopr;
   14515            0 :         int                     i_sortfamily;
   14516            0 :         int                     i_sortfamilynsp;
   14517            0 :         int                     i_amprocnum;
   14518            0 :         int                     i_amproc;
   14519            0 :         int                     i_amproclefttype;
   14520            0 :         int                     i_amprocrighttype;
   14521            0 :         char       *opcintype;
   14522            0 :         char       *opckeytype;
   14523            0 :         char       *opcdefault;
   14524            0 :         char       *opcfamily;
   14525            0 :         char       *opcfamilyname;
   14526            0 :         char       *opcfamilynsp;
   14527            0 :         char       *amname;
   14528            0 :         char       *amopstrategy;
   14529            0 :         char       *amopopr;
   14530            0 :         char       *sortfamily;
   14531            0 :         char       *sortfamilynsp;
   14532            0 :         char       *amprocnum;
   14533            0 :         char       *amproc;
   14534            0 :         char       *amproclefttype;
   14535            0 :         char       *amprocrighttype;
   14536            0 :         bool            needComma;
   14537            0 :         int                     i;
   14538              : 
   14539              :         /* Do nothing if not dumping schema */
   14540            0 :         if (!dopt->dumpSchema)
   14541            0 :                 return;
   14542              : 
   14543            0 :         query = createPQExpBuffer();
   14544            0 :         q = createPQExpBuffer();
   14545            0 :         delq = createPQExpBuffer();
   14546            0 :         nameusing = createPQExpBuffer();
   14547              : 
   14548              :         /* Get additional fields from the pg_opclass row */
   14549            0 :         appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   14550              :                                           "opckeytype::pg_catalog.regtype, "
   14551              :                                           "opcdefault, opcfamily, "
   14552              :                                           "opfname AS opcfamilyname, "
   14553              :                                           "nspname AS opcfamilynsp, "
   14554              :                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   14555              :                                           "FROM pg_catalog.pg_opclass c "
   14556              :                                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   14557              :                                           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14558              :                                           "WHERE c.oid = '%u'::pg_catalog.oid",
   14559            0 :                                           opcinfo->dobj.catId.oid);
   14560              : 
   14561            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14562              : 
   14563            0 :         i_opcintype = PQfnumber(res, "opcintype");
   14564            0 :         i_opckeytype = PQfnumber(res, "opckeytype");
   14565            0 :         i_opcdefault = PQfnumber(res, "opcdefault");
   14566            0 :         i_opcfamily = PQfnumber(res, "opcfamily");
   14567            0 :         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   14568            0 :         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   14569            0 :         i_amname = PQfnumber(res, "amname");
   14570              : 
   14571              :         /* opcintype may still be needed after we PQclear res */
   14572            0 :         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   14573            0 :         opckeytype = PQgetvalue(res, 0, i_opckeytype);
   14574            0 :         opcdefault = PQgetvalue(res, 0, i_opcdefault);
   14575              :         /* opcfamily will still be needed after we PQclear res */
   14576            0 :         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   14577            0 :         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   14578            0 :         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   14579              :         /* amname will still be needed after we PQclear res */
   14580            0 :         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14581              : 
   14582            0 :         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   14583            0 :                                           fmtQualifiedDumpable(opcinfo));
   14584            0 :         appendPQExpBuffer(delq, " USING %s;\n",
   14585            0 :                                           fmtId(amname));
   14586              : 
   14587              :         /* Build the fixed portion of the CREATE command */
   14588            0 :         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   14589            0 :                                           fmtQualifiedDumpable(opcinfo));
   14590            0 :         if (strcmp(opcdefault, "t") == 0)
   14591            0 :                 appendPQExpBufferStr(q, "DEFAULT ");
   14592            0 :         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   14593            0 :                                           opcintype,
   14594            0 :                                           fmtId(amname));
   14595            0 :         if (strlen(opcfamilyname) > 0)
   14596              :         {
   14597            0 :                 appendPQExpBufferStr(q, " FAMILY ");
   14598            0 :                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   14599            0 :                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
   14600            0 :         }
   14601            0 :         appendPQExpBufferStr(q, " AS\n    ");
   14602              : 
   14603            0 :         needComma = false;
   14604              : 
   14605            0 :         if (strcmp(opckeytype, "-") != 0)
   14606              :         {
   14607            0 :                 appendPQExpBuffer(q, "STORAGE %s",
   14608            0 :                                                   opckeytype);
   14609            0 :                 needComma = true;
   14610            0 :         }
   14611              : 
   14612            0 :         PQclear(res);
   14613              : 
   14614              :         /*
   14615              :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   14616              :          *
   14617              :          * Print only those opfamily members that are tied to the opclass by
   14618              :          * pg_depend entries.
   14619              :          */
   14620            0 :         resetPQExpBuffer(query);
   14621            0 :         appendPQExpBuffer(query, "SELECT amopstrategy, "
   14622              :                                           "amopopr::pg_catalog.regoperator, "
   14623              :                                           "opfname AS sortfamily, "
   14624              :                                           "nspname AS sortfamilynsp "
   14625              :                                           "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14626              :                                           "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14627              :                                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14628              :                                           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14629              :                                           "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14630              :                                           "AND refobjid = '%u'::pg_catalog.oid "
   14631              :                                           "AND amopfamily = '%s'::pg_catalog.oid "
   14632              :                                           "ORDER BY amopstrategy",
   14633            0 :                                           opcinfo->dobj.catId.oid,
   14634            0 :                                           opcfamily);
   14635              : 
   14636            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14637              : 
   14638            0 :         ntups = PQntuples(res);
   14639              : 
   14640            0 :         i_amopstrategy = PQfnumber(res, "amopstrategy");
   14641            0 :         i_amopopr = PQfnumber(res, "amopopr");
   14642            0 :         i_sortfamily = PQfnumber(res, "sortfamily");
   14643            0 :         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   14644              : 
   14645            0 :         for (i = 0; i < ntups; i++)
   14646              :         {
   14647            0 :                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   14648            0 :                 amopopr = PQgetvalue(res, i, i_amopopr);
   14649            0 :                 sortfamily = PQgetvalue(res, i, i_sortfamily);
   14650            0 :                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   14651              : 
   14652            0 :                 if (needComma)
   14653            0 :                         appendPQExpBufferStr(q, " ,\n    ");
   14654              : 
   14655            0 :                 appendPQExpBuffer(q, "OPERATOR %s %s",
   14656            0 :                                                   amopstrategy, amopopr);
   14657              : 
   14658            0 :                 if (strlen(sortfamily) > 0)
   14659              :                 {
   14660            0 :                         appendPQExpBufferStr(q, " FOR ORDER BY ");
   14661            0 :                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14662            0 :                         appendPQExpBufferStr(q, fmtId(sortfamily));
   14663            0 :                 }
   14664              : 
   14665            0 :                 needComma = true;
   14666            0 :         }
   14667              : 
   14668            0 :         PQclear(res);
   14669              : 
   14670              :         /*
   14671              :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14672              :          *
   14673              :          * Print only those opfamily members that are tied to the opclass by
   14674              :          * pg_depend entries.
   14675              :          *
   14676              :          * We print the amproclefttype/amprocrighttype even though in most cases
   14677              :          * the backend could deduce the right values, because of the corner case
   14678              :          * of a btree sort support function for a cross-type comparison.
   14679              :          */
   14680            0 :         resetPQExpBuffer(query);
   14681              : 
   14682            0 :         appendPQExpBuffer(query, "SELECT amprocnum, "
   14683              :                                           "amproc::pg_catalog.regprocedure, "
   14684              :                                           "amproclefttype::pg_catalog.regtype, "
   14685              :                                           "amprocrighttype::pg_catalog.regtype "
   14686              :                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14687              :                                           "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14688              :                                           "AND refobjid = '%u'::pg_catalog.oid "
   14689              :                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14690              :                                           "AND objid = ap.oid "
   14691              :                                           "ORDER BY amprocnum",
   14692            0 :                                           opcinfo->dobj.catId.oid);
   14693              : 
   14694            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14695              : 
   14696            0 :         ntups = PQntuples(res);
   14697              : 
   14698            0 :         i_amprocnum = PQfnumber(res, "amprocnum");
   14699            0 :         i_amproc = PQfnumber(res, "amproc");
   14700            0 :         i_amproclefttype = PQfnumber(res, "amproclefttype");
   14701            0 :         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   14702              : 
   14703            0 :         for (i = 0; i < ntups; i++)
   14704              :         {
   14705            0 :                 amprocnum = PQgetvalue(res, i, i_amprocnum);
   14706            0 :                 amproc = PQgetvalue(res, i, i_amproc);
   14707            0 :                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   14708            0 :                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   14709              : 
   14710            0 :                 if (needComma)
   14711            0 :                         appendPQExpBufferStr(q, " ,\n    ");
   14712              : 
   14713            0 :                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   14714              : 
   14715            0 :                 if (*amproclefttype && *amprocrighttype)
   14716            0 :                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   14717              : 
   14718            0 :                 appendPQExpBuffer(q, " %s", amproc);
   14719              : 
   14720            0 :                 needComma = true;
   14721            0 :         }
   14722              : 
   14723            0 :         PQclear(res);
   14724              : 
   14725              :         /*
   14726              :          * If needComma is still false it means we haven't added anything after
   14727              :          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   14728              :          * clause with the same datatype.  This isn't sanctioned by the
   14729              :          * documentation, but actually DefineOpClass will treat it as a no-op.
   14730              :          */
   14731            0 :         if (!needComma)
   14732            0 :                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
   14733              : 
   14734            0 :         appendPQExpBufferStr(q, ";\n");
   14735              : 
   14736            0 :         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   14737            0 :         appendPQExpBuffer(nameusing, " USING %s",
   14738            0 :                                           fmtId(amname));
   14739              : 
   14740            0 :         if (dopt->binary_upgrade)
   14741            0 :                 binary_upgrade_extension_member(q, &opcinfo->dobj,
   14742            0 :                                                                                 "OPERATOR CLASS", nameusing->data,
   14743            0 :                                                                                 opcinfo->dobj.namespace->dobj.name);
   14744              : 
   14745            0 :         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14746            0 :                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   14747            0 :                                          ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   14748              :                                                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   14749              :                                                                   .owner = opcinfo->rolname,
   14750              :                                                                   .description = "OPERATOR CLASS",
   14751              :                                                                   .section = SECTION_PRE_DATA,
   14752              :                                                                   .createStmt = q->data,
   14753              :                                                                   .dropStmt = delq->data));
   14754              : 
   14755              :         /* Dump Operator Class Comments */
   14756            0 :         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14757            0 :                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   14758            0 :                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   14759            0 :                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   14760              : 
   14761            0 :         free(opcintype);
   14762            0 :         free(opcfamily);
   14763            0 :         free(amname);
   14764            0 :         destroyPQExpBuffer(query);
   14765            0 :         destroyPQExpBuffer(q);
   14766            0 :         destroyPQExpBuffer(delq);
   14767            0 :         destroyPQExpBuffer(nameusing);
   14768            0 : }
   14769              : 
   14770              : /*
   14771              :  * dumpOpfamily
   14772              :  *        write out a single operator family definition
   14773              :  *
   14774              :  * Note: this also dumps any "loose" operator members that aren't bound to a
   14775              :  * specific opclass within the opfamily.
   14776              :  */
   14777              : static void
   14778            0 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   14779              : {
   14780            0 :         DumpOptions *dopt = fout->dopt;
   14781            0 :         PQExpBuffer query;
   14782            0 :         PQExpBuffer q;
   14783            0 :         PQExpBuffer delq;
   14784            0 :         PQExpBuffer nameusing;
   14785            0 :         PGresult   *res;
   14786            0 :         PGresult   *res_ops;
   14787            0 :         PGresult   *res_procs;
   14788            0 :         int                     ntups;
   14789            0 :         int                     i_amname;
   14790            0 :         int                     i_amopstrategy;
   14791            0 :         int                     i_amopopr;
   14792            0 :         int                     i_sortfamily;
   14793            0 :         int                     i_sortfamilynsp;
   14794            0 :         int                     i_amprocnum;
   14795            0 :         int                     i_amproc;
   14796            0 :         int                     i_amproclefttype;
   14797            0 :         int                     i_amprocrighttype;
   14798            0 :         char       *amname;
   14799            0 :         char       *amopstrategy;
   14800            0 :         char       *amopopr;
   14801            0 :         char       *sortfamily;
   14802            0 :         char       *sortfamilynsp;
   14803            0 :         char       *amprocnum;
   14804            0 :         char       *amproc;
   14805            0 :         char       *amproclefttype;
   14806            0 :         char       *amprocrighttype;
   14807            0 :         bool            needComma;
   14808            0 :         int                     i;
   14809              : 
   14810              :         /* Do nothing if not dumping schema */
   14811            0 :         if (!dopt->dumpSchema)
   14812            0 :                 return;
   14813              : 
   14814            0 :         query = createPQExpBuffer();
   14815            0 :         q = createPQExpBuffer();
   14816            0 :         delq = createPQExpBuffer();
   14817            0 :         nameusing = createPQExpBuffer();
   14818              : 
   14819              :         /*
   14820              :          * Fetch only those opfamily members that are tied directly to the
   14821              :          * opfamily by pg_depend entries.
   14822              :          */
   14823            0 :         appendPQExpBuffer(query, "SELECT amopstrategy, "
   14824              :                                           "amopopr::pg_catalog.regoperator, "
   14825              :                                           "opfname AS sortfamily, "
   14826              :                                           "nspname AS sortfamilynsp "
   14827              :                                           "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14828              :                                           "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14829              :                                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14830              :                                           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14831              :                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14832              :                                           "AND refobjid = '%u'::pg_catalog.oid "
   14833              :                                           "AND amopfamily = '%u'::pg_catalog.oid "
   14834              :                                           "ORDER BY amopstrategy",
   14835            0 :                                           opfinfo->dobj.catId.oid,
   14836            0 :                                           opfinfo->dobj.catId.oid);
   14837              : 
   14838            0 :         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14839              : 
   14840            0 :         resetPQExpBuffer(query);
   14841              : 
   14842            0 :         appendPQExpBuffer(query, "SELECT amprocnum, "
   14843              :                                           "amproc::pg_catalog.regprocedure, "
   14844              :                                           "amproclefttype::pg_catalog.regtype, "
   14845              :                                           "amprocrighttype::pg_catalog.regtype "
   14846              :                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14847              :                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14848              :                                           "AND refobjid = '%u'::pg_catalog.oid "
   14849              :                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14850              :                                           "AND objid = ap.oid "
   14851              :                                           "ORDER BY amprocnum",
   14852            0 :                                           opfinfo->dobj.catId.oid);
   14853              : 
   14854            0 :         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14855              : 
   14856              :         /* Get additional fields from the pg_opfamily row */
   14857            0 :         resetPQExpBuffer(query);
   14858              : 
   14859            0 :         appendPQExpBuffer(query, "SELECT "
   14860              :                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   14861              :                                           "FROM pg_catalog.pg_opfamily "
   14862              :                                           "WHERE oid = '%u'::pg_catalog.oid",
   14863            0 :                                           opfinfo->dobj.catId.oid);
   14864              : 
   14865            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14866              : 
   14867            0 :         i_amname = PQfnumber(res, "amname");
   14868              : 
   14869              :         /* amname will still be needed after we PQclear res */
   14870            0 :         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14871              : 
   14872            0 :         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   14873            0 :                                           fmtQualifiedDumpable(opfinfo));
   14874            0 :         appendPQExpBuffer(delq, " USING %s;\n",
   14875            0 :                                           fmtId(amname));
   14876              : 
   14877              :         /* Build the fixed portion of the CREATE command */
   14878            0 :         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   14879            0 :                                           fmtQualifiedDumpable(opfinfo));
   14880            0 :         appendPQExpBuffer(q, " USING %s;\n",
   14881            0 :                                           fmtId(amname));
   14882              : 
   14883            0 :         PQclear(res);
   14884              : 
   14885              :         /* Do we need an ALTER to add loose members? */
   14886            0 :         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   14887              :         {
   14888            0 :                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   14889            0 :                                                   fmtQualifiedDumpable(opfinfo));
   14890            0 :                 appendPQExpBuffer(q, " USING %s ADD\n    ",
   14891            0 :                                                   fmtId(amname));
   14892              : 
   14893            0 :                 needComma = false;
   14894              : 
   14895              :                 /*
   14896              :                  * Now fetch and print the OPERATOR entries (pg_amop rows).
   14897              :                  */
   14898            0 :                 ntups = PQntuples(res_ops);
   14899              : 
   14900            0 :                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   14901            0 :                 i_amopopr = PQfnumber(res_ops, "amopopr");
   14902            0 :                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
   14903            0 :                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   14904              : 
   14905            0 :                 for (i = 0; i < ntups; i++)
   14906              :                 {
   14907            0 :                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   14908            0 :                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
   14909            0 :                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   14910            0 :                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   14911              : 
   14912            0 :                         if (needComma)
   14913            0 :                                 appendPQExpBufferStr(q, " ,\n    ");
   14914              : 
   14915            0 :                         appendPQExpBuffer(q, "OPERATOR %s %s",
   14916            0 :                                                           amopstrategy, amopopr);
   14917              : 
   14918            0 :                         if (strlen(sortfamily) > 0)
   14919              :                         {
   14920            0 :                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   14921            0 :                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14922            0 :                                 appendPQExpBufferStr(q, fmtId(sortfamily));
   14923            0 :                         }
   14924              : 
   14925            0 :                         needComma = true;
   14926            0 :                 }
   14927              : 
   14928              :                 /*
   14929              :                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14930              :                  */
   14931            0 :                 ntups = PQntuples(res_procs);
   14932              : 
   14933            0 :                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
   14934            0 :                 i_amproc = PQfnumber(res_procs, "amproc");
   14935            0 :                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   14936            0 :                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   14937              : 
   14938            0 :                 for (i = 0; i < ntups; i++)
   14939              :                 {
   14940            0 :                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   14941            0 :                         amproc = PQgetvalue(res_procs, i, i_amproc);
   14942            0 :                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   14943            0 :                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   14944              : 
   14945            0 :                         if (needComma)
   14946            0 :                                 appendPQExpBufferStr(q, " ,\n    ");
   14947              : 
   14948            0 :                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   14949            0 :                                                           amprocnum, amproclefttype, amprocrighttype,
   14950            0 :                                                           amproc);
   14951              : 
   14952            0 :                         needComma = true;
   14953            0 :                 }
   14954              : 
   14955            0 :                 appendPQExpBufferStr(q, ";\n");
   14956            0 :         }
   14957              : 
   14958            0 :         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   14959            0 :         appendPQExpBuffer(nameusing, " USING %s",
   14960            0 :                                           fmtId(amname));
   14961              : 
   14962            0 :         if (dopt->binary_upgrade)
   14963            0 :                 binary_upgrade_extension_member(q, &opfinfo->dobj,
   14964            0 :                                                                                 "OPERATOR FAMILY", nameusing->data,
   14965            0 :                                                                                 opfinfo->dobj.namespace->dobj.name);
   14966              : 
   14967            0 :         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14968            0 :                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   14969            0 :                                          ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   14970              :                                                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   14971              :                                                                   .owner = opfinfo->rolname,
   14972              :                                                                   .description = "OPERATOR FAMILY",
   14973              :                                                                   .section = SECTION_PRE_DATA,
   14974              :                                                                   .createStmt = q->data,
   14975              :                                                                   .dropStmt = delq->data));
   14976              : 
   14977              :         /* Dump Operator Family Comments */
   14978            0 :         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14979            0 :                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   14980            0 :                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   14981            0 :                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   14982              : 
   14983            0 :         free(amname);
   14984            0 :         PQclear(res_ops);
   14985            0 :         PQclear(res_procs);
   14986            0 :         destroyPQExpBuffer(query);
   14987            0 :         destroyPQExpBuffer(q);
   14988            0 :         destroyPQExpBuffer(delq);
   14989            0 :         destroyPQExpBuffer(nameusing);
   14990            0 : }
   14991              : 
   14992              : /*
   14993              :  * dumpCollation
   14994              :  *        write out a single collation definition
   14995              :  */
   14996              : static void
   14997            0 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   14998              : {
   14999            0 :         DumpOptions *dopt = fout->dopt;
   15000            0 :         PQExpBuffer query;
   15001            0 :         PQExpBuffer q;
   15002            0 :         PQExpBuffer delq;
   15003            0 :         char       *qcollname;
   15004            0 :         PGresult   *res;
   15005            0 :         int                     i_collprovider;
   15006            0 :         int                     i_collisdeterministic;
   15007            0 :         int                     i_collcollate;
   15008            0 :         int                     i_collctype;
   15009            0 :         int                     i_colllocale;
   15010            0 :         int                     i_collicurules;
   15011            0 :         const char *collprovider;
   15012            0 :         const char *collcollate;
   15013            0 :         const char *collctype;
   15014            0 :         const char *colllocale;
   15015            0 :         const char *collicurules;
   15016              : 
   15017              :         /* Do nothing if not dumping schema */
   15018            0 :         if (!dopt->dumpSchema)
   15019            0 :                 return;
   15020              : 
   15021            0 :         query = createPQExpBuffer();
   15022            0 :         q = createPQExpBuffer();
   15023            0 :         delq = createPQExpBuffer();
   15024              : 
   15025            0 :         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   15026              : 
   15027              :         /* Get collation-specific details */
   15028            0 :         appendPQExpBufferStr(query, "SELECT ");
   15029              : 
   15030            0 :         if (fout->remoteVersion >= 100000)
   15031            0 :                 appendPQExpBufferStr(query,
   15032              :                                                          "collprovider, "
   15033              :                                                          "collversion, ");
   15034              :         else
   15035            0 :                 appendPQExpBufferStr(query,
   15036              :                                                          "'c' AS collprovider, "
   15037              :                                                          "NULL AS collversion, ");
   15038              : 
   15039            0 :         if (fout->remoteVersion >= 120000)
   15040            0 :                 appendPQExpBufferStr(query,
   15041              :                                                          "collisdeterministic, ");
   15042              :         else
   15043            0 :                 appendPQExpBufferStr(query,
   15044              :                                                          "true AS collisdeterministic, ");
   15045              : 
   15046            0 :         if (fout->remoteVersion >= 170000)
   15047            0 :                 appendPQExpBufferStr(query,
   15048              :                                                          "colllocale, ");
   15049            0 :         else if (fout->remoteVersion >= 150000)
   15050            0 :                 appendPQExpBufferStr(query,
   15051              :                                                          "colliculocale AS colllocale, ");
   15052              :         else
   15053            0 :                 appendPQExpBufferStr(query,
   15054              :                                                          "NULL AS colllocale, ");
   15055              : 
   15056            0 :         if (fout->remoteVersion >= 160000)
   15057            0 :                 appendPQExpBufferStr(query,
   15058              :                                                          "collicurules, ");
   15059              :         else
   15060            0 :                 appendPQExpBufferStr(query,
   15061              :                                                          "NULL AS collicurules, ");
   15062              : 
   15063            0 :         appendPQExpBuffer(query,
   15064              :                                           "collcollate, "
   15065              :                                           "collctype "
   15066              :                                           "FROM pg_catalog.pg_collation c "
   15067              :                                           "WHERE c.oid = '%u'::pg_catalog.oid",
   15068            0 :                                           collinfo->dobj.catId.oid);
   15069              : 
   15070            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15071              : 
   15072            0 :         i_collprovider = PQfnumber(res, "collprovider");
   15073            0 :         i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   15074            0 :         i_collcollate = PQfnumber(res, "collcollate");
   15075            0 :         i_collctype = PQfnumber(res, "collctype");
   15076            0 :         i_colllocale = PQfnumber(res, "colllocale");
   15077            0 :         i_collicurules = PQfnumber(res, "collicurules");
   15078              : 
   15079            0 :         collprovider = PQgetvalue(res, 0, i_collprovider);
   15080              : 
   15081            0 :         if (!PQgetisnull(res, 0, i_collcollate))
   15082            0 :                 collcollate = PQgetvalue(res, 0, i_collcollate);
   15083              :         else
   15084            0 :                 collcollate = NULL;
   15085              : 
   15086            0 :         if (!PQgetisnull(res, 0, i_collctype))
   15087            0 :                 collctype = PQgetvalue(res, 0, i_collctype);
   15088              :         else
   15089            0 :                 collctype = NULL;
   15090              : 
   15091              :         /*
   15092              :          * Before version 15, collcollate and collctype were of type NAME and
   15093              :          * non-nullable. Treat empty strings as NULL for consistency.
   15094              :          */
   15095            0 :         if (fout->remoteVersion < 150000)
   15096              :         {
   15097            0 :                 if (collcollate[0] == '\0')
   15098            0 :                         collcollate = NULL;
   15099            0 :                 if (collctype[0] == '\0')
   15100            0 :                         collctype = NULL;
   15101            0 :         }
   15102              : 
   15103            0 :         if (!PQgetisnull(res, 0, i_colllocale))
   15104            0 :                 colllocale = PQgetvalue(res, 0, i_colllocale);
   15105              :         else
   15106            0 :                 colllocale = NULL;
   15107              : 
   15108            0 :         if (!PQgetisnull(res, 0, i_collicurules))
   15109            0 :                 collicurules = PQgetvalue(res, 0, i_collicurules);
   15110              :         else
   15111            0 :                 collicurules = NULL;
   15112              : 
   15113            0 :         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   15114            0 :                                           fmtQualifiedDumpable(collinfo));
   15115              : 
   15116            0 :         appendPQExpBuffer(q, "CREATE COLLATION %s (",
   15117            0 :                                           fmtQualifiedDumpable(collinfo));
   15118              : 
   15119            0 :         appendPQExpBufferStr(q, "provider = ");
   15120            0 :         if (collprovider[0] == 'b')
   15121            0 :                 appendPQExpBufferStr(q, "builtin");
   15122            0 :         else if (collprovider[0] == 'c')
   15123            0 :                 appendPQExpBufferStr(q, "libc");
   15124            0 :         else if (collprovider[0] == 'i')
   15125            0 :                 appendPQExpBufferStr(q, "icu");
   15126            0 :         else if (collprovider[0] == 'd')
   15127              :                 /* to allow dumping pg_catalog; not accepted on input */
   15128            0 :                 appendPQExpBufferStr(q, "default");
   15129              :         else
   15130            0 :                 pg_fatal("unrecognized collation provider: %s",
   15131              :                                  collprovider);
   15132              : 
   15133            0 :         if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   15134            0 :                 appendPQExpBufferStr(q, ", deterministic = false");
   15135              : 
   15136            0 :         if (collprovider[0] == 'd')
   15137              :         {
   15138            0 :                 if (collcollate || collctype || colllocale || collicurules)
   15139            0 :                         pg_log_warning("invalid collation \"%s\"", qcollname);
   15140              : 
   15141              :                 /* no locale -- the default collation cannot be reloaded anyway */
   15142            0 :         }
   15143            0 :         else if (collprovider[0] == 'b')
   15144              :         {
   15145            0 :                 if (collcollate || collctype || !colllocale || collicurules)
   15146            0 :                         pg_log_warning("invalid collation \"%s\"", qcollname);
   15147              : 
   15148            0 :                 appendPQExpBufferStr(q, ", locale = ");
   15149            0 :                 appendStringLiteralAH(q, colllocale ? colllocale : "",
   15150              :                                                           fout);
   15151            0 :         }
   15152            0 :         else if (collprovider[0] == 'i')
   15153              :         {
   15154            0 :                 if (fout->remoteVersion >= 150000)
   15155              :                 {
   15156            0 :                         if (collcollate || collctype || !colllocale)
   15157            0 :                                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15158              : 
   15159            0 :                         appendPQExpBufferStr(q, ", locale = ");
   15160            0 :                         appendStringLiteralAH(q, colllocale ? colllocale : "",
   15161              :                                                                   fout);
   15162            0 :                 }
   15163              :                 else
   15164              :                 {
   15165            0 :                         if (!collcollate || !collctype || colllocale ||
   15166            0 :                                 strcmp(collcollate, collctype) != 0)
   15167            0 :                                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15168              : 
   15169            0 :                         appendPQExpBufferStr(q, ", locale = ");
   15170            0 :                         appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15171              :                 }
   15172              : 
   15173            0 :                 if (collicurules)
   15174              :                 {
   15175            0 :                         appendPQExpBufferStr(q, ", rules = ");
   15176            0 :                         appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   15177            0 :                 }
   15178            0 :         }
   15179            0 :         else if (collprovider[0] == 'c')
   15180              :         {
   15181            0 :                 if (colllocale || collicurules || !collcollate || !collctype)
   15182            0 :                         pg_log_warning("invalid collation \"%s\"", qcollname);
   15183              : 
   15184            0 :                 if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   15185              :                 {
   15186            0 :                         appendPQExpBufferStr(q, ", locale = ");
   15187            0 :                         appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15188            0 :                 }
   15189              :                 else
   15190              :                 {
   15191            0 :                         appendPQExpBufferStr(q, ", lc_collate = ");
   15192            0 :                         appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15193            0 :                         appendPQExpBufferStr(q, ", lc_ctype = ");
   15194            0 :                         appendStringLiteralAH(q, collctype ? collctype : "", fout);
   15195              :                 }
   15196            0 :         }
   15197              :         else
   15198            0 :                 pg_fatal("unrecognized collation provider: %s", collprovider);
   15199              : 
   15200              :         /*
   15201              :          * For binary upgrade, carry over the collation version.  For normal
   15202              :          * dump/restore, omit the version, so that it is computed upon restore.
   15203              :          */
   15204            0 :         if (dopt->binary_upgrade)
   15205              :         {
   15206            0 :                 int                     i_collversion;
   15207              : 
   15208            0 :                 i_collversion = PQfnumber(res, "collversion");
   15209            0 :                 if (!PQgetisnull(res, 0, i_collversion))
   15210              :                 {
   15211            0 :                         appendPQExpBufferStr(q, ", version = ");
   15212            0 :                         appendStringLiteralAH(q,
   15213              :                                                                   PQgetvalue(res, 0, i_collversion),
   15214              :                                                                   fout);
   15215            0 :                 }
   15216            0 :         }
   15217              : 
   15218            0 :         appendPQExpBufferStr(q, ");\n");
   15219              : 
   15220            0 :         if (dopt->binary_upgrade)
   15221            0 :                 binary_upgrade_extension_member(q, &collinfo->dobj,
   15222            0 :                                                                                 "COLLATION", qcollname,
   15223            0 :                                                                                 collinfo->dobj.namespace->dobj.name);
   15224              : 
   15225            0 :         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15226            0 :                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   15227            0 :                                          ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   15228              :                                                                   .namespace = collinfo->dobj.namespace->dobj.name,
   15229              :                                                                   .owner = collinfo->rolname,
   15230              :                                                                   .description = "COLLATION",
   15231              :                                                                   .section = SECTION_PRE_DATA,
   15232              :                                                                   .createStmt = q->data,
   15233              :                                                                   .dropStmt = delq->data));
   15234              : 
   15235              :         /* Dump Collation Comments */
   15236            0 :         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15237            0 :                 dumpComment(fout, "COLLATION", qcollname,
   15238            0 :                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   15239            0 :                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   15240              : 
   15241            0 :         PQclear(res);
   15242              : 
   15243            0 :         destroyPQExpBuffer(query);
   15244            0 :         destroyPQExpBuffer(q);
   15245            0 :         destroyPQExpBuffer(delq);
   15246            0 :         free(qcollname);
   15247            0 : }
   15248              : 
   15249              : /*
   15250              :  * dumpConversion
   15251              :  *        write out a single conversion definition
   15252              :  */
   15253              : static void
   15254            0 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   15255              : {
   15256            0 :         DumpOptions *dopt = fout->dopt;
   15257            0 :         PQExpBuffer query;
   15258            0 :         PQExpBuffer q;
   15259            0 :         PQExpBuffer delq;
   15260            0 :         char       *qconvname;
   15261            0 :         PGresult   *res;
   15262            0 :         int                     i_conforencoding;
   15263            0 :         int                     i_contoencoding;
   15264            0 :         int                     i_conproc;
   15265            0 :         int                     i_condefault;
   15266            0 :         const char *conforencoding;
   15267            0 :         const char *contoencoding;
   15268            0 :         const char *conproc;
   15269            0 :         bool            condefault;
   15270              : 
   15271              :         /* Do nothing if not dumping schema */
   15272            0 :         if (!dopt->dumpSchema)
   15273            0 :                 return;
   15274              : 
   15275            0 :         query = createPQExpBuffer();
   15276            0 :         q = createPQExpBuffer();
   15277            0 :         delq = createPQExpBuffer();
   15278              : 
   15279            0 :         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   15280              : 
   15281              :         /* Get conversion-specific details */
   15282            0 :         appendPQExpBuffer(query, "SELECT "
   15283              :                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   15284              :                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   15285              :                                           "conproc, condefault "
   15286              :                                           "FROM pg_catalog.pg_conversion c "
   15287              :                                           "WHERE c.oid = '%u'::pg_catalog.oid",
   15288            0 :                                           convinfo->dobj.catId.oid);
   15289              : 
   15290            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15291              : 
   15292            0 :         i_conforencoding = PQfnumber(res, "conforencoding");
   15293            0 :         i_contoencoding = PQfnumber(res, "contoencoding");
   15294            0 :         i_conproc = PQfnumber(res, "conproc");
   15295            0 :         i_condefault = PQfnumber(res, "condefault");
   15296              : 
   15297            0 :         conforencoding = PQgetvalue(res, 0, i_conforencoding);
   15298            0 :         contoencoding = PQgetvalue(res, 0, i_contoencoding);
   15299            0 :         conproc = PQgetvalue(res, 0, i_conproc);
   15300            0 :         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   15301              : 
   15302            0 :         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   15303            0 :                                           fmtQualifiedDumpable(convinfo));
   15304              : 
   15305            0 :         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   15306            0 :                                           (condefault) ? "DEFAULT " : "",
   15307            0 :                                           fmtQualifiedDumpable(convinfo));
   15308            0 :         appendStringLiteralAH(q, conforencoding, fout);
   15309            0 :         appendPQExpBufferStr(q, " TO ");
   15310            0 :         appendStringLiteralAH(q, contoencoding, fout);
   15311              :         /* regproc output is already sufficiently quoted */
   15312            0 :         appendPQExpBuffer(q, " FROM %s;\n", conproc);
   15313              : 
   15314            0 :         if (dopt->binary_upgrade)
   15315            0 :                 binary_upgrade_extension_member(q, &convinfo->dobj,
   15316            0 :                                                                                 "CONVERSION", qconvname,
   15317            0 :                                                                                 convinfo->dobj.namespace->dobj.name);
   15318              : 
   15319            0 :         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15320            0 :                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   15321            0 :                                          ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   15322              :                                                                   .namespace = convinfo->dobj.namespace->dobj.name,
   15323              :                                                                   .owner = convinfo->rolname,
   15324              :                                                                   .description = "CONVERSION",
   15325              :                                                                   .section = SECTION_PRE_DATA,
   15326              :                                                                   .createStmt = q->data,
   15327              :                                                                   .dropStmt = delq->data));
   15328              : 
   15329              :         /* Dump Conversion Comments */
   15330            0 :         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15331            0 :                 dumpComment(fout, "CONVERSION", qconvname,
   15332            0 :                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   15333            0 :                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   15334              : 
   15335            0 :         PQclear(res);
   15336              : 
   15337            0 :         destroyPQExpBuffer(query);
   15338            0 :         destroyPQExpBuffer(q);
   15339            0 :         destroyPQExpBuffer(delq);
   15340            0 :         free(qconvname);
   15341            0 : }
   15342              : 
   15343              : /*
   15344              :  * format_aggregate_signature: generate aggregate name and argument list
   15345              :  *
   15346              :  * The argument type names are qualified if needed.  The aggregate name
   15347              :  * is never qualified.
   15348              :  */
   15349              : static char *
   15350            0 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   15351              : {
   15352            0 :         PQExpBufferData buf;
   15353            0 :         int                     j;
   15354              : 
   15355            0 :         initPQExpBuffer(&buf);
   15356            0 :         if (honor_quotes)
   15357            0 :                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   15358              :         else
   15359            0 :                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   15360              : 
   15361            0 :         if (agginfo->aggfn.nargs == 0)
   15362            0 :                 appendPQExpBufferStr(&buf, "(*)");
   15363              :         else
   15364              :         {
   15365            0 :                 appendPQExpBufferChar(&buf, '(');
   15366            0 :                 for (j = 0; j < agginfo->aggfn.nargs; j++)
   15367            0 :                         appendPQExpBuffer(&buf, "%s%s",
   15368            0 :                                                           (j > 0) ? ", " : "",
   15369            0 :                                                           getFormattedTypeName(fout,
   15370            0 :                                                                                                    agginfo->aggfn.argtypes[j],
   15371              :                                                                                                    zeroIsError));
   15372            0 :                 appendPQExpBufferChar(&buf, ')');
   15373              :         }
   15374            0 :         return buf.data;
   15375            0 : }
   15376              : 
   15377              : /*
   15378              :  * dumpAgg
   15379              :  *        write out a single aggregate definition
   15380              :  */
   15381              : static void
   15382            0 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   15383              : {
   15384            0 :         DumpOptions *dopt = fout->dopt;
   15385            0 :         PQExpBuffer query;
   15386            0 :         PQExpBuffer q;
   15387            0 :         PQExpBuffer delq;
   15388            0 :         PQExpBuffer details;
   15389            0 :         char       *aggsig;                     /* identity signature */
   15390            0 :         char       *aggfullsig = NULL;  /* full signature */
   15391            0 :         char       *aggsig_tag;
   15392            0 :         PGresult   *res;
   15393            0 :         int                     i_agginitval;
   15394            0 :         int                     i_aggminitval;
   15395            0 :         const char *aggtransfn;
   15396            0 :         const char *aggfinalfn;
   15397            0 :         const char *aggcombinefn;
   15398            0 :         const char *aggserialfn;
   15399            0 :         const char *aggdeserialfn;
   15400            0 :         const char *aggmtransfn;
   15401            0 :         const char *aggminvtransfn;
   15402            0 :         const char *aggmfinalfn;
   15403            0 :         bool            aggfinalextra;
   15404            0 :         bool            aggmfinalextra;
   15405            0 :         char            aggfinalmodify;
   15406            0 :         char            aggmfinalmodify;
   15407            0 :         const char *aggsortop;
   15408            0 :         char       *aggsortconvop;
   15409            0 :         char            aggkind;
   15410            0 :         const char *aggtranstype;
   15411            0 :         const char *aggtransspace;
   15412            0 :         const char *aggmtranstype;
   15413            0 :         const char *aggmtransspace;
   15414            0 :         const char *agginitval;
   15415            0 :         const char *aggminitval;
   15416            0 :         const char *proparallel;
   15417            0 :         char            defaultfinalmodify;
   15418              : 
   15419              :         /* Do nothing if not dumping schema */
   15420            0 :         if (!dopt->dumpSchema)
   15421            0 :                 return;
   15422              : 
   15423            0 :         query = createPQExpBuffer();
   15424            0 :         q = createPQExpBuffer();
   15425            0 :         delq = createPQExpBuffer();
   15426            0 :         details = createPQExpBuffer();
   15427              : 
   15428            0 :         if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   15429              :         {
   15430              :                 /* Set up query for aggregate-specific details */
   15431            0 :                 appendPQExpBufferStr(query,
   15432              :                                                          "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   15433              : 
   15434            0 :                 appendPQExpBufferStr(query,
   15435              :                                                          "SELECT "
   15436              :                                                          "aggtransfn,\n"
   15437              :                                                          "aggfinalfn,\n"
   15438              :                                                          "aggtranstype::pg_catalog.regtype,\n"
   15439              :                                                          "agginitval,\n"
   15440              :                                                          "aggsortop,\n"
   15441              :                                                          "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   15442              :                                                          "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   15443              : 
   15444            0 :                 if (fout->remoteVersion >= 90400)
   15445            0 :                         appendPQExpBufferStr(query,
   15446              :                                                                  "aggkind,\n"
   15447              :                                                                  "aggmtransfn,\n"
   15448              :                                                                  "aggminvtransfn,\n"
   15449              :                                                                  "aggmfinalfn,\n"
   15450              :                                                                  "aggmtranstype::pg_catalog.regtype,\n"
   15451              :                                                                  "aggfinalextra,\n"
   15452              :                                                                  "aggmfinalextra,\n"
   15453              :                                                                  "aggtransspace,\n"
   15454              :                                                                  "aggmtransspace,\n"
   15455              :                                                                  "aggminitval,\n");
   15456              :                 else
   15457            0 :                         appendPQExpBufferStr(query,
   15458              :                                                                  "'n' AS aggkind,\n"
   15459              :                                                                  "'-' AS aggmtransfn,\n"
   15460              :                                                                  "'-' AS aggminvtransfn,\n"
   15461              :                                                                  "'-' AS aggmfinalfn,\n"
   15462              :                                                                  "0 AS aggmtranstype,\n"
   15463              :                                                                  "false AS aggfinalextra,\n"
   15464              :                                                                  "false AS aggmfinalextra,\n"
   15465              :                                                                  "0 AS aggtransspace,\n"
   15466              :                                                                  "0 AS aggmtransspace,\n"
   15467              :                                                                  "NULL AS aggminitval,\n");
   15468              : 
   15469            0 :                 if (fout->remoteVersion >= 90600)
   15470            0 :                         appendPQExpBufferStr(query,
   15471              :                                                                  "aggcombinefn,\n"
   15472              :                                                                  "aggserialfn,\n"
   15473              :                                                                  "aggdeserialfn,\n"
   15474              :                                                                  "proparallel,\n");
   15475              :                 else
   15476            0 :                         appendPQExpBufferStr(query,
   15477              :                                                                  "'-' AS aggcombinefn,\n"
   15478              :                                                                  "'-' AS aggserialfn,\n"
   15479              :                                                                  "'-' AS aggdeserialfn,\n"
   15480              :                                                                  "'u' AS proparallel,\n");
   15481              : 
   15482            0 :                 if (fout->remoteVersion >= 110000)
   15483            0 :                         appendPQExpBufferStr(query,
   15484              :                                                                  "aggfinalmodify,\n"
   15485              :                                                                  "aggmfinalmodify\n");
   15486              :                 else
   15487            0 :                         appendPQExpBufferStr(query,
   15488              :                                                                  "'0' AS aggfinalmodify,\n"
   15489              :                                                                  "'0' AS aggmfinalmodify\n");
   15490              : 
   15491            0 :                 appendPQExpBufferStr(query,
   15492              :                                                          "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   15493              :                                                          "WHERE a.aggfnoid = p.oid "
   15494              :                                                          "AND p.oid = $1");
   15495              : 
   15496            0 :                 ExecuteSqlStatement(fout, query->data);
   15497              : 
   15498            0 :                 fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   15499            0 :         }
   15500              : 
   15501            0 :         printfPQExpBuffer(query,
   15502              :                                           "EXECUTE dumpAgg('%u')",
   15503            0 :                                           agginfo->aggfn.dobj.catId.oid);
   15504              : 
   15505            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15506              : 
   15507            0 :         i_agginitval = PQfnumber(res, "agginitval");
   15508            0 :         i_aggminitval = PQfnumber(res, "aggminitval");
   15509              : 
   15510            0 :         aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   15511            0 :         aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   15512            0 :         aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   15513            0 :         aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   15514            0 :         aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   15515            0 :         aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   15516            0 :         aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   15517            0 :         aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   15518            0 :         aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   15519            0 :         aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   15520            0 :         aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   15521            0 :         aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   15522            0 :         aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   15523            0 :         aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   15524            0 :         aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   15525            0 :         aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   15526            0 :         aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   15527            0 :         aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   15528            0 :         agginitval = PQgetvalue(res, 0, i_agginitval);
   15529            0 :         aggminitval = PQgetvalue(res, 0, i_aggminitval);
   15530            0 :         proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   15531              : 
   15532              :         {
   15533            0 :                 char       *funcargs;
   15534            0 :                 char       *funciargs;
   15535              : 
   15536            0 :                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   15537            0 :                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   15538            0 :                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   15539            0 :                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   15540            0 :         }
   15541              : 
   15542            0 :         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   15543              : 
   15544              :         /* identify default modify flag for aggkind (must match DefineAggregate) */
   15545            0 :         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   15546              :         /* replace omitted flags for old versions */
   15547            0 :         if (aggfinalmodify == '0')
   15548            0 :                 aggfinalmodify = defaultfinalmodify;
   15549            0 :         if (aggmfinalmodify == '0')
   15550            0 :                 aggmfinalmodify = defaultfinalmodify;
   15551              : 
   15552              :         /* regproc and regtype output is already sufficiently quoted */
   15553            0 :         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   15554            0 :                                           aggtransfn, aggtranstype);
   15555              : 
   15556            0 :         if (strcmp(aggtransspace, "0") != 0)
   15557              :         {
   15558            0 :                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
   15559            0 :                                                   aggtransspace);
   15560            0 :         }
   15561              : 
   15562            0 :         if (!PQgetisnull(res, 0, i_agginitval))
   15563              :         {
   15564            0 :                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
   15565            0 :                 appendStringLiteralAH(details, agginitval, fout);
   15566            0 :         }
   15567              : 
   15568            0 :         if (strcmp(aggfinalfn, "-") != 0)
   15569              :         {
   15570            0 :                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   15571            0 :                                                   aggfinalfn);
   15572            0 :                 if (aggfinalextra)
   15573            0 :                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   15574            0 :                 if (aggfinalmodify != defaultfinalmodify)
   15575              :                 {
   15576            0 :                         switch (aggfinalmodify)
   15577              :                         {
   15578              :                                 case AGGMODIFY_READ_ONLY:
   15579            0 :                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   15580            0 :                                         break;
   15581              :                                 case AGGMODIFY_SHAREABLE:
   15582            0 :                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   15583            0 :                                         break;
   15584              :                                 case AGGMODIFY_READ_WRITE:
   15585            0 :                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   15586            0 :                                         break;
   15587              :                                 default:
   15588            0 :                                         pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   15589              :                                                          agginfo->aggfn.dobj.name);
   15590            0 :                                         break;
   15591              :                         }
   15592            0 :                 }
   15593            0 :         }
   15594              : 
   15595            0 :         if (strcmp(aggcombinefn, "-") != 0)
   15596            0 :                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   15597              : 
   15598            0 :         if (strcmp(aggserialfn, "-") != 0)
   15599            0 :                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   15600              : 
   15601            0 :         if (strcmp(aggdeserialfn, "-") != 0)
   15602            0 :                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   15603              : 
   15604            0 :         if (strcmp(aggmtransfn, "-") != 0)
   15605              :         {
   15606            0 :                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   15607            0 :                                                   aggmtransfn,
   15608            0 :                                                   aggminvtransfn,
   15609            0 :                                                   aggmtranstype);
   15610            0 :         }
   15611              : 
   15612            0 :         if (strcmp(aggmtransspace, "0") != 0)
   15613              :         {
   15614            0 :                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   15615            0 :                                                   aggmtransspace);
   15616            0 :         }
   15617              : 
   15618            0 :         if (!PQgetisnull(res, 0, i_aggminitval))
   15619              :         {
   15620            0 :                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   15621            0 :                 appendStringLiteralAH(details, aggminitval, fout);
   15622            0 :         }
   15623              : 
   15624            0 :         if (strcmp(aggmfinalfn, "-") != 0)
   15625              :         {
   15626            0 :                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   15627            0 :                                                   aggmfinalfn);
   15628            0 :                 if (aggmfinalextra)
   15629            0 :                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   15630            0 :                 if (aggmfinalmodify != defaultfinalmodify)
   15631              :                 {
   15632            0 :                         switch (aggmfinalmodify)
   15633              :                         {
   15634              :                                 case AGGMODIFY_READ_ONLY:
   15635            0 :                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   15636            0 :                                         break;
   15637              :                                 case AGGMODIFY_SHAREABLE:
   15638            0 :                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   15639            0 :                                         break;
   15640              :                                 case AGGMODIFY_READ_WRITE:
   15641            0 :                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   15642            0 :                                         break;
   15643              :                                 default:
   15644            0 :                                         pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   15645              :                                                          agginfo->aggfn.dobj.name);
   15646            0 :                                         break;
   15647              :                         }
   15648            0 :                 }
   15649            0 :         }
   15650              : 
   15651            0 :         aggsortconvop = getFormattedOperatorName(aggsortop);
   15652            0 :         if (aggsortconvop)
   15653              :         {
   15654            0 :                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
   15655            0 :                                                   aggsortconvop);
   15656            0 :                 free(aggsortconvop);
   15657            0 :         }
   15658              : 
   15659            0 :         if (aggkind == AGGKIND_HYPOTHETICAL)
   15660            0 :                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   15661              : 
   15662            0 :         if (proparallel[0] != PROPARALLEL_UNSAFE)
   15663              :         {
   15664            0 :                 if (proparallel[0] == PROPARALLEL_SAFE)
   15665            0 :                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   15666            0 :                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   15667            0 :                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   15668            0 :                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
   15669            0 :                         pg_fatal("unrecognized proparallel value for function \"%s\"",
   15670              :                                          agginfo->aggfn.dobj.name);
   15671            0 :         }
   15672              : 
   15673            0 :         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   15674            0 :                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15675            0 :                                           aggsig);
   15676              : 
   15677            0 :         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   15678            0 :                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15679            0 :                                           aggfullsig ? aggfullsig : aggsig, details->data);
   15680              : 
   15681            0 :         if (dopt->binary_upgrade)
   15682            0 :                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   15683            0 :                                                                                 "AGGREGATE", aggsig,
   15684            0 :                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
   15685              : 
   15686            0 :         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   15687            0 :                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   15688            0 :                                          agginfo->aggfn.dobj.dumpId,
   15689            0 :                                          ARCHIVE_OPTS(.tag = aggsig_tag,
   15690              :                                                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   15691              :                                                                   .owner = agginfo->aggfn.rolname,
   15692              :                                                                   .description = "AGGREGATE",
   15693              :                                                                   .section = SECTION_PRE_DATA,
   15694              :                                                                   .createStmt = q->data,
   15695              :                                                                   .dropStmt = delq->data));
   15696              : 
   15697              :         /* Dump Aggregate Comments */
   15698            0 :         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   15699            0 :                 dumpComment(fout, "AGGREGATE", aggsig,
   15700            0 :                                         agginfo->aggfn.dobj.namespace->dobj.name,
   15701            0 :                                         agginfo->aggfn.rolname,
   15702            0 :                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15703              : 
   15704            0 :         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   15705            0 :                 dumpSecLabel(fout, "AGGREGATE", aggsig,
   15706            0 :                                          agginfo->aggfn.dobj.namespace->dobj.name,
   15707            0 :                                          agginfo->aggfn.rolname,
   15708            0 :                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15709              : 
   15710              :         /*
   15711              :          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   15712              :          * command look like a function's GRANT; in particular this affects the
   15713              :          * syntax for zero-argument aggregates and ordered-set aggregates.
   15714              :          */
   15715            0 :         free(aggsig);
   15716              : 
   15717            0 :         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   15718              : 
   15719            0 :         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   15720            0 :                 dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   15721            0 :                                 "FUNCTION", aggsig, NULL,
   15722            0 :                                 agginfo->aggfn.dobj.namespace->dobj.name,
   15723            0 :                                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   15724              : 
   15725            0 :         free(aggsig);
   15726            0 :         free(aggfullsig);
   15727            0 :         free(aggsig_tag);
   15728              : 
   15729            0 :         PQclear(res);
   15730              : 
   15731            0 :         destroyPQExpBuffer(query);
   15732            0 :         destroyPQExpBuffer(q);
   15733            0 :         destroyPQExpBuffer(delq);
   15734            0 :         destroyPQExpBuffer(details);
   15735            0 : }
   15736              : 
   15737              : /*
   15738              :  * dumpTSParser
   15739              :  *        write out a single text search parser
   15740              :  */
   15741              : static void
   15742            0 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   15743              : {
   15744            0 :         DumpOptions *dopt = fout->dopt;
   15745            0 :         PQExpBuffer q;
   15746            0 :         PQExpBuffer delq;
   15747            0 :         char       *qprsname;
   15748              : 
   15749              :         /* Do nothing if not dumping schema */
   15750            0 :         if (!dopt->dumpSchema)
   15751            0 :                 return;
   15752              : 
   15753            0 :         q = createPQExpBuffer();
   15754            0 :         delq = createPQExpBuffer();
   15755              : 
   15756            0 :         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   15757              : 
   15758            0 :         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   15759            0 :                                           fmtQualifiedDumpable(prsinfo));
   15760              : 
   15761            0 :         appendPQExpBuffer(q, "    START = %s,\n",
   15762            0 :                                           convertTSFunction(fout, prsinfo->prsstart));
   15763            0 :         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   15764            0 :                                           convertTSFunction(fout, prsinfo->prstoken));
   15765            0 :         appendPQExpBuffer(q, "    END = %s,\n",
   15766            0 :                                           convertTSFunction(fout, prsinfo->prsend));
   15767            0 :         if (prsinfo->prsheadline != InvalidOid)
   15768            0 :                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   15769            0 :                                                   convertTSFunction(fout, prsinfo->prsheadline));
   15770            0 :         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   15771            0 :                                           convertTSFunction(fout, prsinfo->prslextype));
   15772              : 
   15773            0 :         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   15774            0 :                                           fmtQualifiedDumpable(prsinfo));
   15775              : 
   15776            0 :         if (dopt->binary_upgrade)
   15777            0 :                 binary_upgrade_extension_member(q, &prsinfo->dobj,
   15778            0 :                                                                                 "TEXT SEARCH PARSER", qprsname,
   15779            0 :                                                                                 prsinfo->dobj.namespace->dobj.name);
   15780              : 
   15781            0 :         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15782            0 :                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15783            0 :                                          ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   15784              :                                                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   15785              :                                                                   .description = "TEXT SEARCH PARSER",
   15786              :                                                                   .section = SECTION_PRE_DATA,
   15787              :                                                                   .createStmt = q->data,
   15788              :                                                                   .dropStmt = delq->data));
   15789              : 
   15790              :         /* Dump Parser Comments */
   15791            0 :         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15792            0 :                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15793            0 :                                         prsinfo->dobj.namespace->dobj.name, "",
   15794            0 :                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15795              : 
   15796            0 :         destroyPQExpBuffer(q);
   15797            0 :         destroyPQExpBuffer(delq);
   15798            0 :         free(qprsname);
   15799            0 : }
   15800              : 
   15801              : /*
   15802              :  * dumpTSDictionary
   15803              :  *        write out a single text search dictionary
   15804              :  */
   15805              : static void
   15806            0 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15807              : {
   15808            0 :         DumpOptions *dopt = fout->dopt;
   15809            0 :         PQExpBuffer q;
   15810            0 :         PQExpBuffer delq;
   15811            0 :         PQExpBuffer query;
   15812            0 :         char       *qdictname;
   15813            0 :         PGresult   *res;
   15814            0 :         char       *nspname;
   15815            0 :         char       *tmplname;
   15816              : 
   15817              :         /* Do nothing if not dumping schema */
   15818            0 :         if (!dopt->dumpSchema)
   15819            0 :                 return;
   15820              : 
   15821            0 :         q = createPQExpBuffer();
   15822            0 :         delq = createPQExpBuffer();
   15823            0 :         query = createPQExpBuffer();
   15824              : 
   15825            0 :         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15826              : 
   15827              :         /* Fetch name and namespace of the dictionary's template */
   15828            0 :         appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15829              :                                           "FROM pg_ts_template p, pg_namespace n "
   15830              :                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15831            0 :                                           dictinfo->dicttemplate);
   15832            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15833            0 :         nspname = PQgetvalue(res, 0, 0);
   15834            0 :         tmplname = PQgetvalue(res, 0, 1);
   15835              : 
   15836            0 :         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15837            0 :                                           fmtQualifiedDumpable(dictinfo));
   15838              : 
   15839            0 :         appendPQExpBufferStr(q, "    TEMPLATE = ");
   15840            0 :         appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15841            0 :         appendPQExpBufferStr(q, fmtId(tmplname));
   15842              : 
   15843            0 :         PQclear(res);
   15844              : 
   15845              :         /* the dictinitoption can be dumped straight into the command */
   15846            0 :         if (dictinfo->dictinitoption)
   15847            0 :                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15848              : 
   15849            0 :         appendPQExpBufferStr(q, " );\n");
   15850              : 
   15851            0 :         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   15852            0 :                                           fmtQualifiedDumpable(dictinfo));
   15853              : 
   15854            0 :         if (dopt->binary_upgrade)
   15855            0 :                 binary_upgrade_extension_member(q, &dictinfo->dobj,
   15856            0 :                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
   15857            0 :                                                                                 dictinfo->dobj.namespace->dobj.name);
   15858              : 
   15859            0 :         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15860            0 :                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   15861            0 :                                          ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   15862              :                                                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   15863              :                                                                   .owner = dictinfo->rolname,
   15864              :                                                                   .description = "TEXT SEARCH DICTIONARY",
   15865              :                                                                   .section = SECTION_PRE_DATA,
   15866              :                                                                   .createStmt = q->data,
   15867              :                                                                   .dropStmt = delq->data));
   15868              : 
   15869              :         /* Dump Dictionary Comments */
   15870            0 :         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15871            0 :                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   15872            0 :                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   15873            0 :                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   15874              : 
   15875            0 :         destroyPQExpBuffer(q);
   15876            0 :         destroyPQExpBuffer(delq);
   15877            0 :         destroyPQExpBuffer(query);
   15878            0 :         free(qdictname);
   15879            0 : }
   15880              : 
   15881              : /*
   15882              :  * dumpTSTemplate
   15883              :  *        write out a single text search template
   15884              :  */
   15885              : static void
   15886            0 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   15887              : {
   15888            0 :         DumpOptions *dopt = fout->dopt;
   15889            0 :         PQExpBuffer q;
   15890            0 :         PQExpBuffer delq;
   15891            0 :         char       *qtmplname;
   15892              : 
   15893              :         /* Do nothing if not dumping schema */
   15894            0 :         if (!dopt->dumpSchema)
   15895            0 :                 return;
   15896              : 
   15897            0 :         q = createPQExpBuffer();
   15898            0 :         delq = createPQExpBuffer();
   15899              : 
   15900            0 :         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   15901              : 
   15902            0 :         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   15903            0 :                                           fmtQualifiedDumpable(tmplinfo));
   15904              : 
   15905            0 :         if (tmplinfo->tmplinit != InvalidOid)
   15906            0 :                 appendPQExpBuffer(q, "    INIT = %s,\n",
   15907            0 :                                                   convertTSFunction(fout, tmplinfo->tmplinit));
   15908            0 :         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   15909            0 :                                           convertTSFunction(fout, tmplinfo->tmpllexize));
   15910              : 
   15911            0 :         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   15912            0 :                                           fmtQualifiedDumpable(tmplinfo));
   15913              : 
   15914            0 :         if (dopt->binary_upgrade)
   15915            0 :                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
   15916            0 :                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
   15917            0 :                                                                                 tmplinfo->dobj.namespace->dobj.name);
   15918              : 
   15919            0 :         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15920            0 :                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   15921            0 :                                          ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   15922              :                                                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   15923              :                                                                   .description = "TEXT SEARCH TEMPLATE",
   15924              :                                                                   .section = SECTION_PRE_DATA,
   15925              :                                                                   .createStmt = q->data,
   15926              :                                                                   .dropStmt = delq->data));
   15927              : 
   15928              :         /* Dump Template Comments */
   15929            0 :         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15930            0 :                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   15931            0 :                                         tmplinfo->dobj.namespace->dobj.name, "",
   15932            0 :                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   15933              : 
   15934            0 :         destroyPQExpBuffer(q);
   15935            0 :         destroyPQExpBuffer(delq);
   15936            0 :         free(qtmplname);
   15937            0 : }
   15938              : 
   15939              : /*
   15940              :  * dumpTSConfig
   15941              :  *        write out a single text search configuration
   15942              :  */
   15943              : static void
   15944            0 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   15945              : {
   15946            0 :         DumpOptions *dopt = fout->dopt;
   15947            0 :         PQExpBuffer q;
   15948            0 :         PQExpBuffer delq;
   15949            0 :         PQExpBuffer query;
   15950            0 :         char       *qcfgname;
   15951            0 :         PGresult   *res;
   15952            0 :         char       *nspname;
   15953            0 :         char       *prsname;
   15954            0 :         int                     ntups,
   15955              :                                 i;
   15956            0 :         int                     i_tokenname;
   15957            0 :         int                     i_dictname;
   15958              : 
   15959              :         /* Do nothing if not dumping schema */
   15960            0 :         if (!dopt->dumpSchema)
   15961            0 :                 return;
   15962              : 
   15963            0 :         q = createPQExpBuffer();
   15964            0 :         delq = createPQExpBuffer();
   15965            0 :         query = createPQExpBuffer();
   15966              : 
   15967            0 :         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   15968              : 
   15969              :         /* Fetch name and namespace of the config's parser */
   15970            0 :         appendPQExpBuffer(query, "SELECT nspname, prsname "
   15971              :                                           "FROM pg_ts_parser p, pg_namespace n "
   15972              :                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   15973            0 :                                           cfginfo->cfgparser);
   15974            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15975            0 :         nspname = PQgetvalue(res, 0, 0);
   15976            0 :         prsname = PQgetvalue(res, 0, 1);
   15977              : 
   15978            0 :         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   15979            0 :                                           fmtQualifiedDumpable(cfginfo));
   15980              : 
   15981            0 :         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   15982            0 :         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   15983              : 
   15984            0 :         PQclear(res);
   15985              : 
   15986            0 :         resetPQExpBuffer(query);
   15987            0 :         appendPQExpBuffer(query,
   15988              :                                           "SELECT\n"
   15989              :                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   15990              :                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   15991              :                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   15992              :                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
   15993              :                                           "WHERE m.mapcfg = '%u'\n"
   15994              :                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   15995            0 :                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   15996              : 
   15997            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15998            0 :         ntups = PQntuples(res);
   15999              : 
   16000            0 :         i_tokenname = PQfnumber(res, "tokenname");
   16001            0 :         i_dictname = PQfnumber(res, "dictname");
   16002              : 
   16003            0 :         for (i = 0; i < ntups; i++)
   16004              :         {
   16005            0 :                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
   16006            0 :                 char       *dictname = PQgetvalue(res, i, i_dictname);
   16007              : 
   16008            0 :                 if (i == 0 ||
   16009            0 :                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   16010              :                 {
   16011              :                         /* starting a new token type, so start a new command */
   16012            0 :                         if (i > 0)
   16013            0 :                                 appendPQExpBufferStr(q, ";\n");
   16014            0 :                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   16015            0 :                                                           fmtQualifiedDumpable(cfginfo));
   16016              :                         /* tokenname needs quoting, dictname does NOT */
   16017            0 :                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   16018            0 :                                                           fmtId(tokenname), dictname);
   16019            0 :                 }
   16020              :                 else
   16021            0 :                         appendPQExpBuffer(q, ", %s", dictname);
   16022            0 :         }
   16023              : 
   16024            0 :         if (ntups > 0)
   16025            0 :                 appendPQExpBufferStr(q, ";\n");
   16026              : 
   16027            0 :         PQclear(res);
   16028              : 
   16029            0 :         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   16030            0 :                                           fmtQualifiedDumpable(cfginfo));
   16031              : 
   16032            0 :         if (dopt->binary_upgrade)
   16033            0 :                 binary_upgrade_extension_member(q, &cfginfo->dobj,
   16034            0 :                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
   16035            0 :                                                                                 cfginfo->dobj.namespace->dobj.name);
   16036              : 
   16037            0 :         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16038            0 :                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   16039            0 :                                          ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   16040              :                                                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   16041              :                                                                   .owner = cfginfo->rolname,
   16042              :                                                                   .description = "TEXT SEARCH CONFIGURATION",
   16043              :                                                                   .section = SECTION_PRE_DATA,
   16044              :                                                                   .createStmt = q->data,
   16045              :                                                                   .dropStmt = delq->data));
   16046              : 
   16047              :         /* Dump Configuration Comments */
   16048            0 :         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16049            0 :                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   16050            0 :                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   16051            0 :                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   16052              : 
   16053            0 :         destroyPQExpBuffer(q);
   16054            0 :         destroyPQExpBuffer(delq);
   16055            0 :         destroyPQExpBuffer(query);
   16056            0 :         free(qcfgname);
   16057            0 : }
   16058              : 
   16059              : /*
   16060              :  * dumpForeignDataWrapper
   16061              :  *        write out a single foreign-data wrapper definition
   16062              :  */
   16063              : static void
   16064            0 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   16065              : {
   16066            0 :         DumpOptions *dopt = fout->dopt;
   16067            0 :         PQExpBuffer q;
   16068            0 :         PQExpBuffer delq;
   16069            0 :         char       *qfdwname;
   16070              : 
   16071              :         /* Do nothing if not dumping schema */
   16072            0 :         if (!dopt->dumpSchema)
   16073            0 :                 return;
   16074              : 
   16075            0 :         q = createPQExpBuffer();
   16076            0 :         delq = createPQExpBuffer();
   16077              : 
   16078            0 :         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   16079              : 
   16080            0 :         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   16081            0 :                                           qfdwname);
   16082              : 
   16083            0 :         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   16084            0 :                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   16085              : 
   16086            0 :         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   16087            0 :                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   16088              : 
   16089            0 :         if (strlen(fdwinfo->fdwoptions) > 0)
   16090            0 :                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   16091              : 
   16092            0 :         appendPQExpBufferStr(q, ";\n");
   16093              : 
   16094            0 :         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   16095            0 :                                           qfdwname);
   16096              : 
   16097            0 :         if (dopt->binary_upgrade)
   16098            0 :                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
   16099            0 :                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
   16100              :                                                                                 NULL);
   16101              : 
   16102            0 :         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16103            0 :                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   16104            0 :                                          ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   16105              :                                                                   .owner = fdwinfo->rolname,
   16106              :                                                                   .description = "FOREIGN DATA WRAPPER",
   16107              :                                                                   .section = SECTION_PRE_DATA,
   16108              :                                                                   .createStmt = q->data,
   16109              :                                                                   .dropStmt = delq->data));
   16110              : 
   16111              :         /* Dump Foreign Data Wrapper Comments */
   16112            0 :         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16113            0 :                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   16114            0 :                                         NULL, fdwinfo->rolname,
   16115            0 :                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   16116              : 
   16117              :         /* Handle the ACL */
   16118            0 :         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16119            0 :                 dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   16120            0 :                                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   16121            0 :                                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   16122              : 
   16123            0 :         free(qfdwname);
   16124              : 
   16125            0 :         destroyPQExpBuffer(q);
   16126            0 :         destroyPQExpBuffer(delq);
   16127            0 : }
   16128              : 
   16129              : /*
   16130              :  * dumpForeignServer
   16131              :  *        write out a foreign server definition
   16132              :  */
   16133              : static void
   16134            0 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   16135              : {
   16136            0 :         DumpOptions *dopt = fout->dopt;
   16137            0 :         PQExpBuffer q;
   16138            0 :         PQExpBuffer delq;
   16139            0 :         PQExpBuffer query;
   16140            0 :         PGresult   *res;
   16141            0 :         char       *qsrvname;
   16142            0 :         char       *fdwname;
   16143              : 
   16144              :         /* Do nothing if not dumping schema */
   16145            0 :         if (!dopt->dumpSchema)
   16146            0 :                 return;
   16147              : 
   16148            0 :         q = createPQExpBuffer();
   16149            0 :         delq = createPQExpBuffer();
   16150            0 :         query = createPQExpBuffer();
   16151              : 
   16152            0 :         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   16153              : 
   16154              :         /* look up the foreign-data wrapper */
   16155            0 :         appendPQExpBuffer(query, "SELECT fdwname "
   16156              :                                           "FROM pg_foreign_data_wrapper w "
   16157              :                                           "WHERE w.oid = '%u'",
   16158            0 :                                           srvinfo->srvfdw);
   16159            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16160            0 :         fdwname = PQgetvalue(res, 0, 0);
   16161              : 
   16162            0 :         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   16163            0 :         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   16164              :         {
   16165            0 :                 appendPQExpBufferStr(q, " TYPE ");
   16166            0 :                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
   16167            0 :         }
   16168            0 :         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   16169              :         {
   16170            0 :                 appendPQExpBufferStr(q, " VERSION ");
   16171            0 :                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
   16172            0 :         }
   16173              : 
   16174            0 :         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   16175            0 :         appendPQExpBufferStr(q, fmtId(fdwname));
   16176              : 
   16177            0 :         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   16178            0 :                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   16179              : 
   16180            0 :         appendPQExpBufferStr(q, ";\n");
   16181              : 
   16182            0 :         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   16183            0 :                                           qsrvname);
   16184              : 
   16185            0 :         if (dopt->binary_upgrade)
   16186            0 :                 binary_upgrade_extension_member(q, &srvinfo->dobj,
   16187            0 :                                                                                 "SERVER", qsrvname, NULL);
   16188              : 
   16189            0 :         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16190            0 :                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   16191            0 :                                          ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   16192              :                                                                   .owner = srvinfo->rolname,
   16193              :                                                                   .description = "SERVER",
   16194              :                                                                   .section = SECTION_PRE_DATA,
   16195              :                                                                   .createStmt = q->data,
   16196              :                                                                   .dropStmt = delq->data));
   16197              : 
   16198              :         /* Dump Foreign Server Comments */
   16199            0 :         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16200            0 :                 dumpComment(fout, "SERVER", qsrvname,
   16201            0 :                                         NULL, srvinfo->rolname,
   16202            0 :                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   16203              : 
   16204              :         /* Handle the ACL */
   16205            0 :         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16206            0 :                 dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   16207            0 :                                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   16208            0 :                                 NULL, srvinfo->rolname, &srvinfo->dacl);
   16209              : 
   16210              :         /* Dump user mappings */
   16211            0 :         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   16212            0 :                 dumpUserMappings(fout,
   16213            0 :                                                  srvinfo->dobj.name, NULL,
   16214            0 :                                                  srvinfo->rolname,
   16215            0 :                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   16216              : 
   16217            0 :         PQclear(res);
   16218              : 
   16219            0 :         free(qsrvname);
   16220              : 
   16221            0 :         destroyPQExpBuffer(q);
   16222            0 :         destroyPQExpBuffer(delq);
   16223            0 :         destroyPQExpBuffer(query);
   16224            0 : }
   16225              : 
   16226              : /*
   16227              :  * dumpUserMappings
   16228              :  *
   16229              :  * This routine is used to dump any user mappings associated with the
   16230              :  * server handed to this routine. Should be called after ArchiveEntry()
   16231              :  * for the server.
   16232              :  */
   16233              : static void
   16234            0 : dumpUserMappings(Archive *fout,
   16235              :                                  const char *servername, const char *namespace,
   16236              :                                  const char *owner,
   16237              :                                  CatalogId catalogId, DumpId dumpId)
   16238              : {
   16239            0 :         PQExpBuffer q;
   16240            0 :         PQExpBuffer delq;
   16241            0 :         PQExpBuffer query;
   16242            0 :         PQExpBuffer tag;
   16243            0 :         PGresult   *res;
   16244            0 :         int                     ntups;
   16245            0 :         int                     i_usename;
   16246            0 :         int                     i_umoptions;
   16247            0 :         int                     i;
   16248              : 
   16249            0 :         q = createPQExpBuffer();
   16250            0 :         tag = createPQExpBuffer();
   16251            0 :         delq = createPQExpBuffer();
   16252            0 :         query = createPQExpBuffer();
   16253              : 
   16254              :         /*
   16255              :          * We read from the publicly accessible view pg_user_mappings, so as not
   16256              :          * to fail if run by a non-superuser.  Note that the view will show
   16257              :          * umoptions as null if the user hasn't got privileges for the associated
   16258              :          * server; this means that pg_dump will dump such a mapping, but with no
   16259              :          * OPTIONS clause.  A possible alternative is to skip such mappings
   16260              :          * altogether, but it's not clear that that's an improvement.
   16261              :          */
   16262            0 :         appendPQExpBuffer(query,
   16263              :                                           "SELECT usename, "
   16264              :                                           "array_to_string(ARRAY("
   16265              :                                           "SELECT quote_ident(option_name) || ' ' || "
   16266              :                                           "quote_literal(option_value) "
   16267              :                                           "FROM pg_options_to_table(umoptions) "
   16268              :                                           "ORDER BY option_name"
   16269              :                                           "), E',\n    ') AS umoptions "
   16270              :                                           "FROM pg_user_mappings "
   16271              :                                           "WHERE srvid = '%u' "
   16272              :                                           "ORDER BY usename",
   16273            0 :                                           catalogId.oid);
   16274              : 
   16275            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16276              : 
   16277            0 :         ntups = PQntuples(res);
   16278            0 :         i_usename = PQfnumber(res, "usename");
   16279            0 :         i_umoptions = PQfnumber(res, "umoptions");
   16280              : 
   16281            0 :         for (i = 0; i < ntups; i++)
   16282              :         {
   16283            0 :                 char       *usename;
   16284            0 :                 char       *umoptions;
   16285              : 
   16286            0 :                 usename = PQgetvalue(res, i, i_usename);
   16287            0 :                 umoptions = PQgetvalue(res, i, i_umoptions);
   16288              : 
   16289            0 :                 resetPQExpBuffer(q);
   16290            0 :                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   16291            0 :                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   16292              : 
   16293            0 :                 if (umoptions && strlen(umoptions) > 0)
   16294            0 :                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   16295              : 
   16296            0 :                 appendPQExpBufferStr(q, ";\n");
   16297              : 
   16298            0 :                 resetPQExpBuffer(delq);
   16299            0 :                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   16300            0 :                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   16301              : 
   16302            0 :                 resetPQExpBuffer(tag);
   16303            0 :                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   16304            0 :                                                   usename, servername);
   16305              : 
   16306            0 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16307            0 :                                          ARCHIVE_OPTS(.tag = tag->data,
   16308              :                                                                   .namespace = namespace,
   16309              :                                                                   .owner = owner,
   16310              :                                                                   .description = "USER MAPPING",
   16311              :                                                                   .section = SECTION_PRE_DATA,
   16312              :                                                                   .createStmt = q->data,
   16313              :                                                                   .dropStmt = delq->data));
   16314            0 :         }
   16315              : 
   16316            0 :         PQclear(res);
   16317              : 
   16318            0 :         destroyPQExpBuffer(query);
   16319            0 :         destroyPQExpBuffer(delq);
   16320            0 :         destroyPQExpBuffer(tag);
   16321            0 :         destroyPQExpBuffer(q);
   16322            0 : }
   16323              : 
   16324              : /*
   16325              :  * Write out default privileges information
   16326              :  */
   16327              : static void
   16328            0 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   16329              : {
   16330            0 :         DumpOptions *dopt = fout->dopt;
   16331            0 :         PQExpBuffer q;
   16332            0 :         PQExpBuffer tag;
   16333            0 :         const char *type;
   16334              : 
   16335              :         /* Do nothing if not dumping schema, or if we're skipping ACLs */
   16336            0 :         if (!dopt->dumpSchema || dopt->aclsSkip)
   16337            0 :                 return;
   16338              : 
   16339            0 :         q = createPQExpBuffer();
   16340            0 :         tag = createPQExpBuffer();
   16341              : 
   16342            0 :         switch (daclinfo->defaclobjtype)
   16343              :         {
   16344              :                 case DEFACLOBJ_RELATION:
   16345            0 :                         type = "TABLES";
   16346            0 :                         break;
   16347              :                 case DEFACLOBJ_SEQUENCE:
   16348            0 :                         type = "SEQUENCES";
   16349            0 :                         break;
   16350              :                 case DEFACLOBJ_FUNCTION:
   16351            0 :                         type = "FUNCTIONS";
   16352            0 :                         break;
   16353              :                 case DEFACLOBJ_TYPE:
   16354            0 :                         type = "TYPES";
   16355            0 :                         break;
   16356              :                 case DEFACLOBJ_NAMESPACE:
   16357            0 :                         type = "SCHEMAS";
   16358            0 :                         break;
   16359              :                 case DEFACLOBJ_LARGEOBJECT:
   16360            0 :                         type = "LARGE OBJECTS";
   16361            0 :                         break;
   16362              :                 default:
   16363              :                         /* shouldn't get here */
   16364            0 :                         pg_fatal("unrecognized object type in default privileges: %d",
   16365              :                                          (int) daclinfo->defaclobjtype);
   16366            0 :                         type = "";                    /* keep compiler quiet */
   16367            0 :         }
   16368              : 
   16369            0 :         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   16370              : 
   16371              :         /* build the actual command(s) for this tuple */
   16372            0 :         if (!buildDefaultACLCommands(type,
   16373            0 :                                                                  daclinfo->dobj.namespace != NULL ?
   16374            0 :                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
   16375            0 :                                                                  daclinfo->dacl.acl,
   16376            0 :                                                                  daclinfo->dacl.acldefault,
   16377            0 :                                                                  daclinfo->defaclrole,
   16378            0 :                                                                  fout->remoteVersion,
   16379            0 :                                                                  q))
   16380            0 :                 pg_fatal("could not parse default ACL list (%s)",
   16381              :                                  daclinfo->dacl.acl);
   16382              : 
   16383            0 :         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16384            0 :                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   16385            0 :                                          ARCHIVE_OPTS(.tag = tag->data,
   16386              :                                                                   .namespace = daclinfo->dobj.namespace ?
   16387              :                                                                   daclinfo->dobj.namespace->dobj.name : NULL,
   16388              :                                                                   .owner = daclinfo->defaclrole,
   16389              :                                                                   .description = "DEFAULT ACL",
   16390              :                                                                   .section = SECTION_POST_DATA,
   16391              :                                                                   .createStmt = q->data));
   16392              : 
   16393            0 :         destroyPQExpBuffer(tag);
   16394            0 :         destroyPQExpBuffer(q);
   16395            0 : }
   16396              : 
   16397              : /*----------
   16398              :  * Write out grant/revoke information
   16399              :  *
   16400              :  * 'objDumpId' is the dump ID of the underlying object.
   16401              :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   16402              :  *              or InvalidDumpId if there is no need for a second dependency.
   16403              :  * 'type' must be one of
   16404              :  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   16405              :  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   16406              :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   16407              :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   16408              :  *              (Currently we assume that subname is only provided for table columns.)
   16409              :  * 'nspname' is the namespace the object is in (NULL if none).
   16410              :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   16411              :  *              to use the default for the object type.
   16412              :  * 'owner' is the owner, NULL if there is no owner (for languages).
   16413              :  * 'dacl' is the DumpableAcl struct for the object.
   16414              :  *
   16415              :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   16416              :  * no ACL entry was created.
   16417              :  *----------
   16418              :  */
   16419              : static DumpId
   16420            0 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   16421              :                 const char *type, const char *name, const char *subname,
   16422              :                 const char *nspname, const char *tag, const char *owner,
   16423              :                 const DumpableAcl *dacl)
   16424              : {
   16425            0 :         DumpId          aclDumpId = InvalidDumpId;
   16426            0 :         DumpOptions *dopt = fout->dopt;
   16427            0 :         const char *acls = dacl->acl;
   16428            0 :         const char *acldefault = dacl->acldefault;
   16429            0 :         char            privtype = dacl->privtype;
   16430            0 :         const char *initprivs = dacl->initprivs;
   16431            0 :         const char *baseacls;
   16432            0 :         PQExpBuffer sql;
   16433              : 
   16434              :         /* Do nothing if ACL dump is not enabled */
   16435            0 :         if (dopt->aclsSkip)
   16436            0 :                 return InvalidDumpId;
   16437              : 
   16438              :         /* --data-only skips ACLs *except* large object ACLs */
   16439            0 :         if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   16440            0 :                 return InvalidDumpId;
   16441              : 
   16442            0 :         sql = createPQExpBuffer();
   16443              : 
   16444              :         /*
   16445              :          * In binary upgrade mode, we don't run an extension's script but instead
   16446              :          * dump out the objects independently and then recreate them.  To preserve
   16447              :          * any initial privileges which were set on extension objects, we need to
   16448              :          * compute the set of GRANT and REVOKE commands necessary to get from the
   16449              :          * default privileges of an object to its initial privileges as recorded
   16450              :          * in pg_init_privs.
   16451              :          *
   16452              :          * At restore time, we apply these commands after having called
   16453              :          * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   16454              :          * copy the results into pg_init_privs.  This is how we preserve the
   16455              :          * contents of that catalog across binary upgrades.
   16456              :          */
   16457            0 :         if (dopt->binary_upgrade && privtype == 'e' &&
   16458            0 :                 initprivs && *initprivs != '\0')
   16459              :         {
   16460            0 :                 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   16461            0 :                 if (!buildACLCommands(name, subname, nspname, type,
   16462            0 :                                                           initprivs, acldefault, owner,
   16463            0 :                                                           "", fout->remoteVersion, sql))
   16464            0 :                         pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16465              :                                          initprivs, acldefault, name, type);
   16466            0 :                 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   16467            0 :         }
   16468              : 
   16469              :         /*
   16470              :          * Now figure the GRANT and REVOKE commands needed to get to the object's
   16471              :          * actual current ACL, starting from the initprivs if given, else from the
   16472              :          * object-type-specific default.  Also, while buildACLCommands will assume
   16473              :          * that a NULL/empty acls string means it needn't do anything, what that
   16474              :          * actually represents is the object-type-specific default; so we need to
   16475              :          * substitute the acldefault string to get the right results in that case.
   16476              :          */
   16477            0 :         if (initprivs && *initprivs != '\0')
   16478              :         {
   16479            0 :                 baseacls = initprivs;
   16480            0 :                 if (acls == NULL || *acls == '\0')
   16481            0 :                         acls = acldefault;
   16482            0 :         }
   16483              :         else
   16484            0 :                 baseacls = acldefault;
   16485              : 
   16486            0 :         if (!buildACLCommands(name, subname, nspname, type,
   16487            0 :                                                   acls, baseacls, owner,
   16488            0 :                                                   "", fout->remoteVersion, sql))
   16489            0 :                 pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16490              :                                  acls, baseacls, name, type);
   16491              : 
   16492            0 :         if (sql->len > 0)
   16493              :         {
   16494            0 :                 PQExpBuffer tagbuf = createPQExpBuffer();
   16495            0 :                 DumpId          aclDeps[2];
   16496            0 :                 int                     nDeps = 0;
   16497              : 
   16498            0 :                 if (tag)
   16499            0 :                         appendPQExpBufferStr(tagbuf, tag);
   16500            0 :                 else if (subname)
   16501            0 :                         appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   16502              :                 else
   16503            0 :                         appendPQExpBuffer(tagbuf, "%s %s", type, name);
   16504              : 
   16505            0 :                 aclDeps[nDeps++] = objDumpId;
   16506            0 :                 if (altDumpId != InvalidDumpId)
   16507            0 :                         aclDeps[nDeps++] = altDumpId;
   16508              : 
   16509            0 :                 aclDumpId = createDumpId();
   16510              : 
   16511            0 :                 ArchiveEntry(fout, nilCatalogId, aclDumpId,
   16512            0 :                                          ARCHIVE_OPTS(.tag = tagbuf->data,
   16513              :                                                                   .namespace = nspname,
   16514              :                                                                   .owner = owner,
   16515              :                                                                   .description = "ACL",
   16516              :                                                                   .section = SECTION_NONE,
   16517              :                                                                   .createStmt = sql->data,
   16518              :                                                                   .deps = aclDeps,
   16519              :                                                                   .nDeps = nDeps));
   16520              : 
   16521            0 :                 destroyPQExpBuffer(tagbuf);
   16522            0 :         }
   16523              : 
   16524            0 :         destroyPQExpBuffer(sql);
   16525              : 
   16526            0 :         return aclDumpId;
   16527            0 : }
   16528              : 
   16529              : /*
   16530              :  * dumpSecLabel
   16531              :  *
   16532              :  * This routine is used to dump any security labels associated with the
   16533              :  * object handed to this routine. The routine takes the object type
   16534              :  * and object name (ready to print, except for schema decoration), plus
   16535              :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   16536              :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   16537              :  * plus the dump ID for the object (for setting a dependency).
   16538              :  * If a matching pg_seclabel entry is found, it is dumped.
   16539              :  *
   16540              :  * Note: although this routine takes a dumpId for dependency purposes,
   16541              :  * that purpose is just to mark the dependency in the emitted dump file
   16542              :  * for possible future use by pg_restore.  We do NOT use it for determining
   16543              :  * ordering of the label in the dump file, because this routine is called
   16544              :  * after dependency sorting occurs.  This routine should be called just after
   16545              :  * calling ArchiveEntry() for the specified object.
   16546              :  */
   16547              : static void
   16548            0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   16549              :                          const char *namespace, const char *owner,
   16550              :                          CatalogId catalogId, int subid, DumpId dumpId)
   16551              : {
   16552            0 :         DumpOptions *dopt = fout->dopt;
   16553            0 :         SecLabelItem *labels;
   16554            0 :         int                     nlabels;
   16555            0 :         int                     i;
   16556            0 :         PQExpBuffer query;
   16557              : 
   16558              :         /* do nothing, if --no-security-labels is supplied */
   16559            0 :         if (dopt->no_security_labels)
   16560            0 :                 return;
   16561              : 
   16562              :         /*
   16563              :          * Security labels are schema not data ... except large object labels are
   16564              :          * data
   16565              :          */
   16566            0 :         if (strcmp(type, "LARGE OBJECT") != 0)
   16567              :         {
   16568            0 :                 if (!dopt->dumpSchema)
   16569            0 :                         return;
   16570            0 :         }
   16571              :         else
   16572              :         {
   16573              :                 /* We do dump large object security labels in binary-upgrade mode */
   16574            0 :                 if (!dopt->dumpData && !dopt->binary_upgrade)
   16575            0 :                         return;
   16576              :         }
   16577              : 
   16578              :         /* Search for security labels associated with catalogId, using table */
   16579            0 :         nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   16580              : 
   16581            0 :         query = createPQExpBuffer();
   16582              : 
   16583            0 :         for (i = 0; i < nlabels; i++)
   16584              :         {
   16585              :                 /*
   16586              :                  * Ignore label entries for which the subid doesn't match.
   16587              :                  */
   16588            0 :                 if (labels[i].objsubid != subid)
   16589            0 :                         continue;
   16590              : 
   16591            0 :                 appendPQExpBuffer(query,
   16592              :                                                   "SECURITY LABEL FOR %s ON %s ",
   16593            0 :                                                   fmtId(labels[i].provider), type);
   16594            0 :                 if (namespace && *namespace)
   16595            0 :                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
   16596            0 :                 appendPQExpBuffer(query, "%s IS ", name);
   16597            0 :                 appendStringLiteralAH(query, labels[i].label, fout);
   16598            0 :                 appendPQExpBufferStr(query, ";\n");
   16599            0 :         }
   16600              : 
   16601            0 :         if (query->len > 0)
   16602              :         {
   16603            0 :                 PQExpBuffer tag = createPQExpBuffer();
   16604              : 
   16605            0 :                 appendPQExpBuffer(tag, "%s %s", type, name);
   16606            0 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16607            0 :                                          ARCHIVE_OPTS(.tag = tag->data,
   16608              :                                                                   .namespace = namespace,
   16609              :                                                                   .owner = owner,
   16610              :                                                                   .description = "SECURITY LABEL",
   16611              :                                                                   .section = SECTION_NONE,
   16612              :                                                                   .createStmt = query->data,
   16613              :                                                                   .deps = &dumpId,
   16614              :                                                                   .nDeps = 1));
   16615            0 :                 destroyPQExpBuffer(tag);
   16616            0 :         }
   16617              : 
   16618            0 :         destroyPQExpBuffer(query);
   16619            0 : }
   16620              : 
   16621              : /*
   16622              :  * dumpTableSecLabel
   16623              :  *
   16624              :  * As above, but dump security label for both the specified table (or view)
   16625              :  * and its columns.
   16626              :  */
   16627              : static void
   16628            0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   16629              : {
   16630            0 :         DumpOptions *dopt = fout->dopt;
   16631            0 :         SecLabelItem *labels;
   16632            0 :         int                     nlabels;
   16633            0 :         int                     i;
   16634            0 :         PQExpBuffer query;
   16635            0 :         PQExpBuffer target;
   16636              : 
   16637              :         /* do nothing, if --no-security-labels is supplied */
   16638            0 :         if (dopt->no_security_labels)
   16639            0 :                 return;
   16640              : 
   16641              :         /* SecLabel are SCHEMA not data */
   16642            0 :         if (!dopt->dumpSchema)
   16643            0 :                 return;
   16644              : 
   16645              :         /* Search for comments associated with relation, using table */
   16646            0 :         nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   16647            0 :                                                         tbinfo->dobj.catId.oid,
   16648              :                                                         &labels);
   16649              : 
   16650              :         /* If security labels exist, build SECURITY LABEL statements */
   16651            0 :         if (nlabels <= 0)
   16652            0 :                 return;
   16653              : 
   16654            0 :         query = createPQExpBuffer();
   16655            0 :         target = createPQExpBuffer();
   16656              : 
   16657            0 :         for (i = 0; i < nlabels; i++)
   16658              :         {
   16659            0 :                 const char *colname;
   16660            0 :                 const char *provider = labels[i].provider;
   16661            0 :                 const char *label = labels[i].label;
   16662            0 :                 int                     objsubid = labels[i].objsubid;
   16663              : 
   16664            0 :                 resetPQExpBuffer(target);
   16665            0 :                 if (objsubid == 0)
   16666              :                 {
   16667            0 :                         appendPQExpBuffer(target, "%s %s", reltypename,
   16668            0 :                                                           fmtQualifiedDumpable(tbinfo));
   16669            0 :                 }
   16670              :                 else
   16671              :                 {
   16672            0 :                         colname = getAttrName(objsubid, tbinfo);
   16673              :                         /* first fmtXXX result must be consumed before calling again */
   16674            0 :                         appendPQExpBuffer(target, "COLUMN %s",
   16675            0 :                                                           fmtQualifiedDumpable(tbinfo));
   16676            0 :                         appendPQExpBuffer(target, ".%s", fmtId(colname));
   16677              :                 }
   16678            0 :                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   16679            0 :                                                   fmtId(provider), target->data);
   16680            0 :                 appendStringLiteralAH(query, label, fout);
   16681            0 :                 appendPQExpBufferStr(query, ";\n");
   16682            0 :         }
   16683            0 :         if (query->len > 0)
   16684              :         {
   16685            0 :                 resetPQExpBuffer(target);
   16686            0 :                 appendPQExpBuffer(target, "%s %s", reltypename,
   16687            0 :                                                   fmtId(tbinfo->dobj.name));
   16688            0 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16689            0 :                                          ARCHIVE_OPTS(.tag = target->data,
   16690              :                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16691              :                                                                   .owner = tbinfo->rolname,
   16692              :                                                                   .description = "SECURITY LABEL",
   16693              :                                                                   .section = SECTION_NONE,
   16694              :                                                                   .createStmt = query->data,
   16695              :                                                                   .deps = &(tbinfo->dobj.dumpId),
   16696              :                                                                   .nDeps = 1));
   16697            0 :         }
   16698            0 :         destroyPQExpBuffer(query);
   16699            0 :         destroyPQExpBuffer(target);
   16700            0 : }
   16701              : 
   16702              : /*
   16703              :  * findSecLabels
   16704              :  *
   16705              :  * Find the security label(s), if any, associated with the given object.
   16706              :  * All the objsubid values associated with the given classoid/objoid are
   16707              :  * found with one search.
   16708              :  */
   16709              : static int
   16710            0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   16711              : {
   16712            0 :         SecLabelItem *middle = NULL;
   16713            0 :         SecLabelItem *low;
   16714            0 :         SecLabelItem *high;
   16715            0 :         int                     nmatch;
   16716              : 
   16717            0 :         if (nseclabels <= 0)         /* no labels, so no match is possible */
   16718              :         {
   16719            0 :                 *items = NULL;
   16720            0 :                 return 0;
   16721              :         }
   16722              : 
   16723              :         /*
   16724              :          * Do binary search to find some item matching the object.
   16725              :          */
   16726            0 :         low = &seclabels[0];
   16727            0 :         high = &seclabels[nseclabels - 1];
   16728            0 :         while (low <= high)
   16729              :         {
   16730            0 :                 middle = low + (high - low) / 2;
   16731              : 
   16732            0 :                 if (classoid < middle->classoid)
   16733            0 :                         high = middle - 1;
   16734            0 :                 else if (classoid > middle->classoid)
   16735            0 :                         low = middle + 1;
   16736            0 :                 else if (objoid < middle->objoid)
   16737            0 :                         high = middle - 1;
   16738            0 :                 else if (objoid > middle->objoid)
   16739            0 :                         low = middle + 1;
   16740              :                 else
   16741            0 :                         break;                          /* found a match */
   16742              :         }
   16743              : 
   16744            0 :         if (low > high)                              /* no matches */
   16745              :         {
   16746            0 :                 *items = NULL;
   16747            0 :                 return 0;
   16748              :         }
   16749              : 
   16750              :         /*
   16751              :          * Now determine how many items match the object.  The search loop
   16752              :          * invariant still holds: only items between low and high inclusive could
   16753              :          * match.
   16754              :          */
   16755            0 :         nmatch = 1;
   16756            0 :         while (middle > low)
   16757              :         {
   16758            0 :                 if (classoid != middle[-1].classoid ||
   16759            0 :                         objoid != middle[-1].objoid)
   16760            0 :                         break;
   16761            0 :                 middle--;
   16762            0 :                 nmatch++;
   16763              :         }
   16764              : 
   16765            0 :         *items = middle;
   16766              : 
   16767            0 :         middle += nmatch;
   16768            0 :         while (middle <= high)
   16769              :         {
   16770            0 :                 if (classoid != middle->classoid ||
   16771            0 :                         objoid != middle->objoid)
   16772            0 :                         break;
   16773            0 :                 middle++;
   16774            0 :                 nmatch++;
   16775              :         }
   16776              : 
   16777            0 :         return nmatch;
   16778            0 : }
   16779              : 
   16780              : /*
   16781              :  * collectSecLabels
   16782              :  *
   16783              :  * Construct a table of all security labels available for database objects;
   16784              :  * also set the has-seclabel component flag for each relevant object.
   16785              :  *
   16786              :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   16787              :  */
   16788              : static void
   16789            0 : collectSecLabels(Archive *fout)
   16790              : {
   16791            0 :         PGresult   *res;
   16792            0 :         PQExpBuffer query;
   16793            0 :         int                     i_label;
   16794            0 :         int                     i_provider;
   16795            0 :         int                     i_classoid;
   16796            0 :         int                     i_objoid;
   16797            0 :         int                     i_objsubid;
   16798            0 :         int                     ntups;
   16799            0 :         int                     i;
   16800            0 :         DumpableObject *dobj;
   16801              : 
   16802            0 :         query = createPQExpBuffer();
   16803              : 
   16804            0 :         appendPQExpBufferStr(query,
   16805              :                                                  "SELECT label, provider, classoid, objoid, objsubid "
   16806              :                                                  "FROM pg_catalog.pg_seclabels "
   16807              :                                                  "ORDER BY classoid, objoid, objsubid");
   16808              : 
   16809            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16810              : 
   16811              :         /* Construct lookup table containing OIDs in numeric form */
   16812            0 :         i_label = PQfnumber(res, "label");
   16813            0 :         i_provider = PQfnumber(res, "provider");
   16814            0 :         i_classoid = PQfnumber(res, "classoid");
   16815            0 :         i_objoid = PQfnumber(res, "objoid");
   16816            0 :         i_objsubid = PQfnumber(res, "objsubid");
   16817              : 
   16818            0 :         ntups = PQntuples(res);
   16819              : 
   16820            0 :         seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
   16821            0 :         nseclabels = 0;
   16822            0 :         dobj = NULL;
   16823              : 
   16824            0 :         for (i = 0; i < ntups; i++)
   16825              :         {
   16826            0 :                 CatalogId       objId;
   16827            0 :                 int                     subid;
   16828              : 
   16829            0 :                 objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   16830            0 :                 objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   16831            0 :                 subid = atoi(PQgetvalue(res, i, i_objsubid));
   16832              : 
   16833              :                 /* We needn't remember labels that don't match any dumpable object */
   16834            0 :                 if (dobj == NULL ||
   16835            0 :                         dobj->catId.tableoid != objId.tableoid ||
   16836            0 :                         dobj->catId.oid != objId.oid)
   16837            0 :                         dobj = findObjectByCatalogId(objId);
   16838            0 :                 if (dobj == NULL)
   16839            0 :                         continue;
   16840              : 
   16841              :                 /*
   16842              :                  * Labels on columns of composite types are linked to the type's
   16843              :                  * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   16844              :                  * in the type's own DumpableObject.
   16845              :                  */
   16846            0 :                 if (subid != 0 && dobj->objType == DO_TABLE &&
   16847            0 :                         ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   16848              :                 {
   16849            0 :                         TypeInfo   *cTypeInfo;
   16850              : 
   16851            0 :                         cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   16852            0 :                         if (cTypeInfo)
   16853            0 :                                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   16854            0 :                 }
   16855              :                 else
   16856            0 :                         dobj->components |= DUMP_COMPONENT_SECLABEL;
   16857              : 
   16858            0 :                 seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   16859            0 :                 seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   16860            0 :                 seclabels[nseclabels].classoid = objId.tableoid;
   16861            0 :                 seclabels[nseclabels].objoid = objId.oid;
   16862            0 :                 seclabels[nseclabels].objsubid = subid;
   16863            0 :                 nseclabels++;
   16864            0 :         }
   16865              : 
   16866            0 :         PQclear(res);
   16867            0 :         destroyPQExpBuffer(query);
   16868            0 : }
   16869              : 
   16870              : /*
   16871              :  * dumpTable
   16872              :  *        write out to fout the declarations (not data) of a user-defined table
   16873              :  */
   16874              : static void
   16875            0 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   16876              : {
   16877            0 :         DumpOptions *dopt = fout->dopt;
   16878            0 :         DumpId          tableAclDumpId = InvalidDumpId;
   16879            0 :         char       *namecopy;
   16880              : 
   16881              :         /* Do nothing if not dumping schema */
   16882            0 :         if (!dopt->dumpSchema)
   16883            0 :                 return;
   16884              : 
   16885            0 :         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16886              :         {
   16887            0 :                 if (tbinfo->relkind == RELKIND_SEQUENCE)
   16888            0 :                         dumpSequence(fout, tbinfo);
   16889              :                 else
   16890            0 :                         dumpTableSchema(fout, tbinfo);
   16891            0 :         }
   16892              : 
   16893              :         /* Handle the ACL here */
   16894            0 :         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   16895            0 :         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16896              :         {
   16897            0 :                 const char *objtype =
   16898            0 :                         (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
   16899              : 
   16900            0 :                 tableAclDumpId =
   16901            0 :                         dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   16902            0 :                                         objtype, namecopy, NULL,
   16903            0 :                                         tbinfo->dobj.namespace->dobj.name,
   16904            0 :                                         NULL, tbinfo->rolname, &tbinfo->dacl);
   16905            0 :         }
   16906              : 
   16907              :         /*
   16908              :          * Handle column ACLs, if any.  Note: we pull these with a separate query
   16909              :          * rather than trying to fetch them during getTableAttrs, so that we won't
   16910              :          * miss ACLs on system columns.  Doing it this way also allows us to dump
   16911              :          * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   16912              :          */
   16913            0 :         if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   16914              :         {
   16915            0 :                 PQExpBuffer query = createPQExpBuffer();
   16916            0 :                 PGresult   *res;
   16917            0 :                 int                     i;
   16918              : 
   16919            0 :                 if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   16920              :                 {
   16921              :                         /* Set up query for column ACLs */
   16922            0 :                         appendPQExpBufferStr(query,
   16923              :                                                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   16924              : 
   16925            0 :                         if (fout->remoteVersion >= 90600)
   16926              :                         {
   16927              :                                 /*
   16928              :                                  * In principle we should call acldefault('c', relowner) to
   16929              :                                  * get the default ACL for a column.  However, we don't
   16930              :                                  * currently store the numeric OID of the relowner in
   16931              :                                  * TableInfo.  We could convert the owner name using regrole,
   16932              :                                  * but that creates a risk of failure due to concurrent role
   16933              :                                  * renames.  Given that the default ACL for columns is empty
   16934              :                                  * and is likely to stay that way, it's not worth extra cycles
   16935              :                                  * and risk to avoid hard-wiring that knowledge here.
   16936              :                                  */
   16937            0 :                                 appendPQExpBufferStr(query,
   16938              :                                                                          "SELECT at.attname, "
   16939              :                                                                          "at.attacl, "
   16940              :                                                                          "'{}' AS acldefault, "
   16941              :                                                                          "pip.privtype, pip.initprivs "
   16942              :                                                                          "FROM pg_catalog.pg_attribute at "
   16943              :                                                                          "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   16944              :                                                                          "(at.attrelid = pip.objoid "
   16945              :                                                                          "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   16946              :                                                                          "AND at.attnum = pip.objsubid) "
   16947              :                                                                          "WHERE at.attrelid = $1 AND "
   16948              :                                                                          "NOT at.attisdropped "
   16949              :                                                                          "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   16950              :                                                                          "ORDER BY at.attnum");
   16951            0 :                         }
   16952              :                         else
   16953              :                         {
   16954            0 :                                 appendPQExpBufferStr(query,
   16955              :                                                                          "SELECT attname, attacl, '{}' AS acldefault, "
   16956              :                                                                          "NULL AS privtype, NULL AS initprivs "
   16957              :                                                                          "FROM pg_catalog.pg_attribute "
   16958              :                                                                          "WHERE attrelid = $1 AND NOT attisdropped "
   16959              :                                                                          "AND attacl IS NOT NULL "
   16960              :                                                                          "ORDER BY attnum");
   16961              :                         }
   16962              : 
   16963            0 :                         ExecuteSqlStatement(fout, query->data);
   16964              : 
   16965            0 :                         fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   16966            0 :                 }
   16967              : 
   16968            0 :                 printfPQExpBuffer(query,
   16969              :                                                   "EXECUTE getColumnACLs('%u')",
   16970            0 :                                                   tbinfo->dobj.catId.oid);
   16971              : 
   16972            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16973              : 
   16974            0 :                 for (i = 0; i < PQntuples(res); i++)
   16975              :                 {
   16976            0 :                         char       *attname = PQgetvalue(res, i, 0);
   16977            0 :                         char       *attacl = PQgetvalue(res, i, 1);
   16978            0 :                         char       *acldefault = PQgetvalue(res, i, 2);
   16979            0 :                         char            privtype = *(PQgetvalue(res, i, 3));
   16980            0 :                         char       *initprivs = PQgetvalue(res, i, 4);
   16981            0 :                         DumpableAcl coldacl;
   16982            0 :                         char       *attnamecopy;
   16983              : 
   16984            0 :                         coldacl.acl = attacl;
   16985            0 :                         coldacl.acldefault = acldefault;
   16986            0 :                         coldacl.privtype = privtype;
   16987            0 :                         coldacl.initprivs = initprivs;
   16988            0 :                         attnamecopy = pg_strdup(fmtId(attname));
   16989              : 
   16990              :                         /*
   16991              :                          * Column's GRANT type is always TABLE.  Each column ACL depends
   16992              :                          * on the table-level ACL, since we can restore column ACLs in
   16993              :                          * parallel but the table-level ACL has to be done first.
   16994              :                          */
   16995            0 :                         dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   16996            0 :                                         "TABLE", namecopy, attnamecopy,
   16997            0 :                                         tbinfo->dobj.namespace->dobj.name,
   16998            0 :                                         NULL, tbinfo->rolname, &coldacl);
   16999            0 :                         free(attnamecopy);
   17000            0 :                 }
   17001            0 :                 PQclear(res);
   17002            0 :                 destroyPQExpBuffer(query);
   17003            0 :         }
   17004              : 
   17005            0 :         free(namecopy);
   17006            0 : }
   17007              : 
   17008              : /*
   17009              :  * Create the AS clause for a view or materialized view. The semicolon is
   17010              :  * stripped because a materialized view must add a WITH NO DATA clause.
   17011              :  *
   17012              :  * This returns a new buffer which must be freed by the caller.
   17013              :  */
   17014              : static PQExpBuffer
   17015            0 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17016              : {
   17017            0 :         PQExpBuffer query = createPQExpBuffer();
   17018            0 :         PQExpBuffer result = createPQExpBuffer();
   17019            0 :         PGresult   *res;
   17020            0 :         int                     len;
   17021              : 
   17022              :         /* Fetch the view definition */
   17023            0 :         appendPQExpBuffer(query,
   17024              :                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   17025            0 :                                           tbinfo->dobj.catId.oid);
   17026              : 
   17027            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17028              : 
   17029            0 :         if (PQntuples(res) != 1)
   17030              :         {
   17031            0 :                 if (PQntuples(res) < 1)
   17032            0 :                         pg_fatal("query to obtain definition of view \"%s\" returned no data",
   17033              :                                          tbinfo->dobj.name);
   17034              :                 else
   17035            0 :                         pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   17036              :                                          tbinfo->dobj.name);
   17037            0 :         }
   17038              : 
   17039            0 :         len = PQgetlength(res, 0, 0);
   17040              : 
   17041            0 :         if (len == 0)
   17042            0 :                 pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   17043              :                                  tbinfo->dobj.name);
   17044              : 
   17045              :         /* Strip off the trailing semicolon so that other things may follow. */
   17046            0 :         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   17047            0 :         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   17048              : 
   17049            0 :         PQclear(res);
   17050            0 :         destroyPQExpBuffer(query);
   17051              : 
   17052            0 :         return result;
   17053            0 : }
   17054              : 
   17055              : /*
   17056              :  * Create a dummy AS clause for a view.  This is used when the real view
   17057              :  * definition has to be postponed because of circular dependencies.
   17058              :  * We must duplicate the view's external properties -- column names and types
   17059              :  * (including collation) -- so that it works for subsequent references.
   17060              :  *
   17061              :  * This returns a new buffer which must be freed by the caller.
   17062              :  */
   17063              : static PQExpBuffer
   17064            0 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17065              : {
   17066            0 :         PQExpBuffer result = createPQExpBuffer();
   17067            0 :         int                     j;
   17068              : 
   17069            0 :         appendPQExpBufferStr(result, "SELECT");
   17070              : 
   17071            0 :         for (j = 0; j < tbinfo->numatts; j++)
   17072              :         {
   17073            0 :                 if (j > 0)
   17074            0 :                         appendPQExpBufferChar(result, ',');
   17075            0 :                 appendPQExpBufferStr(result, "\n    ");
   17076              : 
   17077            0 :                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   17078              : 
   17079              :                 /*
   17080              :                  * Must add collation if not default for the type, because CREATE OR
   17081              :                  * REPLACE VIEW won't change it
   17082              :                  */
   17083            0 :                 if (OidIsValid(tbinfo->attcollation[j]))
   17084              :                 {
   17085            0 :                         CollInfo   *coll;
   17086              : 
   17087            0 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   17088            0 :                         if (coll)
   17089            0 :                                 appendPQExpBuffer(result, " COLLATE %s",
   17090            0 :                                                                   fmtQualifiedDumpable(coll));
   17091            0 :                 }
   17092              : 
   17093            0 :                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   17094            0 :         }
   17095              : 
   17096            0 :         return result;
   17097            0 : }
   17098              : 
   17099              : /*
   17100              :  * dumpTableSchema
   17101              :  *        write the declaration (not data) of one user-defined table or view
   17102              :  */
   17103              : static void
   17104            0 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   17105              : {
   17106            0 :         DumpOptions *dopt = fout->dopt;
   17107            0 :         PQExpBuffer q = createPQExpBuffer();
   17108            0 :         PQExpBuffer delq = createPQExpBuffer();
   17109            0 :         PQExpBuffer extra = createPQExpBuffer();
   17110            0 :         char       *qrelname;
   17111            0 :         char       *qualrelname;
   17112            0 :         int                     numParents;
   17113            0 :         TableInfo **parents;
   17114            0 :         int                     actual_atts;    /* number of attrs in this CREATE statement */
   17115            0 :         const char *reltypename;
   17116            0 :         char       *storage;
   17117            0 :         int                     j,
   17118              :                                 k;
   17119              : 
   17120              :         /* We had better have loaded per-column details about this table */
   17121            0 :         Assert(tbinfo->interesting);
   17122              : 
   17123            0 :         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   17124            0 :         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   17125              : 
   17126            0 :         if (tbinfo->hasoids)
   17127            0 :                 pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   17128              :                                            qrelname);
   17129              : 
   17130            0 :         if (dopt->binary_upgrade)
   17131            0 :                 binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   17132              : 
   17133              :         /* Is it a table or a view? */
   17134            0 :         if (tbinfo->relkind == RELKIND_VIEW)
   17135              :         {
   17136            0 :                 PQExpBuffer result;
   17137              : 
   17138              :                 /*
   17139              :                  * Note: keep this code in sync with the is_view case in dumpRule()
   17140              :                  */
   17141              : 
   17142            0 :                 reltypename = "VIEW";
   17143              : 
   17144            0 :                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
   17145              : 
   17146            0 :                 if (dopt->binary_upgrade)
   17147            0 :                         binary_upgrade_set_pg_class_oids(fout, q,
   17148            0 :                                                                                          tbinfo->dobj.catId.oid);
   17149              : 
   17150            0 :                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   17151              : 
   17152            0 :                 if (tbinfo->dummy_view)
   17153            0 :                         result = createDummyViewAsClause(fout, tbinfo);
   17154              :                 else
   17155              :                 {
   17156            0 :                         if (nonemptyReloptions(tbinfo->reloptions))
   17157              :                         {
   17158            0 :                                 appendPQExpBufferStr(q, " WITH (");
   17159            0 :                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17160            0 :                                 appendPQExpBufferChar(q, ')');
   17161            0 :                         }
   17162            0 :                         result = createViewAsClause(fout, tbinfo);
   17163              :                 }
   17164            0 :                 appendPQExpBuffer(q, " AS\n%s", result->data);
   17165            0 :                 destroyPQExpBuffer(result);
   17166              : 
   17167            0 :                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   17168            0 :                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   17169            0 :                 appendPQExpBufferStr(q, ";\n");
   17170            0 :         }
   17171              :         else
   17172              :         {
   17173            0 :                 char       *partkeydef = NULL;
   17174            0 :                 char       *ftoptions = NULL;
   17175            0 :                 char       *srvname = NULL;
   17176            0 :                 const char *foreign = "";
   17177              : 
   17178              :                 /*
   17179              :                  * Set reltypename, and collect any relkind-specific data that we
   17180              :                  * didn't fetch during getTables().
   17181              :                  */
   17182            0 :                 switch (tbinfo->relkind)
   17183              :                 {
   17184              :                         case RELKIND_PARTITIONED_TABLE:
   17185              :                                 {
   17186            0 :                                         PQExpBuffer query = createPQExpBuffer();
   17187            0 :                                         PGresult   *res;
   17188              : 
   17189            0 :                                         reltypename = "TABLE";
   17190              : 
   17191              :                                         /* retrieve partition key definition */
   17192            0 :                                         appendPQExpBuffer(query,
   17193              :                                                                           "SELECT pg_get_partkeydef('%u')",
   17194            0 :                                                                           tbinfo->dobj.catId.oid);
   17195            0 :                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17196            0 :                                         partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   17197            0 :                                         PQclear(res);
   17198            0 :                                         destroyPQExpBuffer(query);
   17199              :                                         break;
   17200            0 :                                 }
   17201              :                         case RELKIND_FOREIGN_TABLE:
   17202              :                                 {
   17203            0 :                                         PQExpBuffer query = createPQExpBuffer();
   17204            0 :                                         PGresult   *res;
   17205            0 :                                         int                     i_srvname;
   17206            0 :                                         int                     i_ftoptions;
   17207              : 
   17208            0 :                                         reltypename = "FOREIGN TABLE";
   17209              : 
   17210              :                                         /* retrieve name of foreign server and generic options */
   17211            0 :                                         appendPQExpBuffer(query,
   17212              :                                                                           "SELECT fs.srvname, "
   17213              :                                                                           "pg_catalog.array_to_string(ARRAY("
   17214              :                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
   17215              :                                                                           "' ' || pg_catalog.quote_literal(option_value) "
   17216              :                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
   17217              :                                                                           "ORDER BY option_name"
   17218              :                                                                           "), E',\n    ') AS ftoptions "
   17219              :                                                                           "FROM pg_catalog.pg_foreign_table ft "
   17220              :                                                                           "JOIN pg_catalog.pg_foreign_server fs "
   17221              :                                                                           "ON (fs.oid = ft.ftserver) "
   17222              :                                                                           "WHERE ft.ftrelid = '%u'",
   17223            0 :                                                                           tbinfo->dobj.catId.oid);
   17224            0 :                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17225            0 :                                         i_srvname = PQfnumber(res, "srvname");
   17226            0 :                                         i_ftoptions = PQfnumber(res, "ftoptions");
   17227            0 :                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   17228            0 :                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   17229            0 :                                         PQclear(res);
   17230            0 :                                         destroyPQExpBuffer(query);
   17231              : 
   17232            0 :                                         foreign = "FOREIGN ";
   17233              :                                         break;
   17234            0 :                                 }
   17235              :                         case RELKIND_MATVIEW:
   17236            0 :                                 reltypename = "MATERIALIZED VIEW";
   17237            0 :                                 break;
   17238              :                         default:
   17239            0 :                                 reltypename = "TABLE";
   17240            0 :                                 break;
   17241              :                 }
   17242              : 
   17243            0 :                 numParents = tbinfo->numParents;
   17244            0 :                 parents = tbinfo->parents;
   17245              : 
   17246            0 :                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   17247              : 
   17248            0 :                 if (dopt->binary_upgrade)
   17249            0 :                         binary_upgrade_set_pg_class_oids(fout, q,
   17250            0 :                                                                                          tbinfo->dobj.catId.oid);
   17251              : 
   17252              :                 /*
   17253              :                  * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   17254              :                  * ignore it when dumping if it was set in this case.
   17255              :                  */
   17256            0 :                 appendPQExpBuffer(q, "CREATE %s%s %s",
   17257            0 :                                                   (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   17258            0 :                                                    tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   17259              :                                                   "UNLOGGED " : "",
   17260            0 :                                                   reltypename,
   17261            0 :                                                   qualrelname);
   17262              : 
   17263              :                 /*
   17264              :                  * Attach to type, if reloftype; except in case of a binary upgrade,
   17265              :                  * we dump the table normally and attach it to the type afterward.
   17266              :                  */
   17267            0 :                 if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   17268            0 :                         appendPQExpBuffer(q, " OF %s",
   17269            0 :                                                           getFormattedTypeName(fout, tbinfo->reloftype,
   17270              :                                                                                                    zeroIsError));
   17271              : 
   17272            0 :                 if (tbinfo->relkind != RELKIND_MATVIEW)
   17273              :                 {
   17274              :                         /* Dump the attributes */
   17275            0 :                         actual_atts = 0;
   17276            0 :                         for (j = 0; j < tbinfo->numatts; j++)
   17277              :                         {
   17278              :                                 /*
   17279              :                                  * Normally, dump if it's locally defined in this table, and
   17280              :                                  * not dropped.  But for binary upgrade, we'll dump all the
   17281              :                                  * columns, and then fix up the dropped and nonlocal cases
   17282              :                                  * below.
   17283              :                                  */
   17284            0 :                                 if (shouldPrintColumn(dopt, tbinfo, j))
   17285              :                                 {
   17286            0 :                                         bool            print_default;
   17287            0 :                                         bool            print_notnull;
   17288              : 
   17289              :                                         /*
   17290              :                                          * Default value --- suppress if to be printed separately
   17291              :                                          * or not at all.
   17292              :                                          */
   17293            0 :                                         print_default = (tbinfo->attrdefs[j] != NULL &&
   17294            0 :                                                                          tbinfo->attrdefs[j]->dobj.dump &&
   17295            0 :                                                                          !tbinfo->attrdefs[j]->separate);
   17296              : 
   17297              :                                         /*
   17298              :                                          * Not Null constraint --- print it if it is locally
   17299              :                                          * defined, or if binary upgrade.  (In the latter case, we
   17300              :                                          * reset conislocal below.)
   17301              :                                          */
   17302            0 :                                         print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   17303            0 :                                                                          (tbinfo->notnull_islocal[j] ||
   17304            0 :                                                                           dopt->binary_upgrade ||
   17305            0 :                                                                           tbinfo->ispartition));
   17306              : 
   17307              :                                         /*
   17308              :                                          * Skip column if fully defined by reloftype, except in
   17309              :                                          * binary upgrade
   17310              :                                          */
   17311            0 :                                         if (OidIsValid(tbinfo->reloftype) &&
   17312            0 :                                                 !print_default && !print_notnull &&
   17313            0 :                                                 !dopt->binary_upgrade)
   17314            0 :                                                 continue;
   17315              : 
   17316              :                                         /* Format properly if not first attr */
   17317            0 :                                         if (actual_atts == 0)
   17318            0 :                                                 appendPQExpBufferStr(q, " (");
   17319              :                                         else
   17320            0 :                                                 appendPQExpBufferChar(q, ',');
   17321            0 :                                         appendPQExpBufferStr(q, "\n    ");
   17322            0 :                                         actual_atts++;
   17323              : 
   17324              :                                         /* Attribute name */
   17325            0 :                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   17326              : 
   17327            0 :                                         if (tbinfo->attisdropped[j])
   17328              :                                         {
   17329              :                                                 /*
   17330              :                                                  * ALTER TABLE DROP COLUMN clears
   17331              :                                                  * pg_attribute.atttypid, so we will not have gotten a
   17332              :                                                  * valid type name; insert INTEGER as a stopgap. We'll
   17333              :                                                  * clean things up later.
   17334              :                                                  */
   17335            0 :                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
   17336              :                                                 /* and skip to the next column */
   17337            0 :                                                 continue;
   17338              :                                         }
   17339              : 
   17340              :                                         /*
   17341              :                                          * Attribute type; print it except when creating a typed
   17342              :                                          * table ('OF type_name'), but in binary-upgrade mode,
   17343              :                                          * print it in that case too.
   17344              :                                          */
   17345            0 :                                         if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   17346              :                                         {
   17347            0 :                                                 appendPQExpBuffer(q, " %s",
   17348            0 :                                                                                   tbinfo->atttypnames[j]);
   17349            0 :                                         }
   17350              : 
   17351            0 :                                         if (print_default)
   17352              :                                         {
   17353            0 :                                                 if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   17354            0 :                                                         appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   17355            0 :                                                                                           tbinfo->attrdefs[j]->adef_expr);
   17356            0 :                                                 else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   17357            0 :                                                         appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   17358            0 :                                                                                           tbinfo->attrdefs[j]->adef_expr);
   17359              :                                                 else
   17360            0 :                                                         appendPQExpBuffer(q, " DEFAULT %s",
   17361            0 :                                                                                           tbinfo->attrdefs[j]->adef_expr);
   17362            0 :                                         }
   17363              : 
   17364            0 :                                         if (print_notnull)
   17365              :                                         {
   17366            0 :                                                 if (tbinfo->notnull_constrs[j][0] == '\0')
   17367            0 :                                                         appendPQExpBufferStr(q, " NOT NULL");
   17368              :                                                 else
   17369            0 :                                                         appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   17370            0 :                                                                                           fmtId(tbinfo->notnull_constrs[j]));
   17371              : 
   17372            0 :                                                 if (tbinfo->notnull_noinh[j])
   17373            0 :                                                         appendPQExpBufferStr(q, " NO INHERIT");
   17374            0 :                                         }
   17375              : 
   17376              :                                         /* Add collation if not default for the type */
   17377            0 :                                         if (OidIsValid(tbinfo->attcollation[j]))
   17378              :                                         {
   17379            0 :                                                 CollInfo   *coll;
   17380              : 
   17381            0 :                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
   17382            0 :                                                 if (coll)
   17383            0 :                                                         appendPQExpBuffer(q, " COLLATE %s",
   17384            0 :                                                                                           fmtQualifiedDumpable(coll));
   17385            0 :                                         }
   17386            0 :                                 }
   17387              : 
   17388              :                                 /*
   17389              :                                  * On the other hand, if we choose not to print a column
   17390              :                                  * (likely because it is created by inheritance), but the
   17391              :                                  * column has a locally-defined not-null constraint, we need
   17392              :                                  * to dump the constraint as a standalone object.
   17393              :                                  *
   17394              :                                  * This syntax isn't SQL-conforming, but if you wanted
   17395              :                                  * standard output you wouldn't be creating non-standard
   17396              :                                  * objects to begin with.
   17397              :                                  */
   17398            0 :                                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   17399            0 :                                         !tbinfo->attisdropped[j] &&
   17400            0 :                                         tbinfo->notnull_constrs[j] != NULL &&
   17401            0 :                                         tbinfo->notnull_islocal[j])
   17402              :                                 {
   17403              :                                         /* Format properly if not first attr */
   17404            0 :                                         if (actual_atts == 0)
   17405            0 :                                                 appendPQExpBufferStr(q, " (");
   17406              :                                         else
   17407            0 :                                                 appendPQExpBufferChar(q, ',');
   17408            0 :                                         appendPQExpBufferStr(q, "\n    ");
   17409            0 :                                         actual_atts++;
   17410              : 
   17411            0 :                                         if (tbinfo->notnull_constrs[j][0] == '\0')
   17412            0 :                                                 appendPQExpBuffer(q, "NOT NULL %s",
   17413            0 :                                                                                   fmtId(tbinfo->attnames[j]));
   17414              :                                         else
   17415            0 :                                                 appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   17416            0 :                                                                                   tbinfo->notnull_constrs[j],
   17417            0 :                                                                                   fmtId(tbinfo->attnames[j]));
   17418            0 :                                 }
   17419            0 :                         }
   17420              : 
   17421              :                         /*
   17422              :                          * Add non-inherited CHECK constraints, if any.
   17423              :                          *
   17424              :                          * For partitions, we need to include check constraints even if
   17425              :                          * they're not defined locally, because the ALTER TABLE ATTACH
   17426              :                          * PARTITION that we'll emit later expects the constraint to be
   17427              :                          * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   17428              :                          */
   17429            0 :                         for (j = 0; j < tbinfo->ncheck; j++)
   17430              :                         {
   17431            0 :                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17432              : 
   17433            0 :                                 if (constr->separate ||
   17434            0 :                                         (!constr->conislocal && !tbinfo->ispartition))
   17435            0 :                                         continue;
   17436              : 
   17437            0 :                                 if (actual_atts == 0)
   17438            0 :                                         appendPQExpBufferStr(q, " (\n    ");
   17439              :                                 else
   17440            0 :                                         appendPQExpBufferStr(q, ",\n    ");
   17441              : 
   17442            0 :                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   17443            0 :                                                                   fmtId(constr->dobj.name));
   17444            0 :                                 appendPQExpBufferStr(q, constr->condef);
   17445              : 
   17446            0 :                                 actual_atts++;
   17447            0 :                         }
   17448              : 
   17449            0 :                         if (actual_atts)
   17450            0 :                                 appendPQExpBufferStr(q, "\n)");
   17451            0 :                         else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   17452              :                         {
   17453              :                                 /*
   17454              :                                  * No attributes? we must have a parenthesized attribute list,
   17455              :                                  * even though empty, when not using the OF TYPE syntax.
   17456              :                                  */
   17457            0 :                                 appendPQExpBufferStr(q, " (\n)");
   17458            0 :                         }
   17459              : 
   17460              :                         /*
   17461              :                          * Emit the INHERITS clause (not for partitions), except in
   17462              :                          * binary-upgrade mode.
   17463              :                          */
   17464            0 :                         if (numParents > 0 && !tbinfo->ispartition &&
   17465            0 :                                 !dopt->binary_upgrade)
   17466              :                         {
   17467            0 :                                 appendPQExpBufferStr(q, "\nINHERITS (");
   17468            0 :                                 for (k = 0; k < numParents; k++)
   17469              :                                 {
   17470            0 :                                         TableInfo  *parentRel = parents[k];
   17471              : 
   17472            0 :                                         if (k > 0)
   17473            0 :                                                 appendPQExpBufferStr(q, ", ");
   17474            0 :                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   17475            0 :                                 }
   17476            0 :                                 appendPQExpBufferChar(q, ')');
   17477            0 :                         }
   17478              : 
   17479            0 :                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17480            0 :                                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   17481              : 
   17482            0 :                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   17483            0 :                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   17484            0 :                 }
   17485              : 
   17486            0 :                 if (nonemptyReloptions(tbinfo->reloptions) ||
   17487            0 :                         nonemptyReloptions(tbinfo->toast_reloptions))
   17488              :                 {
   17489            0 :                         bool            addcomma = false;
   17490              : 
   17491            0 :                         appendPQExpBufferStr(q, "\nWITH (");
   17492            0 :                         if (nonemptyReloptions(tbinfo->reloptions))
   17493              :                         {
   17494            0 :                                 addcomma = true;
   17495            0 :                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17496            0 :                         }
   17497            0 :                         if (nonemptyReloptions(tbinfo->toast_reloptions))
   17498              :                         {
   17499            0 :                                 if (addcomma)
   17500            0 :                                         appendPQExpBufferStr(q, ", ");
   17501            0 :                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   17502            0 :                                                                                 fout);
   17503            0 :                         }
   17504            0 :                         appendPQExpBufferChar(q, ')');
   17505            0 :                 }
   17506              : 
   17507              :                 /* Dump generic options if any */
   17508            0 :                 if (ftoptions && ftoptions[0])
   17509            0 :                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   17510              : 
   17511              :                 /*
   17512              :                  * For materialized views, create the AS clause just like a view. At
   17513              :                  * this point, we always mark the view as not populated.
   17514              :                  */
   17515            0 :                 if (tbinfo->relkind == RELKIND_MATVIEW)
   17516              :                 {
   17517            0 :                         PQExpBuffer result;
   17518              : 
   17519            0 :                         result = createViewAsClause(fout, tbinfo);
   17520            0 :                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   17521            0 :                                                           result->data);
   17522            0 :                         destroyPQExpBuffer(result);
   17523            0 :                 }
   17524              :                 else
   17525            0 :                         appendPQExpBufferStr(q, ";\n");
   17526              : 
   17527              :                 /* Materialized views can depend on extensions */
   17528            0 :                 if (tbinfo->relkind == RELKIND_MATVIEW)
   17529            0 :                         append_depends_on_extension(fout, q, &tbinfo->dobj,
   17530              :                                                                                 "pg_catalog.pg_class",
   17531              :                                                                                 "MATERIALIZED VIEW",
   17532            0 :                                                                                 qualrelname);
   17533              : 
   17534              :                 /*
   17535              :                  * in binary upgrade mode, update the catalog with any missing values
   17536              :                  * that might be present.
   17537              :                  */
   17538            0 :                 if (dopt->binary_upgrade)
   17539              :                 {
   17540            0 :                         for (j = 0; j < tbinfo->numatts; j++)
   17541              :                         {
   17542            0 :                                 if (tbinfo->attmissingval[j][0] != '\0')
   17543              :                                 {
   17544            0 :                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
   17545            0 :                                         appendPQExpBufferStr(q,
   17546              :                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   17547            0 :                                         appendStringLiteralAH(q, qualrelname, fout);
   17548            0 :                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   17549            0 :                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17550            0 :                                         appendPQExpBufferChar(q, ',');
   17551            0 :                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   17552            0 :                                         appendPQExpBufferStr(q, ");\n\n");
   17553            0 :                                 }
   17554            0 :                         }
   17555            0 :                 }
   17556              : 
   17557              :                 /*
   17558              :                  * To create binary-compatible heap files, we have to ensure the same
   17559              :                  * physical column order, including dropped columns, as in the
   17560              :                  * original.  Therefore, we create dropped columns above and drop them
   17561              :                  * here, also updating their attlen/attalign values so that the
   17562              :                  * dropped column can be skipped properly.  (We do not bother with
   17563              :                  * restoring the original attbyval setting.)  Also, inheritance
   17564              :                  * relationships are set up by doing ALTER TABLE INHERIT rather than
   17565              :                  * using an INHERITS clause --- the latter would possibly mess up the
   17566              :                  * column order.  That also means we have to take care about setting
   17567              :                  * attislocal correctly, plus fix up any inherited CHECK constraints.
   17568              :                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
   17569              :                  *
   17570              :                  * We process foreign and partitioned tables here, even though they
   17571              :                  * lack heap storage, because they can participate in inheritance
   17572              :                  * relationships and we want this stuff to be consistent across the
   17573              :                  * inheritance tree.  We can exclude indexes, toast tables, sequences
   17574              :                  * and matviews, even though they have storage, because we don't
   17575              :                  * support altering or dropping columns in them, nor can they be part
   17576              :                  * of inheritance trees.
   17577              :                  */
   17578            0 :                 if (dopt->binary_upgrade &&
   17579            0 :                         (tbinfo->relkind == RELKIND_RELATION ||
   17580            0 :                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   17581            0 :                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   17582              :                 {
   17583            0 :                         bool            firstitem;
   17584            0 :                         bool            firstitem_extra;
   17585              : 
   17586              :                         /*
   17587              :                          * Drop any dropped columns.  Merge the pg_attribute manipulations
   17588              :                          * into a single SQL command, so that we don't cause repeated
   17589              :                          * relcache flushes on the target table.  Otherwise we risk O(N^2)
   17590              :                          * relcache bloat while dropping N columns.
   17591              :                          */
   17592            0 :                         resetPQExpBuffer(extra);
   17593            0 :                         firstitem = true;
   17594            0 :                         for (j = 0; j < tbinfo->numatts; j++)
   17595              :                         {
   17596            0 :                                 if (tbinfo->attisdropped[j])
   17597              :                                 {
   17598            0 :                                         if (firstitem)
   17599              :                                         {
   17600            0 :                                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   17601              :                                                                                          "UPDATE pg_catalog.pg_attribute\n"
   17602              :                                                                                          "SET attlen = v.dlen, "
   17603              :                                                                                          "attalign = v.dalign, "
   17604              :                                                                                          "attbyval = false\n"
   17605              :                                                                                          "FROM (VALUES ");
   17606            0 :                                                 firstitem = false;
   17607            0 :                                         }
   17608              :                                         else
   17609            0 :                                                 appendPQExpBufferStr(q, ",\n             ");
   17610            0 :                                         appendPQExpBufferChar(q, '(');
   17611            0 :                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17612            0 :                                         appendPQExpBuffer(q, ", %d, '%c')",
   17613            0 :                                                                           tbinfo->attlen[j],
   17614            0 :                                                                           tbinfo->attalign[j]);
   17615              :                                         /* The ALTER ... DROP COLUMN commands must come after */
   17616            0 :                                         appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   17617            0 :                                                                           foreign, qualrelname);
   17618            0 :                                         appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   17619            0 :                                                                           fmtId(tbinfo->attnames[j]));
   17620            0 :                                 }
   17621            0 :                         }
   17622            0 :                         if (!firstitem)
   17623              :                         {
   17624            0 :                                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   17625              :                                                                          "WHERE attrelid = ");
   17626            0 :                                 appendStringLiteralAH(q, qualrelname, fout);
   17627            0 :                                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17628              :                                                                          "  AND attname = v.dname;\n");
   17629              :                                 /* Now we can issue the actual DROP COLUMN commands */
   17630            0 :                                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17631            0 :                         }
   17632              : 
   17633              :                         /*
   17634              :                          * Fix up inherited columns.  As above, do the pg_attribute
   17635              :                          * manipulations in a single SQL command.
   17636              :                          */
   17637            0 :                         firstitem = true;
   17638            0 :                         for (j = 0; j < tbinfo->numatts; j++)
   17639              :                         {
   17640            0 :                                 if (!tbinfo->attisdropped[j] &&
   17641            0 :                                         !tbinfo->attislocal[j])
   17642              :                                 {
   17643            0 :                                         if (firstitem)
   17644              :                                         {
   17645            0 :                                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   17646            0 :                                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   17647              :                                                                                          "SET attislocal = false\n"
   17648              :                                                                                          "WHERE attrelid = ");
   17649            0 :                                                 appendStringLiteralAH(q, qualrelname, fout);
   17650            0 :                                                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17651              :                                                                                          "  AND attname IN (");
   17652            0 :                                                 firstitem = false;
   17653            0 :                                         }
   17654              :                                         else
   17655            0 :                                                 appendPQExpBufferStr(q, ", ");
   17656            0 :                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17657            0 :                                 }
   17658            0 :                         }
   17659            0 :                         if (!firstitem)
   17660            0 :                                 appendPQExpBufferStr(q, ");\n");
   17661              : 
   17662              :                         /*
   17663              :                          * Fix up not-null constraints that come from inheritance.  As
   17664              :                          * above, do the pg_constraint manipulations in a single SQL
   17665              :                          * command.  (Actually, two in special cases, if we're doing an
   17666              :                          * upgrade from < 18).
   17667              :                          */
   17668            0 :                         firstitem = true;
   17669            0 :                         firstitem_extra = true;
   17670            0 :                         resetPQExpBuffer(extra);
   17671            0 :                         for (j = 0; j < tbinfo->numatts; j++)
   17672              :                         {
   17673              :                                 /*
   17674              :                                  * If a not-null constraint comes from inheritance, reset
   17675              :                                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   17676              :                                  * below.  Special hack: in versions < 18, columns with no
   17677              :                                  * local definition need their constraint to be matched by
   17678              :                                  * column number in conkeys instead of by constraint name,
   17679              :                                  * because the latter is not available.  (We distinguish the
   17680              :                                  * case because the constraint name is the empty string.)
   17681              :                                  */
   17682            0 :                                 if (tbinfo->notnull_constrs[j] != NULL &&
   17683            0 :                                         !tbinfo->notnull_islocal[j])
   17684              :                                 {
   17685            0 :                                         if (tbinfo->notnull_constrs[j][0] != '\0')
   17686              :                                         {
   17687            0 :                                                 if (firstitem)
   17688              :                                                 {
   17689            0 :                                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   17690              :                                                                                                  "SET conislocal = false\n"
   17691              :                                                                                                  "WHERE contype = 'n' AND conrelid = ");
   17692            0 :                                                         appendStringLiteralAH(q, qualrelname, fout);
   17693            0 :                                                         appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   17694              :                                                                                                  "conname IN (");
   17695            0 :                                                         firstitem = false;
   17696            0 :                                                 }
   17697              :                                                 else
   17698            0 :                                                         appendPQExpBufferStr(q, ", ");
   17699            0 :                                                 appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   17700            0 :                                         }
   17701              :                                         else
   17702              :                                         {
   17703            0 :                                                 if (firstitem_extra)
   17704              :                                                 {
   17705            0 :                                                         appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17706              :                                                                                                  "SET conislocal = false\n"
   17707              :                                                                                                  "WHERE contype = 'n' AND conrelid = ");
   17708            0 :                                                         appendStringLiteralAH(extra, qualrelname, fout);
   17709            0 :                                                         appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   17710              :                                                                                                  "conkey IN (");
   17711            0 :                                                         firstitem_extra = false;
   17712            0 :                                                 }
   17713              :                                                 else
   17714            0 :                                                         appendPQExpBufferStr(extra, ", ");
   17715            0 :                                                 appendPQExpBuffer(extra, "'{%d}'", j + 1);
   17716              :                                         }
   17717            0 :                                 }
   17718            0 :                         }
   17719            0 :                         if (!firstitem)
   17720            0 :                                 appendPQExpBufferStr(q, ");\n");
   17721            0 :                         if (!firstitem_extra)
   17722            0 :                                 appendPQExpBufferStr(extra, ");\n");
   17723              : 
   17724            0 :                         if (extra->len > 0)
   17725            0 :                                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17726              : 
   17727              :                         /*
   17728              :                          * Add inherited CHECK constraints, if any.
   17729              :                          *
   17730              :                          * For partitions, they were already dumped, and conislocal
   17731              :                          * doesn't need fixing.
   17732              :                          *
   17733              :                          * As above, issue only one direct manipulation of pg_constraint.
   17734              :                          * Although it is tempting to merge the ALTER ADD CONSTRAINT
   17735              :                          * commands into one as well, refrain for now due to concern about
   17736              :                          * possible backend memory bloat if there are many such
   17737              :                          * constraints.
   17738              :                          */
   17739            0 :                         resetPQExpBuffer(extra);
   17740            0 :                         firstitem = true;
   17741            0 :                         for (k = 0; k < tbinfo->ncheck; k++)
   17742              :                         {
   17743            0 :                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   17744              : 
   17745            0 :                                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   17746            0 :                                         continue;
   17747              : 
   17748            0 :                                 if (firstitem)
   17749            0 :                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   17750            0 :                                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   17751            0 :                                                                   foreign, qualrelname,
   17752            0 :                                                                   fmtId(constr->dobj.name),
   17753            0 :                                                                   constr->condef);
   17754              :                                 /* Update pg_constraint after all the ALTER TABLEs */
   17755            0 :                                 if (firstitem)
   17756              :                                 {
   17757            0 :                                         appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17758              :                                                                                  "SET conislocal = false\n"
   17759              :                                                                                  "WHERE contype = 'c' AND conrelid = ");
   17760            0 :                                         appendStringLiteralAH(extra, qualrelname, fout);
   17761            0 :                                         appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   17762            0 :                                         appendPQExpBufferStr(extra, "  AND conname IN (");
   17763            0 :                                         firstitem = false;
   17764            0 :                                 }
   17765              :                                 else
   17766            0 :                                         appendPQExpBufferStr(extra, ", ");
   17767            0 :                                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   17768            0 :                         }
   17769            0 :                         if (!firstitem)
   17770              :                         {
   17771            0 :                                 appendPQExpBufferStr(extra, ");\n");
   17772            0 :                                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17773            0 :                         }
   17774              : 
   17775            0 :                         if (numParents > 0 && !tbinfo->ispartition)
   17776              :                         {
   17777            0 :                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   17778            0 :                                 for (k = 0; k < numParents; k++)
   17779              :                                 {
   17780            0 :                                         TableInfo  *parentRel = parents[k];
   17781              : 
   17782            0 :                                         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   17783            0 :                                                                           qualrelname,
   17784            0 :                                                                           fmtQualifiedDumpable(parentRel));
   17785            0 :                                 }
   17786            0 :                         }
   17787              : 
   17788            0 :                         if (OidIsValid(tbinfo->reloftype))
   17789              :                         {
   17790            0 :                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   17791            0 :                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   17792            0 :                                                                   qualrelname,
   17793            0 :                                                                   getFormattedTypeName(fout, tbinfo->reloftype,
   17794              :                                                                                                            zeroIsError));
   17795            0 :                         }
   17796            0 :                 }
   17797              : 
   17798              :                 /*
   17799              :                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   17800              :                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
   17801              :                  * TOAST tables semi-independently, here we see them only as children
   17802              :                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   17803              :                  * child toast table is handled below.)
   17804              :                  */
   17805            0 :                 if (dopt->binary_upgrade &&
   17806            0 :                         (tbinfo->relkind == RELKIND_RELATION ||
   17807            0 :                          tbinfo->relkind == RELKIND_MATVIEW))
   17808              :                 {
   17809            0 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   17810            0 :                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17811              :                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17812              :                                                           "WHERE oid = ",
   17813            0 :                                                           tbinfo->frozenxid, tbinfo->minmxid);
   17814            0 :                         appendStringLiteralAH(q, qualrelname, fout);
   17815            0 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17816              : 
   17817            0 :                         if (tbinfo->toast_oid)
   17818              :                         {
   17819              :                                 /*
   17820              :                                  * The toast table will have the same OID at restore, so we
   17821              :                                  * can safely target it by OID.
   17822              :                                  */
   17823            0 :                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   17824            0 :                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17825              :                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17826              :                                                                   "WHERE oid = '%u';\n",
   17827            0 :                                                                   tbinfo->toast_frozenxid,
   17828            0 :                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   17829            0 :                         }
   17830            0 :                 }
   17831              : 
   17832              :                 /*
   17833              :                  * In binary_upgrade mode, restore matviews' populated status by
   17834              :                  * poking pg_class directly.  This is pretty ugly, but we can't use
   17835              :                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   17836              :                  * matview is not populated even though this matview is; in any case,
   17837              :                  * we want to transfer the matview's heap storage, not run REFRESH.
   17838              :                  */
   17839            0 :                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   17840            0 :                         tbinfo->relispopulated)
   17841              :                 {
   17842            0 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   17843            0 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   17844              :                                                                  "SET relispopulated = 't'\n"
   17845              :                                                                  "WHERE oid = ");
   17846            0 :                         appendStringLiteralAH(q, qualrelname, fout);
   17847            0 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17848            0 :                 }
   17849              : 
   17850              :                 /*
   17851              :                  * Dump additional per-column properties that we can't handle in the
   17852              :                  * main CREATE TABLE command.
   17853              :                  */
   17854            0 :                 for (j = 0; j < tbinfo->numatts; j++)
   17855              :                 {
   17856              :                         /* None of this applies to dropped columns */
   17857            0 :                         if (tbinfo->attisdropped[j])
   17858            0 :                                 continue;
   17859              : 
   17860              :                         /*
   17861              :                          * Dump per-column statistics information. We only issue an ALTER
   17862              :                          * TABLE statement if the attstattarget entry for this column is
   17863              :                          * not the default value.
   17864              :                          */
   17865            0 :                         if (tbinfo->attstattarget[j] >= 0)
   17866            0 :                                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   17867            0 :                                                                   foreign, qualrelname,
   17868            0 :                                                                   fmtId(tbinfo->attnames[j]),
   17869            0 :                                                                   tbinfo->attstattarget[j]);
   17870              : 
   17871              :                         /*
   17872              :                          * Dump per-column storage information.  The statement is only
   17873              :                          * dumped if the storage has been changed from the type's default.
   17874              :                          */
   17875            0 :                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   17876              :                         {
   17877            0 :                                 switch (tbinfo->attstorage[j])
   17878              :                                 {
   17879              :                                         case TYPSTORAGE_PLAIN:
   17880            0 :                                                 storage = "PLAIN";
   17881            0 :                                                 break;
   17882              :                                         case TYPSTORAGE_EXTERNAL:
   17883            0 :                                                 storage = "EXTERNAL";
   17884            0 :                                                 break;
   17885              :                                         case TYPSTORAGE_EXTENDED:
   17886            0 :                                                 storage = "EXTENDED";
   17887            0 :                                                 break;
   17888              :                                         case TYPSTORAGE_MAIN:
   17889            0 :                                                 storage = "MAIN";
   17890            0 :                                                 break;
   17891              :                                         default:
   17892            0 :                                                 storage = NULL;
   17893            0 :                                 }
   17894              : 
   17895              :                                 /*
   17896              :                                  * Only dump the statement if it's a storage type we recognize
   17897              :                                  */
   17898            0 :                                 if (storage != NULL)
   17899            0 :                                         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   17900            0 :                                                                           foreign, qualrelname,
   17901            0 :                                                                           fmtId(tbinfo->attnames[j]),
   17902            0 :                                                                           storage);
   17903            0 :                         }
   17904              : 
   17905              :                         /*
   17906              :                          * Dump per-column compression, if it's been set.
   17907              :                          */
   17908            0 :                         if (!dopt->no_toast_compression)
   17909              :                         {
   17910            0 :                                 const char *cmname;
   17911              : 
   17912            0 :                                 switch (tbinfo->attcompression[j])
   17913              :                                 {
   17914              :                                         case 'p':
   17915            0 :                                                 cmname = "pglz";
   17916            0 :                                                 break;
   17917              :                                         case 'l':
   17918            0 :                                                 cmname = "lz4";
   17919            0 :                                                 break;
   17920              :                                         default:
   17921            0 :                                                 cmname = NULL;
   17922            0 :                                                 break;
   17923              :                                 }
   17924              : 
   17925            0 :                                 if (cmname != NULL)
   17926            0 :                                         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   17927            0 :                                                                           foreign, qualrelname,
   17928            0 :                                                                           fmtId(tbinfo->attnames[j]),
   17929            0 :                                                                           cmname);
   17930            0 :                         }
   17931              : 
   17932              :                         /*
   17933              :                          * Dump per-column attributes.
   17934              :                          */
   17935            0 :                         if (tbinfo->attoptions[j][0] != '\0')
   17936            0 :                                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   17937            0 :                                                                   foreign, qualrelname,
   17938            0 :                                                                   fmtId(tbinfo->attnames[j]),
   17939            0 :                                                                   tbinfo->attoptions[j]);
   17940              : 
   17941              :                         /*
   17942              :                          * Dump per-column fdw options.
   17943              :                          */
   17944            0 :                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   17945            0 :                                 tbinfo->attfdwoptions[j][0] != '\0')
   17946            0 :                                 appendPQExpBuffer(q,
   17947              :                                                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   17948              :                                                                   "    %s\n"
   17949              :                                                                   ");\n",
   17950            0 :                                                                   qualrelname,
   17951            0 :                                                                   fmtId(tbinfo->attnames[j]),
   17952            0 :                                                                   tbinfo->attfdwoptions[j]);
   17953            0 :                 }                                               /* end loop over columns */
   17954              : 
   17955            0 :                 free(partkeydef);
   17956            0 :                 free(ftoptions);
   17957            0 :                 free(srvname);
   17958            0 :         }
   17959              : 
   17960              :         /*
   17961              :          * dump properties we only have ALTER TABLE syntax for
   17962              :          */
   17963            0 :         if ((tbinfo->relkind == RELKIND_RELATION ||
   17964            0 :                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   17965            0 :                  tbinfo->relkind == RELKIND_MATVIEW) &&
   17966            0 :                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   17967              :         {
   17968            0 :                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   17969              :                 {
   17970              :                         /* nothing to do, will be set when the index is dumped */
   17971            0 :                 }
   17972            0 :                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   17973              :                 {
   17974            0 :                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   17975            0 :                                                           qualrelname);
   17976            0 :                 }
   17977            0 :                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   17978              :                 {
   17979            0 :                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   17980            0 :                                                           qualrelname);
   17981            0 :                 }
   17982            0 :         }
   17983              : 
   17984            0 :         if (tbinfo->forcerowsec)
   17985            0 :                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   17986            0 :                                                   qualrelname);
   17987              : 
   17988            0 :         if (dopt->binary_upgrade)
   17989            0 :                 binary_upgrade_extension_member(q, &tbinfo->dobj,
   17990            0 :                                                                                 reltypename, qrelname,
   17991            0 :                                                                                 tbinfo->dobj.namespace->dobj.name);
   17992              : 
   17993            0 :         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17994              :         {
   17995            0 :                 char       *tablespace = NULL;
   17996            0 :                 char       *tableam = NULL;
   17997              : 
   17998              :                 /*
   17999              :                  * _selectTablespace() relies on tablespace-enabled objects in the
   18000              :                  * default tablespace to have a tablespace of "" (empty string) versus
   18001              :                  * non-tablespace-enabled objects to have a tablespace of NULL.
   18002              :                  * getTables() sets tbinfo->reltablespace to "" for the default
   18003              :                  * tablespace (not NULL).
   18004              :                  */
   18005            0 :                 if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   18006            0 :                         tablespace = tbinfo->reltablespace;
   18007              : 
   18008            0 :                 if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   18009            0 :                         tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   18010            0 :                         tableam = tbinfo->amname;
   18011              : 
   18012            0 :                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   18013            0 :                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18014              :                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18015              :                                                                   .tablespace = tablespace,
   18016              :                                                                   .tableam = tableam,
   18017              :                                                                   .relkind = tbinfo->relkind,
   18018              :                                                                   .owner = tbinfo->rolname,
   18019              :                                                                   .description = reltypename,
   18020              :                                                                   .section = tbinfo->postponed_def ?
   18021              :                                                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   18022              :                                                                   .createStmt = q->data,
   18023              :                                                                   .dropStmt = delq->data));
   18024            0 :         }
   18025              : 
   18026              :         /* Dump Table Comments */
   18027            0 :         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18028            0 :                 dumpTableComment(fout, tbinfo, reltypename);
   18029              : 
   18030              :         /* Dump Table Security Labels */
   18031            0 :         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   18032            0 :                 dumpTableSecLabel(fout, tbinfo, reltypename);
   18033              : 
   18034              :         /*
   18035              :          * Dump comments for not-null constraints that aren't to be dumped
   18036              :          * separately (those are processed by collectComments/dumpComment).
   18037              :          */
   18038            0 :         if (!fout->dopt->no_comments && dopt->dumpSchema &&
   18039            0 :                 fout->remoteVersion >= 180000)
   18040              :         {
   18041            0 :                 PQExpBuffer comment = NULL;
   18042            0 :                 PQExpBuffer tag = NULL;
   18043              : 
   18044            0 :                 for (j = 0; j < tbinfo->numatts; j++)
   18045              :                 {
   18046            0 :                         if (tbinfo->notnull_constrs[j] != NULL &&
   18047            0 :                                 tbinfo->notnull_comment[j] != NULL)
   18048              :                         {
   18049            0 :                                 if (comment == NULL)
   18050              :                                 {
   18051            0 :                                         comment = createPQExpBuffer();
   18052            0 :                                         tag = createPQExpBuffer();
   18053            0 :                                 }
   18054              :                                 else
   18055              :                                 {
   18056            0 :                                         resetPQExpBuffer(comment);
   18057            0 :                                         resetPQExpBuffer(tag);
   18058              :                                 }
   18059              : 
   18060            0 :                                 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
   18061            0 :                                                                   fmtId(tbinfo->notnull_constrs[j]), qualrelname);
   18062            0 :                                 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
   18063            0 :                                 appendPQExpBufferStr(comment, ";\n");
   18064              : 
   18065            0 :                                 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
   18066            0 :                                                                   fmtId(tbinfo->notnull_constrs[j]), qrelname);
   18067              : 
   18068            0 :                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18069            0 :                                                          ARCHIVE_OPTS(.tag = tag->data,
   18070              :                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18071              :                                                                                   .owner = tbinfo->rolname,
   18072              :                                                                                   .description = "COMMENT",
   18073              :                                                                                   .section = SECTION_NONE,
   18074              :                                                                                   .createStmt = comment->data,
   18075              :                                                                                   .deps = &(tbinfo->dobj.dumpId),
   18076              :                                                                                   .nDeps = 1));
   18077            0 :                         }
   18078            0 :                 }
   18079              : 
   18080            0 :                 destroyPQExpBuffer(comment);
   18081            0 :                 destroyPQExpBuffer(tag);
   18082            0 :         }
   18083              : 
   18084              :         /* Dump comments on inlined table constraints */
   18085            0 :         for (j = 0; j < tbinfo->ncheck; j++)
   18086              :         {
   18087            0 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   18088              : 
   18089            0 :                 if (constr->separate || !constr->conislocal)
   18090            0 :                         continue;
   18091              : 
   18092            0 :                 if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   18093            0 :                         dumpTableConstraintComment(fout, constr);
   18094            0 :         }
   18095              : 
   18096            0 :         destroyPQExpBuffer(q);
   18097            0 :         destroyPQExpBuffer(delq);
   18098            0 :         destroyPQExpBuffer(extra);
   18099            0 :         free(qrelname);
   18100            0 :         free(qualrelname);
   18101            0 : }
   18102              : 
   18103              : /*
   18104              :  * dumpTableAttach
   18105              :  *        write to fout the commands to attach a child partition
   18106              :  *
   18107              :  * Child partitions are always made by creating them separately
   18108              :  * and then using ATTACH PARTITION, rather than using
   18109              :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   18110              :  * any possible discrepancy in column layout, to allow assigning the
   18111              :  * correct tablespace if different, and so that it's possible to restore
   18112              :  * a partition without restoring its parent.  (You'll get an error from
   18113              :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   18114              :  * using "pg_restore -L" if you prefer.)  The last point motivates
   18115              :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   18116              :  * rather than emitting it within the child partition's ArchiveEntry.
   18117              :  */
   18118              : static void
   18119            0 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   18120              : {
   18121            0 :         DumpOptions *dopt = fout->dopt;
   18122            0 :         PQExpBuffer q;
   18123            0 :         PGresult   *res;
   18124            0 :         char       *partbound;
   18125              : 
   18126              :         /* Do nothing if not dumping schema */
   18127            0 :         if (!dopt->dumpSchema)
   18128            0 :                 return;
   18129              : 
   18130            0 :         q = createPQExpBuffer();
   18131              : 
   18132            0 :         if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   18133              :         {
   18134              :                 /* Set up query for partbound details */
   18135            0 :                 appendPQExpBufferStr(q,
   18136              :                                                          "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   18137              : 
   18138            0 :                 appendPQExpBufferStr(q,
   18139              :                                                          "SELECT pg_get_expr(c.relpartbound, c.oid) "
   18140              :                                                          "FROM pg_class c "
   18141              :                                                          "WHERE c.oid = $1");
   18142              : 
   18143            0 :                 ExecuteSqlStatement(fout, q->data);
   18144              : 
   18145            0 :                 fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   18146            0 :         }
   18147              : 
   18148            0 :         printfPQExpBuffer(q,
   18149              :                                           "EXECUTE dumpTableAttach('%u')",
   18150            0 :                                           attachinfo->partitionTbl->dobj.catId.oid);
   18151              : 
   18152            0 :         res = ExecuteSqlQueryForSingleRow(fout, q->data);
   18153            0 :         partbound = PQgetvalue(res, 0, 0);
   18154              : 
   18155              :         /* Perform ALTER TABLE on the parent */
   18156            0 :         printfPQExpBuffer(q,
   18157              :                                           "ALTER TABLE ONLY %s ",
   18158            0 :                                           fmtQualifiedDumpable(attachinfo->parentTbl));
   18159            0 :         appendPQExpBuffer(q,
   18160              :                                           "ATTACH PARTITION %s %s;\n",
   18161            0 :                                           fmtQualifiedDumpable(attachinfo->partitionTbl),
   18162            0 :                                           partbound);
   18163              : 
   18164              :         /*
   18165              :          * There is no point in creating a drop query as the drop is done by table
   18166              :          * drop.  (If you think to change this, see also _printTocEntry().)
   18167              :          * Although this object doesn't really have ownership as such, set the
   18168              :          * owner field anyway to ensure that the command is run by the correct
   18169              :          * role at restore time.
   18170              :          */
   18171            0 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18172            0 :                                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18173              :                                                           .namespace = attachinfo->dobj.namespace->dobj.name,
   18174              :                                                           .owner = attachinfo->partitionTbl->rolname,
   18175              :                                                           .description = "TABLE ATTACH",
   18176              :                                                           .section = SECTION_PRE_DATA,
   18177              :                                                           .createStmt = q->data));
   18178              : 
   18179            0 :         PQclear(res);
   18180            0 :         destroyPQExpBuffer(q);
   18181            0 : }
   18182              : 
   18183              : /*
   18184              :  * dumpAttrDef --- dump an attribute's default-value declaration
   18185              :  */
   18186              : static void
   18187            0 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   18188              : {
   18189            0 :         DumpOptions *dopt = fout->dopt;
   18190            0 :         TableInfo  *tbinfo = adinfo->adtable;
   18191            0 :         int                     adnum = adinfo->adnum;
   18192            0 :         PQExpBuffer q;
   18193            0 :         PQExpBuffer delq;
   18194            0 :         char       *qualrelname;
   18195            0 :         char       *tag;
   18196            0 :         char       *foreign;
   18197              : 
   18198              :         /* Do nothing if not dumping schema */
   18199            0 :         if (!dopt->dumpSchema)
   18200            0 :                 return;
   18201              : 
   18202              :         /* Skip if not "separate"; it was dumped in the table's definition */
   18203            0 :         if (!adinfo->separate)
   18204            0 :                 return;
   18205              : 
   18206            0 :         q = createPQExpBuffer();
   18207            0 :         delq = createPQExpBuffer();
   18208              : 
   18209            0 :         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   18210              : 
   18211            0 :         foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18212              : 
   18213            0 :         appendPQExpBuffer(q,
   18214              :                                           "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   18215            0 :                                           foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   18216            0 :                                           adinfo->adef_expr);
   18217              : 
   18218            0 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   18219            0 :                                           foreign, qualrelname,
   18220            0 :                                           fmtId(tbinfo->attnames[adnum - 1]));
   18221              : 
   18222            0 :         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   18223              : 
   18224            0 :         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18225            0 :                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   18226            0 :                                          ARCHIVE_OPTS(.tag = tag,
   18227              :                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18228              :                                                                   .owner = tbinfo->rolname,
   18229              :                                                                   .description = "DEFAULT",
   18230              :                                                                   .section = SECTION_PRE_DATA,
   18231              :                                                                   .createStmt = q->data,
   18232              :                                                                   .dropStmt = delq->data));
   18233              : 
   18234            0 :         free(tag);
   18235            0 :         destroyPQExpBuffer(q);
   18236            0 :         destroyPQExpBuffer(delq);
   18237            0 :         free(qualrelname);
   18238            0 : }
   18239              : 
   18240              : /*
   18241              :  * getAttrName: extract the correct name for an attribute
   18242              :  *
   18243              :  * The array tblInfo->attnames[] only provides names of user attributes;
   18244              :  * if a system attribute number is supplied, we have to fake it.
   18245              :  * We also do a little bit of bounds checking for safety's sake.
   18246              :  */
   18247              : static const char *
   18248            0 : getAttrName(int attrnum, const TableInfo *tblInfo)
   18249              : {
   18250            0 :         if (attrnum > 0 && attrnum <= tblInfo->numatts)
   18251            0 :                 return tblInfo->attnames[attrnum - 1];
   18252            0 :         switch (attrnum)
   18253              :         {
   18254              :                 case SelfItemPointerAttributeNumber:
   18255            0 :                         return "ctid";
   18256              :                 case MinTransactionIdAttributeNumber:
   18257            0 :                         return "xmin";
   18258              :                 case MinCommandIdAttributeNumber:
   18259            0 :                         return "cmin";
   18260              :                 case MaxTransactionIdAttributeNumber:
   18261            0 :                         return "xmax";
   18262              :                 case MaxCommandIdAttributeNumber:
   18263            0 :                         return "cmax";
   18264              :                 case TableOidAttributeNumber:
   18265            0 :                         return "tableoid";
   18266              :         }
   18267            0 :         pg_fatal("invalid column number %d for table \"%s\"",
   18268              :                          attrnum, tblInfo->dobj.name);
   18269            0 :         return NULL;                            /* keep compiler quiet */
   18270            0 : }
   18271              : 
   18272              : /*
   18273              :  * dumpIndex
   18274              :  *        write out to fout a user-defined index
   18275              :  */
   18276              : static void
   18277            0 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   18278              : {
   18279            0 :         DumpOptions *dopt = fout->dopt;
   18280            0 :         TableInfo  *tbinfo = indxinfo->indextable;
   18281            0 :         bool            is_constraint = (indxinfo->indexconstraint != 0);
   18282            0 :         PQExpBuffer q;
   18283            0 :         PQExpBuffer delq;
   18284            0 :         char       *qindxname;
   18285            0 :         char       *qqindxname;
   18286              : 
   18287              :         /* Do nothing if not dumping schema */
   18288            0 :         if (!dopt->dumpSchema)
   18289            0 :                 return;
   18290              : 
   18291            0 :         q = createPQExpBuffer();
   18292            0 :         delq = createPQExpBuffer();
   18293              : 
   18294            0 :         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   18295            0 :         qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   18296              : 
   18297              :         /*
   18298              :          * If there's an associated constraint, don't dump the index per se, but
   18299              :          * do dump any comment for it.  (This is safe because dependency ordering
   18300              :          * will have ensured the constraint is emitted first.)  Note that the
   18301              :          * emitted comment has to be shown as depending on the constraint, not the
   18302              :          * index, in such cases.
   18303              :          */
   18304            0 :         if (!is_constraint)
   18305              :         {
   18306            0 :                 char       *indstatcols = indxinfo->indstatcols;
   18307            0 :                 char       *indstatvals = indxinfo->indstatvals;
   18308            0 :                 char      **indstatcolsarray = NULL;
   18309            0 :                 char      **indstatvalsarray = NULL;
   18310            0 :                 int                     nstatcols = 0;
   18311            0 :                 int                     nstatvals = 0;
   18312              : 
   18313            0 :                 if (dopt->binary_upgrade)
   18314            0 :                         binary_upgrade_set_pg_class_oids(fout, q,
   18315            0 :                                                                                          indxinfo->dobj.catId.oid);
   18316              : 
   18317              :                 /* Plain secondary index */
   18318            0 :                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   18319              : 
   18320              :                 /*
   18321              :                  * Append ALTER TABLE commands as needed to set properties that we
   18322              :                  * only have ALTER TABLE syntax for.  Keep this in sync with the
   18323              :                  * similar code in dumpConstraint!
   18324              :                  */
   18325              : 
   18326              :                 /* If the index is clustered, we need to record that. */
   18327            0 :                 if (indxinfo->indisclustered)
   18328              :                 {
   18329            0 :                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18330            0 :                                                           fmtQualifiedDumpable(tbinfo));
   18331              :                         /* index name is not qualified in this syntax */
   18332            0 :                         appendPQExpBuffer(q, " ON %s;\n",
   18333            0 :                                                           qindxname);
   18334            0 :                 }
   18335              : 
   18336              :                 /*
   18337              :                  * If the index has any statistics on some of its columns, generate
   18338              :                  * the associated ALTER INDEX queries.
   18339              :                  */
   18340            0 :                 if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   18341              :                 {
   18342            0 :                         int                     j;
   18343              : 
   18344            0 :                         if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   18345            0 :                                 pg_fatal("could not parse index statistic columns");
   18346            0 :                         if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   18347            0 :                                 pg_fatal("could not parse index statistic values");
   18348            0 :                         if (nstatcols != nstatvals)
   18349            0 :                                 pg_fatal("mismatched number of columns and values for index statistics");
   18350              : 
   18351            0 :                         for (j = 0; j < nstatcols; j++)
   18352              :                         {
   18353            0 :                                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   18354              : 
   18355              :                                 /*
   18356              :                                  * Note that this is a column number, so no quotes should be
   18357              :                                  * used.
   18358              :                                  */
   18359            0 :                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   18360            0 :                                                                   indstatcolsarray[j]);
   18361            0 :                                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   18362            0 :                                                                   indstatvalsarray[j]);
   18363            0 :                         }
   18364            0 :                 }
   18365              : 
   18366              :                 /* Indexes can depend on extensions */
   18367            0 :                 append_depends_on_extension(fout, q, &indxinfo->dobj,
   18368              :                                                                         "pg_catalog.pg_class",
   18369            0 :                                                                         "INDEX", qqindxname);
   18370              : 
   18371              :                 /* If the index defines identity, we need to record that. */
   18372            0 :                 if (indxinfo->indisreplident)
   18373              :                 {
   18374            0 :                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18375            0 :                                                           fmtQualifiedDumpable(tbinfo));
   18376              :                         /* index name is not qualified in this syntax */
   18377            0 :                         appendPQExpBuffer(q, " INDEX %s;\n",
   18378            0 :                                                           qindxname);
   18379            0 :                 }
   18380              : 
   18381              :                 /*
   18382              :                  * If this index is a member of a partitioned index, the backend will
   18383              :                  * not allow us to drop it separately, so don't try.  It will go away
   18384              :                  * automatically when we drop either the index's table or the
   18385              :                  * partitioned index.  (If, in a selective restore with --clean, we
   18386              :                  * drop neither of those, then this index will not be dropped either.
   18387              :                  * But that's fine, and even if you think it's not, the backend won't
   18388              :                  * let us do differently.)
   18389              :                  */
   18390            0 :                 if (indxinfo->parentidx == 0)
   18391            0 :                         appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   18392              : 
   18393            0 :                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18394            0 :                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   18395            0 :                                                  ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   18396              :                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18397              :                                                                           .tablespace = indxinfo->tablespace,
   18398              :                                                                           .owner = tbinfo->rolname,
   18399              :                                                                           .description = "INDEX",
   18400              :                                                                           .section = SECTION_POST_DATA,
   18401              :                                                                           .createStmt = q->data,
   18402              :                                                                           .dropStmt = delq->data));
   18403              : 
   18404            0 :                 free(indstatcolsarray);
   18405            0 :                 free(indstatvalsarray);
   18406            0 :         }
   18407              : 
   18408              :         /* Dump Index Comments */
   18409            0 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18410            0 :                 dumpComment(fout, "INDEX", qindxname,
   18411            0 :                                         tbinfo->dobj.namespace->dobj.name,
   18412            0 :                                         tbinfo->rolname,
   18413            0 :                                         indxinfo->dobj.catId, 0,
   18414            0 :                                         is_constraint ? indxinfo->indexconstraint :
   18415            0 :                                         indxinfo->dobj.dumpId);
   18416              : 
   18417            0 :         destroyPQExpBuffer(q);
   18418            0 :         destroyPQExpBuffer(delq);
   18419            0 :         free(qindxname);
   18420            0 :         free(qqindxname);
   18421            0 : }
   18422              : 
   18423              : /*
   18424              :  * dumpIndexAttach
   18425              :  *        write out to fout a partitioned-index attachment clause
   18426              :  */
   18427              : static void
   18428            0 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   18429              : {
   18430              :         /* Do nothing if not dumping schema */
   18431            0 :         if (!fout->dopt->dumpSchema)
   18432            0 :                 return;
   18433              : 
   18434            0 :         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18435              :         {
   18436            0 :                 PQExpBuffer q = createPQExpBuffer();
   18437              : 
   18438            0 :                 appendPQExpBuffer(q, "ALTER INDEX %s ",
   18439            0 :                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
   18440            0 :                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   18441            0 :                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
   18442              : 
   18443              :                 /*
   18444              :                  * There is no need for a dropStmt since the drop is done implicitly
   18445              :                  * when we drop either the index's table or the partitioned index.
   18446              :                  * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
   18447              :                  * there's no way to do it anyway.  (If you think to change this,
   18448              :                  * consider also what to do with --if-exists.)
   18449              :                  *
   18450              :                  * Although this object doesn't really have ownership as such, set the
   18451              :                  * owner field anyway to ensure that the command is run by the correct
   18452              :                  * role at restore time.
   18453              :                  */
   18454            0 :                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18455            0 :                                          ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18456              :                                                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   18457              :                                                                   .owner = attachinfo->parentIdx->indextable->rolname,
   18458              :                                                                   .description = "INDEX ATTACH",
   18459              :                                                                   .section = SECTION_POST_DATA,
   18460              :                                                                   .createStmt = q->data));
   18461              : 
   18462            0 :                 destroyPQExpBuffer(q);
   18463            0 :         }
   18464            0 : }
   18465              : 
   18466              : /*
   18467              :  * dumpStatisticsExt
   18468              :  *        write out to fout an extended statistics object
   18469              :  */
   18470              : static void
   18471            0 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   18472              : {
   18473            0 :         DumpOptions *dopt = fout->dopt;
   18474            0 :         PQExpBuffer q;
   18475            0 :         PQExpBuffer delq;
   18476            0 :         PQExpBuffer query;
   18477            0 :         char       *qstatsextname;
   18478            0 :         PGresult   *res;
   18479            0 :         char       *stxdef;
   18480              : 
   18481              :         /* Do nothing if not dumping schema */
   18482            0 :         if (!dopt->dumpSchema)
   18483            0 :                 return;
   18484              : 
   18485            0 :         q = createPQExpBuffer();
   18486            0 :         delq = createPQExpBuffer();
   18487            0 :         query = createPQExpBuffer();
   18488              : 
   18489            0 :         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   18490              : 
   18491            0 :         appendPQExpBuffer(query, "SELECT "
   18492              :                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   18493            0 :                                           statsextinfo->dobj.catId.oid);
   18494              : 
   18495            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   18496              : 
   18497            0 :         stxdef = PQgetvalue(res, 0, 0);
   18498              : 
   18499              :         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   18500            0 :         appendPQExpBuffer(q, "%s;\n", stxdef);
   18501              : 
   18502              :         /*
   18503              :          * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   18504              :          * for this statistics object is not the default value.
   18505              :          */
   18506            0 :         if (statsextinfo->stattarget >= 0)
   18507              :         {
   18508            0 :                 appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   18509            0 :                                                   fmtQualifiedDumpable(statsextinfo));
   18510            0 :                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   18511            0 :                                                   statsextinfo->stattarget);
   18512            0 :         }
   18513              : 
   18514            0 :         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   18515            0 :                                           fmtQualifiedDumpable(statsextinfo));
   18516              : 
   18517            0 :         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18518            0 :                 ArchiveEntry(fout, statsextinfo->dobj.catId,
   18519            0 :                                          statsextinfo->dobj.dumpId,
   18520            0 :                                          ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   18521              :                                                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   18522              :                                                                   .owner = statsextinfo->rolname,
   18523              :                                                                   .description = "STATISTICS",
   18524              :                                                                   .section = SECTION_POST_DATA,
   18525              :                                                                   .createStmt = q->data,
   18526              :                                                                   .dropStmt = delq->data));
   18527              : 
   18528              :         /* Dump Statistics Comments */
   18529            0 :         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18530            0 :                 dumpComment(fout, "STATISTICS", qstatsextname,
   18531            0 :                                         statsextinfo->dobj.namespace->dobj.name,
   18532            0 :                                         statsextinfo->rolname,
   18533            0 :                                         statsextinfo->dobj.catId, 0,
   18534            0 :                                         statsextinfo->dobj.dumpId);
   18535              : 
   18536            0 :         PQclear(res);
   18537            0 :         destroyPQExpBuffer(q);
   18538            0 :         destroyPQExpBuffer(delq);
   18539            0 :         destroyPQExpBuffer(query);
   18540            0 :         free(qstatsextname);
   18541            0 : }
   18542              : 
   18543              : /*
   18544              :  * dumpConstraint
   18545              :  *        write out to fout a user-defined constraint
   18546              :  */
   18547              : static void
   18548            0 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   18549              : {
   18550            0 :         DumpOptions *dopt = fout->dopt;
   18551            0 :         TableInfo  *tbinfo = coninfo->contable;
   18552            0 :         PQExpBuffer q;
   18553            0 :         PQExpBuffer delq;
   18554            0 :         char       *tag = NULL;
   18555            0 :         char       *foreign;
   18556              : 
   18557              :         /* Do nothing if not dumping schema */
   18558            0 :         if (!dopt->dumpSchema)
   18559            0 :                 return;
   18560              : 
   18561            0 :         q = createPQExpBuffer();
   18562            0 :         delq = createPQExpBuffer();
   18563              : 
   18564            0 :         foreign = tbinfo &&
   18565            0 :                 tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18566              : 
   18567            0 :         if (coninfo->contype == 'p' ||
   18568            0 :                 coninfo->contype == 'u' ||
   18569            0 :                 coninfo->contype == 'x')
   18570              :         {
   18571              :                 /* Index-related constraint */
   18572            0 :                 IndxInfo   *indxinfo;
   18573            0 :                 int                     k;
   18574              : 
   18575            0 :                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   18576              : 
   18577            0 :                 if (indxinfo == NULL)
   18578            0 :                         pg_fatal("missing index for constraint \"%s\"",
   18579              :                                          coninfo->dobj.name);
   18580              : 
   18581            0 :                 if (dopt->binary_upgrade)
   18582            0 :                         binary_upgrade_set_pg_class_oids(fout, q,
   18583            0 :                                                                                          indxinfo->dobj.catId.oid);
   18584              : 
   18585            0 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   18586            0 :                                                   fmtQualifiedDumpable(tbinfo));
   18587            0 :                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   18588            0 :                                                   fmtId(coninfo->dobj.name));
   18589              : 
   18590            0 :                 if (coninfo->condef)
   18591              :                 {
   18592              :                         /* pg_get_constraintdef should have provided everything */
   18593            0 :                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   18594            0 :                 }
   18595              :                 else
   18596              :                 {
   18597            0 :                         appendPQExpBufferStr(q,
   18598            0 :                                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   18599              : 
   18600              :                         /*
   18601              :                          * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   18602              :                          * indexes. Being able to create this was fixed, but we need to
   18603              :                          * make the index distinct in order to be able to restore the
   18604              :                          * dump.
   18605              :                          */
   18606            0 :                         if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   18607            0 :                                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   18608            0 :                         appendPQExpBufferStr(q, " (");
   18609            0 :                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
   18610              :                         {
   18611            0 :                                 int                     indkey = (int) indxinfo->indkeys[k];
   18612            0 :                                 const char *attname;
   18613              : 
   18614            0 :                                 if (indkey == InvalidAttrNumber)
   18615            0 :                                         break;
   18616            0 :                                 attname = getAttrName(indkey, tbinfo);
   18617              : 
   18618            0 :                                 appendPQExpBuffer(q, "%s%s",
   18619            0 :                                                                   (k == 0) ? "" : ", ",
   18620            0 :                                                                   fmtId(attname));
   18621            0 :                         }
   18622            0 :                         if (coninfo->conperiod)
   18623            0 :                                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   18624              : 
   18625            0 :                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   18626            0 :                                 appendPQExpBufferStr(q, ") INCLUDE (");
   18627              : 
   18628            0 :                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   18629              :                         {
   18630            0 :                                 int                     indkey = (int) indxinfo->indkeys[k];
   18631            0 :                                 const char *attname;
   18632              : 
   18633            0 :                                 if (indkey == InvalidAttrNumber)
   18634            0 :                                         break;
   18635            0 :                                 attname = getAttrName(indkey, tbinfo);
   18636              : 
   18637            0 :                                 appendPQExpBuffer(q, "%s%s",
   18638            0 :                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   18639            0 :                                                                   fmtId(attname));
   18640            0 :                         }
   18641              : 
   18642            0 :                         appendPQExpBufferChar(q, ')');
   18643              : 
   18644            0 :                         if (nonemptyReloptions(indxinfo->indreloptions))
   18645              :                         {
   18646            0 :                                 appendPQExpBufferStr(q, " WITH (");
   18647            0 :                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   18648            0 :                                 appendPQExpBufferChar(q, ')');
   18649            0 :                         }
   18650              : 
   18651            0 :                         if (coninfo->condeferrable)
   18652              :                         {
   18653            0 :                                 appendPQExpBufferStr(q, " DEFERRABLE");
   18654            0 :                                 if (coninfo->condeferred)
   18655            0 :                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   18656            0 :                         }
   18657              : 
   18658            0 :                         appendPQExpBufferStr(q, ";\n");
   18659              :                 }
   18660              : 
   18661              :                 /*
   18662              :                  * Append ALTER TABLE commands as needed to set properties that we
   18663              :                  * only have ALTER TABLE syntax for.  Keep this in sync with the
   18664              :                  * similar code in dumpIndex!
   18665              :                  */
   18666              : 
   18667              :                 /* If the index is clustered, we need to record that. */
   18668            0 :                 if (indxinfo->indisclustered)
   18669              :                 {
   18670            0 :                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18671            0 :                                                           fmtQualifiedDumpable(tbinfo));
   18672              :                         /* index name is not qualified in this syntax */
   18673            0 :                         appendPQExpBuffer(q, " ON %s;\n",
   18674            0 :                                                           fmtId(indxinfo->dobj.name));
   18675            0 :                 }
   18676              : 
   18677              :                 /* If the index defines identity, we need to record that. */
   18678            0 :                 if (indxinfo->indisreplident)
   18679              :                 {
   18680            0 :                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18681            0 :                                                           fmtQualifiedDumpable(tbinfo));
   18682              :                         /* index name is not qualified in this syntax */
   18683            0 :                         appendPQExpBuffer(q, " INDEX %s;\n",
   18684            0 :                                                           fmtId(indxinfo->dobj.name));
   18685            0 :                 }
   18686              : 
   18687              :                 /* Indexes can depend on extensions */
   18688            0 :                 append_depends_on_extension(fout, q, &indxinfo->dobj,
   18689              :                                                                         "pg_catalog.pg_class", "INDEX",
   18690            0 :                                                                         fmtQualifiedDumpable(indxinfo));
   18691              : 
   18692            0 :                 appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   18693            0 :                                                   fmtQualifiedDumpable(tbinfo));
   18694            0 :                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18695            0 :                                                   fmtId(coninfo->dobj.name));
   18696              : 
   18697            0 :                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18698              : 
   18699            0 :                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18700            0 :                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18701            0 :                                                  ARCHIVE_OPTS(.tag = tag,
   18702              :                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18703              :                                                                           .tablespace = indxinfo->tablespace,
   18704              :                                                                           .owner = tbinfo->rolname,
   18705              :                                                                           .description = "CONSTRAINT",
   18706              :                                                                           .section = SECTION_POST_DATA,
   18707              :                                                                           .createStmt = q->data,
   18708              :                                                                           .dropStmt = delq->data));
   18709            0 :         }
   18710            0 :         else if (coninfo->contype == 'f')
   18711              :         {
   18712            0 :                 char       *only;
   18713              : 
   18714              :                 /*
   18715              :                  * Foreign keys on partitioned tables are always declared as
   18716              :                  * inheriting to partitions; for all other cases, emit them as
   18717              :                  * applying ONLY directly to the named table, because that's how they
   18718              :                  * work for regular inherited tables.
   18719              :                  */
   18720            0 :                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   18721              : 
   18722              :                 /*
   18723              :                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   18724              :                  * current table data is not processed
   18725              :                  */
   18726            0 :                 appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   18727            0 :                                                   only, fmtQualifiedDumpable(tbinfo));
   18728            0 :                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18729            0 :                                                   fmtId(coninfo->dobj.name),
   18730            0 :                                                   coninfo->condef);
   18731              : 
   18732            0 :                 appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   18733            0 :                                                   only, fmtQualifiedDumpable(tbinfo));
   18734            0 :                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18735            0 :                                                   fmtId(coninfo->dobj.name));
   18736              : 
   18737            0 :                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18738              : 
   18739            0 :                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18740            0 :                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18741            0 :                                                  ARCHIVE_OPTS(.tag = tag,
   18742              :                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18743              :                                                                           .owner = tbinfo->rolname,
   18744              :                                                                           .description = "FK CONSTRAINT",
   18745              :                                                                           .section = SECTION_POST_DATA,
   18746              :                                                                           .createStmt = q->data,
   18747              :                                                                           .dropStmt = delq->data));
   18748            0 :         }
   18749            0 :         else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
   18750              :         {
   18751              :                 /* CHECK or invalid not-null constraint on a table */
   18752              : 
   18753              :                 /* Ignore if not to be dumped separately, or if it was inherited */
   18754            0 :                 if (coninfo->separate && coninfo->conislocal)
   18755              :                 {
   18756            0 :                         const char *keyword;
   18757              : 
   18758            0 :                         if (coninfo->contype == 'c')
   18759            0 :                                 keyword = "CHECK CONSTRAINT";
   18760              :                         else
   18761            0 :                                 keyword = "CONSTRAINT";
   18762              : 
   18763              :                         /* not ONLY since we want it to propagate to children */
   18764            0 :                         appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   18765            0 :                                                           fmtQualifiedDumpable(tbinfo));
   18766            0 :                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18767            0 :                                                           fmtId(coninfo->dobj.name),
   18768            0 :                                                           coninfo->condef);
   18769              : 
   18770            0 :                         appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   18771            0 :                                                           fmtQualifiedDumpable(tbinfo));
   18772            0 :                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18773            0 :                                                           fmtId(coninfo->dobj.name));
   18774              : 
   18775            0 :                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18776              : 
   18777            0 :                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18778            0 :                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18779            0 :                                                          ARCHIVE_OPTS(.tag = tag,
   18780              :                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18781              :                                                                                   .owner = tbinfo->rolname,
   18782              :                                                                                   .description = keyword,
   18783              :                                                                                   .section = SECTION_POST_DATA,
   18784              :                                                                                   .createStmt = q->data,
   18785              :                                                                                   .dropStmt = delq->data));
   18786            0 :                 }
   18787            0 :         }
   18788            0 :         else if (tbinfo == NULL)
   18789              :         {
   18790              :                 /* CHECK, NOT NULL constraint on a domain */
   18791            0 :                 TypeInfo   *tyinfo = coninfo->condomain;
   18792              : 
   18793            0 :                 Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
   18794              : 
   18795              :                 /* Ignore if not to be dumped separately */
   18796            0 :                 if (coninfo->separate)
   18797              :                 {
   18798            0 :                         const char *keyword;
   18799              : 
   18800            0 :                         if (coninfo->contype == 'c')
   18801            0 :                                 keyword = "CHECK CONSTRAINT";
   18802              :                         else
   18803            0 :                                 keyword = "CONSTRAINT";
   18804              : 
   18805            0 :                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   18806            0 :                                                           fmtQualifiedDumpable(tyinfo));
   18807            0 :                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18808            0 :                                                           fmtId(coninfo->dobj.name),
   18809            0 :                                                           coninfo->condef);
   18810              : 
   18811            0 :                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   18812            0 :                                                           fmtQualifiedDumpable(tyinfo));
   18813            0 :                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18814            0 :                                                           fmtId(coninfo->dobj.name));
   18815              : 
   18816            0 :                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   18817              : 
   18818            0 :                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18819            0 :                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18820            0 :                                                          ARCHIVE_OPTS(.tag = tag,
   18821              :                                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   18822              :                                                                                   .owner = tyinfo->rolname,
   18823              :                                                                                   .description = keyword,
   18824              :                                                                                   .section = SECTION_POST_DATA,
   18825              :                                                                                   .createStmt = q->data,
   18826              :                                                                                   .dropStmt = delq->data));
   18827              : 
   18828            0 :                         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18829              :                         {
   18830            0 :                                 PQExpBuffer conprefix = createPQExpBuffer();
   18831            0 :                                 char       *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   18832              : 
   18833            0 :                                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   18834            0 :                                                                   fmtId(coninfo->dobj.name));
   18835              : 
   18836            0 :                                 dumpComment(fout, conprefix->data, qtypname,
   18837            0 :                                                         tyinfo->dobj.namespace->dobj.name,
   18838            0 :                                                         tyinfo->rolname,
   18839            0 :                                                         coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
   18840            0 :                                 destroyPQExpBuffer(conprefix);
   18841            0 :                                 free(qtypname);
   18842            0 :                         }
   18843            0 :                 }
   18844            0 :         }
   18845              :         else
   18846              :         {
   18847            0 :                 pg_fatal("unrecognized constraint type: %c",
   18848              :                                  coninfo->contype);
   18849              :         }
   18850              : 
   18851              :         /* Dump Constraint Comments --- only works for table constraints */
   18852            0 :         if (tbinfo && coninfo->separate &&
   18853            0 :                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18854            0 :                 dumpTableConstraintComment(fout, coninfo);
   18855              : 
   18856            0 :         free(tag);
   18857            0 :         destroyPQExpBuffer(q);
   18858            0 :         destroyPQExpBuffer(delq);
   18859            0 : }
   18860              : 
   18861              : /*
   18862              :  * dumpTableConstraintComment --- dump a constraint's comment if any
   18863              :  *
   18864              :  * This is split out because we need the function in two different places
   18865              :  * depending on whether the constraint is dumped as part of CREATE TABLE
   18866              :  * or as a separate ALTER command.
   18867              :  */
   18868              : static void
   18869            0 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   18870              : {
   18871            0 :         TableInfo  *tbinfo = coninfo->contable;
   18872            0 :         PQExpBuffer conprefix = createPQExpBuffer();
   18873            0 :         char       *qtabname;
   18874              : 
   18875            0 :         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18876              : 
   18877            0 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   18878            0 :                                           fmtId(coninfo->dobj.name));
   18879              : 
   18880            0 :         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18881            0 :                 dumpComment(fout, conprefix->data, qtabname,
   18882            0 :                                         tbinfo->dobj.namespace->dobj.name,
   18883            0 :                                         tbinfo->rolname,
   18884            0 :                                         coninfo->dobj.catId, 0,
   18885            0 :                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   18886              : 
   18887            0 :         destroyPQExpBuffer(conprefix);
   18888            0 :         free(qtabname);
   18889            0 : }
   18890              : 
   18891              : static inline SeqType
   18892            0 : parse_sequence_type(const char *name)
   18893              : {
   18894            0 :         for (int i = 0; i < lengthof(SeqTypeNames); i++)
   18895              :         {
   18896            0 :                 if (strcmp(SeqTypeNames[i], name) == 0)
   18897            0 :                         return (SeqType) i;
   18898            0 :         }
   18899              : 
   18900            0 :         pg_fatal("unrecognized sequence type: %s", name);
   18901            0 :         return (SeqType) 0;                     /* keep compiler quiet */
   18902            0 : }
   18903              : 
   18904              : /*
   18905              :  * bsearch() comparator for SequenceItem
   18906              :  */
   18907              : static int
   18908            0 : SequenceItemCmp(const void *p1, const void *p2)
   18909              : {
   18910            0 :         SequenceItem v1 = *((const SequenceItem *) p1);
   18911            0 :         SequenceItem v2 = *((const SequenceItem *) p2);
   18912              : 
   18913            0 :         return pg_cmp_u32(v1.oid, v2.oid);
   18914            0 : }
   18915              : 
   18916              : /*
   18917              :  * collectSequences
   18918              :  *
   18919              :  * Construct a table of sequence information.  This table is sorted by OID for
   18920              :  * speed in lookup.
   18921              :  */
   18922              : static void
   18923            0 : collectSequences(Archive *fout)
   18924              : {
   18925            0 :         PGresult   *res;
   18926            0 :         const char *query;
   18927              : 
   18928              :         /*
   18929              :          * Before Postgres 10, sequence metadata is in the sequence itself.  With
   18930              :          * some extra effort, we might be able to use the sorted table for those
   18931              :          * versions, but for now it seems unlikely to be worth it.
   18932              :          *
   18933              :          * Since version 18, we can gather the sequence data in this query with
   18934              :          * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   18935              :          */
   18936            0 :         if (fout->remoteVersion < 100000)
   18937            0 :                 return;
   18938            0 :         else if (fout->remoteVersion < 180000 ||
   18939            0 :                          (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   18940            0 :                 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18941              :                         "seqstart, seqincrement, "
   18942              :                         "seqmax, seqmin, "
   18943              :                         "seqcache, seqcycle, "
   18944              :                         "NULL, 'f' "
   18945              :                         "FROM pg_catalog.pg_sequence "
   18946              :                         "ORDER BY seqrelid";
   18947              :         else
   18948            0 :                 query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18949              :                         "seqstart, seqincrement, "
   18950              :                         "seqmax, seqmin, "
   18951              :                         "seqcache, seqcycle, "
   18952              :                         "last_value, is_called "
   18953              :                         "FROM pg_catalog.pg_sequence, "
   18954              :                         "pg_get_sequence_data(seqrelid) "
   18955              :                         "ORDER BY seqrelid;";
   18956              : 
   18957            0 :         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   18958              : 
   18959            0 :         nsequences = PQntuples(res);
   18960            0 :         sequences = (SequenceItem *) pg_malloc(nsequences * sizeof(SequenceItem));
   18961              : 
   18962            0 :         for (int i = 0; i < nsequences; i++)
   18963              :         {
   18964            0 :                 sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   18965            0 :                 sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   18966            0 :                 sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   18967            0 :                 sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   18968            0 :                 sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   18969            0 :                 sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   18970            0 :                 sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   18971            0 :                 sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   18972            0 :                 sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   18973            0 :                 sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   18974            0 :                 sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
   18975            0 :         }
   18976              : 
   18977            0 :         PQclear(res);
   18978            0 : }
   18979              : 
   18980              : /*
   18981              :  * dumpSequence
   18982              :  *        write the declaration (not data) of one user-defined sequence
   18983              :  */
   18984              : static void
   18985            0 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   18986              : {
   18987            0 :         DumpOptions *dopt = fout->dopt;
   18988            0 :         SequenceItem *seq;
   18989            0 :         bool            is_ascending;
   18990            0 :         int64           default_minv,
   18991              :                                 default_maxv;
   18992            0 :         PQExpBuffer query = createPQExpBuffer();
   18993            0 :         PQExpBuffer delqry = createPQExpBuffer();
   18994            0 :         char       *qseqname;
   18995            0 :         TableInfo  *owning_tab = NULL;
   18996              : 
   18997            0 :         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   18998              : 
   18999              :         /*
   19000              :          * For versions >= 10, the sequence information is gathered in a sorted
   19001              :          * table before any calls to dumpSequence().  See collectSequences() for
   19002              :          * more information.
   19003              :          */
   19004            0 :         if (fout->remoteVersion >= 100000)
   19005              :         {
   19006            0 :                 SequenceItem key = {0};
   19007              : 
   19008            0 :                 Assert(sequences);
   19009              : 
   19010            0 :                 key.oid = tbinfo->dobj.catId.oid;
   19011            0 :                 seq = bsearch(&key, sequences, nsequences,
   19012              :                                           sizeof(SequenceItem), SequenceItemCmp);
   19013            0 :         }
   19014              :         else
   19015              :         {
   19016            0 :                 PGresult   *res;
   19017              : 
   19018              :                 /*
   19019              :                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   19020              :                  *
   19021              :                  * Note: it might seem that 'bigint' potentially needs to be
   19022              :                  * schema-qualified, but actually that's a keyword.
   19023              :                  */
   19024            0 :                 appendPQExpBuffer(query,
   19025              :                                                   "SELECT 'bigint' AS sequence_type, "
   19026              :                                                   "start_value, increment_by, max_value, min_value, "
   19027              :                                                   "cache_value, is_cycled FROM %s",
   19028            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19029              : 
   19030            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19031              : 
   19032            0 :                 if (PQntuples(res) != 1)
   19033            0 :                         pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19034              :                                                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19035              :                                                           PQntuples(res)),
   19036              :                                          tbinfo->dobj.name, PQntuples(res));
   19037              : 
   19038            0 :                 seq = pg_malloc0(sizeof(SequenceItem));
   19039            0 :                 seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
   19040            0 :                 seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
   19041            0 :                 seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
   19042            0 :                 seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
   19043            0 :                 seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
   19044            0 :                 seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
   19045            0 :                 seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   19046              : 
   19047            0 :                 PQclear(res);
   19048            0 :         }
   19049              : 
   19050              :         /* Calculate default limits for a sequence of this type */
   19051            0 :         is_ascending = (seq->incby >= 0);
   19052            0 :         if (seq->seqtype == SEQTYPE_SMALLINT)
   19053              :         {
   19054            0 :                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
   19055            0 :                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
   19056            0 :         }
   19057            0 :         else if (seq->seqtype == SEQTYPE_INTEGER)
   19058              :         {
   19059            0 :                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
   19060            0 :                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
   19061            0 :         }
   19062            0 :         else if (seq->seqtype == SEQTYPE_BIGINT)
   19063              :         {
   19064            0 :                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
   19065            0 :                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
   19066            0 :         }
   19067              :         else
   19068              :         {
   19069            0 :                 pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   19070            0 :                 default_minv = default_maxv = 0;        /* keep compiler quiet */
   19071              :         }
   19072              : 
   19073              :         /*
   19074              :          * Identity sequences are not to be dropped separately.
   19075              :          */
   19076            0 :         if (!tbinfo->is_identity_sequence)
   19077              :         {
   19078            0 :                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   19079            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19080            0 :         }
   19081              : 
   19082            0 :         resetPQExpBuffer(query);
   19083              : 
   19084            0 :         if (dopt->binary_upgrade)
   19085              :         {
   19086            0 :                 binary_upgrade_set_pg_class_oids(fout, query,
   19087            0 :                                                                                  tbinfo->dobj.catId.oid);
   19088              : 
   19089              :                 /*
   19090              :                  * In older PG versions a sequence will have a pg_type entry, but v14
   19091              :                  * and up don't use that, so don't attempt to preserve the type OID.
   19092              :                  */
   19093            0 :         }
   19094              : 
   19095            0 :         if (tbinfo->is_identity_sequence)
   19096              :         {
   19097            0 :                 owning_tab = findTableByOid(tbinfo->owning_tab);
   19098              : 
   19099            0 :                 appendPQExpBuffer(query,
   19100              :                                                   "ALTER TABLE %s ",
   19101            0 :                                                   fmtQualifiedDumpable(owning_tab));
   19102            0 :                 appendPQExpBuffer(query,
   19103              :                                                   "ALTER COLUMN %s ADD GENERATED ",
   19104            0 :                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19105            0 :                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   19106            0 :                         appendPQExpBufferStr(query, "ALWAYS");
   19107            0 :                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   19108            0 :                         appendPQExpBufferStr(query, "BY DEFAULT");
   19109            0 :                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   19110            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19111              : 
   19112              :                 /*
   19113              :                  * Emit persistence option only if it's different from the owning
   19114              :                  * table's.  This avoids using this new syntax unnecessarily.
   19115              :                  */
   19116            0 :                 if (tbinfo->relpersistence != owning_tab->relpersistence)
   19117            0 :                         appendPQExpBuffer(query, "    %s\n",
   19118            0 :                                                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19119              :                                                           "UNLOGGED" : "LOGGED");
   19120            0 :         }
   19121              :         else
   19122              :         {
   19123            0 :                 appendPQExpBuffer(query,
   19124              :                                                   "CREATE %sSEQUENCE %s\n",
   19125            0 :                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19126              :                                                   "UNLOGGED " : "",
   19127            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19128              : 
   19129            0 :                 if (seq->seqtype != SEQTYPE_BIGINT)
   19130            0 :                         appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   19131              :         }
   19132              : 
   19133            0 :         appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   19134              : 
   19135            0 :         appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   19136              : 
   19137            0 :         if (seq->minv != default_minv)
   19138            0 :                 appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   19139              :         else
   19140            0 :                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
   19141              : 
   19142            0 :         if (seq->maxv != default_maxv)
   19143            0 :                 appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   19144              :         else
   19145            0 :                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   19146              : 
   19147            0 :         appendPQExpBuffer(query,
   19148              :                                           "    CACHE " INT64_FORMAT "%s",
   19149            0 :                                           seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   19150              : 
   19151            0 :         if (tbinfo->is_identity_sequence)
   19152            0 :                 appendPQExpBufferStr(query, "\n);\n");
   19153              :         else
   19154            0 :                 appendPQExpBufferStr(query, ";\n");
   19155              : 
   19156              :         /* binary_upgrade:      no need to clear TOAST table oid */
   19157              : 
   19158            0 :         if (dopt->binary_upgrade)
   19159            0 :                 binary_upgrade_extension_member(query, &tbinfo->dobj,
   19160            0 :                                                                                 "SEQUENCE", qseqname,
   19161            0 :                                                                                 tbinfo->dobj.namespace->dobj.name);
   19162              : 
   19163            0 :         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19164            0 :                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   19165            0 :                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19166              :                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19167              :                                                                   .owner = tbinfo->rolname,
   19168              :                                                                   .description = "SEQUENCE",
   19169              :                                                                   .section = SECTION_PRE_DATA,
   19170              :                                                                   .createStmt = query->data,
   19171              :                                                                   .dropStmt = delqry->data));
   19172              : 
   19173              :         /*
   19174              :          * If the sequence is owned by a table column, emit the ALTER for it as a
   19175              :          * separate TOC entry immediately following the sequence's own entry. It's
   19176              :          * OK to do this rather than using full sorting logic, because the
   19177              :          * dependency that tells us it's owned will have forced the table to be
   19178              :          * created first.  We can't just include the ALTER in the TOC entry
   19179              :          * because it will fail if we haven't reassigned the sequence owner to
   19180              :          * match the table's owner.
   19181              :          *
   19182              :          * We need not schema-qualify the table reference because both sequence
   19183              :          * and table must be in the same schema.
   19184              :          */
   19185            0 :         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   19186              :         {
   19187            0 :                 owning_tab = findTableByOid(tbinfo->owning_tab);
   19188              : 
   19189            0 :                 if (owning_tab == NULL)
   19190            0 :                         pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   19191              :                                          tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   19192              : 
   19193            0 :                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19194              :                 {
   19195            0 :                         resetPQExpBuffer(query);
   19196            0 :                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   19197            0 :                                                           fmtQualifiedDumpable(tbinfo));
   19198            0 :                         appendPQExpBuffer(query, " OWNED BY %s",
   19199            0 :                                                           fmtQualifiedDumpable(owning_tab));
   19200            0 :                         appendPQExpBuffer(query, ".%s;\n",
   19201            0 :                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19202              : 
   19203            0 :                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19204            0 :                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19205            0 :                                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19206              :                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19207              :                                                                                   .owner = tbinfo->rolname,
   19208              :                                                                                   .description = "SEQUENCE OWNED BY",
   19209              :                                                                                   .section = SECTION_PRE_DATA,
   19210              :                                                                                   .createStmt = query->data,
   19211              :                                                                                   .deps = &(tbinfo->dobj.dumpId),
   19212              :                                                                                   .nDeps = 1));
   19213            0 :                 }
   19214            0 :         }
   19215              : 
   19216              :         /* Dump Sequence Comments and Security Labels */
   19217            0 :         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19218            0 :                 dumpComment(fout, "SEQUENCE", qseqname,
   19219            0 :                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19220            0 :                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19221              : 
   19222            0 :         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19223            0 :                 dumpSecLabel(fout, "SEQUENCE", qseqname,
   19224            0 :                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19225            0 :                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19226              : 
   19227            0 :         if (fout->remoteVersion < 100000)
   19228            0 :                 pg_free(seq);
   19229            0 :         destroyPQExpBuffer(query);
   19230            0 :         destroyPQExpBuffer(delqry);
   19231            0 :         free(qseqname);
   19232            0 : }
   19233              : 
   19234              : /*
   19235              :  * dumpSequenceData
   19236              :  *        write the data of one user-defined sequence
   19237              :  */
   19238              : static void
   19239            0 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   19240              : {
   19241            0 :         TableInfo  *tbinfo = tdinfo->tdtable;
   19242            0 :         int64           last;
   19243            0 :         bool            called;
   19244            0 :         PQExpBuffer query;
   19245              : 
   19246              :         /* needn't bother if not dumping sequence data */
   19247            0 :         if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
   19248            0 :                 return;
   19249              : 
   19250            0 :         query = createPQExpBuffer();
   19251              : 
   19252              :         /*
   19253              :          * For versions >= 18, the sequence information is gathered in the sorted
   19254              :          * array before any calls to dumpSequenceData().  See collectSequences()
   19255              :          * for more information.
   19256              :          *
   19257              :          * For older versions, we have to query the sequence relations
   19258              :          * individually.
   19259              :          */
   19260            0 :         if (fout->remoteVersion < 180000)
   19261              :         {
   19262            0 :                 PGresult   *res;
   19263              : 
   19264            0 :                 appendPQExpBuffer(query,
   19265              :                                                   "SELECT last_value, is_called FROM %s",
   19266            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19267              : 
   19268            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19269              : 
   19270            0 :                 if (PQntuples(res) != 1)
   19271            0 :                         pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19272              :                                                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19273              :                                                           PQntuples(res)),
   19274              :                                          tbinfo->dobj.name, PQntuples(res));
   19275              : 
   19276            0 :                 last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   19277            0 :                 called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   19278              : 
   19279            0 :                 PQclear(res);
   19280            0 :         }
   19281              :         else
   19282              :         {
   19283            0 :                 SequenceItem key = {0};
   19284            0 :                 SequenceItem *entry;
   19285              : 
   19286            0 :                 Assert(sequences);
   19287            0 :                 Assert(tbinfo->dobj.catId.oid);
   19288              : 
   19289            0 :                 key.oid = tbinfo->dobj.catId.oid;
   19290            0 :                 entry = bsearch(&key, sequences, nsequences,
   19291              :                                                 sizeof(SequenceItem), SequenceItemCmp);
   19292              : 
   19293            0 :                 if (entry->null_seqtuple)
   19294            0 :                         pg_fatal("failed to get data for sequence \"%s\"; user may lack "
   19295              :                                          "SELECT privilege on the sequence or the sequence may "
   19296              :                                          "have been concurrently dropped",
   19297              :                                          tbinfo->dobj.name);
   19298              : 
   19299            0 :                 last = entry->last_value;
   19300            0 :                 called = entry->is_called;
   19301            0 :         }
   19302              : 
   19303            0 :         resetPQExpBuffer(query);
   19304            0 :         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   19305            0 :         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   19306            0 :         appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   19307            0 :                                           last, (called ? "true" : "false"));
   19308              : 
   19309            0 :         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   19310            0 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19311            0 :                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19312              :                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19313              :                                                                   .owner = tbinfo->rolname,
   19314              :                                                                   .description = "SEQUENCE SET",
   19315              :                                                                   .section = SECTION_DATA,
   19316              :                                                                   .createStmt = query->data,
   19317              :                                                                   .deps = &(tbinfo->dobj.dumpId),
   19318              :                                                                   .nDeps = 1));
   19319              : 
   19320            0 :         destroyPQExpBuffer(query);
   19321            0 : }
   19322              : 
   19323              : /*
   19324              :  * dumpTrigger
   19325              :  *        write the declaration of one user-defined table trigger
   19326              :  */
   19327              : static void
   19328            0 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   19329              : {
   19330            0 :         DumpOptions *dopt = fout->dopt;
   19331            0 :         TableInfo  *tbinfo = tginfo->tgtable;
   19332            0 :         PQExpBuffer query;
   19333            0 :         PQExpBuffer delqry;
   19334            0 :         PQExpBuffer trigprefix;
   19335            0 :         PQExpBuffer trigidentity;
   19336            0 :         char       *qtabname;
   19337            0 :         char       *tag;
   19338              : 
   19339              :         /* Do nothing if not dumping schema */
   19340            0 :         if (!dopt->dumpSchema)
   19341            0 :                 return;
   19342              : 
   19343            0 :         query = createPQExpBuffer();
   19344            0 :         delqry = createPQExpBuffer();
   19345            0 :         trigprefix = createPQExpBuffer();
   19346            0 :         trigidentity = createPQExpBuffer();
   19347              : 
   19348            0 :         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19349              : 
   19350            0 :         appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   19351            0 :         appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   19352              : 
   19353            0 :         appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   19354            0 :         appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   19355              : 
   19356              :         /* Triggers can depend on extensions */
   19357            0 :         append_depends_on_extension(fout, query, &tginfo->dobj,
   19358              :                                                                 "pg_catalog.pg_trigger", "TRIGGER",
   19359            0 :                                                                 trigidentity->data);
   19360              : 
   19361            0 :         if (tginfo->tgispartition)
   19362              :         {
   19363            0 :                 Assert(tbinfo->ispartition);
   19364              : 
   19365              :                 /*
   19366              :                  * Partition triggers only appear here because their 'tgenabled' flag
   19367              :                  * differs from its parent's.  The trigger is created already, so
   19368              :                  * remove the CREATE and replace it with an ALTER.  (Clear out the
   19369              :                  * DROP query too, so that pg_dump --create does not cause errors.)
   19370              :                  */
   19371            0 :                 resetPQExpBuffer(query);
   19372            0 :                 resetPQExpBuffer(delqry);
   19373            0 :                 appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19374            0 :                                                   tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19375            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19376            0 :                 switch (tginfo->tgenabled)
   19377              :                 {
   19378              :                         case 'f':
   19379              :                         case 'D':
   19380            0 :                                 appendPQExpBufferStr(query, "DISABLE");
   19381            0 :                                 break;
   19382              :                         case 't':
   19383              :                         case 'O':
   19384            0 :                                 appendPQExpBufferStr(query, "ENABLE");
   19385            0 :                                 break;
   19386              :                         case 'R':
   19387            0 :                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19388            0 :                                 break;
   19389              :                         case 'A':
   19390            0 :                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19391            0 :                                 break;
   19392              :                 }
   19393            0 :                 appendPQExpBuffer(query, " TRIGGER %s;\n",
   19394            0 :                                                   fmtId(tginfo->dobj.name));
   19395            0 :         }
   19396            0 :         else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   19397              :         {
   19398            0 :                 appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19399            0 :                                                   tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19400            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19401            0 :                 switch (tginfo->tgenabled)
   19402              :                 {
   19403              :                         case 'D':
   19404              :                         case 'f':
   19405            0 :                                 appendPQExpBufferStr(query, "DISABLE");
   19406            0 :                                 break;
   19407              :                         case 'A':
   19408            0 :                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19409            0 :                                 break;
   19410              :                         case 'R':
   19411            0 :                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19412            0 :                                 break;
   19413              :                         default:
   19414            0 :                                 appendPQExpBufferStr(query, "ENABLE");
   19415            0 :                                 break;
   19416              :                 }
   19417            0 :                 appendPQExpBuffer(query, " TRIGGER %s;\n",
   19418            0 :                                                   fmtId(tginfo->dobj.name));
   19419            0 :         }
   19420              : 
   19421            0 :         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   19422            0 :                                           fmtId(tginfo->dobj.name));
   19423              : 
   19424            0 :         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   19425              : 
   19426            0 :         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19427            0 :                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   19428            0 :                                          ARCHIVE_OPTS(.tag = tag,
   19429              :                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19430              :                                                                   .owner = tbinfo->rolname,
   19431              :                                                                   .description = "TRIGGER",
   19432              :                                                                   .section = SECTION_POST_DATA,
   19433              :                                                                   .createStmt = query->data,
   19434              :                                                                   .dropStmt = delqry->data));
   19435              : 
   19436            0 :         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19437            0 :                 dumpComment(fout, trigprefix->data, qtabname,
   19438            0 :                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19439            0 :                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   19440              : 
   19441            0 :         free(tag);
   19442            0 :         destroyPQExpBuffer(query);
   19443            0 :         destroyPQExpBuffer(delqry);
   19444            0 :         destroyPQExpBuffer(trigprefix);
   19445            0 :         destroyPQExpBuffer(trigidentity);
   19446            0 :         free(qtabname);
   19447            0 : }
   19448              : 
   19449              : /*
   19450              :  * dumpEventTrigger
   19451              :  *        write the declaration of one user-defined event trigger
   19452              :  */
   19453              : static void
   19454            0 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   19455              : {
   19456            0 :         DumpOptions *dopt = fout->dopt;
   19457            0 :         PQExpBuffer query;
   19458            0 :         PQExpBuffer delqry;
   19459            0 :         char       *qevtname;
   19460              : 
   19461              :         /* Do nothing if not dumping schema */
   19462            0 :         if (!dopt->dumpSchema)
   19463            0 :                 return;
   19464              : 
   19465            0 :         query = createPQExpBuffer();
   19466            0 :         delqry = createPQExpBuffer();
   19467              : 
   19468            0 :         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   19469              : 
   19470            0 :         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   19471            0 :         appendPQExpBufferStr(query, qevtname);
   19472            0 :         appendPQExpBufferStr(query, " ON ");
   19473            0 :         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   19474              : 
   19475            0 :         if (strcmp("", evtinfo->evttags) != 0)
   19476              :         {
   19477            0 :                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   19478            0 :                 appendPQExpBufferStr(query, evtinfo->evttags);
   19479            0 :                 appendPQExpBufferChar(query, ')');
   19480            0 :         }
   19481              : 
   19482            0 :         appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   19483            0 :         appendPQExpBufferStr(query, evtinfo->evtfname);
   19484            0 :         appendPQExpBufferStr(query, "();\n");
   19485              : 
   19486            0 :         if (evtinfo->evtenabled != 'O')
   19487              :         {
   19488            0 :                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   19489            0 :                                                   qevtname);
   19490            0 :                 switch (evtinfo->evtenabled)
   19491              :                 {
   19492              :                         case 'D':
   19493            0 :                                 appendPQExpBufferStr(query, "DISABLE");
   19494            0 :                                 break;
   19495              :                         case 'A':
   19496            0 :                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19497            0 :                                 break;
   19498              :                         case 'R':
   19499            0 :                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19500            0 :                                 break;
   19501              :                         default:
   19502            0 :                                 appendPQExpBufferStr(query, "ENABLE");
   19503            0 :                                 break;
   19504              :                 }
   19505            0 :                 appendPQExpBufferStr(query, ";\n");
   19506            0 :         }
   19507              : 
   19508            0 :         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   19509            0 :                                           qevtname);
   19510              : 
   19511            0 :         if (dopt->binary_upgrade)
   19512            0 :                 binary_upgrade_extension_member(query, &evtinfo->dobj,
   19513            0 :                                                                                 "EVENT TRIGGER", qevtname, NULL);
   19514              : 
   19515            0 :         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19516            0 :                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   19517            0 :                                          ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   19518              :                                                                   .owner = evtinfo->evtowner,
   19519              :                                                                   .description = "EVENT TRIGGER",
   19520              :                                                                   .section = SECTION_POST_DATA,
   19521              :                                                                   .createStmt = query->data,
   19522              :                                                                   .dropStmt = delqry->data));
   19523              : 
   19524            0 :         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19525            0 :                 dumpComment(fout, "EVENT TRIGGER", qevtname,
   19526            0 :                                         NULL, evtinfo->evtowner,
   19527            0 :                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   19528              : 
   19529            0 :         if (evtinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19530            0 :                 dumpSecLabel(fout, "EVENT TRIGGER", qevtname,
   19531            0 :                                          NULL, evtinfo->evtowner,
   19532            0 :                                          evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   19533              : 
   19534            0 :         destroyPQExpBuffer(query);
   19535            0 :         destroyPQExpBuffer(delqry);
   19536            0 :         free(qevtname);
   19537            0 : }
   19538              : 
   19539              : /*
   19540              :  * dumpRule
   19541              :  *              Dump a rule
   19542              :  */
   19543              : static void
   19544            0 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   19545              : {
   19546            0 :         DumpOptions *dopt = fout->dopt;
   19547            0 :         TableInfo  *tbinfo = rinfo->ruletable;
   19548            0 :         bool            is_view;
   19549            0 :         PQExpBuffer query;
   19550            0 :         PQExpBuffer cmd;
   19551            0 :         PQExpBuffer delcmd;
   19552            0 :         PQExpBuffer ruleprefix;
   19553            0 :         char       *qtabname;
   19554            0 :         PGresult   *res;
   19555            0 :         char       *tag;
   19556              : 
   19557              :         /* Do nothing if not dumping schema */
   19558            0 :         if (!dopt->dumpSchema)
   19559            0 :                 return;
   19560              : 
   19561              :         /*
   19562              :          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   19563              :          * we do not want to dump it as a separate object.
   19564              :          */
   19565            0 :         if (!rinfo->separate)
   19566            0 :                 return;
   19567              : 
   19568              :         /*
   19569              :          * If it's an ON SELECT rule, we want to print it as a view definition,
   19570              :          * instead of a rule.
   19571              :          */
   19572            0 :         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   19573              : 
   19574            0 :         query = createPQExpBuffer();
   19575            0 :         cmd = createPQExpBuffer();
   19576            0 :         delcmd = createPQExpBuffer();
   19577            0 :         ruleprefix = createPQExpBuffer();
   19578              : 
   19579            0 :         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19580              : 
   19581            0 :         if (is_view)
   19582              :         {
   19583            0 :                 PQExpBuffer result;
   19584              : 
   19585              :                 /*
   19586              :                  * We need OR REPLACE here because we'll be replacing a dummy view.
   19587              :                  * Otherwise this should look largely like the regular view dump code.
   19588              :                  */
   19589            0 :                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   19590            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19591            0 :                 if (nonemptyReloptions(tbinfo->reloptions))
   19592              :                 {
   19593            0 :                         appendPQExpBufferStr(cmd, " WITH (");
   19594            0 :                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   19595            0 :                         appendPQExpBufferChar(cmd, ')');
   19596            0 :                 }
   19597            0 :                 result = createViewAsClause(fout, tbinfo);
   19598            0 :                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
   19599            0 :                 destroyPQExpBuffer(result);
   19600            0 :                 if (tbinfo->checkoption != NULL)
   19601            0 :                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   19602            0 :                                                           tbinfo->checkoption);
   19603            0 :                 appendPQExpBufferStr(cmd, ";\n");
   19604            0 :         }
   19605              :         else
   19606              :         {
   19607              :                 /* In the rule case, just print pg_get_ruledef's result verbatim */
   19608            0 :                 appendPQExpBuffer(query,
   19609              :                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   19610            0 :                                                   rinfo->dobj.catId.oid);
   19611              : 
   19612            0 :                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19613              : 
   19614            0 :                 if (PQntuples(res) != 1)
   19615            0 :                         pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   19616              :                                          rinfo->dobj.name, tbinfo->dobj.name);
   19617              : 
   19618            0 :                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   19619              : 
   19620            0 :                 PQclear(res);
   19621              :         }
   19622              : 
   19623              :         /*
   19624              :          * Add the command to alter the rules replication firing semantics if it
   19625              :          * differs from the default.
   19626              :          */
   19627            0 :         if (rinfo->ev_enabled != 'O')
   19628              :         {
   19629            0 :                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   19630            0 :                 switch (rinfo->ev_enabled)
   19631              :                 {
   19632              :                         case 'A':
   19633            0 :                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   19634            0 :                                                                   fmtId(rinfo->dobj.name));
   19635            0 :                                 break;
   19636              :                         case 'R':
   19637            0 :                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   19638            0 :                                                                   fmtId(rinfo->dobj.name));
   19639            0 :                                 break;
   19640              :                         case 'D':
   19641            0 :                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   19642            0 :                                                                   fmtId(rinfo->dobj.name));
   19643            0 :                                 break;
   19644              :                 }
   19645            0 :         }
   19646              : 
   19647            0 :         if (is_view)
   19648              :         {
   19649              :                 /*
   19650              :                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   19651              :                  * REPLACE VIEW to replace the rule with something with minimal
   19652              :                  * dependencies.
   19653              :                  */
   19654            0 :                 PQExpBuffer result;
   19655              : 
   19656            0 :                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   19657            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19658            0 :                 result = createDummyViewAsClause(fout, tbinfo);
   19659            0 :                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   19660            0 :                 destroyPQExpBuffer(result);
   19661            0 :         }
   19662              :         else
   19663              :         {
   19664            0 :                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
   19665            0 :                                                   fmtId(rinfo->dobj.name));
   19666            0 :                 appendPQExpBuffer(delcmd, "ON %s;\n",
   19667            0 :                                                   fmtQualifiedDumpable(tbinfo));
   19668              :         }
   19669              : 
   19670            0 :         appendPQExpBuffer(ruleprefix, "RULE %s ON",
   19671            0 :                                           fmtId(rinfo->dobj.name));
   19672              : 
   19673            0 :         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   19674              : 
   19675            0 :         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19676            0 :                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   19677            0 :                                          ARCHIVE_OPTS(.tag = tag,
   19678              :                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19679              :                                                                   .owner = tbinfo->rolname,
   19680              :                                                                   .description = "RULE",
   19681              :                                                                   .section = SECTION_POST_DATA,
   19682              :                                                                   .createStmt = cmd->data,
   19683              :                                                                   .dropStmt = delcmd->data));
   19684              : 
   19685              :         /* Dump rule comments */
   19686            0 :         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19687            0 :                 dumpComment(fout, ruleprefix->data, qtabname,
   19688            0 :                                         tbinfo->dobj.namespace->dobj.name,
   19689            0 :                                         tbinfo->rolname,
   19690            0 :                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   19691              : 
   19692            0 :         free(tag);
   19693            0 :         destroyPQExpBuffer(query);
   19694            0 :         destroyPQExpBuffer(cmd);
   19695            0 :         destroyPQExpBuffer(delcmd);
   19696            0 :         destroyPQExpBuffer(ruleprefix);
   19697            0 :         free(qtabname);
   19698            0 : }
   19699              : 
   19700              : /*
   19701              :  * getExtensionMembership --- obtain extension membership data
   19702              :  *
   19703              :  * We need to identify objects that are extension members as soon as they're
   19704              :  * loaded, so that we can correctly determine whether they need to be dumped.
   19705              :  * Generally speaking, extension member objects will get marked as *not* to
   19706              :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   19707              :  * command.  However, in binary upgrade mode we still need to dump the members
   19708              :  * individually.
   19709              :  */
   19710              : void
   19711            0 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   19712              :                                            int numExtensions)
   19713              : {
   19714            0 :         PQExpBuffer query;
   19715            0 :         PGresult   *res;
   19716            0 :         int                     ntups,
   19717              :                                 i;
   19718            0 :         int                     i_classid,
   19719              :                                 i_objid,
   19720              :                                 i_refobjid;
   19721            0 :         ExtensionInfo *ext;
   19722              : 
   19723              :         /* Nothing to do if no extensions */
   19724            0 :         if (numExtensions == 0)
   19725            0 :                 return;
   19726              : 
   19727            0 :         query = createPQExpBuffer();
   19728              : 
   19729              :         /* refclassid constraint is redundant but may speed the search */
   19730            0 :         appendPQExpBufferStr(query, "SELECT "
   19731              :                                                  "classid, objid, refobjid "
   19732              :                                                  "FROM pg_depend "
   19733              :                                                  "WHERE refclassid = 'pg_extension'::regclass "
   19734              :                                                  "AND deptype = 'e' "
   19735              :                                                  "ORDER BY 3");
   19736              : 
   19737            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19738              : 
   19739            0 :         ntups = PQntuples(res);
   19740              : 
   19741            0 :         i_classid = PQfnumber(res, "classid");
   19742            0 :         i_objid = PQfnumber(res, "objid");
   19743            0 :         i_refobjid = PQfnumber(res, "refobjid");
   19744              : 
   19745              :         /*
   19746              :          * Since we ordered the SELECT by referenced ID, we can expect that
   19747              :          * multiple entries for the same extension will appear together; this
   19748              :          * saves on searches.
   19749              :          */
   19750            0 :         ext = NULL;
   19751              : 
   19752            0 :         for (i = 0; i < ntups; i++)
   19753              :         {
   19754            0 :                 CatalogId       objId;
   19755            0 :                 Oid                     extId;
   19756              : 
   19757            0 :                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   19758            0 :                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
   19759            0 :                 extId = atooid(PQgetvalue(res, i, i_refobjid));
   19760              : 
   19761            0 :                 if (ext == NULL ||
   19762            0 :                         ext->dobj.catId.oid != extId)
   19763            0 :                         ext = findExtensionByOid(extId);
   19764              : 
   19765            0 :                 if (ext == NULL)
   19766              :                 {
   19767              :                         /* shouldn't happen */
   19768            0 :                         pg_log_warning("could not find referenced extension %u", extId);
   19769            0 :                         continue;
   19770              :                 }
   19771              : 
   19772            0 :                 recordExtensionMembership(objId, ext);
   19773            0 :         }
   19774              : 
   19775            0 :         PQclear(res);
   19776              : 
   19777            0 :         destroyPQExpBuffer(query);
   19778            0 : }
   19779              : 
   19780              : /*
   19781              :  * processExtensionTables --- deal with extension configuration tables
   19782              :  *
   19783              :  * There are two parts to this process:
   19784              :  *
   19785              :  * 1. Identify and create dump records for extension configuration tables.
   19786              :  *
   19787              :  *        Extensions can mark tables as "configuration", which means that the user
   19788              :  *        is able and expected to modify those tables after the extension has been
   19789              :  *        loaded.  For these tables, we dump out only the data- the structure is
   19790              :  *        expected to be handled at CREATE EXTENSION time, including any indexes or
   19791              :  *        foreign keys, which brings us to-
   19792              :  *
   19793              :  * 2. Record FK dependencies between configuration tables.
   19794              :  *
   19795              :  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
   19796              :  *        the data is loaded, we have to work out what the best order for reloading
   19797              :  *        the data is, to avoid FK violations when the tables are restored.  This is
   19798              :  *        not perfect- we can't handle circular dependencies and if any exist they
   19799              :  *        will cause an invalid dump to be produced (though at least all of the data
   19800              :  *        is included for a user to manually restore).  This is currently documented
   19801              :  *        but perhaps we can provide a better solution in the future.
   19802              :  */
   19803              : void
   19804            0 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   19805              :                                            int numExtensions)
   19806              : {
   19807            0 :         DumpOptions *dopt = fout->dopt;
   19808            0 :         PQExpBuffer query;
   19809            0 :         PGresult   *res;
   19810            0 :         int                     ntups,
   19811              :                                 i;
   19812            0 :         int                     i_conrelid,
   19813              :                                 i_confrelid;
   19814              : 
   19815              :         /* Nothing to do if no extensions */
   19816            0 :         if (numExtensions == 0)
   19817            0 :                 return;
   19818              : 
   19819              :         /*
   19820              :          * Identify extension configuration tables and create TableDataInfo
   19821              :          * objects for them, ensuring their data will be dumped even though the
   19822              :          * tables themselves won't be.
   19823              :          *
   19824              :          * Note that we create TableDataInfo objects even in schema-only mode, ie,
   19825              :          * user data in a configuration table is treated like schema data. This
   19826              :          * seems appropriate since system data in a config table would get
   19827              :          * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   19828              :          * list of extensions to be included, none of its data is dumped.
   19829              :          */
   19830            0 :         for (i = 0; i < numExtensions; i++)
   19831              :         {
   19832            0 :                 ExtensionInfo *curext = &(extinfo[i]);
   19833            0 :                 char       *extconfig = curext->extconfig;
   19834            0 :                 char       *extcondition = curext->extcondition;
   19835            0 :                 char      **extconfigarray = NULL;
   19836            0 :                 char      **extconditionarray = NULL;
   19837            0 :                 int                     nconfigitems = 0;
   19838            0 :                 int                     nconditionitems = 0;
   19839              : 
   19840              :                 /*
   19841              :                  * Check if this extension is listed as to include in the dump.  If
   19842              :                  * not, any table data associated with it is discarded.
   19843              :                  */
   19844            0 :                 if (extension_include_oids.head != NULL &&
   19845            0 :                         !simple_oid_list_member(&extension_include_oids,
   19846            0 :                                                                         curext->dobj.catId.oid))
   19847            0 :                         continue;
   19848              : 
   19849              :                 /*
   19850              :                  * Check if this extension is listed as to exclude in the dump.  If
   19851              :                  * yes, any table data associated with it is discarded.
   19852              :                  */
   19853            0 :                 if (extension_exclude_oids.head != NULL &&
   19854            0 :                         simple_oid_list_member(&extension_exclude_oids,
   19855            0 :                                                                    curext->dobj.catId.oid))
   19856            0 :                         continue;
   19857              : 
   19858            0 :                 if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   19859              :                 {
   19860            0 :                         int                     j;
   19861              : 
   19862            0 :                         if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   19863            0 :                                 pg_fatal("could not parse %s array", "extconfig");
   19864            0 :                         if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   19865            0 :                                 pg_fatal("could not parse %s array", "extcondition");
   19866            0 :                         if (nconfigitems != nconditionitems)
   19867            0 :                                 pg_fatal("mismatched number of configurations and conditions for extension");
   19868              : 
   19869            0 :                         for (j = 0; j < nconfigitems; j++)
   19870              :                         {
   19871            0 :                                 TableInfo  *configtbl;
   19872            0 :                                 Oid                     configtbloid = atooid(extconfigarray[j]);
   19873            0 :                                 bool            dumpobj =
   19874            0 :                                         curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   19875              : 
   19876            0 :                                 configtbl = findTableByOid(configtbloid);
   19877            0 :                                 if (configtbl == NULL)
   19878            0 :                                         continue;
   19879              : 
   19880              :                                 /*
   19881              :                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   19882              :                                  * unless the table or its schema is explicitly included
   19883              :                                  */
   19884            0 :                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   19885              :                                 {
   19886              :                                         /* check table explicitly requested */
   19887            0 :                                         if (table_include_oids.head != NULL &&
   19888            0 :                                                 simple_oid_list_member(&table_include_oids,
   19889            0 :                                                                                            configtbloid))
   19890            0 :                                                 dumpobj = true;
   19891              : 
   19892              :                                         /* check table's schema explicitly requested */
   19893            0 :                                         if (configtbl->dobj.namespace->dobj.dump &
   19894              :                                                 DUMP_COMPONENT_DATA)
   19895            0 :                                                 dumpobj = true;
   19896            0 :                                 }
   19897              : 
   19898              :                                 /* check table excluded by an exclusion switch */
   19899            0 :                                 if (table_exclude_oids.head != NULL &&
   19900            0 :                                         simple_oid_list_member(&table_exclude_oids,
   19901            0 :                                                                                    configtbloid))
   19902            0 :                                         dumpobj = false;
   19903              : 
   19904              :                                 /* check schema excluded by an exclusion switch */
   19905            0 :                                 if (simple_oid_list_member(&schema_exclude_oids,
   19906            0 :                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
   19907            0 :                                         dumpobj = false;
   19908              : 
   19909            0 :                                 if (dumpobj)
   19910              :                                 {
   19911            0 :                                         makeTableDataInfo(dopt, configtbl);
   19912            0 :                                         if (configtbl->dataObj != NULL)
   19913              :                                         {
   19914            0 :                                                 if (strlen(extconditionarray[j]) > 0)
   19915            0 :                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   19916            0 :                                         }
   19917            0 :                                 }
   19918            0 :                         }
   19919            0 :                 }
   19920            0 :                 if (extconfigarray)
   19921            0 :                         free(extconfigarray);
   19922            0 :                 if (extconditionarray)
   19923            0 :                         free(extconditionarray);
   19924            0 :         }
   19925              : 
   19926              :         /*
   19927              :          * Now that all the TableDataInfo objects have been created for all the
   19928              :          * extensions, check their FK dependencies and register them to try and
   19929              :          * dump the data out in an order that they can be restored in.
   19930              :          *
   19931              :          * Note that this is not a problem for user tables as their FKs are
   19932              :          * recreated after the data has been loaded.
   19933              :          */
   19934              : 
   19935            0 :         query = createPQExpBuffer();
   19936              : 
   19937            0 :         printfPQExpBuffer(query,
   19938              :                                           "SELECT conrelid, confrelid "
   19939              :                                           "FROM pg_constraint "
   19940              :                                           "JOIN pg_depend ON (objid = confrelid) "
   19941              :                                           "WHERE contype = 'f' "
   19942              :                                           "AND refclassid = 'pg_extension'::regclass "
   19943              :                                           "AND classid = 'pg_class'::regclass;");
   19944              : 
   19945            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19946            0 :         ntups = PQntuples(res);
   19947              : 
   19948            0 :         i_conrelid = PQfnumber(res, "conrelid");
   19949            0 :         i_confrelid = PQfnumber(res, "confrelid");
   19950              : 
   19951              :         /* Now get the dependencies and register them */
   19952            0 :         for (i = 0; i < ntups; i++)
   19953              :         {
   19954            0 :                 Oid                     conrelid,
   19955              :                                         confrelid;
   19956            0 :                 TableInfo  *reftable,
   19957              :                                    *contable;
   19958              : 
   19959            0 :                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   19960            0 :                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   19961            0 :                 contable = findTableByOid(conrelid);
   19962            0 :                 reftable = findTableByOid(confrelid);
   19963              : 
   19964            0 :                 if (reftable == NULL ||
   19965            0 :                         reftable->dataObj == NULL ||
   19966            0 :                         contable == NULL ||
   19967            0 :                         contable->dataObj == NULL)
   19968            0 :                         continue;
   19969              : 
   19970              :                 /*
   19971              :                  * Make referencing TABLE_DATA object depend on the referenced table's
   19972              :                  * TABLE_DATA object.
   19973              :                  */
   19974            0 :                 addObjectDependency(&contable->dataObj->dobj,
   19975            0 :                                                         reftable->dataObj->dobj.dumpId);
   19976            0 :         }
   19977            0 :         PQclear(res);
   19978            0 :         destroyPQExpBuffer(query);
   19979            0 : }
   19980              : 
   19981              : /*
   19982              :  * getDependencies --- obtain available dependency data
   19983              :  */
   19984              : static void
   19985            0 : getDependencies(Archive *fout)
   19986              : {
   19987            0 :         PQExpBuffer query;
   19988            0 :         PGresult   *res;
   19989            0 :         int                     ntups,
   19990              :                                 i;
   19991            0 :         int                     i_classid,
   19992              :                                 i_objid,
   19993              :                                 i_refclassid,
   19994              :                                 i_refobjid,
   19995              :                                 i_deptype;
   19996            0 :         DumpableObject *dobj,
   19997              :                            *refdobj;
   19998              : 
   19999            0 :         pg_log_info("reading dependency data");
   20000              : 
   20001            0 :         query = createPQExpBuffer();
   20002              : 
   20003              :         /*
   20004              :          * Messy query to collect the dependency data we need.  Note that we
   20005              :          * ignore the sub-object column, so that dependencies of or on a column
   20006              :          * look the same as dependencies of or on a whole table.
   20007              :          *
   20008              :          * PIN dependencies aren't interesting, and EXTENSION dependencies were
   20009              :          * already processed by getExtensionMembership.
   20010              :          */
   20011            0 :         appendPQExpBufferStr(query, "SELECT "
   20012              :                                                  "classid, objid, refclassid, refobjid, deptype "
   20013              :                                                  "FROM pg_depend "
   20014              :                                                  "WHERE deptype != 'p' AND deptype != 'e'\n");
   20015              : 
   20016              :         /*
   20017              :          * Since we don't treat pg_amop entries as separate DumpableObjects, we
   20018              :          * have to translate their dependencies into dependencies of their parent
   20019              :          * opfamily.  Ignore internal dependencies though, as those will point to
   20020              :          * their parent opclass, which we needn't consider here (and if we did,
   20021              :          * it'd just result in circular dependencies).  Also, "loose" opfamily
   20022              :          * entries will have dependencies on their parent opfamily, which we
   20023              :          * should drop since they'd likewise become useless self-dependencies.
   20024              :          * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   20025              :          */
   20026            0 :         appendPQExpBufferStr(query, "UNION ALL\n"
   20027              :                                                  "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   20028              :                                                  "FROM pg_depend d, pg_amop o "
   20029              :                                                  "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20030              :                                                  "classid = 'pg_amop'::regclass AND objid = o.oid "
   20031              :                                                  "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   20032              : 
   20033              :         /* Likewise for pg_amproc entries */
   20034            0 :         appendPQExpBufferStr(query, "UNION ALL\n"
   20035              :                                                  "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   20036              :                                                  "FROM pg_depend d, pg_amproc p "
   20037              :                                                  "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20038              :                                                  "classid = 'pg_amproc'::regclass AND objid = p.oid "
   20039              :                                                  "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   20040              : 
   20041              :         /* Sort the output for efficiency below */
   20042            0 :         appendPQExpBufferStr(query, "ORDER BY 1,2");
   20043              : 
   20044            0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20045              : 
   20046            0 :         ntups = PQntuples(res);
   20047              : 
   20048            0 :         i_classid = PQfnumber(res, "classid");
   20049            0 :         i_objid = PQfnumber(res, "objid");
   20050            0 :         i_refclassid = PQfnumber(res, "refclassid");
   20051            0 :         i_refobjid = PQfnumber(res, "refobjid");
   20052            0 :         i_deptype = PQfnumber(res, "deptype");
   20053              : 
   20054              :         /*
   20055              :          * Since we ordered the SELECT by referencing ID, we can expect that
   20056              :          * multiple entries for the same object will appear together; this saves
   20057              :          * on searches.
   20058              :          */
   20059            0 :         dobj = NULL;
   20060              : 
   20061            0 :         for (i = 0; i < ntups; i++)
   20062              :         {
   20063            0 :                 CatalogId       objId;
   20064            0 :                 CatalogId       refobjId;
   20065            0 :                 char            deptype;
   20066              : 
   20067            0 :                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20068            0 :                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20069            0 :                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   20070            0 :                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   20071            0 :                 deptype = *(PQgetvalue(res, i, i_deptype));
   20072              : 
   20073            0 :                 if (dobj == NULL ||
   20074            0 :                         dobj->catId.tableoid != objId.tableoid ||
   20075            0 :                         dobj->catId.oid != objId.oid)
   20076            0 :                         dobj = findObjectByCatalogId(objId);
   20077              : 
   20078              :                 /*
   20079              :                  * Failure to find objects mentioned in pg_depend is not unexpected,
   20080              :                  * since for example we don't collect info about TOAST tables.
   20081              :                  */
   20082            0 :                 if (dobj == NULL)
   20083              :                 {
   20084              : #ifdef NOT_USED
   20085              :                         pg_log_warning("no referencing object %u %u",
   20086              :                                                    objId.tableoid, objId.oid);
   20087              : #endif
   20088            0 :                         continue;
   20089              :                 }
   20090              : 
   20091            0 :                 refdobj = findObjectByCatalogId(refobjId);
   20092              : 
   20093            0 :                 if (refdobj == NULL)
   20094              :                 {
   20095              : #ifdef NOT_USED
   20096              :                         pg_log_warning("no referenced object %u %u",
   20097              :                                                    refobjId.tableoid, refobjId.oid);
   20098              : #endif
   20099            0 :                         continue;
   20100              :                 }
   20101              : 
   20102              :                 /*
   20103              :                  * For 'x' dependencies, mark the object for later; we still add the
   20104              :                  * normal dependency, for possible ordering purposes.  Currently
   20105              :                  * pg_dump_sort.c knows to put extensions ahead of all object types
   20106              :                  * that could possibly depend on them, but this is safer.
   20107              :                  */
   20108            0 :                 if (deptype == 'x')
   20109            0 :                         dobj->depends_on_ext = true;
   20110              : 
   20111              :                 /*
   20112              :                  * Ordinarily, table rowtypes have implicit dependencies on their
   20113              :                  * tables.  However, for a composite type the implicit dependency goes
   20114              :                  * the other way in pg_depend; which is the right thing for DROP but
   20115              :                  * it doesn't produce the dependency ordering we need. So in that one
   20116              :                  * case, we reverse the direction of the dependency.
   20117              :                  */
   20118            0 :                 if (deptype == 'i' &&
   20119            0 :                         dobj->objType == DO_TABLE &&
   20120            0 :                         refdobj->objType == DO_TYPE)
   20121            0 :                         addObjectDependency(refdobj, dobj->dumpId);
   20122              :                 else
   20123              :                         /* normal case */
   20124            0 :                         addObjectDependency(dobj, refdobj->dumpId);
   20125            0 :         }
   20126              : 
   20127            0 :         PQclear(res);
   20128              : 
   20129            0 :         destroyPQExpBuffer(query);
   20130            0 : }
   20131              : 
   20132              : 
   20133              : /*
   20134              :  * createBoundaryObjects - create dummy DumpableObjects to represent
   20135              :  * dump section boundaries.
   20136              :  */
   20137              : static DumpableObject *
   20138            0 : createBoundaryObjects(void)
   20139              : {
   20140            0 :         DumpableObject *dobjs;
   20141              : 
   20142            0 :         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
   20143              : 
   20144            0 :         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   20145            0 :         dobjs[0].catId = nilCatalogId;
   20146            0 :         AssignDumpId(dobjs + 0);
   20147            0 :         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   20148              : 
   20149            0 :         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   20150            0 :         dobjs[1].catId = nilCatalogId;
   20151            0 :         AssignDumpId(dobjs + 1);
   20152            0 :         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   20153              : 
   20154            0 :         return dobjs;
   20155            0 : }
   20156              : 
   20157              : /*
   20158              :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   20159              :  * section boundaries.
   20160              :  */
   20161              : static void
   20162            0 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   20163              :                                                 DumpableObject *boundaryObjs)
   20164              : {
   20165            0 :         DumpableObject *preDataBound = boundaryObjs + 0;
   20166            0 :         DumpableObject *postDataBound = boundaryObjs + 1;
   20167            0 :         int                     i;
   20168              : 
   20169            0 :         for (i = 0; i < numObjs; i++)
   20170              :         {
   20171            0 :                 DumpableObject *dobj = dobjs[i];
   20172              : 
   20173              :                 /*
   20174              :                  * The classification of object types here must match the SECTION_xxx
   20175              :                  * values assigned during subsequent ArchiveEntry calls!
   20176              :                  */
   20177            0 :                 switch (dobj->objType)
   20178              :                 {
   20179              :                         case DO_NAMESPACE:
   20180              :                         case DO_EXTENSION:
   20181              :                         case DO_TYPE:
   20182              :                         case DO_SHELL_TYPE:
   20183              :                         case DO_FUNC:
   20184              :                         case DO_AGG:
   20185              :                         case DO_OPERATOR:
   20186              :                         case DO_ACCESS_METHOD:
   20187              :                         case DO_OPCLASS:
   20188              :                         case DO_OPFAMILY:
   20189              :                         case DO_COLLATION:
   20190              :                         case DO_CONVERSION:
   20191              :                         case DO_TABLE:
   20192              :                         case DO_TABLE_ATTACH:
   20193              :                         case DO_ATTRDEF:
   20194              :                         case DO_PROCLANG:
   20195              :                         case DO_CAST:
   20196              :                         case DO_DUMMY_TYPE:
   20197              :                         case DO_TSPARSER:
   20198              :                         case DO_TSDICT:
   20199              :                         case DO_TSTEMPLATE:
   20200              :                         case DO_TSCONFIG:
   20201              :                         case DO_FDW:
   20202              :                         case DO_FOREIGN_SERVER:
   20203              :                         case DO_TRANSFORM:
   20204              :                                 /* Pre-data objects: must come before the pre-data boundary */
   20205            0 :                                 addObjectDependency(preDataBound, dobj->dumpId);
   20206            0 :                                 break;
   20207              :                         case DO_TABLE_DATA:
   20208              :                         case DO_SEQUENCE_SET:
   20209              :                         case DO_LARGE_OBJECT:
   20210              :                         case DO_LARGE_OBJECT_DATA:
   20211              :                                 /* Data objects: must come between the boundaries */
   20212            0 :                                 addObjectDependency(dobj, preDataBound->dumpId);
   20213            0 :                                 addObjectDependency(postDataBound, dobj->dumpId);
   20214            0 :                                 break;
   20215              :                         case DO_INDEX:
   20216              :                         case DO_INDEX_ATTACH:
   20217              :                         case DO_STATSEXT:
   20218              :                         case DO_REFRESH_MATVIEW:
   20219              :                         case DO_TRIGGER:
   20220              :                         case DO_EVENT_TRIGGER:
   20221              :                         case DO_DEFAULT_ACL:
   20222              :                         case DO_POLICY:
   20223              :                         case DO_PUBLICATION:
   20224              :                         case DO_PUBLICATION_REL:
   20225              :                         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   20226              :                         case DO_SUBSCRIPTION:
   20227              :                         case DO_SUBSCRIPTION_REL:
   20228              :                                 /* Post-data objects: must come after the post-data boundary */
   20229            0 :                                 addObjectDependency(dobj, postDataBound->dumpId);
   20230            0 :                                 break;
   20231              :                         case DO_RULE:
   20232              :                                 /* Rules are post-data, but only if dumped separately */
   20233            0 :                                 if (((RuleInfo *) dobj)->separate)
   20234            0 :                                         addObjectDependency(dobj, postDataBound->dumpId);
   20235            0 :                                 break;
   20236              :                         case DO_CONSTRAINT:
   20237              :                         case DO_FK_CONSTRAINT:
   20238              :                                 /* Constraints are post-data, but only if dumped separately */
   20239            0 :                                 if (((ConstraintInfo *) dobj)->separate)
   20240            0 :                                         addObjectDependency(dobj, postDataBound->dumpId);
   20241            0 :                                 break;
   20242              :                         case DO_PRE_DATA_BOUNDARY:
   20243              :                                 /* nothing to do */
   20244              :                                 break;
   20245              :                         case DO_POST_DATA_BOUNDARY:
   20246              :                                 /* must come after the pre-data boundary */
   20247            0 :                                 addObjectDependency(dobj, preDataBound->dumpId);
   20248            0 :                                 break;
   20249              :                         case DO_REL_STATS:
   20250              :                                 /* stats section varies by parent object type, DATA or POST */
   20251            0 :                                 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
   20252              :                                 {
   20253            0 :                                         addObjectDependency(dobj, preDataBound->dumpId);
   20254            0 :                                         addObjectDependency(postDataBound, dobj->dumpId);
   20255            0 :                                 }
   20256              :                                 else
   20257            0 :                                         addObjectDependency(dobj, postDataBound->dumpId);
   20258            0 :                                 break;
   20259              :                 }
   20260            0 :         }
   20261            0 : }
   20262              : 
   20263              : 
   20264              : /*
   20265              :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   20266              :  *
   20267              :  * The raw dependency data obtained by getDependencies() is not terribly
   20268              :  * useful in an archive dump, because in many cases there are dependency
   20269              :  * chains linking through objects that don't appear explicitly in the dump.
   20270              :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   20271              :  * will depend on other objects --- but the rule will not appear as a separate
   20272              :  * object in the dump.  We need to adjust the view's dependencies to include
   20273              :  * whatever the rule depends on that is included in the dump.
   20274              :  *
   20275              :  * Just to make things more complicated, there are also "special" dependencies
   20276              :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   20277              :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   20278              :  * its table.  In these cases we must leave the dependencies strictly as-is
   20279              :  * even if they refer to not-to-be-dumped objects.
   20280              :  *
   20281              :  * To handle this, the convention is that "special" dependencies are created
   20282              :  * during ArchiveEntry calls, and an archive TOC item that has any such
   20283              :  * entries will not be touched here.  Otherwise, we recursively search the
   20284              :  * DumpableObject data structures to build the correct dependencies for each
   20285              :  * archive TOC item.
   20286              :  */
   20287              : static void
   20288            0 : BuildArchiveDependencies(Archive *fout)
   20289              : {
   20290            0 :         ArchiveHandle *AH = (ArchiveHandle *) fout;
   20291            0 :         TocEntry   *te;
   20292              : 
   20293              :         /* Scan all TOC entries in the archive */
   20294            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
   20295              :         {
   20296            0 :                 DumpableObject *dobj;
   20297            0 :                 DumpId     *dependencies;
   20298            0 :                 int                     nDeps;
   20299            0 :                 int                     allocDeps;
   20300              : 
   20301              :                 /* No need to process entries that will not be dumped */
   20302            0 :                 if (te->reqs == 0)
   20303            0 :                         continue;
   20304              :                 /* Ignore entries that already have "special" dependencies */
   20305            0 :                 if (te->nDeps > 0)
   20306            0 :                         continue;
   20307              :                 /* Otherwise, look up the item's original DumpableObject, if any */
   20308            0 :                 dobj = findObjectByDumpId(te->dumpId);
   20309            0 :                 if (dobj == NULL)
   20310            0 :                         continue;
   20311              :                 /* No work if it has no dependencies */
   20312            0 :                 if (dobj->nDeps <= 0)
   20313            0 :                         continue;
   20314              :                 /* Set up work array */
   20315            0 :                 allocDeps = 64;
   20316            0 :                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
   20317            0 :                 nDeps = 0;
   20318              :                 /* Recursively find all dumpable dependencies */
   20319            0 :                 findDumpableDependencies(AH, dobj,
   20320              :                                                                  &dependencies, &nDeps, &allocDeps);
   20321              :                 /* And save 'em ... */
   20322            0 :                 if (nDeps > 0)
   20323              :                 {
   20324            0 :                         dependencies = (DumpId *) pg_realloc(dependencies,
   20325            0 :                                                                                                  nDeps * sizeof(DumpId));
   20326            0 :                         te->dependencies = dependencies;
   20327            0 :                         te->nDeps = nDeps;
   20328            0 :                 }
   20329              :                 else
   20330            0 :                         free(dependencies);
   20331            0 :         }
   20332            0 : }
   20333              : 
   20334              : /* Recursive search subroutine for BuildArchiveDependencies */
   20335              : static void
   20336            0 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   20337              :                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
   20338              : {
   20339            0 :         int                     i;
   20340              : 
   20341              :         /*
   20342              :          * Ignore section boundary objects: if we search through them, we'll
   20343              :          * report lots of bogus dependencies.
   20344              :          */
   20345            0 :         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   20346            0 :                 dobj->objType == DO_POST_DATA_BOUNDARY)
   20347            0 :                 return;
   20348              : 
   20349            0 :         for (i = 0; i < dobj->nDeps; i++)
   20350              :         {
   20351            0 :                 DumpId          depid = dobj->dependencies[i];
   20352              : 
   20353            0 :                 if (TocIDRequired(AH, depid) != 0)
   20354              :                 {
   20355              :                         /* Object will be dumped, so just reference it as a dependency */
   20356            0 :                         if (*nDeps >= *allocDeps)
   20357              :                         {
   20358            0 :                                 *allocDeps *= 2;
   20359            0 :                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
   20360            0 :                                                                                                           *allocDeps * sizeof(DumpId));
   20361            0 :                         }
   20362            0 :                         (*dependencies)[*nDeps] = depid;
   20363            0 :                         (*nDeps)++;
   20364            0 :                 }
   20365              :                 else
   20366              :                 {
   20367              :                         /*
   20368              :                          * Object will not be dumped, so recursively consider its deps. We
   20369              :                          * rely on the assumption that sortDumpableObjects already broke
   20370              :                          * any dependency loops, else we might recurse infinitely.
   20371              :                          */
   20372            0 :                         DumpableObject *otherdobj = findObjectByDumpId(depid);
   20373              : 
   20374            0 :                         if (otherdobj)
   20375            0 :                                 findDumpableDependencies(AH, otherdobj,
   20376            0 :                                                                                  dependencies, nDeps, allocDeps);
   20377            0 :                 }
   20378            0 :         }
   20379            0 : }
   20380              : 
   20381              : 
   20382              : /*
   20383              :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   20384              :  * given type OID.
   20385              :  *
   20386              :  * This does not guarantee to schema-qualify the output, so it should not
   20387              :  * be used to create the target object name for CREATE or ALTER commands.
   20388              :  *
   20389              :  * Note that the result is cached and must not be freed by the caller.
   20390              :  */
   20391              : static const char *
   20392            0 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   20393              : {
   20394            0 :         TypeInfo   *typeInfo;
   20395            0 :         char       *result;
   20396            0 :         PQExpBuffer query;
   20397            0 :         PGresult   *res;
   20398              : 
   20399            0 :         if (oid == 0)
   20400              :         {
   20401            0 :                 if ((opts & zeroAsStar) != 0)
   20402            0 :                         return "*";
   20403            0 :                 else if ((opts & zeroAsNone) != 0)
   20404            0 :                         return "NONE";
   20405            0 :         }
   20406              : 
   20407              :         /* see if we have the result cached in the type's TypeInfo record */
   20408            0 :         typeInfo = findTypeByOid(oid);
   20409            0 :         if (typeInfo && typeInfo->ftypname)
   20410            0 :                 return typeInfo->ftypname;
   20411              : 
   20412            0 :         query = createPQExpBuffer();
   20413            0 :         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   20414            0 :                                           oid);
   20415              : 
   20416            0 :         res = ExecuteSqlQueryForSingleRow(fout, query->data);
   20417              : 
   20418              :         /* result of format_type is already quoted */
   20419            0 :         result = pg_strdup(PQgetvalue(res, 0, 0));
   20420              : 
   20421            0 :         PQclear(res);
   20422            0 :         destroyPQExpBuffer(query);
   20423              : 
   20424              :         /*
   20425              :          * Cache the result for re-use in later requests, if possible.  If we
   20426              :          * don't have a TypeInfo for the type, the string will be leaked once the
   20427              :          * caller is done with it ... but that case really should not happen, so
   20428              :          * leaking if it does seems acceptable.
   20429              :          */
   20430            0 :         if (typeInfo)
   20431            0 :                 typeInfo->ftypname = result;
   20432              : 
   20433            0 :         return result;
   20434            0 : }
   20435              : 
   20436              : /*
   20437              :  * Return a column list clause for the given relation.
   20438              :  *
   20439              :  * Special case: if there are no undropped columns in the relation, return
   20440              :  * "", not an invalid "()" column list.
   20441              :  */
   20442              : static const char *
   20443            0 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   20444              : {
   20445            0 :         int                     numatts = ti->numatts;
   20446            0 :         char      **attnames = ti->attnames;
   20447            0 :         bool       *attisdropped = ti->attisdropped;
   20448            0 :         char       *attgenerated = ti->attgenerated;
   20449            0 :         bool            needComma;
   20450            0 :         int                     i;
   20451              : 
   20452            0 :         appendPQExpBufferChar(buffer, '(');
   20453            0 :         needComma = false;
   20454            0 :         for (i = 0; i < numatts; i++)
   20455              :         {
   20456            0 :                 if (attisdropped[i])
   20457            0 :                         continue;
   20458            0 :                 if (attgenerated[i])
   20459            0 :                         continue;
   20460            0 :                 if (needComma)
   20461            0 :                         appendPQExpBufferStr(buffer, ", ");
   20462            0 :                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   20463            0 :                 needComma = true;
   20464            0 :         }
   20465              : 
   20466            0 :         if (!needComma)
   20467            0 :                 return "";                            /* no undropped columns */
   20468              : 
   20469            0 :         appendPQExpBufferChar(buffer, ')');
   20470            0 :         return buffer->data;
   20471            0 : }
   20472              : 
   20473              : /*
   20474              :  * Check if a reloptions array is nonempty.
   20475              :  */
   20476              : static bool
   20477            0 : nonemptyReloptions(const char *reloptions)
   20478              : {
   20479              :         /* Don't want to print it if it's just "{}" */
   20480            0 :         return (reloptions != NULL && strlen(reloptions) > 2);
   20481              : }
   20482              : 
   20483              : /*
   20484              :  * Format a reloptions array and append it to the given buffer.
   20485              :  *
   20486              :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   20487              :  */
   20488              : static void
   20489            0 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   20490              :                                                 const char *prefix, Archive *fout)
   20491              : {
   20492            0 :         bool            res;
   20493              : 
   20494            0 :         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   20495            0 :                                                                 fout->std_strings);
   20496            0 :         if (!res)
   20497            0 :                 pg_log_warning("could not parse %s array", "reloptions");
   20498            0 : }
   20499              : 
   20500              : /*
   20501              :  * read_dump_filters - retrieve object identifier patterns from file
   20502              :  *
   20503              :  * Parse the specified filter file for include and exclude patterns, and add
   20504              :  * them to the relevant lists.  If the filename is "-" then filters will be
   20505              :  * read from STDIN rather than a file.
   20506              :  */
   20507              : static void
   20508            0 : read_dump_filters(const char *filename, DumpOptions *dopt)
   20509              : {
   20510            0 :         FilterStateData fstate;
   20511            0 :         char       *objname;
   20512            0 :         FilterCommandType comtype;
   20513            0 :         FilterObjectType objtype;
   20514              : 
   20515            0 :         filter_init(&fstate, filename, exit_nicely);
   20516              : 
   20517            0 :         while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   20518              :         {
   20519            0 :                 if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   20520              :                 {
   20521            0 :                         switch (objtype)
   20522              :                         {
   20523              :                                 case FILTER_OBJECT_TYPE_NONE:
   20524              :                                         break;
   20525              :                                 case FILTER_OBJECT_TYPE_DATABASE:
   20526              :                                 case FILTER_OBJECT_TYPE_FUNCTION:
   20527              :                                 case FILTER_OBJECT_TYPE_INDEX:
   20528              :                                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20529              :                                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20530              :                                 case FILTER_OBJECT_TYPE_TRIGGER:
   20531            0 :                                         pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20532              :                                                                                 "include",
   20533            0 :                                                                                 filter_object_type_name(objtype));
   20534            0 :                                         exit_nicely(1);
   20535              :                                         break;          /* unreachable */
   20536              : 
   20537              :                                 case FILTER_OBJECT_TYPE_EXTENSION:
   20538            0 :                                         simple_string_list_append(&extension_include_patterns, objname);
   20539            0 :                                         break;
   20540              :                                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20541            0 :                                         simple_string_list_append(&foreign_servers_include_patterns, objname);
   20542            0 :                                         break;
   20543              :                                 case FILTER_OBJECT_TYPE_SCHEMA:
   20544            0 :                                         simple_string_list_append(&schema_include_patterns, objname);
   20545            0 :                                         dopt->include_everything = false;
   20546            0 :                                         break;
   20547              :                                 case FILTER_OBJECT_TYPE_TABLE:
   20548            0 :                                         simple_string_list_append(&table_include_patterns, objname);
   20549            0 :                                         dopt->include_everything = false;
   20550            0 :                                         break;
   20551              :                                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20552            0 :                                         simple_string_list_append(&table_include_patterns_and_children,
   20553            0 :                                                                                           objname);
   20554            0 :                                         dopt->include_everything = false;
   20555            0 :                                         break;
   20556              :                         }
   20557            0 :                 }
   20558            0 :                 else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   20559              :                 {
   20560            0 :                         switch (objtype)
   20561              :                         {
   20562              :                                 case FILTER_OBJECT_TYPE_NONE:
   20563              :                                         break;
   20564              :                                 case FILTER_OBJECT_TYPE_DATABASE:
   20565              :                                 case FILTER_OBJECT_TYPE_FUNCTION:
   20566              :                                 case FILTER_OBJECT_TYPE_INDEX:
   20567              :                                 case FILTER_OBJECT_TYPE_TRIGGER:
   20568              :                                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20569            0 :                                         pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20570              :                                                                                 "exclude",
   20571            0 :                                                                                 filter_object_type_name(objtype));
   20572            0 :                                         exit_nicely(1);
   20573              :                                         break;
   20574              : 
   20575              :                                 case FILTER_OBJECT_TYPE_EXTENSION:
   20576            0 :                                         simple_string_list_append(&extension_exclude_patterns, objname);
   20577            0 :                                         break;
   20578              :                                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20579            0 :                                         simple_string_list_append(&tabledata_exclude_patterns,
   20580            0 :                                                                                           objname);
   20581            0 :                                         break;
   20582              :                                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20583            0 :                                         simple_string_list_append(&tabledata_exclude_patterns_and_children,
   20584            0 :                                                                                           objname);
   20585            0 :                                         break;
   20586              :                                 case FILTER_OBJECT_TYPE_SCHEMA:
   20587            0 :                                         simple_string_list_append(&schema_exclude_patterns, objname);
   20588            0 :                                         break;
   20589              :                                 case FILTER_OBJECT_TYPE_TABLE:
   20590            0 :                                         simple_string_list_append(&table_exclude_patterns, objname);
   20591            0 :                                         break;
   20592              :                                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20593            0 :                                         simple_string_list_append(&table_exclude_patterns_and_children,
   20594            0 :                                                                                           objname);
   20595            0 :                                         break;
   20596              :                         }
   20597            0 :                 }
   20598              :                 else
   20599              :                 {
   20600            0 :                         Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   20601            0 :                         Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   20602              :                 }
   20603              : 
   20604            0 :                 if (objname)
   20605            0 :                         free(objname);
   20606              :         }
   20607              : 
   20608            0 :         filter_free(&fstate);
   20609            0 : }
        

Generated by: LCOV version 2.3.2-1