LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 91.5 % 8462 7739
Test Date: 2026-07-15 23:15:44 Functions: 98.9 % 189 187
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 78.9 % 3847 3035

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * pg_dump.c
       4                 :             :  *    pg_dump is a utility for dumping out a postgres database
       5                 :             :  *    into a script file.
       6                 :             :  *
       7                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :             :  *
      10                 :             :  *  pg_dump will read the system catalogs in a database and dump out a
      11                 :             :  *  script that reproduces the schema in terms of SQL that is understood
      12                 :             :  *  by PostgreSQL
      13                 :             :  *
      14                 :             :  *  Note that pg_dump runs in a transaction-snapshot mode transaction,
      15                 :             :  *  so it sees a consistent snapshot of the database including system
      16                 :             :  *  catalogs. However, it relies in part on various specialized backend
      17                 :             :  *  functions like pg_get_indexdef(), and those things tend to look at
      18                 :             :  *  the currently committed state.  So it is possible to get 'cache
      19                 :             :  *  lookup failed' error if someone performs DDL changes while a dump is
      20                 :             :  *  happening. The window for this sort of thing is from the acquisition
      21                 :             :  *  of the transaction snapshot to getSchemaData() (when pg_dump acquires
      22                 :             :  *  AccessShareLock on every table it intends to dump). It isn't very large,
      23                 :             :  *  but it can happen.
      24                 :             :  *
      25                 :             :  *  http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
      26                 :             :  *
      27                 :             :  * IDENTIFICATION
      28                 :             :  *    src/bin/pg_dump/pg_dump.c
      29                 :             :  *
      30                 :             :  *-------------------------------------------------------------------------
      31                 :             :  */
      32                 :             : #include "postgres_fe.h"
      33                 :             : 
      34                 :             : #include <unistd.h>
      35                 :             : #include <ctype.h>
      36                 :             : #include <limits.h>
      37                 :             : #ifdef HAVE_TERMIOS_H
      38                 :             : #include <termios.h>
      39                 :             : #endif
      40                 :             : 
      41                 :             : #include "access/attnum.h"
      42                 :             : #include "access/sysattr.h"
      43                 :             : #include "access/transam.h"
      44                 :             : #include "catalog/pg_aggregate_d.h"
      45                 :             : #include "catalog/pg_am_d.h"
      46                 :             : #include "catalog/pg_attribute_d.h"
      47                 :             : #include "catalog/pg_authid_d.h"
      48                 :             : #include "catalog/pg_cast_d.h"
      49                 :             : #include "catalog/pg_class_d.h"
      50                 :             : #include "catalog/pg_constraint_d.h"
      51                 :             : #include "catalog/pg_default_acl_d.h"
      52                 :             : #include "catalog/pg_largeobject_d.h"
      53                 :             : #include "catalog/pg_largeobject_metadata_d.h"
      54                 :             : #include "catalog/pg_proc_d.h"
      55                 :             : #include "catalog/pg_publication_d.h"
      56                 :             : #include "catalog/pg_shdepend_d.h"
      57                 :             : #include "catalog/pg_subscription_d.h"
      58                 :             : #include "catalog/pg_type_d.h"
      59                 :             : #include "common/connect.h"
      60                 :             : #include "common/int.h"
      61                 :             : #include "common/relpath.h"
      62                 :             : #include "common/shortest_dec.h"
      63                 :             : #include "compress_io.h"
      64                 :             : #include "dumputils.h"
      65                 :             : #include "fe_utils/option_utils.h"
      66                 :             : #include "fe_utils/string_utils.h"
      67                 :             : #include "filter.h"
      68                 :             : #include "getopt_long.h"
      69                 :             : #include "libpq/libpq-fs.h"
      70                 :             : #include "parallel.h"
      71                 :             : #include "pg_backup_db.h"
      72                 :             : #include "pg_backup_utils.h"
      73                 :             : #include "pg_dump.h"
      74                 :             : #include "statistics/statistics_format.h"
      75                 :             : #include "storage/block.h"
      76                 :             : 
      77                 :             : typedef struct
      78                 :             : {
      79                 :             :     Oid         roleoid;        /* role's OID */
      80                 :             :     const char *rolename;       /* role's name */
      81                 :             : } RoleNameItem;
      82                 :             : 
      83                 :             : typedef struct
      84                 :             : {
      85                 :             :     const char *descr;          /* comment for an object */
      86                 :             :     Oid         classoid;       /* object class (catalog OID) */
      87                 :             :     Oid         objoid;         /* object OID */
      88                 :             :     int         objsubid;       /* subobject (table column #) */
      89                 :             : } CommentItem;
      90                 :             : 
      91                 :             : typedef struct
      92                 :             : {
      93                 :             :     const char *provider;       /* label provider of this security label */
      94                 :             :     const char *label;          /* security label for an object */
      95                 :             :     Oid         classoid;       /* object class (catalog OID) */
      96                 :             :     Oid         objoid;         /* object OID */
      97                 :             :     int         objsubid;       /* subobject (table column #) */
      98                 :             : } SecLabelItem;
      99                 :             : 
     100                 :             : typedef struct
     101                 :             : {
     102                 :             :     Oid         oid;            /* object OID */
     103                 :             :     char        relkind;        /* object kind */
     104                 :             :     RelFileNumber relfilenumber;    /* object filenode */
     105                 :             :     Oid         toast_oid;      /* toast table OID */
     106                 :             :     RelFileNumber toast_relfilenumber;  /* toast table filenode */
     107                 :             :     Oid         toast_index_oid;    /* toast table index OID */
     108                 :             :     RelFileNumber toast_index_relfilenumber;    /* toast table index filenode */
     109                 :             : } BinaryUpgradeClassOidItem;
     110                 :             : 
     111                 :             : /* sequence types */
     112                 :             : typedef enum SeqType
     113                 :             : {
     114                 :             :     SEQTYPE_SMALLINT,
     115                 :             :     SEQTYPE_INTEGER,
     116                 :             :     SEQTYPE_BIGINT,
     117                 :             : } SeqType;
     118                 :             : 
     119                 :             : static const char *const SeqTypeNames[] =
     120                 :             : {
     121                 :             :     [SEQTYPE_SMALLINT] = "smallint",
     122                 :             :     [SEQTYPE_INTEGER] = "integer",
     123                 :             :     [SEQTYPE_BIGINT] = "bigint",
     124                 :             : };
     125                 :             : 
     126                 :             : StaticAssertDecl(lengthof(SeqTypeNames) == (SEQTYPE_BIGINT + 1),
     127                 :             :                  "array length mismatch");
     128                 :             : 
     129                 :             : typedef struct
     130                 :             : {
     131                 :             :     Oid         oid;            /* sequence OID */
     132                 :             :     SeqType     seqtype;        /* data type of sequence */
     133                 :             :     bool        cycled;         /* whether sequence cycles */
     134                 :             :     int64       minv;           /* minimum value */
     135                 :             :     int64       maxv;           /* maximum value */
     136                 :             :     int64       startv;         /* start value */
     137                 :             :     int64       incby;          /* increment value */
     138                 :             :     int64       cache;          /* cache size */
     139                 :             :     int64       last_value;     /* last value of sequence */
     140                 :             :     bool        is_called;      /* whether nextval advances before returning */
     141                 :             :     bool        null_seqtuple;  /* did pg_get_sequence_data return nulls? */
     142                 :             : } SequenceItem;
     143                 :             : 
     144                 :             : typedef enum OidOptions
     145                 :             : {
     146                 :             :     zeroIsError = 1,
     147                 :             :     zeroAsStar = 2,
     148                 :             :     zeroAsNone = 4,
     149                 :             : } OidOptions;
     150                 :             : 
     151                 :             : /* global decls */
     152                 :             : static bool dosync = true;      /* Issue fsync() to make dump durable on disk. */
     153                 :             : 
     154                 :             : static Oid  g_last_builtin_oid; /* value of the last builtin oid */
     155                 :             : 
     156                 :             : /* The specified names/patterns should to match at least one entity */
     157                 :             : static int  strict_names = 0;
     158                 :             : 
     159                 :             : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
     160                 :             : 
     161                 :             : /*
     162                 :             :  * Object inclusion/exclusion lists
     163                 :             :  *
     164                 :             :  * The string lists record the patterns given by command-line switches,
     165                 :             :  * which we then convert to lists of OIDs of matching objects.
     166                 :             :  */
     167                 :             : static SimpleStringList schema_include_patterns = {NULL, NULL};
     168                 :             : static SimpleOidList schema_include_oids = {NULL, NULL};
     169                 :             : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     170                 :             : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     171                 :             : 
     172                 :             : static SimpleStringList table_include_patterns = {NULL, NULL};
     173                 :             : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
     174                 :             : static SimpleOidList table_include_oids = {NULL, NULL};
     175                 :             : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     176                 :             : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
     177                 :             : static SimpleOidList table_exclude_oids = {NULL, NULL};
     178                 :             : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     179                 :             : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
     180                 :             : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     181                 :             : 
     182                 :             : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
     183                 :             : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
     184                 :             : 
     185                 :             : static SimpleStringList extension_include_patterns = {NULL, NULL};
     186                 :             : static SimpleOidList extension_include_oids = {NULL, NULL};
     187                 :             : 
     188                 :             : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
     189                 :             : static SimpleOidList extension_exclude_oids = {NULL, NULL};
     190                 :             : 
     191                 :             : static const CatalogId nilCatalogId = {0, 0};
     192                 :             : 
     193                 :             : /* override for standard extra_float_digits setting */
     194                 :             : static bool have_extra_float_digits = false;
     195                 :             : static int  extra_float_digits;
     196                 :             : 
     197                 :             : /* sorted table of role names */
     198                 :             : static RoleNameItem *rolenames = NULL;
     199                 :             : static int  nrolenames = 0;
     200                 :             : 
     201                 :             : /* sorted table of comments */
     202                 :             : static CommentItem *comments = NULL;
     203                 :             : static int  ncomments = 0;
     204                 :             : 
     205                 :             : /* sorted table of security labels */
     206                 :             : static SecLabelItem *seclabels = NULL;
     207                 :             : static int  nseclabels = 0;
     208                 :             : 
     209                 :             : /* sorted table of pg_class information for binary upgrade */
     210                 :             : static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
     211                 :             : static int  nbinaryUpgradeClassOids = 0;
     212                 :             : 
     213                 :             : /* sorted table of sequences */
     214                 :             : static SequenceItem *sequences = NULL;
     215                 :             : static int  nsequences = 0;
     216                 :             : 
     217                 :             : /* Maximum number of relations to fetch in a fetchAttributeStats() call. */
     218                 :             : #define MAX_ATTR_STATS_RELS 64
     219                 :             : 
     220                 :             : /*
     221                 :             :  * The default number of rows per INSERT when
     222                 :             :  * --inserts is specified without --rows-per-insert
     223                 :             :  */
     224                 :             : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     225                 :             : 
     226                 :             : /*
     227                 :             :  * Maximum number of large objects to group into a single ArchiveEntry.
     228                 :             :  * At some point we might want to make this user-controllable, but for now
     229                 :             :  * a hard-wired setting will suffice.
     230                 :             :  */
     231                 :             : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
     232                 :             : 
     233                 :             : /*
     234                 :             :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     235                 :             :  */
     236                 :             : #define fmtQualifiedDumpable(obj) \
     237                 :             :     fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     238                 :             :                    (obj)->dobj.name)
     239                 :             : 
     240                 :             : static void help(const char *progname);
     241                 :             : static void setup_connection(Archive *AH,
     242                 :             :                              const char *dumpencoding, const char *dumpsnapshot,
     243                 :             :                              char *use_role);
     244                 :             : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     245                 :             : static void expand_schema_name_patterns(Archive *fout,
     246                 :             :                                         SimpleStringList *patterns,
     247                 :             :                                         SimpleOidList *oids,
     248                 :             :                                         bool strict_names);
     249                 :             : static void expand_extension_name_patterns(Archive *fout,
     250                 :             :                                            SimpleStringList *patterns,
     251                 :             :                                            SimpleOidList *oids,
     252                 :             :                                            bool strict_names);
     253                 :             : static void expand_foreign_server_name_patterns(Archive *fout,
     254                 :             :                                                 SimpleStringList *patterns,
     255                 :             :                                                 SimpleOidList *oids);
     256                 :             : static void expand_table_name_patterns(Archive *fout,
     257                 :             :                                        SimpleStringList *patterns,
     258                 :             :                                        SimpleOidList *oids,
     259                 :             :                                        bool strict_names,
     260                 :             :                                        bool with_child_tables);
     261                 :             : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
     262                 :             :                                   const char *pattern);
     263                 :             : 
     264                 :             : static NamespaceInfo *findNamespace(Oid nsoid);
     265                 :             : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
     266                 :             : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
     267                 :             : static const char *getRoleName(const char *roleoid_str);
     268                 :             : static void collectRoleNames(Archive *fout);
     269                 :             : static void getAdditionalACLs(Archive *fout);
     270                 :             : static void dumpCommentExtended(Archive *fout, const char *type,
     271                 :             :                                 const char *name, const char *namespace,
     272                 :             :                                 const char *owner, CatalogId catalogId,
     273                 :             :                                 int subid, DumpId dumpId,
     274                 :             :                                 const char *initdb_comment);
     275                 :             : static inline void dumpComment(Archive *fout, const char *type,
     276                 :             :                                const char *name, const char *namespace,
     277                 :             :                                const char *owner, CatalogId catalogId,
     278                 :             :                                int subid, DumpId dumpId);
     279                 :             : static int  findComments(Oid classoid, Oid objoid, CommentItem **items);
     280                 :             : static void collectComments(Archive *fout);
     281                 :             : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     282                 :             :                          const char *namespace, const char *owner,
     283                 :             :                          CatalogId catalogId, int subid, DumpId dumpId);
     284                 :             : static int  findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
     285                 :             : static void collectSecLabels(Archive *fout);
     286                 :             : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     287                 :             : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
     288                 :             : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
     289                 :             : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
     290                 :             : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
     291                 :             : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
     292                 :             : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
     293                 :             : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
     294                 :             : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
     295                 :             : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
     296                 :             : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
     297                 :             :                                          PGresult *res);
     298                 :             : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
     299                 :             : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
     300                 :             : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
     301                 :             : static void dumpCast(Archive *fout, const CastInfo *cast);
     302                 :             : static void dumpTransform(Archive *fout, const TransformInfo *transform);
     303                 :             : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
     304                 :             : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
     305                 :             : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
     306                 :             : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
     307                 :             : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
     308                 :             : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
     309                 :             : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
     310                 :             : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
     311                 :             : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
     312                 :             : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
     313                 :             : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
     314                 :             : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
     315                 :             : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
     316                 :             : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
     317                 :             : static void collectSequences(Archive *fout);
     318                 :             : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
     319                 :             : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
     320                 :             : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
     321                 :             : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
     322                 :             : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
     323                 :             : static void dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo);
     324                 :             : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
     325                 :             : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
     326                 :             : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
     327                 :             : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
     328                 :             : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
     329                 :             : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
     330                 :             : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
     331                 :             : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
     332                 :             : static void dumpUserMappings(Archive *fout,
     333                 :             :                              const char *servername, const char *namespace,
     334                 :             :                              const char *owner, CatalogId catalogId, DumpId dumpId);
     335                 :             : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
     336                 :             : 
     337                 :             : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     338                 :             :                       const char *type, const char *name, const char *subname,
     339                 :             :                       const char *nspname, const char *tag, const char *owner,
     340                 :             :                       const DumpableAcl *dacl);
     341                 :             : 
     342                 :             : static void getDependencies(Archive *fout);
     343                 :             : static void BuildArchiveDependencies(Archive *fout);
     344                 :             : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
     345                 :             :                                      DumpId **dependencies, int *nDeps, int *allocDeps);
     346                 :             : 
     347                 :             : static DumpableObject *createBoundaryObjects(void);
     348                 :             : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     349                 :             :                                     DumpableObject *boundaryObjs);
     350                 :             : 
     351                 :             : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
     352                 :             : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     353                 :             : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     354                 :             : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     355                 :             : static void buildMatViewRefreshDependencies(Archive *fout);
     356                 :             : static void getTableDataFKConstraints(void);
     357                 :             : static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
     358                 :             :                                   TableInfo *tbinfo, int j,
     359                 :             :                                   int i_notnull_name,
     360                 :             :                                   int i_notnull_comment,
     361                 :             :                                   int i_notnull_invalidoid,
     362                 :             :                                   int i_notnull_noinherit,
     363                 :             :                                   int i_notnull_islocal,
     364                 :             :                                   PQExpBuffer *invalidnotnulloids);
     365                 :             : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
     366                 :             :                                        bool is_agg);
     367                 :             : static char *format_function_signature(Archive *fout,
     368                 :             :                                        const FuncInfo *finfo, bool honor_quotes);
     369                 :             : static char *convertRegProcReference(const char *proc);
     370                 :             : static char *getFormattedOperatorName(const char *oproid);
     371                 :             : static char *convertTSFunction(Archive *fout, Oid funcOid);
     372                 :             : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     373                 :             : static void getLOs(Archive *fout);
     374                 :             : static void dumpLO(Archive *fout, const LoInfo *loinfo);
     375                 :             : static int  dumpLOs(Archive *fout, const void *arg);
     376                 :             : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
     377                 :             : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
     378                 :             : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
     379                 :             : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
     380                 :             : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
     381                 :             : static void dumpDatabase(Archive *fout);
     382                 :             : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     383                 :             :                                const char *dbname, Oid dboid);
     384                 :             : static void dumpEncoding(Archive *AH);
     385                 :             : static void dumpStdStrings(Archive *AH);
     386                 :             : static void dumpSearchPath(Archive *AH);
     387                 :             : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     388                 :             :                                                      PQExpBuffer upgrade_buffer,
     389                 :             :                                                      Oid pg_type_oid,
     390                 :             :                                                      bool force_array_type,
     391                 :             :                                                      bool include_multirange_type);
     392                 :             : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
     393                 :             :                                                 PQExpBuffer upgrade_buffer,
     394                 :             :                                                 const TableInfo *tbinfo);
     395                 :             : static void collectBinaryUpgradeClassOids(Archive *fout);
     396                 :             : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     397                 :             :                                              PQExpBuffer upgrade_buffer,
     398                 :             :                                              Oid pg_class_oid);
     399                 :             : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     400                 :             :                                             const DumpableObject *dobj,
     401                 :             :                                             const char *objtype,
     402                 :             :                                             const char *objname,
     403                 :             :                                             const char *objnamespace);
     404                 :             : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
     405                 :             : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     406                 :             : static bool nonemptyReloptions(const char *reloptions);
     407                 :             : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     408                 :             :                                     const char *prefix, Archive *fout);
     409                 :             : static char *get_synchronized_snapshot(Archive *fout);
     410                 :             : static void set_restrict_relation_kind(Archive *AH, const char *value);
     411                 :             : static void setupDumpWorker(Archive *AH);
     412                 :             : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
     413                 :             : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
     414                 :             : static void read_dump_filters(const char *filename, DumpOptions *dopt);
     415                 :             : 
     416                 :             : 
     417                 :             : int
     418                 :         302 : main(int argc, char **argv)
     419                 :             : {
     420                 :             :     int         c;
     421                 :         302 :     const char *filename = NULL;
     422                 :         302 :     const char *format = "p";
     423                 :             :     TableInfo  *tblinfo;
     424                 :             :     int         numTables;
     425                 :             :     DumpableObject **dobjs;
     426                 :             :     int         numObjs;
     427                 :             :     DumpableObject *boundaryObjs;
     428                 :             :     int         i;
     429                 :             :     int         optindex;
     430                 :             :     RestoreOptions *ropt;
     431                 :             :     Archive    *fout;           /* the script file */
     432                 :         302 :     bool        g_verbose = false;
     433                 :         302 :     const char *dumpencoding = NULL;
     434                 :         302 :     const char *dumpsnapshot = NULL;
     435                 :         302 :     char       *use_role = NULL;
     436                 :         302 :     int         numWorkers = 1;
     437                 :         302 :     int         plainText = 0;
     438                 :         302 :     ArchiveFormat archiveFormat = archUnknown;
     439                 :             :     ArchiveMode archiveMode;
     440                 :         302 :     pg_compress_specification compression_spec = {0};
     441                 :         302 :     char       *compression_detail = NULL;
     442                 :         302 :     char       *compression_algorithm_str = "none";
     443                 :         302 :     char       *error_detail = NULL;
     444                 :         302 :     bool        user_compression_defined = false;
     445                 :         302 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     446                 :         302 :     bool        data_only = false;
     447                 :         302 :     bool        schema_only = false;
     448                 :         302 :     bool        statistics_only = false;
     449                 :         302 :     bool        with_statistics = false;
     450                 :         302 :     bool        no_data = false;
     451                 :         302 :     bool        no_schema = false;
     452                 :         302 :     bool        no_statistics = false;
     453                 :             : 
     454                 :             :     static DumpOptions dopt;
     455                 :             : 
     456                 :             :     static struct option long_options[] = {
     457                 :             :         {"data-only", no_argument, NULL, 'a'},
     458                 :             :         {"blobs", no_argument, NULL, 'b'},
     459                 :             :         {"large-objects", no_argument, NULL, 'b'},
     460                 :             :         {"no-blobs", no_argument, NULL, 'B'},
     461                 :             :         {"no-large-objects", no_argument, NULL, 'B'},
     462                 :             :         {"clean", no_argument, NULL, 'c'},
     463                 :             :         {"create", no_argument, NULL, 'C'},
     464                 :             :         {"dbname", required_argument, NULL, 'd'},
     465                 :             :         {"extension", required_argument, NULL, 'e'},
     466                 :             :         {"file", required_argument, NULL, 'f'},
     467                 :             :         {"format", required_argument, NULL, 'F'},
     468                 :             :         {"host", required_argument, NULL, 'h'},
     469                 :             :         {"jobs", 1, NULL, 'j'},
     470                 :             :         {"no-reconnect", no_argument, NULL, 'R'},
     471                 :             :         {"no-owner", no_argument, NULL, 'O'},
     472                 :             :         {"port", required_argument, NULL, 'p'},
     473                 :             :         {"schema", required_argument, NULL, 'n'},
     474                 :             :         {"exclude-schema", required_argument, NULL, 'N'},
     475                 :             :         {"schema-only", no_argument, NULL, 's'},
     476                 :             :         {"superuser", required_argument, NULL, 'S'},
     477                 :             :         {"table", required_argument, NULL, 't'},
     478                 :             :         {"exclude-table", required_argument, NULL, 'T'},
     479                 :             :         {"no-password", no_argument, NULL, 'w'},
     480                 :             :         {"password", no_argument, NULL, 'W'},
     481                 :             :         {"username", required_argument, NULL, 'U'},
     482                 :             :         {"verbose", no_argument, NULL, 'v'},
     483                 :             :         {"no-privileges", no_argument, NULL, 'x'},
     484                 :             :         {"no-acl", no_argument, NULL, 'x'},
     485                 :             :         {"compress", required_argument, NULL, 'Z'},
     486                 :             :         {"encoding", required_argument, NULL, 'E'},
     487                 :             :         {"help", no_argument, NULL, '?'},
     488                 :             :         {"version", no_argument, NULL, 'V'},
     489                 :             : 
     490                 :             :         /*
     491                 :             :          * the following options don't have an equivalent short option letter
     492                 :             :          */
     493                 :             :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     494                 :             :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     495                 :             :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     496                 :             :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     497                 :             :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     498                 :             :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     499                 :             :         {"exclude-table-data", required_argument, NULL, 4},
     500                 :             :         {"extra-float-digits", required_argument, NULL, 8},
     501                 :             :         {"if-exists", no_argument, &dopt.if_exists, 1},
     502                 :             :         {"inserts", no_argument, NULL, 9},
     503                 :             :         {"lock-wait-timeout", required_argument, NULL, 2},
     504                 :             :         {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     505                 :             :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     506                 :             :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     507                 :             :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     508                 :             :         {"role", required_argument, NULL, 3},
     509                 :             :         {"section", required_argument, NULL, 5},
     510                 :             :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     511                 :             :         {"snapshot", required_argument, NULL, 6},
     512                 :             :         {"statistics", no_argument, NULL, 22},
     513                 :             :         {"statistics-only", no_argument, NULL, 18},
     514                 :             :         {"strict-names", no_argument, &strict_names, 1},
     515                 :             :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     516                 :             :         {"no-comments", no_argument, &dopt.no_comments, 1},
     517                 :             :         {"no-data", no_argument, NULL, 19},
     518                 :             :         {"no-policies", no_argument, &dopt.no_policies, 1},
     519                 :             :         {"no-publications", no_argument, &dopt.no_publications, 1},
     520                 :             :         {"no-schema", no_argument, NULL, 20},
     521                 :             :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     522                 :             :         {"no-statistics", no_argument, NULL, 21},
     523                 :             :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     524                 :             :         {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     525                 :             :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     526                 :             :         {"no-sync", no_argument, NULL, 7},
     527                 :             :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     528                 :             :         {"rows-per-insert", required_argument, NULL, 10},
     529                 :             :         {"include-foreign-data", required_argument, NULL, 11},
     530                 :             :         {"table-and-children", required_argument, NULL, 12},
     531                 :             :         {"exclude-table-and-children", required_argument, NULL, 13},
     532                 :             :         {"exclude-table-data-and-children", required_argument, NULL, 14},
     533                 :             :         {"sync-method", required_argument, NULL, 15},
     534                 :             :         {"filter", required_argument, NULL, 16},
     535                 :             :         {"exclude-extension", required_argument, NULL, 17},
     536                 :             :         {"sequence-data", no_argument, &dopt.sequence_data, 1},
     537                 :             :         {"restrict-key", required_argument, NULL, 25},
     538                 :             : 
     539                 :             :         {NULL, 0, NULL, 0}
     540                 :             :     };
     541                 :             : 
     542                 :         302 :     pg_logging_init(argv[0]);
     543                 :         302 :     pg_logging_set_level(PG_LOG_WARNING);
     544                 :         302 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     545                 :             : 
     546                 :             :     /*
     547                 :             :      * Initialize what we need for parallel execution, especially for thread
     548                 :             :      * support on Windows.
     549                 :             :      */
     550                 :         302 :     init_parallel_dump_utils();
     551                 :             : 
     552                 :         302 :     progname = get_progname(argv[0]);
     553                 :             : 
     554         [ +  - ]:         302 :     if (argc > 1)
     555                 :             :     {
     556   [ +  +  -  + ]:         302 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     557                 :             :         {
     558                 :           1 :             help(progname);
     559                 :           1 :             exit_nicely(0);
     560                 :             :         }
     561   [ +  +  +  + ]:         301 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     562                 :             :         {
     563                 :          65 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     564                 :          65 :             exit_nicely(0);
     565                 :             :         }
     566                 :             :     }
     567                 :             : 
     568                 :         236 :     InitDumpOptions(&dopt);
     569                 :             : 
     570                 :        1352 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     571         [ +  + ]:        1352 :                             long_options, &optindex)) != -1)
     572                 :             :     {
     573   [ +  +  +  +  :        1124 :         switch (c)
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          -  +  +  +  +  
          +  +  +  -  +  
          +  +  +  +  +  
          +  +  -  +  +  
          +  +  +  +  +  
                   +  + ]
     574                 :             :         {
     575                 :           9 :             case 'a':           /* Dump data only */
     576                 :           9 :                 data_only = true;
     577                 :           9 :                 break;
     578                 :             : 
     579                 :           1 :             case 'b':           /* Dump LOs */
     580                 :           1 :                 dopt.outputLOs = true;
     581                 :           1 :                 break;
     582                 :             : 
     583                 :           2 :             case 'B':           /* Don't dump LOs */
     584                 :           2 :                 dopt.dontOutputLOs = true;
     585                 :           2 :                 break;
     586                 :             : 
     587                 :           6 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     588                 :           6 :                 dopt.outputClean = 1;
     589                 :           6 :                 break;
     590                 :             : 
     591                 :          29 :             case 'C':           /* Create DB */
     592                 :          29 :                 dopt.outputCreateDB = 1;
     593                 :          29 :                 break;
     594                 :             : 
     595                 :           5 :             case 'd':           /* database name */
     596                 :           5 :                 dopt.cparams.dbname = pg_strdup(optarg);
     597                 :           5 :                 break;
     598                 :             : 
     599                 :           4 :             case 'e':           /* include extension(s) */
     600                 :           4 :                 simple_string_list_append(&extension_include_patterns, optarg);
     601                 :           4 :                 dopt.include_everything = false;
     602                 :           4 :                 break;
     603                 :             : 
     604                 :           2 :             case 'E':           /* Dump encoding */
     605                 :           2 :                 dumpencoding = pg_strdup(optarg);
     606                 :           2 :                 break;
     607                 :             : 
     608                 :         197 :             case 'f':
     609                 :         197 :                 filename = pg_strdup(optarg);
     610                 :         197 :                 break;
     611                 :             : 
     612                 :         116 :             case 'F':
     613                 :         116 :                 format = pg_strdup(optarg);
     614                 :         116 :                 break;
     615                 :             : 
     616                 :          38 :             case 'h':           /* server host */
     617                 :          38 :                 dopt.cparams.pghost = pg_strdup(optarg);
     618                 :          38 :                 break;
     619                 :             : 
     620                 :          11 :             case 'j':           /* number of dump jobs */
     621         [ +  + ]:          11 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     622                 :             :                                       PG_MAX_JOBS,
     623                 :             :                                       &numWorkers))
     624                 :           1 :                     exit_nicely(1);
     625                 :          10 :                 break;
     626                 :             : 
     627                 :          18 :             case 'n':           /* include schema(s) */
     628                 :          18 :                 simple_string_list_append(&schema_include_patterns, optarg);
     629                 :          18 :                 dopt.include_everything = false;
     630                 :          18 :                 break;
     631                 :             : 
     632                 :           1 :             case 'N':           /* exclude schema(s) */
     633                 :           1 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     634                 :           1 :                 break;
     635                 :             : 
     636                 :           2 :             case 'O':           /* Don't reconnect to match owner */
     637                 :           2 :                 dopt.outputNoOwner = 1;
     638                 :           2 :                 break;
     639                 :             : 
     640                 :          77 :             case 'p':           /* server port */
     641                 :          77 :                 dopt.cparams.pgport = pg_strdup(optarg);
     642                 :          77 :                 break;
     643                 :             : 
     644                 :           2 :             case 'R':
     645                 :             :                 /* no-op, still accepted for backwards compatibility */
     646                 :           2 :                 break;
     647                 :             : 
     648                 :           7 :             case 's':           /* dump schema only */
     649                 :           7 :                 schema_only = true;
     650                 :           7 :                 break;
     651                 :             : 
     652                 :           1 :             case 'S':           /* Username for superuser in plain text output */
     653                 :           1 :                 dopt.outputSuperuser = pg_strdup(optarg);
     654                 :           1 :                 break;
     655                 :             : 
     656                 :           8 :             case 't':           /* include table(s) */
     657                 :           8 :                 simple_string_list_append(&table_include_patterns, optarg);
     658                 :           8 :                 dopt.include_everything = false;
     659                 :           8 :                 break;
     660                 :             : 
     661                 :           4 :             case 'T':           /* exclude table(s) */
     662                 :           4 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     663                 :           4 :                 break;
     664                 :             : 
     665                 :          40 :             case 'U':
     666                 :          40 :                 dopt.cparams.username = pg_strdup(optarg);
     667                 :          40 :                 break;
     668                 :             : 
     669                 :           6 :             case 'v':           /* verbose */
     670                 :           6 :                 g_verbose = true;
     671                 :           6 :                 pg_logging_increase_verbosity();
     672                 :           6 :                 break;
     673                 :             : 
     674                 :           1 :             case 'w':
     675                 :           1 :                 dopt.cparams.promptPassword = TRI_NO;
     676                 :           1 :                 break;
     677                 :             : 
     678                 :           0 :             case 'W':
     679                 :           0 :                 dopt.cparams.promptPassword = TRI_YES;
     680                 :           0 :                 break;
     681                 :             : 
     682                 :           2 :             case 'x':           /* skip ACL dump */
     683                 :           2 :                 dopt.aclsSkip = true;
     684                 :           2 :                 break;
     685                 :             : 
     686                 :          13 :             case 'Z':           /* Compression */
     687                 :          13 :                 parse_compress_options(optarg, &compression_algorithm_str,
     688                 :             :                                        &compression_detail);
     689                 :          13 :                 user_compression_defined = true;
     690                 :          13 :                 break;
     691                 :             : 
     692                 :         141 :             case 0:
     693                 :             :                 /* This covers the long options. */
     694                 :         141 :                 break;
     695                 :             : 
     696                 :           2 :             case 2:             /* lock-wait-timeout */
     697                 :           2 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     698                 :           2 :                 break;
     699                 :             : 
     700                 :           3 :             case 3:             /* SET ROLE */
     701                 :           3 :                 use_role = pg_strdup(optarg);
     702                 :           3 :                 break;
     703                 :             : 
     704                 :           1 :             case 4:             /* exclude table(s) data */
     705                 :           1 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     706                 :           1 :                 break;
     707                 :             : 
     708                 :           6 :             case 5:             /* section */
     709                 :           6 :                 set_dump_section(optarg, &dopt.dumpSections);
     710                 :           6 :                 break;
     711                 :             : 
     712                 :           0 :             case 6:             /* snapshot */
     713                 :           0 :                 dumpsnapshot = pg_strdup(optarg);
     714                 :           0 :                 break;
     715                 :             : 
     716                 :         154 :             case 7:             /* no-sync */
     717                 :         154 :                 dosync = false;
     718                 :         154 :                 break;
     719                 :             : 
     720                 :           1 :             case 8:
     721                 :           1 :                 have_extra_float_digits = true;
     722         [ +  - ]:           1 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     723                 :             :                                       &extra_float_digits))
     724                 :           1 :                     exit_nicely(1);
     725                 :           0 :                 break;
     726                 :             : 
     727                 :           2 :             case 9:             /* inserts */
     728                 :             : 
     729                 :             :                 /*
     730                 :             :                  * dump_inserts also stores --rows-per-insert, careful not to
     731                 :             :                  * overwrite that.
     732                 :             :                  */
     733         [ +  - ]:           2 :                 if (dopt.dump_inserts == 0)
     734                 :           2 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     735                 :           2 :                 break;
     736                 :             : 
     737                 :           2 :             case 10:            /* rows per insert */
     738         [ +  + ]:           2 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     739                 :             :                                       &dopt.dump_inserts))
     740                 :           1 :                     exit_nicely(1);
     741                 :           1 :                 break;
     742                 :             : 
     743                 :           4 :             case 11:            /* include foreign data */
     744                 :           4 :                 simple_string_list_append(&foreign_servers_include_patterns,
     745                 :             :                                           optarg);
     746                 :           4 :                 break;
     747                 :             : 
     748                 :           1 :             case 12:            /* include table(s) and their children */
     749                 :           1 :                 simple_string_list_append(&table_include_patterns_and_children,
     750                 :             :                                           optarg);
     751                 :           1 :                 dopt.include_everything = false;
     752                 :           1 :                 break;
     753                 :             : 
     754                 :           1 :             case 13:            /* exclude table(s) and their children */
     755                 :           1 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     756                 :             :                                           optarg);
     757                 :           1 :                 break;
     758                 :             : 
     759                 :           1 :             case 14:            /* exclude data of table(s) and children */
     760                 :           1 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     761                 :             :                                           optarg);
     762                 :           1 :                 break;
     763                 :             : 
     764                 :           0 :             case 15:
     765         [ #  # ]:           0 :                 if (!parse_sync_method(optarg, &sync_method))
     766                 :           0 :                     exit_nicely(1);
     767                 :           0 :                 break;
     768                 :             : 
     769                 :          26 :             case 16:            /* read object filters from file */
     770                 :          26 :                 read_dump_filters(optarg, &dopt);
     771                 :          22 :                 break;
     772                 :             : 
     773                 :           1 :             case 17:            /* exclude extension(s) */
     774                 :           1 :                 simple_string_list_append(&extension_exclude_patterns,
     775                 :             :                                           optarg);
     776                 :           1 :                 break;
     777                 :             : 
     778                 :           5 :             case 18:
     779                 :           5 :                 statistics_only = true;
     780                 :           5 :                 break;
     781                 :             : 
     782                 :          40 :             case 19:
     783                 :          40 :                 no_data = true;
     784                 :          40 :                 break;
     785                 :             : 
     786                 :           2 :             case 20:
     787                 :           2 :                 no_schema = true;
     788                 :           2 :                 break;
     789                 :             : 
     790                 :           8 :             case 21:
     791                 :           8 :                 no_statistics = true;
     792                 :           8 :                 break;
     793                 :             : 
     794                 :          94 :             case 22:
     795                 :          94 :                 with_statistics = true;
     796                 :          94 :                 break;
     797                 :             : 
     798                 :          26 :             case 25:
     799                 :          26 :                 dopt.restrict_key = pg_strdup(optarg);
     800                 :          26 :                 break;
     801                 :             : 
     802                 :           1 :             default:
     803                 :             :                 /* getopt_long already emitted a complaint */
     804                 :           1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     805                 :           1 :                 exit_nicely(1);
     806                 :             :         }
     807                 :             :     }
     808                 :             : 
     809                 :             :     /*
     810                 :             :      * Non-option argument specifies database name as long as it wasn't
     811                 :             :      * already specified with -d / --dbname
     812                 :             :      */
     813   [ +  +  +  - ]:         228 :     if (optind < argc && dopt.cparams.dbname == NULL)
     814                 :         192 :         dopt.cparams.dbname = argv[optind++];
     815                 :             : 
     816                 :             :     /* Complain if any arguments remain */
     817         [ +  + ]:         228 :     if (optind < argc)
     818                 :             :     {
     819                 :           1 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     820                 :             :                      argv[optind]);
     821                 :           1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     822                 :           1 :         exit_nicely(1);
     823                 :             :     }
     824                 :             : 
     825                 :             :     /* --column-inserts implies --inserts */
     826   [ +  +  +  - ]:         227 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     827                 :           1 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     828                 :             : 
     829                 :             :     /* *-only options are incompatible with each other */
     830                 :         227 :     check_mut_excl_opts(data_only, "-a/--data-only",
     831                 :             :                         schema_only, "-s/--schema-only",
     832                 :             :                         statistics_only, "--statistics-only");
     833                 :             : 
     834                 :             :     /* --no-* and *-only for same thing are incompatible */
     835                 :         224 :     check_mut_excl_opts(data_only, "-a/--data-only",
     836                 :             :                         no_data, "--no-data");
     837                 :         224 :     check_mut_excl_opts(schema_only, "-s/--schema-only",
     838                 :             :                         no_schema, "--no-schema");
     839                 :         224 :     check_mut_excl_opts(statistics_only, "--statistics-only",
     840                 :             :                         no_statistics, "--no-statistics");
     841                 :             : 
     842                 :             :     /* --statistics and --no-statistics are incompatible */
     843                 :         223 :     check_mut_excl_opts(with_statistics, "--statistics",
     844                 :             :                         no_statistics, "--no-statistics");
     845                 :             : 
     846                 :             :     /* --statistics is incompatible with *-only (except --statistics-only) */
     847                 :         223 :     check_mut_excl_opts(with_statistics, "--statistics",
     848                 :             :                         data_only, "-a/--data-only",
     849                 :             :                         schema_only, "-s/--schema-only");
     850                 :             : 
     851                 :             :     /* --include-foreign-data is incompatible with --schema-only */
     852                 :         222 :     check_mut_excl_opts(foreign_servers_include_patterns.head, "--include-foreign-data",
     853                 :             :                         schema_only, "-s/--schema-only");
     854                 :             : 
     855   [ +  +  +  + ]:         221 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     856                 :           1 :         pg_fatal("option %s is not supported with parallel backup",
     857                 :             :                  "--include-foreign-data");
     858                 :             : 
     859                 :             :     /* --clean is incompatible with --data-only */
     860                 :         220 :     check_mut_excl_opts(dopt.outputClean, "-c/--clean",
     861                 :             :                         data_only, "-a/--data-only");
     862                 :             : 
     863   [ +  +  +  + ]:         219 :     if (dopt.if_exists && !dopt.outputClean)
     864                 :           1 :         pg_fatal("option %s requires option %s",
     865                 :             :                  "--if-exists", "-c/--clean");
     866                 :             : 
     867                 :             :     /*
     868                 :             :      * Set derivative flags. Ambiguous or nonsensical combinations, e.g.
     869                 :             :      * "--schema-only --no-schema", will have already caused an error in one
     870                 :             :      * of the checks above.
     871                 :             :      */
     872   [ +  +  +  +  :         218 :     dopt.dumpData = ((dopt.dumpData && !schema_only && !statistics_only) ||
                   -  + ]
     873   [ +  -  +  + ]:         436 :                      data_only) && !no_data;
     874   [ +  +  +  +  :         218 :     dopt.dumpSchema = ((dopt.dumpSchema && !data_only && !statistics_only) ||
                   -  + ]
     875   [ +  -  +  + ]:         436 :                        schema_only) && !no_schema;
     876   [ -  -  -  -  :         218 :     dopt.dumpStatistics = ((dopt.dumpStatistics && !schema_only && !data_only) ||
                   +  + ]
     877   [ -  +  +  +  :         436 :                            (statistics_only || with_statistics)) && !no_statistics;
                   +  - ]
     878                 :             : 
     879                 :             : 
     880                 :             :     /*
     881                 :             :      * --inserts are already implied above if --column-inserts or
     882                 :             :      * --rows-per-insert were specified.
     883                 :             :      */
     884   [ +  +  +  - ]:         218 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     885                 :           1 :         pg_fatal("option %s requires option %s, %s, or %s",
     886                 :             :                  "--on-conflict-do-nothing",
     887                 :             :                  "--inserts", "--rows-per-insert", "--column-inserts");
     888                 :             : 
     889                 :             :     /* Identify archive format to emit */
     890                 :         217 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     891                 :             : 
     892                 :             :     /* archiveFormat specific setup */
     893         [ +  + ]:         216 :     if (archiveFormat == archNull)
     894                 :             :     {
     895                 :         152 :         plainText = 1;
     896                 :             : 
     897                 :             :         /*
     898                 :             :          * If you don't provide a restrict key, one will be appointed for you.
     899                 :             :          */
     900         [ +  + ]:         152 :         if (!dopt.restrict_key)
     901                 :         126 :             dopt.restrict_key = generate_restrict_key();
     902         [ -  + ]:         152 :         if (!dopt.restrict_key)
     903                 :           0 :             pg_fatal("could not generate restrict key");
     904         [ -  + ]:         152 :         if (!valid_restrict_key(dopt.restrict_key))
     905                 :           0 :             pg_fatal("invalid restrict key");
     906                 :             :     }
     907         [ -  + ]:          64 :     else if (dopt.restrict_key)
     908                 :           0 :         pg_fatal("option %s can only be used with %s",
     909                 :             :                  "--restrict-key", "--format=plain");
     910                 :             : 
     911                 :             :     /*
     912                 :             :      * Custom and directory formats are compressed by default with gzip when
     913                 :             :      * available, not the others.  If gzip is not available, no compression is
     914                 :             :      * done by default.
     915                 :             :      */
     916   [ +  +  +  + ]:         216 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     917         [ +  + ]:          61 :         !user_compression_defined)
     918                 :             :     {
     919                 :             : #ifdef HAVE_LIBZ
     920                 :          55 :         compression_algorithm_str = "gzip";
     921                 :             : #else
     922                 :             :         compression_algorithm_str = "none";
     923                 :             : #endif
     924                 :             :     }
     925                 :             : 
     926                 :             :     /*
     927                 :             :      * Compression options
     928                 :             :      */
     929         [ +  + ]:         216 :     if (!parse_compress_algorithm(compression_algorithm_str,
     930                 :             :                                   &compression_algorithm))
     931                 :           1 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     932                 :             :                  compression_algorithm_str);
     933                 :             : 
     934                 :         215 :     parse_compress_specification(compression_algorithm, compression_detail,
     935                 :             :                                  &compression_spec);
     936                 :         215 :     error_detail = validate_compress_specification(&compression_spec);
     937         [ +  + ]:         215 :     if (error_detail != NULL)
     938                 :           3 :         pg_fatal("invalid compression specification: %s",
     939                 :             :                  error_detail);
     940                 :             : 
     941                 :         212 :     error_detail = supports_compression(compression_spec);
     942         [ -  + ]:         212 :     if (error_detail != NULL)
     943                 :           0 :         pg_fatal("%s", error_detail);
     944                 :             : 
     945                 :             :     /*
     946                 :             :      * Disable support for zstd workers for now - these are based on
     947                 :             :      * threading, and it's unclear how it interacts with parallel dumps on
     948                 :             :      * platforms where that relies on threads too (e.g. Windows).
     949                 :             :      */
     950         [ -  + ]:         212 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     951                 :           0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     952                 :             :                        "workers");
     953                 :             : 
     954                 :             :     /*
     955                 :             :      * If emitting an archive format, we always want to emit a DATABASE item,
     956                 :             :      * in case --create is specified at pg_restore time.
     957                 :             :      */
     958         [ +  + ]:         212 :     if (!plainText)
     959                 :          64 :         dopt.outputCreateDB = 1;
     960                 :             : 
     961                 :             :     /* Parallel backup only in the directory archive format so far */
     962   [ +  +  +  + ]:         212 :     if (archiveFormat != archDirectory && numWorkers > 1)
     963                 :           1 :         pg_fatal("parallel backup only supported by the directory format");
     964                 :             : 
     965                 :             :     /* Open the output file */
     966                 :         211 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     967                 :             :                          dosync, archiveMode, setupDumpWorker, sync_method);
     968                 :             : 
     969                 :             :     /* Make dump options accessible right away */
     970                 :         210 :     SetArchiveOptions(fout, &dopt, NULL);
     971                 :             : 
     972                 :             :     /* Register the cleanup hook */
     973                 :         210 :     on_exit_close_archive(fout);
     974                 :             : 
     975                 :             :     /* Let the archiver know how noisy to be */
     976                 :         210 :     fout->verbose = g_verbose;
     977                 :             : 
     978                 :             : 
     979                 :             :     /*
     980                 :             :      * We allow the server to be back to 10, and up to any minor release of
     981                 :             :      * our own major version.  (See also version check in pg_dumpall.c.)
     982                 :             :      */
     983                 :         210 :     fout->minRemoteVersion = 100000;
     984                 :         210 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     985                 :             : 
     986                 :         210 :     fout->numWorkers = numWorkers;
     987                 :             : 
     988                 :             :     /*
     989                 :             :      * Open the database using the Archiver, so it knows about it. Errors mean
     990                 :             :      * death.
     991                 :             :      */
     992                 :         210 :     ConnectDatabaseAhx(fout, &dopt.cparams, false);
     993                 :         208 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     994                 :             : 
     995                 :             :     /*
     996                 :             :      * On hot standbys, never try to dump unlogged table data, since it will
     997                 :             :      * just throw an error.
     998                 :             :      */
     999         [ +  + ]:         208 :     if (fout->isStandby)
    1000                 :           4 :         dopt.no_unlogged_table_data = true;
    1001                 :             : 
    1002                 :             :     /*
    1003                 :             :      * Find the last built-in OID, if needed (prior to 8.1)
    1004                 :             :      *
    1005                 :             :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
    1006                 :             :      */
    1007                 :         208 :     g_last_builtin_oid = FirstNormalObjectId - 1;
    1008                 :             : 
    1009                 :         208 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
    1010                 :             : 
    1011                 :             :     /* Expand schema selection patterns into OID lists */
    1012         [ +  + ]:         208 :     if (schema_include_patterns.head != NULL)
    1013                 :             :     {
    1014                 :          19 :         expand_schema_name_patterns(fout, &schema_include_patterns,
    1015                 :             :                                     &schema_include_oids,
    1016                 :             :                                     strict_names);
    1017         [ +  + ]:          13 :         if (schema_include_oids.head == NULL)
    1018                 :           1 :             pg_fatal("no matching schemas were found");
    1019                 :             :     }
    1020                 :         201 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
    1021                 :             :                                 &schema_exclude_oids,
    1022                 :             :                                 false);
    1023                 :             :     /* non-matching exclusion patterns aren't an error */
    1024                 :             : 
    1025                 :             :     /* Expand table selection patterns into OID lists */
    1026                 :         201 :     expand_table_name_patterns(fout, &table_include_patterns,
    1027                 :             :                                &table_include_oids,
    1028                 :             :                                strict_names, false);
    1029                 :         196 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
    1030                 :             :                                &table_include_oids,
    1031                 :             :                                strict_names, true);
    1032         [ +  + ]:         196 :     if ((table_include_patterns.head != NULL ||
    1033         [ +  + ]:         185 :          table_include_patterns_and_children.head != NULL) &&
    1034         [ +  + ]:          13 :         table_include_oids.head == NULL)
    1035                 :           2 :         pg_fatal("no matching tables were found");
    1036                 :             : 
    1037                 :         194 :     expand_table_name_patterns(fout, &table_exclude_patterns,
    1038                 :             :                                &table_exclude_oids,
    1039                 :             :                                false, false);
    1040                 :         194 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
    1041                 :             :                                &table_exclude_oids,
    1042                 :             :                                false, true);
    1043                 :             : 
    1044                 :         194 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
    1045                 :             :                                &tabledata_exclude_oids,
    1046                 :             :                                false, false);
    1047                 :         194 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
    1048                 :             :                                &tabledata_exclude_oids,
    1049                 :             :                                false, true);
    1050                 :             : 
    1051                 :         194 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
    1052                 :             :                                         &foreign_servers_include_oids);
    1053                 :             : 
    1054                 :             :     /* non-matching exclusion patterns aren't an error */
    1055                 :             : 
    1056                 :             :     /* Expand extension selection patterns into OID lists */
    1057         [ +  + ]:         193 :     if (extension_include_patterns.head != NULL)
    1058                 :             :     {
    1059                 :           5 :         expand_extension_name_patterns(fout, &extension_include_patterns,
    1060                 :             :                                        &extension_include_oids,
    1061                 :             :                                        strict_names);
    1062         [ +  + ]:           5 :         if (extension_include_oids.head == NULL)
    1063                 :           1 :             pg_fatal("no matching extensions were found");
    1064                 :             :     }
    1065                 :         192 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
    1066                 :             :                                    &extension_exclude_oids,
    1067                 :             :                                    false);
    1068                 :             :     /* non-matching exclusion patterns aren't an error */
    1069                 :             : 
    1070                 :             :     /*
    1071                 :             :      * Dumping LOs is the default for dumps where an inclusion switch is not
    1072                 :             :      * used (an "include everything" dump).  -B can be used to exclude LOs
    1073                 :             :      * from those dumps.  -b can be used to include LOs even when an inclusion
    1074                 :             :      * switch is used.
    1075                 :             :      *
    1076                 :             :      * -s means "schema only" and LOs are data, not schema, so we never
    1077                 :             :      * include LOs when -s is used.
    1078                 :             :      */
    1079   [ +  +  +  +  :         192 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
                   +  + ]
    1080                 :         122 :         dopt.outputLOs = true;
    1081                 :             : 
    1082                 :             :     /*
    1083                 :             :      * Collect role names so we can map object owner OIDs to names.
    1084                 :             :      */
    1085                 :         192 :     collectRoleNames(fout);
    1086                 :             : 
    1087                 :             :     /*
    1088                 :             :      * Now scan the database and create DumpableObject structs for all the
    1089                 :             :      * objects we intend to dump.
    1090                 :             :      */
    1091                 :         192 :     tblinfo = getSchemaData(fout, &numTables);
    1092                 :             : 
    1093         [ +  + ]:         191 :     if (dopt.dumpData)
    1094                 :             :     {
    1095                 :         146 :         getTableData(&dopt, tblinfo, numTables, 0);
    1096                 :         146 :         buildMatViewRefreshDependencies(fout);
    1097         [ +  + ]:         146 :         if (!dopt.dumpSchema)
    1098                 :           7 :             getTableDataFKConstraints();
    1099                 :             :     }
    1100                 :             : 
    1101   [ +  +  +  + ]:         191 :     if (!dopt.dumpData && dopt.sequence_data)
    1102                 :          36 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1103                 :             : 
    1104                 :             :     /*
    1105                 :             :      * For binary upgrade mode, dump the pg_shdepend rows for large objects
    1106                 :             :      * and maybe even pg_largeobject_metadata (see comment below for details).
    1107                 :             :      * This is faster to restore than the equivalent set of large object
    1108                 :             :      * commands.
    1109                 :             :      */
    1110         [ +  + ]:         191 :     if (dopt.binary_upgrade)
    1111                 :             :     {
    1112                 :             :         TableInfo  *shdepend;
    1113                 :             : 
    1114                 :          40 :         shdepend = findTableByOid(SharedDependRelationId);
    1115                 :          40 :         makeTableDataInfo(&dopt, shdepend);
    1116                 :             : 
    1117                 :             :         /*
    1118                 :             :          * Only dump large object shdepend rows for this database.
    1119                 :             :          */
    1120                 :          40 :         shdepend->dataObj->filtercond = "WHERE classid = 'pg_largeobject'::regclass "
    1121                 :             :             "AND dbid = (SELECT oid FROM pg_database "
    1122                 :             :             "            WHERE datname = current_database())";
    1123                 :             : 
    1124                 :             :         /*
    1125                 :             :          * For binary upgrades from v16 and newer versions, we can copy
    1126                 :             :          * pg_largeobject_metadata's files from the old cluster, so we don't
    1127                 :             :          * need to dump its contents.  pg_upgrade can't copy/link the files
    1128                 :             :          * from older versions because aclitem (needed by
    1129                 :             :          * pg_largeobject_metadata.lomacl) changed its storage format in v16.
    1130                 :             :          */
    1131         [ -  + ]:          40 :         if (fout->remoteVersion < 160000)
    1132                 :             :         {
    1133                 :             :             TableInfo  *lo_metadata;
    1134                 :             : 
    1135                 :           0 :             lo_metadata = findTableByOid(LargeObjectMetadataRelationId);
    1136                 :           0 :             makeTableDataInfo(&dopt, lo_metadata);
    1137                 :             :         }
    1138                 :             :     }
    1139                 :             : 
    1140                 :             :     /*
    1141                 :             :      * In binary-upgrade mode, we do not have to worry about the actual LO
    1142                 :             :      * data or the associated metadata that resides in the pg_largeobject and
    1143                 :             :      * pg_largeobject_metadata tables, respectively.
    1144                 :             :      *
    1145                 :             :      * However, we do need to collect LO information as there may be comments
    1146                 :             :      * or other information on LOs that we do need to dump out.
    1147                 :             :      */
    1148   [ +  +  +  + ]:         191 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1149                 :         162 :         getLOs(fout);
    1150                 :             : 
    1151                 :             :     /*
    1152                 :             :      * Collect dependency data to assist in ordering the objects.
    1153                 :             :      */
    1154                 :         191 :     getDependencies(fout);
    1155                 :             : 
    1156                 :             :     /*
    1157                 :             :      * Collect ACLs, comments, and security labels, if wanted.
    1158                 :             :      */
    1159         [ +  + ]:         191 :     if (!dopt.aclsSkip)
    1160                 :         189 :         getAdditionalACLs(fout);
    1161         [ +  - ]:         191 :     if (!dopt.no_comments)
    1162                 :         191 :         collectComments(fout);
    1163         [ +  - ]:         191 :     if (!dopt.no_security_labels)
    1164                 :         191 :         collectSecLabels(fout);
    1165                 :             : 
    1166                 :             :     /* For binary upgrade mode, collect required pg_class information. */
    1167         [ +  + ]:         191 :     if (dopt.binary_upgrade)
    1168                 :          40 :         collectBinaryUpgradeClassOids(fout);
    1169                 :             : 
    1170                 :             :     /* Collect sequence information. */
    1171                 :         191 :     collectSequences(fout);
    1172                 :             : 
    1173                 :             :     /* Lastly, create dummy objects to represent the section boundaries */
    1174                 :         191 :     boundaryObjs = createBoundaryObjects();
    1175                 :             : 
    1176                 :             :     /* Get pointers to all the known DumpableObjects */
    1177                 :         191 :     getDumpableObjects(&dobjs, &numObjs);
    1178                 :             : 
    1179                 :             :     /*
    1180                 :             :      * Add dummy dependencies to enforce the dump section ordering.
    1181                 :             :      */
    1182                 :         191 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1183                 :             : 
    1184                 :             :     /*
    1185                 :             :      * Sort the objects into a safe dump order (no forward references).
    1186                 :             :      *
    1187                 :             :      * We rely on dependency information to help us determine a safe order, so
    1188                 :             :      * the initial sort is mostly for cosmetic purposes: we sort by name to
    1189                 :             :      * ensure that logically identical schemas will dump identically.
    1190                 :             :      */
    1191                 :         191 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1192                 :             : 
    1193                 :         191 :     sortDumpableObjects(dobjs, numObjs,
    1194                 :         191 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1195                 :             : 
    1196                 :             :     /*
    1197                 :             :      * Create archive TOC entries for all the objects to be dumped, in a safe
    1198                 :             :      * order.
    1199                 :             :      */
    1200                 :             : 
    1201                 :             :     /*
    1202                 :             :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1203                 :             :      */
    1204                 :         191 :     dumpEncoding(fout);
    1205                 :         191 :     dumpStdStrings(fout);
    1206                 :         191 :     dumpSearchPath(fout);
    1207                 :             : 
    1208                 :             :     /* The database items are always next, unless we don't want them at all */
    1209         [ +  + ]:         191 :     if (dopt.outputCreateDB)
    1210                 :          92 :         dumpDatabase(fout);
    1211                 :             : 
    1212                 :             :     /* Now the rearrangeable objects. */
    1213         [ +  + ]:      738561 :     for (i = 0; i < numObjs; i++)
    1214                 :      738370 :         dumpDumpableObject(fout, dobjs[i]);
    1215                 :             : 
    1216                 :             :     /*
    1217                 :             :      * Set up options info to ensure we dump what we want.
    1218                 :             :      */
    1219                 :         191 :     ropt = NewRestoreOptions();
    1220                 :         191 :     ropt->filename = filename;
    1221                 :             : 
    1222                 :             :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1223         [ +  + ]:         191 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1224         [ +  + ]:         191 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1225         [ +  + ]:         191 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1226         [ +  + ]:         191 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1227                 :         191 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1228                 :         191 :     ropt->dropSchema = dopt.outputClean;
    1229                 :         191 :     ropt->dumpData = dopt.dumpData;
    1230                 :         191 :     ropt->dumpSchema = dopt.dumpSchema;
    1231                 :         191 :     ropt->dumpStatistics = dopt.dumpStatistics;
    1232                 :         191 :     ropt->if_exists = dopt.if_exists;
    1233                 :         191 :     ropt->column_inserts = dopt.column_inserts;
    1234                 :         191 :     ropt->dumpSections = dopt.dumpSections;
    1235                 :         191 :     ropt->aclsSkip = dopt.aclsSkip;
    1236                 :         191 :     ropt->superuser = dopt.outputSuperuser;
    1237                 :         191 :     ropt->createDB = dopt.outputCreateDB;
    1238                 :         191 :     ropt->noOwner = dopt.outputNoOwner;
    1239                 :         191 :     ropt->noTableAm = dopt.outputNoTableAm;
    1240                 :         191 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1241                 :         191 :     ropt->disable_triggers = dopt.disable_triggers;
    1242                 :         191 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1243                 :         191 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1244                 :         191 :     ropt->dump_inserts = dopt.dump_inserts;
    1245                 :         191 :     ropt->no_comments = dopt.no_comments;
    1246                 :         191 :     ropt->no_policies = dopt.no_policies;
    1247                 :         191 :     ropt->no_publications = dopt.no_publications;
    1248                 :         191 :     ropt->no_security_labels = dopt.no_security_labels;
    1249                 :         191 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1250                 :         191 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1251                 :         191 :     ropt->include_everything = dopt.include_everything;
    1252                 :         191 :     ropt->enable_row_security = dopt.enable_row_security;
    1253                 :         191 :     ropt->sequence_data = dopt.sequence_data;
    1254                 :         191 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1255         [ +  + ]:         191 :     ropt->restrict_key = dopt.restrict_key ? pg_strdup(dopt.restrict_key) : NULL;
    1256                 :             : 
    1257                 :         191 :     ropt->compression_spec = compression_spec;
    1258                 :             : 
    1259                 :         191 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1260                 :             : 
    1261                 :         191 :     SetArchiveOptions(fout, &dopt, ropt);
    1262                 :             : 
    1263                 :             :     /* Mark which entries should be output */
    1264                 :         191 :     ProcessArchiveRestoreOptions(fout);
    1265                 :             : 
    1266                 :             :     /*
    1267                 :             :      * The archive's TOC entries are now marked as to which ones will actually
    1268                 :             :      * be output, so we can set up their dependency lists properly. This isn't
    1269                 :             :      * necessary for plain-text output, though.
    1270                 :             :      */
    1271         [ +  + ]:         191 :     if (!plainText)
    1272                 :          63 :         BuildArchiveDependencies(fout);
    1273                 :             : 
    1274                 :             :     /*
    1275                 :             :      * And finally we can do the actual output.
    1276                 :             :      *
    1277                 :             :      * Note: for non-plain-text output formats, the output file is written
    1278                 :             :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1279                 :             :      * right now.
    1280                 :             :      */
    1281         [ +  + ]:         191 :     if (plainText)
    1282                 :         128 :         RestoreArchive(fout);
    1283                 :             : 
    1284                 :         190 :     CloseArchive(fout);
    1285                 :             : 
    1286                 :         190 :     exit_nicely(0);
    1287                 :             : }
    1288                 :             : 
    1289                 :             : 
    1290                 :             : static void
    1291                 :           1 : help(const char *progname)
    1292                 :             : {
    1293                 :           1 :     printf(_("%s exports a PostgreSQL database as an SQL script or to other formats.\n\n"), progname);
    1294                 :           1 :     printf(_("Usage:\n"));
    1295                 :           1 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1296                 :             : 
    1297                 :           1 :     printf(_("\nGeneral options:\n"));
    1298                 :           1 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1299                 :           1 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1300                 :             :              "                               plain text (default))\n"));
    1301                 :           1 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1302                 :           1 :     printf(_("  -v, --verbose                verbose mode\n"));
    1303                 :           1 :     printf(_("  -V, --version                output version information, then exit\n"));
    1304                 :           1 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1305                 :             :              "                               compress as specified\n"));
    1306                 :           1 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1307                 :           1 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1308                 :           1 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1309                 :           1 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1310                 :             : 
    1311                 :           1 :     printf(_("\nOptions controlling the output content:\n"));
    1312                 :           1 :     printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
    1313                 :           1 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1314                 :           1 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1315                 :           1 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1316                 :           1 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1317                 :           1 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1318                 :           1 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1319                 :           1 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1320                 :           1 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1321                 :           1 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1322                 :           1 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1323                 :           1 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1324                 :             :              "                               plain-text format\n"));
    1325                 :           1 :     printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
    1326                 :           1 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1327                 :           1 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1328                 :           1 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1329                 :           1 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1330                 :           1 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1331                 :           1 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1332                 :           1 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1333                 :           1 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1334                 :           1 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1335                 :             :              "                               access to)\n"));
    1336                 :           1 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1337                 :           1 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1338                 :             :              "                               do NOT dump the specified table(s), including\n"
    1339                 :             :              "                               child and partition tables\n"));
    1340                 :           1 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1341                 :           1 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1342                 :             :              "                               do NOT dump data for the specified table(s),\n"
    1343                 :             :              "                               including child and partition tables\n"));
    1344                 :           1 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1345                 :           1 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1346                 :             :              "                               based on expressions in FILENAME\n"));
    1347                 :           1 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1348                 :           1 :     printf(_("  --include-foreign-data=PATTERN\n"
    1349                 :             :              "                               include data of foreign tables on foreign\n"
    1350                 :             :              "                               servers matching PATTERN\n"));
    1351                 :           1 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1352                 :           1 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1353                 :           1 :     printf(_("  --no-comments                do not dump comment commands\n"));
    1354                 :           1 :     printf(_("  --no-data                    do not dump data\n"));
    1355                 :           1 :     printf(_("  --no-policies                do not dump row security policies\n"));
    1356                 :           1 :     printf(_("  --no-publications            do not dump publications\n"));
    1357                 :           1 :     printf(_("  --no-schema                  do not dump schema\n"));
    1358                 :           1 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1359                 :           1 :     printf(_("  --no-statistics              do not dump statistics\n"));
    1360                 :           1 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1361                 :           1 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1362                 :           1 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1363                 :           1 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1364                 :           1 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1365                 :           1 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1366                 :           1 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1367                 :           1 :     printf(_("  --restrict-key=RESTRICT_KEY  use provided string as psql \\restrict key\n"));
    1368                 :           1 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1369                 :           1 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1370                 :           1 :     printf(_("  --sequence-data              include sequence data in dump\n"));
    1371                 :           1 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1372                 :           1 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1373                 :           1 :     printf(_("  --statistics                 dump the statistics\n"));
    1374                 :           1 :     printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
    1375                 :           1 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1376                 :             :              "                               match at least one entity each\n"));
    1377                 :           1 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1378                 :             :              "                               child and partition tables\n"));
    1379                 :           1 :     printf(_("  --use-set-session-authorization\n"
    1380                 :             :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1381                 :             :              "                               ALTER OWNER commands to set ownership\n"));
    1382                 :             : 
    1383                 :           1 :     printf(_("\nConnection options:\n"));
    1384                 :           1 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1385                 :           1 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1386                 :           1 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1387                 :           1 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1388                 :           1 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1389                 :           1 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1390                 :           1 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1391                 :             : 
    1392                 :           1 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1393                 :             :              "variable value is used.\n\n"));
    1394                 :           1 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1395                 :           1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1396                 :           1 : }
    1397                 :             : 
    1398                 :             : static void
    1399                 :         224 : setup_connection(Archive *AH, const char *dumpencoding,
    1400                 :             :                  const char *dumpsnapshot, char *use_role)
    1401                 :             : {
    1402                 :         224 :     DumpOptions *dopt = AH->dopt;
    1403                 :         224 :     PGconn     *conn = GetConnection(AH);
    1404                 :             : 
    1405                 :         224 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1406                 :             : 
    1407                 :             :     /*
    1408                 :             :      * Set the client encoding if requested.
    1409                 :             :      */
    1410         [ +  + ]:         224 :     if (dumpencoding)
    1411                 :             :     {
    1412         [ -  + ]:          18 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1413                 :           0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1414                 :             :                      dumpencoding);
    1415                 :             :     }
    1416                 :             : 
    1417                 :             :     /*
    1418                 :             :      * Force standard_conforming_strings on, just in case we are dumping from
    1419                 :             :      * an old server that has it disabled.  Without this, literals in views,
    1420                 :             :      * expressions, etc, would be incorrect for modern servers.
    1421                 :             :      */
    1422                 :         224 :     ExecuteSqlStatement(AH, "SET standard_conforming_strings = on");
    1423                 :             : 
    1424                 :             :     /*
    1425                 :             :      * And reflect that to AH->std_strings.  You might think that we should
    1426                 :             :      * just delete that variable and the code that checks it, but that would
    1427                 :             :      * be problematic for pg_restore, which at least for now should still cope
    1428                 :             :      * with archives containing the other setting (cf. processStdStringsEntry
    1429                 :             :      * in pg_backup_archiver.c).
    1430                 :             :      */
    1431                 :         224 :     AH->std_strings = true;
    1432                 :             : 
    1433                 :             :     /*
    1434                 :             :      * Get the active encoding, so we know how to escape strings.
    1435                 :             :      */
    1436                 :         224 :     AH->encoding = PQclientEncoding(conn);
    1437                 :         224 :     setFmtEncoding(AH->encoding);
    1438                 :             : 
    1439                 :             :     /*
    1440                 :             :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1441                 :             :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1442                 :             :      * originally) and we should use that.
    1443                 :             :      */
    1444   [ +  +  +  + ]:         224 :     if (!use_role && AH->use_role)
    1445                 :           2 :         use_role = AH->use_role;
    1446                 :             : 
    1447                 :             :     /* Set the role if requested */
    1448         [ +  + ]:         224 :     if (use_role)
    1449                 :             :     {
    1450                 :           5 :         PQExpBuffer query = createPQExpBuffer();
    1451                 :             : 
    1452                 :           5 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1453                 :           5 :         ExecuteSqlStatement(AH, query->data);
    1454                 :           5 :         destroyPQExpBuffer(query);
    1455                 :             : 
    1456                 :             :         /* save it for possible later use by parallel workers */
    1457         [ +  + ]:           5 :         if (!AH->use_role)
    1458                 :           3 :             AH->use_role = pg_strdup(use_role);
    1459                 :             :     }
    1460                 :             : 
    1461                 :             :     /* Set the datestyle to ISO to ensure the dump's portability */
    1462                 :         224 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1463                 :             : 
    1464                 :             :     /* Likewise, avoid using sql_standard intervalstyle */
    1465                 :         224 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1466                 :             : 
    1467                 :             :     /*
    1468                 :             :      * Use an explicitly specified extra_float_digits if it has been provided.
    1469                 :             :      * Otherwise, set extra_float_digits so that we can dump float data
    1470                 :             :      * exactly (given correctly implemented float I/O code, anyway).
    1471                 :             :      */
    1472         [ -  + ]:         224 :     if (have_extra_float_digits)
    1473                 :             :     {
    1474                 :           0 :         PQExpBuffer q = createPQExpBuffer();
    1475                 :             : 
    1476                 :           0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1477                 :             :                           extra_float_digits);
    1478                 :           0 :         ExecuteSqlStatement(AH, q->data);
    1479                 :           0 :         destroyPQExpBuffer(q);
    1480                 :             :     }
    1481                 :             :     else
    1482                 :         224 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1483                 :             : 
    1484                 :             :     /*
    1485                 :             :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1486                 :             :      * ordering across a dump and reload.
    1487                 :             :      */
    1488                 :         224 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1489                 :             : 
    1490                 :             :     /*
    1491                 :             :      * Disable timeouts if supported.
    1492                 :             :      */
    1493                 :         224 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1494                 :         224 :     ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1495                 :         224 :     ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1496         [ +  - ]:         224 :     if (AH->remoteVersion >= 170000)
    1497                 :         224 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1498                 :             : 
    1499                 :             :     /*
    1500                 :             :      * Quote all identifiers, if requested.
    1501                 :             :      */
    1502         [ +  + ]:         224 :     if (quote_all_identifiers)
    1503                 :          38 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1504                 :             : 
    1505                 :             :     /*
    1506                 :             :      * Adjust row-security mode, if supported.
    1507                 :             :      */
    1508         [ -  + ]:         224 :     if (dopt->enable_row_security)
    1509                 :           0 :         ExecuteSqlStatement(AH, "SET row_security = on");
    1510                 :             :     else
    1511                 :         224 :         ExecuteSqlStatement(AH, "SET row_security = off");
    1512                 :             : 
    1513                 :             :     /*
    1514                 :             :      * For security reasons, we restrict the expansion of non-system views and
    1515                 :             :      * access to foreign tables during the pg_dump process. This restriction
    1516                 :             :      * is adjusted when dumping foreign table data.
    1517                 :             :      */
    1518                 :         224 :     set_restrict_relation_kind(AH, "view, foreign-table");
    1519                 :             : 
    1520                 :             :     /*
    1521                 :             :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1522                 :             :      * so that a parallel dump worker will have its own state.
    1523                 :             :      */
    1524                 :         224 :     AH->is_prepared = pg_malloc0_array(bool, NUM_PREP_QUERIES);
    1525                 :             : 
    1526                 :             :     /*
    1527                 :             :      * Start transaction-snapshot mode transaction to dump consistent data.
    1528                 :             :      */
    1529                 :         224 :     ExecuteSqlStatement(AH, "BEGIN");
    1530                 :             : 
    1531                 :             :     /*
    1532                 :             :      * To support the combination of serializable_deferrable with the jobs
    1533                 :             :      * option we use REPEATABLE READ for the worker connections that are
    1534                 :             :      * passed a snapshot.  As long as the snapshot is acquired in a
    1535                 :             :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1536                 :             :      * REPEATABLE READ transaction provides the appropriate integrity
    1537                 :             :      * guarantees.  This is a kluge, but safe for back-patching.
    1538                 :             :      */
    1539   [ -  +  -  - ]:         224 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1540                 :           0 :         ExecuteSqlStatement(AH,
    1541                 :             :                             "SET TRANSACTION ISOLATION LEVEL "
    1542                 :             :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1543                 :             :     else
    1544                 :         224 :         ExecuteSqlStatement(AH,
    1545                 :             :                             "SET TRANSACTION ISOLATION LEVEL "
    1546                 :             :                             "REPEATABLE READ, READ ONLY");
    1547                 :             : 
    1548                 :             :     /*
    1549                 :             :      * If user specified a snapshot to use, select that.  In a parallel dump
    1550                 :             :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1551                 :             :      * is already set (if the server can handle it) and we should use that.
    1552                 :             :      */
    1553         [ -  + ]:         224 :     if (dumpsnapshot)
    1554                 :           0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1555                 :             : 
    1556         [ +  + ]:         224 :     if (AH->sync_snapshot_id)
    1557                 :             :     {
    1558                 :          16 :         PQExpBuffer query = createPQExpBuffer();
    1559                 :             : 
    1560                 :          16 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1561                 :          16 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1562                 :          16 :         ExecuteSqlStatement(AH, query->data);
    1563                 :          16 :         destroyPQExpBuffer(query);
    1564                 :             :     }
    1565         [ +  + ]:         208 :     else if (AH->numWorkers > 1)
    1566                 :           8 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1567                 :         224 : }
    1568                 :             : 
    1569                 :             : /* Set up connection for a parallel worker process */
    1570                 :             : static void
    1571                 :          16 : setupDumpWorker(Archive *AH)
    1572                 :             : {
    1573                 :             :     /*
    1574                 :             :      * We want to re-select all the same values the leader connection is
    1575                 :             :      * using.  We'll have inherited directly-usable values in
    1576                 :             :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1577                 :             :      * inherited encoding value back to a string to pass to setup_connection.
    1578                 :             :      */
    1579                 :          16 :     setup_connection(AH,
    1580                 :             :                      pg_encoding_to_char(AH->encoding),
    1581                 :             :                      NULL,
    1582                 :             :                      NULL);
    1583                 :          16 : }
    1584                 :             : 
    1585                 :             : static char *
    1586                 :           8 : get_synchronized_snapshot(Archive *fout)
    1587                 :             : {
    1588                 :           8 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1589                 :             :     char       *result;
    1590                 :             :     PGresult   *res;
    1591                 :             : 
    1592                 :           8 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1593                 :           8 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1594                 :           8 :     PQclear(res);
    1595                 :             : 
    1596                 :           8 :     return result;
    1597                 :             : }
    1598                 :             : 
    1599                 :             : static ArchiveFormat
    1600                 :         217 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1601                 :             : {
    1602                 :             :     ArchiveFormat archiveFormat;
    1603                 :             : 
    1604                 :         217 :     *mode = archModeWrite;
    1605                 :             : 
    1606   [ +  +  -  + ]:         217 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1607                 :             :     {
    1608                 :             :         /* This is used by pg_dumpall, and is not documented */
    1609                 :          48 :         archiveFormat = archNull;
    1610                 :          48 :         *mode = archModeAppend;
    1611                 :             :     }
    1612         [ -  + ]:         169 :     else if (pg_strcasecmp(format, "c") == 0)
    1613                 :           0 :         archiveFormat = archCustom;
    1614         [ +  + ]:         169 :     else if (pg_strcasecmp(format, "custom") == 0)
    1615                 :          51 :         archiveFormat = archCustom;
    1616         [ -  + ]:         118 :     else if (pg_strcasecmp(format, "d") == 0)
    1617                 :           0 :         archiveFormat = archDirectory;
    1618         [ +  + ]:         118 :     else if (pg_strcasecmp(format, "directory") == 0)
    1619                 :          10 :         archiveFormat = archDirectory;
    1620         [ +  + ]:         108 :     else if (pg_strcasecmp(format, "p") == 0)
    1621                 :         101 :         archiveFormat = archNull;
    1622         [ +  + ]:           7 :     else if (pg_strcasecmp(format, "plain") == 0)
    1623                 :           3 :         archiveFormat = archNull;
    1624         [ -  + ]:           4 :     else if (pg_strcasecmp(format, "t") == 0)
    1625                 :           0 :         archiveFormat = archTar;
    1626         [ +  + ]:           4 :     else if (pg_strcasecmp(format, "tar") == 0)
    1627                 :           3 :         archiveFormat = archTar;
    1628                 :             :     else
    1629                 :           1 :         pg_fatal("invalid output format \"%s\" specified", format);
    1630                 :         216 :     return archiveFormat;
    1631                 :             : }
    1632                 :             : 
    1633                 :             : /*
    1634                 :             :  * Find the OIDs of all schemas matching the given list of patterns,
    1635                 :             :  * and append them to the given OID list.
    1636                 :             :  */
    1637                 :             : static void
    1638                 :         220 : expand_schema_name_patterns(Archive *fout,
    1639                 :             :                             SimpleStringList *patterns,
    1640                 :             :                             SimpleOidList *oids,
    1641                 :             :                             bool strict_names)
    1642                 :             : {
    1643                 :             :     PQExpBuffer query;
    1644                 :             :     PGresult   *res;
    1645                 :             :     SimpleStringListCell *cell;
    1646                 :             :     int         i;
    1647                 :             : 
    1648         [ +  + ]:         220 :     if (patterns->head == NULL)
    1649                 :         198 :         return;                 /* nothing to do */
    1650                 :             : 
    1651                 :          22 :     query = createPQExpBuffer();
    1652                 :             : 
    1653                 :             :     /*
    1654                 :             :      * The loop below runs multiple SELECTs might sometimes result in
    1655                 :             :      * duplicate entries in the OID list, but we don't care.
    1656                 :             :      */
    1657                 :             : 
    1658         [ +  + ]:          38 :     for (cell = patterns->head; cell; cell = cell->next)
    1659                 :             :     {
    1660                 :             :         PQExpBufferData dbbuf;
    1661                 :             :         int         dotcnt;
    1662                 :             : 
    1663                 :          22 :         appendPQExpBufferStr(query,
    1664                 :             :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1665                 :          22 :         initPQExpBuffer(&dbbuf);
    1666                 :          22 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1667                 :             :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1668                 :             :                               &dotcnt);
    1669         [ +  + ]:          22 :         if (dotcnt > 1)
    1670                 :           2 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1671                 :             :                      cell->val);
    1672         [ +  + ]:          20 :         else if (dotcnt == 1)
    1673                 :           3 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1674                 :          17 :         termPQExpBuffer(&dbbuf);
    1675                 :             : 
    1676                 :          17 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1677   [ +  +  +  - ]:          17 :         if (strict_names && PQntuples(res) == 0)
    1678                 :           1 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1679                 :             : 
    1680         [ +  + ]:          31 :         for (i = 0; i < PQntuples(res); i++)
    1681                 :             :         {
    1682                 :          15 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1683                 :             :         }
    1684                 :             : 
    1685                 :          16 :         PQclear(res);
    1686                 :          16 :         resetPQExpBuffer(query);
    1687                 :             :     }
    1688                 :             : 
    1689                 :          16 :     destroyPQExpBuffer(query);
    1690                 :             : }
    1691                 :             : 
    1692                 :             : /*
    1693                 :             :  * Find the OIDs of all extensions matching the given list of patterns,
    1694                 :             :  * and append them to the given OID list.
    1695                 :             :  */
    1696                 :             : static void
    1697                 :         197 : expand_extension_name_patterns(Archive *fout,
    1698                 :             :                                SimpleStringList *patterns,
    1699                 :             :                                SimpleOidList *oids,
    1700                 :             :                                bool strict_names)
    1701                 :             : {
    1702                 :             :     PQExpBuffer query;
    1703                 :             :     PGresult   *res;
    1704                 :             :     SimpleStringListCell *cell;
    1705                 :             :     int         i;
    1706                 :             : 
    1707         [ +  + ]:         197 :     if (patterns->head == NULL)
    1708                 :         190 :         return;                 /* nothing to do */
    1709                 :             : 
    1710                 :           7 :     query = createPQExpBuffer();
    1711                 :             : 
    1712                 :             :     /*
    1713                 :             :      * The loop below runs multiple SELECTs might sometimes result in
    1714                 :             :      * duplicate entries in the OID list, but we don't care.
    1715                 :             :      */
    1716         [ +  + ]:          14 :     for (cell = patterns->head; cell; cell = cell->next)
    1717                 :             :     {
    1718                 :             :         int         dotcnt;
    1719                 :             : 
    1720                 :           7 :         appendPQExpBufferStr(query,
    1721                 :             :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1722                 :           7 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1723                 :             :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1724                 :             :                               &dotcnt);
    1725         [ -  + ]:           7 :         if (dotcnt > 0)
    1726                 :           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1727                 :             :                      cell->val);
    1728                 :             : 
    1729                 :           7 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1730   [ -  +  -  - ]:           7 :         if (strict_names && PQntuples(res) == 0)
    1731                 :           0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1732                 :             : 
    1733         [ +  + ]:          13 :         for (i = 0; i < PQntuples(res); i++)
    1734                 :             :         {
    1735                 :           6 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1736                 :             :         }
    1737                 :             : 
    1738                 :           7 :         PQclear(res);
    1739                 :           7 :         resetPQExpBuffer(query);
    1740                 :             :     }
    1741                 :             : 
    1742                 :           7 :     destroyPQExpBuffer(query);
    1743                 :             : }
    1744                 :             : 
    1745                 :             : /*
    1746                 :             :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1747                 :             :  * and append them to the given OID list.
    1748                 :             :  */
    1749                 :             : static void
    1750                 :         194 : expand_foreign_server_name_patterns(Archive *fout,
    1751                 :             :                                     SimpleStringList *patterns,
    1752                 :             :                                     SimpleOidList *oids)
    1753                 :             : {
    1754                 :             :     PQExpBuffer query;
    1755                 :             :     PGresult   *res;
    1756                 :             :     SimpleStringListCell *cell;
    1757                 :             :     int         i;
    1758                 :             : 
    1759         [ +  + ]:         194 :     if (patterns->head == NULL)
    1760                 :         191 :         return;                 /* nothing to do */
    1761                 :             : 
    1762                 :           3 :     query = createPQExpBuffer();
    1763                 :             : 
    1764                 :             :     /*
    1765                 :             :      * The loop below runs multiple SELECTs might sometimes result in
    1766                 :             :      * duplicate entries in the OID list, but we don't care.
    1767                 :             :      */
    1768                 :             : 
    1769         [ +  + ]:           5 :     for (cell = patterns->head; cell; cell = cell->next)
    1770                 :             :     {
    1771                 :             :         int         dotcnt;
    1772                 :             : 
    1773                 :           3 :         appendPQExpBufferStr(query,
    1774                 :             :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1775                 :           3 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1776                 :             :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1777                 :             :                               &dotcnt);
    1778         [ -  + ]:           3 :         if (dotcnt > 0)
    1779                 :           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1780                 :             :                      cell->val);
    1781                 :             : 
    1782                 :           3 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1783         [ +  + ]:           3 :         if (PQntuples(res) == 0)
    1784                 :           1 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1785                 :             : 
    1786         [ +  + ]:           4 :         for (i = 0; i < PQntuples(res); i++)
    1787                 :           2 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1788                 :             : 
    1789                 :           2 :         PQclear(res);
    1790                 :           2 :         resetPQExpBuffer(query);
    1791                 :             :     }
    1792                 :             : 
    1793                 :           2 :     destroyPQExpBuffer(query);
    1794                 :             : }
    1795                 :             : 
    1796                 :             : /*
    1797                 :             :  * Find the OIDs of all tables matching the given list of patterns,
    1798                 :             :  * and append them to the given OID list. See also expand_dbname_patterns()
    1799                 :             :  * in pg_dumpall.c
    1800                 :             :  */
    1801                 :             : static void
    1802                 :        1173 : expand_table_name_patterns(Archive *fout,
    1803                 :             :                            SimpleStringList *patterns, SimpleOidList *oids,
    1804                 :             :                            bool strict_names, bool with_child_tables)
    1805                 :             : {
    1806                 :             :     PQExpBuffer query;
    1807                 :             :     PGresult   *res;
    1808                 :             :     SimpleStringListCell *cell;
    1809                 :             :     int         i;
    1810                 :             : 
    1811         [ +  + ]:        1173 :     if (patterns->head == NULL)
    1812                 :        1144 :         return;                 /* nothing to do */
    1813                 :             : 
    1814                 :          29 :     query = createPQExpBuffer();
    1815                 :             : 
    1816                 :             :     /*
    1817                 :             :      * this might sometimes result in duplicate entries in the OID list, but
    1818                 :             :      * we don't care.
    1819                 :             :      */
    1820                 :             : 
    1821         [ +  + ]:          59 :     for (cell = patterns->head; cell; cell = cell->next)
    1822                 :             :     {
    1823                 :             :         PQExpBufferData dbbuf;
    1824                 :             :         int         dotcnt;
    1825                 :             : 
    1826                 :             :         /*
    1827                 :             :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1828                 :             :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1829                 :             :          * search_path argument.
    1830                 :             :          *
    1831                 :             :          * For with_child_tables, we start with the basic query's results and
    1832                 :             :          * recursively search the inheritance tree to add child tables.
    1833                 :             :          */
    1834         [ +  + ]:          35 :         if (with_child_tables)
    1835                 :             :         {
    1836                 :           6 :             appendPQExpBufferStr(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1837                 :             :         }
    1838                 :             : 
    1839                 :          35 :         appendPQExpBuffer(query,
    1840                 :             :                           "SELECT c.oid"
    1841                 :             :                           "\nFROM pg_catalog.pg_class c"
    1842                 :             :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1843                 :             :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1844                 :             :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1845                 :             :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1846                 :             :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1847                 :             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1848                 :             :                           RELKIND_PARTITIONED_TABLE, RELKIND_PROPGRAPH);
    1849                 :          35 :         initPQExpBuffer(&dbbuf);
    1850                 :          35 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1851                 :             :                               false, "n.nspname", "c.relname", NULL,
    1852                 :             :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1853                 :             :                               &dotcnt);
    1854         [ +  + ]:          35 :         if (dotcnt > 2)
    1855                 :           1 :             pg_fatal("improper relation name (too many dotted names): %s",
    1856                 :             :                      cell->val);
    1857         [ +  + ]:          34 :         else if (dotcnt == 2)
    1858                 :           2 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1859                 :          32 :         termPQExpBuffer(&dbbuf);
    1860                 :             : 
    1861         [ +  + ]:          32 :         if (with_child_tables)
    1862                 :             :         {
    1863                 :           6 :             appendPQExpBufferStr(query, "UNION"
    1864                 :             :                                  "\nSELECT i.inhrelid"
    1865                 :             :                                  "\nFROM partition_tree p"
    1866                 :             :                                  "\n     JOIN pg_catalog.pg_inherits i"
    1867                 :             :                                  "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1868                 :             :                                  "\n)"
    1869                 :             :                                  "\nSELECT relid FROM partition_tree");
    1870                 :             :         }
    1871                 :             : 
    1872                 :          32 :         ExecuteSqlStatement(fout, "RESET search_path");
    1873                 :          32 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1874                 :          32 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1875                 :             :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1876   [ +  +  +  + ]:          32 :         if (strict_names && PQntuples(res) == 0)
    1877                 :           2 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1878                 :             : 
    1879         [ +  + ]:          74 :         for (i = 0; i < PQntuples(res); i++)
    1880                 :             :         {
    1881                 :          44 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1882                 :             :         }
    1883                 :             : 
    1884                 :          30 :         PQclear(res);
    1885                 :          30 :         resetPQExpBuffer(query);
    1886                 :             :     }
    1887                 :             : 
    1888                 :          24 :     destroyPQExpBuffer(query);
    1889                 :             : }
    1890                 :             : 
    1891                 :             : /*
    1892                 :             :  * Verifies that the connected database name matches the given database name,
    1893                 :             :  * and if not, dies with an error about the given pattern.
    1894                 :             :  *
    1895                 :             :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1896                 :             :  */
    1897                 :             : static void
    1898                 :           5 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1899                 :             : {
    1900                 :             :     const char *db;
    1901                 :             : 
    1902                 :           5 :     db = PQdb(conn);
    1903         [ -  + ]:           5 :     if (db == NULL)
    1904                 :           0 :         pg_fatal("You are currently not connected to a database.");
    1905                 :             : 
    1906         [ +  - ]:           5 :     if (strcmp(db, dbname) != 0)
    1907                 :           5 :         pg_fatal("cross-database references are not implemented: %s",
    1908                 :             :                  pattern);
    1909                 :           0 : }
    1910                 :             : 
    1911                 :             : /*
    1912                 :             :  * checkExtensionMembership
    1913                 :             :  *      Determine whether object is an extension member, and if so,
    1914                 :             :  *      record an appropriate dependency and set the object's dump flag.
    1915                 :             :  *
    1916                 :             :  * It's important to call this for each object that could be an extension
    1917                 :             :  * member.  Generally, we integrate this with determining the object's
    1918                 :             :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1919                 :             :  *
    1920                 :             :  * Returns true if object is an extension member, else false.
    1921                 :             :  */
    1922                 :             : static bool
    1923                 :      623246 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1924                 :             : {
    1925                 :      623246 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1926                 :             : 
    1927         [ +  + ]:      623246 :     if (ext == NULL)
    1928                 :      622429 :         return false;
    1929                 :             : 
    1930                 :         817 :     dobj->ext_member = true;
    1931                 :             : 
    1932                 :             :     /* Record dependency so that getDependencies needn't deal with that */
    1933                 :         817 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1934                 :             : 
    1935                 :             :     /*
    1936                 :             :      * Mark the member object to have any non-initial ACLs dumped.  (Any
    1937                 :             :      * initial ACLs will be removed later, using data from pg_init_privs, so
    1938                 :             :      * that we'll dump only the delta from the extension's initial setup.)
    1939                 :             :      *
    1940                 :             :      * In binary upgrades, we still dump all components of the members
    1941                 :             :      * individually, since the idea is to exactly reproduce the database
    1942                 :             :      * contents rather than replace the extension contents with something
    1943                 :             :      * different.
    1944                 :             :      *
    1945                 :             :      * Note: it might be interesting someday to implement storage and delta
    1946                 :             :      * dumping of extension members' RLS policies and/or security labels.
    1947                 :             :      * However there is a pitfall for RLS policies: trying to dump them
    1948                 :             :      * requires getting a lock on their tables, and the calling user might not
    1949                 :             :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1950                 :             :      * so the current feature doesn't have a problem of that sort.
    1951                 :             :      */
    1952         [ +  + ]:         817 :     if (fout->dopt->binary_upgrade)
    1953                 :         186 :         dobj->dump = ext->dobj.dump;
    1954                 :             :     else
    1955                 :         631 :         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1956                 :             : 
    1957                 :         817 :     return true;
    1958                 :             : }
    1959                 :             : 
    1960                 :             : /*
    1961                 :             :  * selectDumpableNamespace: policy-setting subroutine
    1962                 :             :  *      Mark a namespace as to be dumped or not
    1963                 :             :  */
    1964                 :             : static void
    1965                 :        1696 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1966                 :             : {
    1967                 :             :     /*
    1968                 :             :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1969                 :             :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    1970                 :             :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    1971                 :             :      */
    1972                 :        1696 :     nsinfo->create = true;
    1973                 :             : 
    1974                 :             :     /*
    1975                 :             :      * If specific tables are being dumped, do not dump any complete
    1976                 :             :      * namespaces. If specific namespaces are being dumped, dump just those
    1977                 :             :      * namespaces. Otherwise, dump all non-system namespaces.
    1978                 :             :      */
    1979         [ +  + ]:        1696 :     if (table_include_oids.head != NULL)
    1980                 :          61 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1981         [ +  + ]:        1635 :     else if (schema_include_oids.head != NULL)
    1982                 :         213 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    1983                 :         213 :             simple_oid_list_member(&schema_include_oids,
    1984                 :             :                                    nsinfo->dobj.catId.oid) ?
    1985         [ +  + ]:         213 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1986         [ +  + ]:        1422 :     else if (strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    1987                 :             :     {
    1988                 :             :         /*
    1989                 :             :          * We dump out any ACLs defined in pg_catalog, if they are interesting
    1990                 :             :          * (and not the original ACLs which were set at initdb time, see
    1991                 :             :          * pg_init_privs).
    1992                 :             :          */
    1993                 :         169 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    1994                 :             :     }
    1995         [ +  + ]:        1253 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    1996         [ +  + ]:         535 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    1997                 :             :     {
    1998                 :             :         /* Other system schemas don't get dumped */
    1999                 :         887 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2000                 :             :     }
    2001         [ +  + ]:         366 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    2002                 :             :     {
    2003                 :             :         /*
    2004                 :             :          * The public schema is a strange beast that sits in a sort of
    2005                 :             :          * no-mans-land between being a system object and a user object.
    2006                 :             :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    2007                 :             :          * a comment and an indication of ownership.  If the owner is the
    2008                 :             :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    2009                 :             :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    2010                 :             :          */
    2011                 :         165 :         nsinfo->create = false;
    2012                 :         165 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2013         [ +  + ]:         165 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    2014                 :         121 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    2015                 :         165 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    2016                 :             : 
    2017                 :             :         /*
    2018                 :             :          * Also, make like it has a comment even if it doesn't; this is so
    2019                 :             :          * that we'll emit a command to drop the comment, if appropriate.
    2020                 :             :          * (Without this, we'd not call dumpCommentExtended for it.)
    2021                 :             :          */
    2022                 :         165 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    2023                 :             :     }
    2024                 :             :     else
    2025                 :         201 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    2026                 :             : 
    2027                 :             :     /*
    2028                 :             :      * In any case, a namespace can be excluded by an exclusion switch
    2029                 :             :      */
    2030   [ +  +  +  + ]:        2243 :     if (nsinfo->dobj.dump_contains &&
    2031                 :         547 :         simple_oid_list_member(&schema_exclude_oids,
    2032                 :             :                                nsinfo->dobj.catId.oid))
    2033                 :           3 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2034                 :             : 
    2035                 :             :     /*
    2036                 :             :      * If the schema belongs to an extension, allow extension membership to
    2037                 :             :      * override the dump decision for the schema itself.  However, this does
    2038                 :             :      * not change dump_contains, so this won't change what we do with objects
    2039                 :             :      * within the schema.  (If they belong to the extension, they'll get
    2040                 :             :      * suppressed by it, otherwise not.)
    2041                 :             :      */
    2042                 :        1696 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    2043                 :        1696 : }
    2044                 :             : 
    2045                 :             : /*
    2046                 :             :  * selectDumpableTable: policy-setting subroutine
    2047                 :             :  *      Mark a table as to be dumped or not
    2048                 :             :  */
    2049                 :             : static void
    2050                 :       55102 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    2051                 :             : {
    2052         [ +  + ]:       55102 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    2053                 :         225 :         return;                 /* extension membership overrides all else */
    2054                 :             : 
    2055                 :             :     /*
    2056                 :             :      * If specific tables are being dumped, dump just those tables; else, dump
    2057                 :             :      * according to the parent namespace's dump flag.
    2058                 :             :      */
    2059         [ +  + ]:       54877 :     if (table_include_oids.head != NULL)
    2060                 :        5668 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    2061                 :             :                                                    tbinfo->dobj.catId.oid) ?
    2062         [ +  + ]:        2834 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2063                 :             :     else
    2064                 :       52043 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    2065                 :             : 
    2066                 :             :     /*
    2067                 :             :      * In any case, a table can be excluded by an exclusion switch
    2068                 :             :      */
    2069   [ +  +  +  + ]:       89133 :     if (tbinfo->dobj.dump &&
    2070                 :       34256 :         simple_oid_list_member(&table_exclude_oids,
    2071                 :             :                                tbinfo->dobj.catId.oid))
    2072                 :          12 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2073                 :             : }
    2074                 :             : 
    2075                 :             : /*
    2076                 :             :  * selectDumpableType: policy-setting subroutine
    2077                 :             :  *      Mark a type as to be dumped or not
    2078                 :             :  *
    2079                 :             :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    2080                 :             :  * special type code to facilitate sorting into the desired order.  (We don't
    2081                 :             :  * want to consider those to be ordinary types because that would bring tables
    2082                 :             :  * up into the datatype part of the dump order.)  We still set the object's
    2083                 :             :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    2084                 :             :  * need it so that casts involving such types will be dumped correctly -- see
    2085                 :             :  * dumpCast.  This means the flag should be set the same as for the underlying
    2086                 :             :  * object (the table or base type).
    2087                 :             :  */
    2088                 :             : static void
    2089                 :      147978 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    2090                 :             : {
    2091                 :             :     /* skip complex types, except for standalone composite types */
    2092         [ +  + ]:      147978 :     if (OidIsValid(tyinfo->typrelid) &&
    2093         [ +  + ]:       54200 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2094                 :             :     {
    2095                 :       54015 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2096                 :             : 
    2097                 :       54015 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2098         [ +  - ]:       54015 :         if (tytable != NULL)
    2099                 :       54015 :             tyinfo->dobj.dump = tytable->dobj.dump;
    2100                 :             :         else
    2101                 :           0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2102                 :       54015 :         return;
    2103                 :             :     }
    2104                 :             : 
    2105                 :             :     /* skip auto-generated array and multirange types */
    2106   [ +  +  +  + ]:       93963 :     if (tyinfo->isArray || tyinfo->isMultirange)
    2107                 :             :     {
    2108                 :       72483 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2109                 :             : 
    2110                 :             :         /*
    2111                 :             :          * Fall through to set the dump flag; we assume that the subsequent
    2112                 :             :          * rules will do the same thing as they would for the array's base
    2113                 :             :          * type or multirange's range type.  (We cannot reliably look up the
    2114                 :             :          * base type here, since getTypes may not have processed it yet.)
    2115                 :             :          */
    2116                 :             :     }
    2117                 :             : 
    2118         [ +  + ]:       93963 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    2119                 :         150 :         return;                 /* extension membership overrides all else */
    2120                 :             : 
    2121                 :             :     /* Dump based on if the contents of the namespace are being dumped */
    2122                 :       93813 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    2123                 :             : }
    2124                 :             : 
    2125                 :             : /*
    2126                 :             :  * selectDumpableDefaultACL: policy-setting subroutine
    2127                 :             :  *      Mark a default ACL as to be dumped or not
    2128                 :             :  *
    2129                 :             :  * For per-schema default ACLs, dump if the schema is to be dumped.
    2130                 :             :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    2131                 :             :  * and aclsSkip are checked separately.
    2132                 :             :  */
    2133                 :             : static void
    2134                 :         206 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2135                 :             : {
    2136                 :             :     /* Default ACLs can't be extension members */
    2137                 :             : 
    2138         [ +  + ]:         206 :     if (dinfo->dobj.namespace)
    2139                 :             :         /* default ACLs are considered part of the namespace */
    2140                 :          96 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2141                 :             :     else
    2142                 :         110 :         dinfo->dobj.dump = dopt->include_everything ?
    2143         [ +  + ]:         110 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2144                 :         206 : }
    2145                 :             : 
    2146                 :             : /*
    2147                 :             :  * selectDumpableCast: policy-setting subroutine
    2148                 :             :  *      Mark a cast as to be dumped or not
    2149                 :             :  *
    2150                 :             :  * Casts do not belong to any particular namespace (since they haven't got
    2151                 :             :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2152                 :             :  * casts from built-in ones, we must resort to checking whether the cast's
    2153                 :             :  * OID is in the range reserved for initdb.
    2154                 :             :  */
    2155                 :             : static void
    2156                 :       46503 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2157                 :             : {
    2158         [ -  + ]:       46503 :     if (checkExtensionMembership(&cast->dobj, fout))
    2159                 :           0 :         return;                 /* extension membership overrides all else */
    2160                 :             : 
    2161                 :             :     /*
    2162                 :             :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2163                 :             :      * support ACLs currently.
    2164                 :             :      */
    2165         [ +  + ]:       46503 :     if (cast->dobj.catId.oid <= g_last_builtin_oid)
    2166                 :       46413 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2167                 :             :     else
    2168                 :          90 :         cast->dobj.dump = fout->dopt->include_everything ?
    2169         [ +  + ]:          90 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2170                 :             : }
    2171                 :             : 
    2172                 :             : /*
    2173                 :             :  * selectDumpableProcLang: policy-setting subroutine
    2174                 :             :  *      Mark a procedural language as to be dumped or not
    2175                 :             :  *
    2176                 :             :  * Procedural languages do not belong to any particular namespace.  To
    2177                 :             :  * identify built-in languages, we must resort to checking whether the
    2178                 :             :  * language's OID is in the range reserved for initdb.
    2179                 :             :  */
    2180                 :             : static void
    2181                 :         239 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2182                 :             : {
    2183         [ +  + ]:         239 :     if (checkExtensionMembership(&plang->dobj, fout))
    2184                 :         191 :         return;                 /* extension membership overrides all else */
    2185                 :             : 
    2186                 :             :     /*
    2187                 :             :      * Only include procedural languages when we are dumping everything.
    2188                 :             :      *
    2189                 :             :      * For from-initdb procedural languages, only include ACLs, as we do for
    2190                 :             :      * the pg_catalog namespace.  We need this because procedural languages do
    2191                 :             :      * not live in any namespace.
    2192                 :             :      */
    2193         [ +  + ]:          48 :     if (!fout->dopt->include_everything)
    2194                 :           9 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2195                 :             :     else
    2196                 :             :     {
    2197         [ -  + ]:          39 :         if (plang->dobj.catId.oid <= g_last_builtin_oid)
    2198                 :           0 :             plang->dobj.dump = DUMP_COMPONENT_ACL;
    2199                 :             :         else
    2200                 :          39 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    2201                 :             :     }
    2202                 :             : }
    2203                 :             : 
    2204                 :             : /*
    2205                 :             :  * selectDumpableAccessMethod: policy-setting subroutine
    2206                 :             :  *      Mark an access method as to be dumped or not
    2207                 :             :  *
    2208                 :             :  * Access methods do not belong to any particular namespace.  To identify
    2209                 :             :  * built-in access methods, we must resort to checking whether the
    2210                 :             :  * method's OID is in the range reserved for initdb.
    2211                 :             :  */
    2212                 :             : static void
    2213                 :        1465 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2214                 :             : {
    2215         [ +  + ]:        1465 :     if (checkExtensionMembership(&method->dobj, fout))
    2216                 :          25 :         return;                 /* extension membership overrides all else */
    2217                 :             : 
    2218                 :             :     /*
    2219                 :             :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2220                 :             :      * they do not support ACLs currently.
    2221                 :             :      */
    2222         [ +  + ]:        1440 :     if (method->dobj.catId.oid <= g_last_builtin_oid)
    2223                 :        1337 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2224                 :             :     else
    2225                 :         103 :         method->dobj.dump = fout->dopt->include_everything ?
    2226         [ +  + ]:         103 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2227                 :             : }
    2228                 :             : 
    2229                 :             : /*
    2230                 :             :  * selectDumpableExtension: policy-setting subroutine
    2231                 :             :  *      Mark an extension as to be dumped or not
    2232                 :             :  *
    2233                 :             :  * Built-in extensions should be skipped except for checking ACLs, since we
    2234                 :             :  * assume those will already be installed in the target database.  We identify
    2235                 :             :  * such extensions by their having OIDs in the range reserved for initdb.
    2236                 :             :  * We dump all user-added extensions by default.  No extensions are dumped
    2237                 :             :  * if include_everything is false (i.e., a --schema or --table switch was
    2238                 :             :  * given), except if --extension specifies a list of extensions to dump.
    2239                 :             :  */
    2240                 :             : static void
    2241                 :         223 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2242                 :             : {
    2243                 :             :     /*
    2244                 :             :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2245                 :             :      * change permissions on their member objects, if they wish to, and have
    2246                 :             :      * those changes preserved.
    2247                 :             :      */
    2248         [ +  + ]:         223 :     if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
    2249                 :         192 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2250                 :             :     else
    2251                 :             :     {
    2252                 :             :         /* check if there is a list of extensions to dump */
    2253         [ +  + ]:          31 :         if (extension_include_oids.head != NULL)
    2254                 :           4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2255                 :           4 :                 simple_oid_list_member(&extension_include_oids,
    2256                 :             :                                        extinfo->dobj.catId.oid) ?
    2257         [ +  + ]:           4 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2258                 :             :         else
    2259                 :          27 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2260                 :          27 :                 dopt->include_everything ?
    2261         [ +  + ]:          27 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2262                 :             : 
    2263                 :             :         /* check that the extension is not explicitly excluded */
    2264   [ +  +  +  + ]:          58 :         if (extinfo->dobj.dump &&
    2265                 :          27 :             simple_oid_list_member(&extension_exclude_oids,
    2266                 :             :                                    extinfo->dobj.catId.oid))
    2267                 :           2 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2268                 :             :     }
    2269                 :         223 : }
    2270                 :             : 
    2271                 :             : /*
    2272                 :             :  * selectDumpablePublicationObject: policy-setting subroutine
    2273                 :             :  *      Mark a publication object as to be dumped or not
    2274                 :             :  *
    2275                 :             :  * A publication can have schemas and tables which have schemas, but those are
    2276                 :             :  * ignored in decision making, because publications are only dumped when we are
    2277                 :             :  * dumping everything.
    2278                 :             :  */
    2279                 :             : static void
    2280                 :         502 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2281                 :             : {
    2282         [ -  + ]:         502 :     if (checkExtensionMembership(dobj, fout))
    2283                 :           0 :         return;                 /* extension membership overrides all else */
    2284                 :             : 
    2285                 :         502 :     dobj->dump = fout->dopt->include_everything ?
    2286         [ +  + ]:         502 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2287                 :             : }
    2288                 :             : 
    2289                 :             : /*
    2290                 :             :  * selectDumpableStatisticsObject: policy-setting subroutine
    2291                 :             :  *      Mark an extended statistics object as to be dumped or not
    2292                 :             :  *
    2293                 :             :  * We dump an extended statistics object if the schema it's in and the table
    2294                 :             :  * it's for are being dumped.  (This'll need more thought if statistics
    2295                 :             :  * objects ever support cross-table stats.)
    2296                 :             :  */
    2297                 :             : static void
    2298                 :         220 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2299                 :             : {
    2300         [ -  + ]:         220 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2301                 :           0 :         return;                 /* extension membership overrides all else */
    2302                 :             : 
    2303                 :         220 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2304         [ +  - ]:         220 :     if (sobj->stattable == NULL ||
    2305         [ +  + ]:         220 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2306                 :          35 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2307                 :             : }
    2308                 :             : 
    2309                 :             : /*
    2310                 :             :  * selectDumpableObject: policy-setting subroutine
    2311                 :             :  *      Mark a generic dumpable object as to be dumped or not
    2312                 :             :  *
    2313                 :             :  * Use this only for object types without a special-case routine above.
    2314                 :             :  */
    2315                 :             : static void
    2316                 :      423556 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2317                 :             : {
    2318         [ +  + ]:      423556 :     if (checkExtensionMembership(dobj, fout))
    2319                 :         201 :         return;                 /* extension membership overrides all else */
    2320                 :             : 
    2321                 :             :     /*
    2322                 :             :      * Default policy is to dump if parent namespace is dumpable, or for
    2323                 :             :      * non-namespace-associated items, dump if we're dumping "everything".
    2324                 :             :      */
    2325         [ +  + ]:      423355 :     if (dobj->namespace)
    2326                 :      422440 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2327                 :             :     else
    2328                 :         915 :         dobj->dump = fout->dopt->include_everything ?
    2329         [ +  + ]:         915 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2330                 :             : }
    2331                 :             : 
    2332                 :             : /*
    2333                 :             :  *  Dump a table's contents for loading using the COPY command
    2334                 :             :  *  - this routine is called by the Archiver when it wants the table
    2335                 :             :  *    to be dumped.
    2336                 :             :  */
    2337                 :             : static int
    2338                 :        4432 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2339                 :             : {
    2340                 :        4432 :     const TableDataInfo *tdinfo = dcontext;
    2341                 :        4432 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2342                 :        4432 :     const char *classname = tbinfo->dobj.name;
    2343                 :        4432 :     PQExpBuffer q = createPQExpBuffer();
    2344                 :             : 
    2345                 :             :     /*
    2346                 :             :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2347                 :             :      * which uses it already.
    2348                 :             :      */
    2349                 :        4432 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2350                 :        4432 :     PGconn     *conn = GetConnection(fout);
    2351                 :             :     PGresult   *res;
    2352                 :             :     int         ret;
    2353                 :             :     char       *copybuf;
    2354                 :             :     const char *column_list;
    2355                 :             : 
    2356                 :        4432 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2357                 :             :                 tbinfo->dobj.namespace->dobj.name, classname);
    2358                 :             : 
    2359                 :             :     /*
    2360                 :             :      * Specify the column list explicitly so that we have no possibility of
    2361                 :             :      * retrieving data in the wrong column order.  (The default column
    2362                 :             :      * ordering of COPY will not be what we want in certain corner cases
    2363                 :             :      * involving ADD COLUMN and inheritance.)
    2364                 :             :      */
    2365                 :        4432 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2366                 :             : 
    2367                 :             :     /*
    2368                 :             :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, when a
    2369                 :             :      * filter condition was specified, and when in binary upgrade mode and
    2370                 :             :      * dumping an old pg_largeobject_metadata defined WITH OIDS.  For other
    2371                 :             :      * cases a simple COPY suffices.
    2372                 :             :      */
    2373   [ +  +  +  + ]:        4432 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
    2374   [ -  +  -  - ]:        4391 :         (fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
    2375         [ #  # ]:           0 :          tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
    2376                 :             :     {
    2377                 :             :         /* Temporary allows to access to foreign tables to dump data */
    2378         [ +  + ]:          41 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2379                 :           1 :             set_restrict_relation_kind(fout, "view");
    2380                 :             : 
    2381                 :          41 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2382                 :             :         /* klugery to get rid of parens in column list */
    2383         [ +  - ]:          41 :         if (strlen(column_list) > 2)
    2384                 :             :         {
    2385                 :          41 :             appendPQExpBufferStr(q, column_list + 1);
    2386                 :          41 :             q->data[q->len - 1] = ' ';
    2387                 :             :         }
    2388                 :             :         else
    2389                 :           0 :             appendPQExpBufferStr(q, "* ");
    2390                 :             : 
    2391                 :          82 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2392                 :          41 :                           fmtQualifiedDumpable(tbinfo),
    2393         [ +  + ]:          41 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2394                 :             :     }
    2395                 :             :     else
    2396                 :             :     {
    2397                 :        4391 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2398                 :        4391 :                           fmtQualifiedDumpable(tbinfo),
    2399                 :             :                           column_list);
    2400                 :             :     }
    2401                 :        4432 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2402                 :        4431 :     PQclear(res);
    2403                 :        4431 :     destroyPQExpBuffer(clistBuf);
    2404                 :             : 
    2405                 :             :     for (;;)
    2406                 :             :     {
    2407                 :     1824115 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2408                 :             : 
    2409         [ +  + ]:     1824115 :         if (ret < 0)
    2410                 :        4431 :             break;              /* done or error */
    2411                 :             : 
    2412         [ +  - ]:     1819684 :         if (copybuf)
    2413                 :             :         {
    2414                 :     1819684 :             WriteData(fout, copybuf, ret);
    2415                 :     1819684 :             PQfreemem(copybuf);
    2416                 :             :         }
    2417                 :             : 
    2418                 :             :         /* ----------
    2419                 :             :          * THROTTLE:
    2420                 :             :          *
    2421                 :             :          * There was considerable discussion in late July, 2000 regarding
    2422                 :             :          * slowing down pg_dump when backing up large tables. Users with both
    2423                 :             :          * slow & fast (multi-processor) machines experienced performance
    2424                 :             :          * degradation when doing a backup.
    2425                 :             :          *
    2426                 :             :          * Initial attempts based on sleeping for a number of ms for each ms
    2427                 :             :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2428                 :             :          * implementation was suggested. The latter failed because the loop
    2429                 :             :          * was too tight. Finally, the following was implemented:
    2430                 :             :          *
    2431                 :             :          * If throttle is non-zero, then
    2432                 :             :          *      See how long since the last sleep.
    2433                 :             :          *      Work out how long to sleep (based on ratio).
    2434                 :             :          *      If sleep is more than 100ms, then
    2435                 :             :          *          sleep
    2436                 :             :          *          reset timer
    2437                 :             :          *      EndIf
    2438                 :             :          * EndIf
    2439                 :             :          *
    2440                 :             :          * where the throttle value was the number of ms to sleep per ms of
    2441                 :             :          * work. The calculation was done in each loop.
    2442                 :             :          *
    2443                 :             :          * Most of the hard work is done in the backend, and this solution
    2444                 :             :          * still did not work particularly well: on slow machines, the ratio
    2445                 :             :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2446                 :             :          * multi-processor machines, it had little or no effect, for reasons
    2447                 :             :          * that were unclear.
    2448                 :             :          *
    2449                 :             :          * Further discussion ensued, and the proposal was dropped.
    2450                 :             :          *
    2451                 :             :          * For those people who want this feature, it can be implemented using
    2452                 :             :          * gettimeofday in each loop, calculating the time since last sleep,
    2453                 :             :          * multiplying that by the sleep ratio, then if the result is more
    2454                 :             :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2455                 :             :          * function to sleep for a subsecond period ie.
    2456                 :             :          *
    2457                 :             :          * select(0, NULL, NULL, NULL, &tvi);
    2458                 :             :          *
    2459                 :             :          * This will return after the interval specified in the structure tvi.
    2460                 :             :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2461                 :             :          * ----------
    2462                 :             :          */
    2463                 :             :     }
    2464                 :        4431 :     archprintf(fout, "\\.\n\n\n");
    2465                 :             : 
    2466         [ -  + ]:        4431 :     if (ret == -2)
    2467                 :             :     {
    2468                 :             :         /* copy data transfer failed */
    2469                 :           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2470                 :           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2471                 :           0 :         pg_log_error_detail("Command was: %s", q->data);
    2472                 :           0 :         exit_nicely(1);
    2473                 :             :     }
    2474                 :             : 
    2475                 :             :     /* Check command status and return to normal libpq state */
    2476                 :        4431 :     res = PQgetResult(conn);
    2477         [ -  + ]:        4431 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2478                 :             :     {
    2479                 :           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2480                 :           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2481                 :           0 :         pg_log_error_detail("Command was: %s", q->data);
    2482                 :           0 :         exit_nicely(1);
    2483                 :             :     }
    2484                 :        4431 :     PQclear(res);
    2485                 :             : 
    2486                 :             :     /* Do this to ensure we've pumped libpq back to idle state */
    2487         [ -  + ]:        4431 :     if (PQgetResult(conn) != NULL)
    2488                 :           0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2489                 :             :                        classname);
    2490                 :             : 
    2491                 :        4431 :     destroyPQExpBuffer(q);
    2492                 :             : 
    2493                 :             :     /* Revert back the setting */
    2494         [ -  + ]:        4431 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2495                 :           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2496                 :             : 
    2497                 :        4431 :     return 1;
    2498                 :             : }
    2499                 :             : 
    2500                 :             : /*
    2501                 :             :  * Dump table data using INSERT commands.
    2502                 :             :  *
    2503                 :             :  * Caution: when we restore from an archive file direct to database, the
    2504                 :             :  * INSERT commands emitted by this function have to be parsed by
    2505                 :             :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2506                 :             :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2507                 :             :  */
    2508                 :             : static int
    2509                 :          87 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2510                 :             : {
    2511                 :          87 :     const TableDataInfo *tdinfo = dcontext;
    2512                 :          87 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2513                 :          87 :     DumpOptions *dopt = fout->dopt;
    2514                 :          87 :     PQExpBuffer q = createPQExpBuffer();
    2515                 :          87 :     PQExpBuffer insertStmt = NULL;
    2516                 :             :     char       *attgenerated;
    2517                 :             :     PGresult   *res;
    2518                 :             :     int         nfields,
    2519                 :             :                 i;
    2520                 :          87 :     int         rows_per_statement = dopt->dump_inserts;
    2521                 :          87 :     int         rows_this_statement = 0;
    2522                 :             : 
    2523                 :             :     /* Temporary allows to access to foreign tables to dump data */
    2524         [ -  + ]:          87 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2525                 :           0 :         set_restrict_relation_kind(fout, "view");
    2526                 :             : 
    2527                 :             :     /*
    2528                 :             :      * If we're going to emit INSERTs with column names, the most efficient
    2529                 :             :      * way to deal with generated columns is to exclude them entirely.  For
    2530                 :             :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2531                 :             :      * actual column value --- but we can save a few cycles by fetching nulls
    2532                 :             :      * rather than the uninteresting-to-us value.
    2533                 :             :      */
    2534                 :          87 :     attgenerated = pg_malloc_array(char, tbinfo->numatts);
    2535                 :          87 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2536                 :          87 :     nfields = 0;
    2537         [ +  + ]:         269 :     for (i = 0; i < tbinfo->numatts; i++)
    2538                 :             :     {
    2539         [ +  + ]:         182 :         if (tbinfo->attisdropped[i])
    2540                 :           2 :             continue;
    2541   [ +  +  +  + ]:         180 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2542                 :           8 :             continue;
    2543         [ +  + ]:         172 :         if (nfields > 0)
    2544                 :          92 :             appendPQExpBufferStr(q, ", ");
    2545         [ +  + ]:         172 :         if (tbinfo->attgenerated[i])
    2546                 :           8 :             appendPQExpBufferStr(q, "NULL");
    2547                 :             :         else
    2548                 :         164 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2549                 :         172 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2550                 :         172 :         nfields++;
    2551                 :             :     }
    2552                 :             :     /* Servers before 9.4 will complain about zero-column SELECT */
    2553         [ +  + ]:          87 :     if (nfields == 0)
    2554                 :           7 :         appendPQExpBufferStr(q, "NULL");
    2555                 :          87 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2556                 :          87 :                       fmtQualifiedDumpable(tbinfo));
    2557         [ -  + ]:          87 :     if (tdinfo->filtercond)
    2558                 :           0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2559                 :             : 
    2560                 :          87 :     ExecuteSqlStatement(fout, q->data);
    2561                 :             : 
    2562                 :             :     while (1)
    2563                 :             :     {
    2564                 :         139 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2565                 :             :                               PGRES_TUPLES_OK);
    2566                 :             : 
    2567                 :             :         /* cross-check field count, allowing for dummy NULL if any */
    2568   [ +  +  +  - ]:         139 :         if (nfields != PQnfields(res) &&
    2569         [ -  + ]:          10 :             !(nfields == 0 && PQnfields(res) == 1))
    2570                 :           0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2571                 :             :                      tbinfo->dobj.name);
    2572                 :             : 
    2573                 :             :         /*
    2574                 :             :          * First time through, we build as much of the INSERT statement as
    2575                 :             :          * possible in "insertStmt", which we can then just print for each
    2576                 :             :          * statement. If the table happens to have zero dumpable columns then
    2577                 :             :          * this will be a complete statement, otherwise it will end in
    2578                 :             :          * "VALUES" and be ready to have the row's column values printed.
    2579                 :             :          */
    2580         [ +  + ]:         139 :         if (insertStmt == NULL)
    2581                 :             :         {
    2582                 :             :             const TableInfo *targettab;
    2583                 :             : 
    2584                 :          87 :             insertStmt = createPQExpBuffer();
    2585                 :             : 
    2586                 :             :             /*
    2587                 :             :              * When load-via-partition-root is set or forced, get the root
    2588                 :             :              * table name for the partition table, so that we can reload data
    2589                 :             :              * through the root table.
    2590                 :             :              */
    2591         [ +  + ]:          87 :             if (tbinfo->ispartition &&
    2592   [ +  -  +  + ]:          48 :                 (dopt->load_via_partition_root ||
    2593                 :          24 :                  forcePartitionRootLoad(tbinfo)))
    2594                 :           7 :                 targettab = getRootTableInfo(tbinfo);
    2595                 :             :             else
    2596                 :          80 :                 targettab = tbinfo;
    2597                 :             : 
    2598                 :          87 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2599                 :          87 :                               fmtQualifiedDumpable(targettab));
    2600                 :             : 
    2601                 :             :             /* corner case for zero-column table */
    2602         [ +  + ]:          87 :             if (nfields == 0)
    2603                 :             :             {
    2604                 :           7 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2605                 :             :             }
    2606                 :             :             else
    2607                 :             :             {
    2608                 :             :                 /* append the list of column names if required */
    2609         [ +  + ]:          80 :                 if (dopt->column_inserts)
    2610                 :             :                 {
    2611                 :          36 :                     appendPQExpBufferChar(insertStmt, '(');
    2612         [ +  + ]:         109 :                     for (int field = 0; field < nfields; field++)
    2613                 :             :                     {
    2614         [ +  + ]:          73 :                         if (field > 0)
    2615                 :          37 :                             appendPQExpBufferStr(insertStmt, ", ");
    2616                 :          73 :                         appendPQExpBufferStr(insertStmt,
    2617                 :          73 :                                              fmtId(PQfname(res, field)));
    2618                 :             :                     }
    2619                 :          36 :                     appendPQExpBufferStr(insertStmt, ") ");
    2620                 :             :                 }
    2621                 :             : 
    2622         [ +  + ]:          80 :                 if (tbinfo->needs_override)
    2623                 :           2 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2624                 :             : 
    2625                 :          80 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2626                 :             :             }
    2627                 :             :         }
    2628                 :             : 
    2629         [ +  + ]:        3608 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2630                 :             :         {
    2631                 :             :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2632         [ +  + ]:        3469 :             if (rows_this_statement == 0)
    2633                 :        3463 :                 archputs(insertStmt->data, fout);
    2634                 :             : 
    2635                 :             :             /*
    2636                 :             :              * If it is zero-column table then we've already written the
    2637                 :             :              * complete statement, which will mean we've disobeyed
    2638                 :             :              * --rows-per-insert when it's set greater than 1.  We do support
    2639                 :             :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2640                 :             :              * UNION ALL ... but that's non-standard so we should avoid it
    2641                 :             :              * given that using INSERTs is mostly only ever needed for
    2642                 :             :              * cross-database exports.
    2643                 :             :              */
    2644         [ +  + ]:        3469 :             if (nfields == 0)
    2645                 :           6 :                 continue;
    2646                 :             : 
    2647                 :             :             /* Emit a row heading */
    2648         [ +  + ]:        3463 :             if (rows_per_statement == 1)
    2649                 :        3454 :                 archputs(" (", fout);
    2650         [ +  + ]:           9 :             else if (rows_this_statement > 0)
    2651                 :           6 :                 archputs(",\n\t(", fout);
    2652                 :             :             else
    2653                 :           3 :                 archputs("\n\t(", fout);
    2654                 :             : 
    2655         [ +  + ]:       10445 :             for (int field = 0; field < nfields; field++)
    2656                 :             :             {
    2657         [ +  + ]:        6982 :                 if (field > 0)
    2658                 :        3519 :                     archputs(", ", fout);
    2659         [ +  + ]:        6982 :                 if (attgenerated[field])
    2660                 :             :                 {
    2661                 :           2 :                     archputs("DEFAULT", fout);
    2662                 :           2 :                     continue;
    2663                 :             :                 }
    2664         [ +  + ]:        6980 :                 if (PQgetisnull(res, tuple, field))
    2665                 :             :                 {
    2666                 :          83 :                     archputs("NULL", fout);
    2667                 :          83 :                     continue;
    2668                 :             :                 }
    2669                 :             : 
    2670                 :             :                 /* XXX This code is partially duplicated in ruleutils.c */
    2671   [ +  +  +  + ]:        6897 :                 switch (PQftype(res, field))
    2672                 :             :                 {
    2673                 :        4869 :                     case INT2OID:
    2674                 :             :                     case INT4OID:
    2675                 :             :                     case INT8OID:
    2676                 :             :                     case OIDOID:
    2677                 :             :                     case FLOAT4OID:
    2678                 :             :                     case FLOAT8OID:
    2679                 :             :                     case NUMERICOID:
    2680                 :             :                         {
    2681                 :             :                             /*
    2682                 :             :                              * These types are printed without quotes unless
    2683                 :             :                              * they contain values that aren't accepted by the
    2684                 :             :                              * scanner unquoted (e.g., 'NaN').  Note that
    2685                 :             :                              * strtod() and friends might accept NaN, so we
    2686                 :             :                              * can't use that to test.
    2687                 :             :                              *
    2688                 :             :                              * In reality we only need to defend against
    2689                 :             :                              * infinity and NaN, so we need not get too crazy
    2690                 :             :                              * about pattern matching here.
    2691                 :             :                              */
    2692                 :        4869 :                             const char *s = PQgetvalue(res, tuple, field);
    2693                 :             : 
    2694         [ +  + ]:        4869 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2695                 :        4867 :                                 archputs(s, fout);
    2696                 :             :                             else
    2697                 :           2 :                                 archprintf(fout, "'%s'", s);
    2698                 :             :                         }
    2699                 :        4869 :                         break;
    2700                 :             : 
    2701                 :           2 :                     case BITOID:
    2702                 :             :                     case VARBITOID:
    2703                 :           2 :                         archprintf(fout, "B'%s'",
    2704                 :             :                                    PQgetvalue(res, tuple, field));
    2705                 :           2 :                         break;
    2706                 :             : 
    2707                 :           4 :                     case BOOLOID:
    2708         [ +  + ]:           4 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2709                 :           2 :                             archputs("true", fout);
    2710                 :             :                         else
    2711                 :           2 :                             archputs("false", fout);
    2712                 :           4 :                         break;
    2713                 :             : 
    2714                 :        2022 :                     default:
    2715                 :             :                         /* All other types are printed as string literals. */
    2716                 :        2022 :                         resetPQExpBuffer(q);
    2717                 :        2022 :                         appendStringLiteralAH(q,
    2718                 :             :                                               PQgetvalue(res, tuple, field),
    2719                 :             :                                               fout);
    2720                 :        2022 :                         archputs(q->data, fout);
    2721                 :        2022 :                         break;
    2722                 :             :                 }
    2723                 :             :             }
    2724                 :             : 
    2725                 :             :             /* Terminate the row ... */
    2726                 :        3463 :             archputs(")", fout);
    2727                 :             : 
    2728                 :             :             /* ... and the statement, if the target no. of rows is reached */
    2729         [ +  + ]:        3463 :             if (++rows_this_statement >= rows_per_statement)
    2730                 :             :             {
    2731         [ -  + ]:        3456 :                 if (dopt->do_nothing)
    2732                 :           0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2733                 :             :                 else
    2734                 :        3456 :                     archputs(";\n", fout);
    2735                 :             :                 /* Reset the row counter */
    2736                 :        3456 :                 rows_this_statement = 0;
    2737                 :             :             }
    2738                 :             :         }
    2739                 :             : 
    2740         [ +  + ]:         139 :         if (PQntuples(res) <= 0)
    2741                 :             :         {
    2742                 :          87 :             PQclear(res);
    2743                 :          87 :             break;
    2744                 :             :         }
    2745                 :          52 :         PQclear(res);
    2746                 :             :     }
    2747                 :             : 
    2748                 :             :     /* Terminate any statements that didn't make the row count. */
    2749         [ +  + ]:          87 :     if (rows_this_statement > 0)
    2750                 :             :     {
    2751         [ -  + ]:           1 :         if (dopt->do_nothing)
    2752                 :           0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2753                 :             :         else
    2754                 :           1 :             archputs(";\n", fout);
    2755                 :             :     }
    2756                 :             : 
    2757                 :          87 :     archputs("\n\n", fout);
    2758                 :             : 
    2759                 :          87 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2760                 :             : 
    2761                 :          87 :     destroyPQExpBuffer(q);
    2762         [ +  - ]:          87 :     if (insertStmt != NULL)
    2763                 :          87 :         destroyPQExpBuffer(insertStmt);
    2764                 :          87 :     pg_free(attgenerated);
    2765                 :             : 
    2766                 :             :     /* Revert back the setting */
    2767         [ -  + ]:          87 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2768                 :           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2769                 :             : 
    2770                 :          87 :     return 1;
    2771                 :             : }
    2772                 :             : 
    2773                 :             : /*
    2774                 :             :  * getRootTableInfo:
    2775                 :             :  *     get the root TableInfo for the given partition table.
    2776                 :             :  */
    2777                 :             : static TableInfo *
    2778                 :          83 : getRootTableInfo(const TableInfo *tbinfo)
    2779                 :             : {
    2780                 :             :     TableInfo  *parentTbinfo;
    2781                 :             : 
    2782                 :             :     Assert(tbinfo->ispartition);
    2783                 :             :     Assert(tbinfo->numParents == 1);
    2784                 :             : 
    2785                 :          83 :     parentTbinfo = tbinfo->parents[0];
    2786         [ -  + ]:          83 :     while (parentTbinfo->ispartition)
    2787                 :             :     {
    2788                 :             :         Assert(parentTbinfo->numParents == 1);
    2789                 :           0 :         parentTbinfo = parentTbinfo->parents[0];
    2790                 :             :     }
    2791                 :             : 
    2792                 :          83 :     return parentTbinfo;
    2793                 :             : }
    2794                 :             : 
    2795                 :             : /*
    2796                 :             :  * forcePartitionRootLoad
    2797                 :             :  *     Check if we must force load_via_partition_root for this partition.
    2798                 :             :  *
    2799                 :             :  * This is required if any level of ancestral partitioned table has an
    2800                 :             :  * unsafe partitioning scheme.
    2801                 :             :  */
    2802                 :             : static bool
    2803                 :        1102 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2804                 :             : {
    2805                 :             :     TableInfo  *parentTbinfo;
    2806                 :             : 
    2807                 :             :     Assert(tbinfo->ispartition);
    2808                 :             :     Assert(tbinfo->numParents == 1);
    2809                 :             : 
    2810                 :        1102 :     parentTbinfo = tbinfo->parents[0];
    2811         [ +  + ]:        1102 :     if (parentTbinfo->unsafe_partitions)
    2812                 :          83 :         return true;
    2813         [ +  + ]:        1239 :     while (parentTbinfo->ispartition)
    2814                 :             :     {
    2815                 :             :         Assert(parentTbinfo->numParents == 1);
    2816                 :         220 :         parentTbinfo = parentTbinfo->parents[0];
    2817         [ -  + ]:         220 :         if (parentTbinfo->unsafe_partitions)
    2818                 :           0 :             return true;
    2819                 :             :     }
    2820                 :             : 
    2821                 :        1019 :     return false;
    2822                 :             : }
    2823                 :             : 
    2824                 :             : /*
    2825                 :             :  * dumpTableData -
    2826                 :             :  *    dump the contents of a single table
    2827                 :             :  *
    2828                 :             :  * Actually, this just makes an ArchiveEntry for the table contents.
    2829                 :             :  */
    2830                 :             : static void
    2831                 :        4605 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2832                 :             : {
    2833                 :        4605 :     DumpOptions *dopt = fout->dopt;
    2834                 :        4605 :     const TableInfo *tbinfo = tdinfo->tdtable;
    2835                 :        4605 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2836                 :        4605 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2837                 :             :     DataDumperPtr dumpFn;
    2838                 :        4605 :     char       *tdDefn = NULL;
    2839                 :             :     char       *copyStmt;
    2840                 :             :     const char *copyFrom;
    2841                 :             : 
    2842                 :             :     /* We had better have loaded per-column details about this table */
    2843                 :             :     Assert(tbinfo->interesting);
    2844                 :             : 
    2845                 :             :     /*
    2846                 :             :      * When load-via-partition-root is set or forced, get the root table name
    2847                 :             :      * for the partition table, so that we can reload data through the root
    2848                 :             :      * table.  Then construct a comment to be inserted into the TOC entry's
    2849                 :             :      * defn field, so that such cases can be identified reliably.
    2850                 :             :      */
    2851         [ +  + ]:        4605 :     if (tbinfo->ispartition &&
    2852   [ +  -  +  + ]:        2156 :         (dopt->load_via_partition_root ||
    2853                 :        1078 :          forcePartitionRootLoad(tbinfo)))
    2854                 :          76 :     {
    2855                 :             :         const TableInfo *parentTbinfo;
    2856                 :             :         char       *sanitized;
    2857                 :             : 
    2858                 :          76 :         parentTbinfo = getRootTableInfo(tbinfo);
    2859                 :          76 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2860                 :          76 :         sanitized = sanitize_line(copyFrom, true);
    2861                 :          76 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2862                 :             :                           sanitized);
    2863                 :          76 :         free(sanitized);
    2864                 :          76 :         tdDefn = pg_strdup(copyBuf->data);
    2865                 :             :     }
    2866                 :             :     else
    2867                 :        4529 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2868                 :             : 
    2869         [ +  + ]:        4605 :     if (dopt->dump_inserts == 0)
    2870                 :             :     {
    2871                 :             :         /* Dump/restore using COPY */
    2872                 :        4518 :         dumpFn = dumpTableData_copy;
    2873                 :             :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2874                 :        4518 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2875                 :             :                           copyFrom);
    2876                 :        4518 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2877                 :             :                           fmtCopyColumnList(tbinfo, clistBuf));
    2878                 :        4518 :         copyStmt = copyBuf->data;
    2879                 :             :     }
    2880                 :             :     else
    2881                 :             :     {
    2882                 :             :         /* Restore using INSERT */
    2883                 :          87 :         dumpFn = dumpTableData_insert;
    2884                 :          87 :         copyStmt = NULL;
    2885                 :             :     }
    2886                 :             : 
    2887                 :             :     /*
    2888                 :             :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2889                 :             :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2890                 :             :      * See comments for BuildArchiveDependencies.
    2891                 :             :      */
    2892         [ +  - ]:        4605 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2893                 :             :     {
    2894                 :             :         TocEntry   *te;
    2895                 :             : 
    2896                 :        4605 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2897                 :        4605 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2898                 :             :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2899                 :             :                                        .owner = tbinfo->rolname,
    2900                 :             :                                        .description = "TABLE DATA",
    2901                 :             :                                        .section = SECTION_DATA,
    2902                 :             :                                        .createStmt = tdDefn,
    2903                 :             :                                        .copyStmt = copyStmt,
    2904                 :             :                                        .deps = &(tbinfo->dobj.dumpId),
    2905                 :             :                                        .nDeps = 1,
    2906                 :             :                                        .dumpFn = dumpFn,
    2907                 :             :                                        .dumpArg = tdinfo));
    2908                 :             : 
    2909                 :             :         /*
    2910                 :             :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2911                 :             :          * and want to order dump jobs by table size.  We choose to measure
    2912                 :             :          * dataLength in table pages (including TOAST pages) during dump, so
    2913                 :             :          * no scaling is needed.
    2914                 :             :          *
    2915                 :             :          * However, relpages is declared as "integer" in pg_class, and hence
    2916                 :             :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2917                 :             :          * Cast so that we get the right interpretation of table sizes
    2918                 :             :          * exceeding INT_MAX pages.
    2919                 :             :          */
    2920                 :        4605 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2921                 :        4605 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2922                 :             : 
    2923                 :             :         /*
    2924                 :             :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2925                 :             :          * and instead we'd better worry about integer overflow.  Clamp to
    2926                 :             :          * INT_MAX if the correct result exceeds that.
    2927                 :             :          */
    2928                 :             :         if (sizeof(te->dataLength) == 4 &&
    2929                 :             :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2930                 :             :              te->dataLength < 0))
    2931                 :             :             te->dataLength = INT_MAX;
    2932                 :             :     }
    2933                 :             : 
    2934                 :        4605 :     destroyPQExpBuffer(copyBuf);
    2935                 :        4605 :     destroyPQExpBuffer(clistBuf);
    2936                 :        4605 : }
    2937                 :             : 
    2938                 :             : /*
    2939                 :             :  * refreshMatViewData -
    2940                 :             :  *    load or refresh the contents of a single materialized view
    2941                 :             :  *
    2942                 :             :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2943                 :             :  * statement.
    2944                 :             :  */
    2945                 :             : static void
    2946                 :         363 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2947                 :             : {
    2948                 :         363 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2949                 :             :     PQExpBuffer q;
    2950                 :             : 
    2951                 :             :     /* If the materialized view is not flagged as populated, skip this. */
    2952         [ +  + ]:         363 :     if (!tbinfo->relispopulated)
    2953                 :          72 :         return;
    2954                 :             : 
    2955                 :         291 :     q = createPQExpBuffer();
    2956                 :             : 
    2957                 :         291 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2958                 :         291 :                       fmtQualifiedDumpable(tbinfo));
    2959                 :             : 
    2960         [ +  - ]:         291 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2961                 :         291 :         ArchiveEntry(fout,
    2962                 :             :                      tdinfo->dobj.catId, /* catalog ID */
    2963                 :         291 :                      tdinfo->dobj.dumpId,    /* dump ID */
    2964                 :         291 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2965                 :             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2966                 :             :                                   .owner = tbinfo->rolname,
    2967                 :             :                                   .description = "MATERIALIZED VIEW DATA",
    2968                 :             :                                   .section = SECTION_POST_DATA,
    2969                 :             :                                   .createStmt = q->data,
    2970                 :             :                                   .deps = tdinfo->dobj.dependencies,
    2971                 :             :                                   .nDeps = tdinfo->dobj.nDeps));
    2972                 :             : 
    2973                 :         291 :     destroyPQExpBuffer(q);
    2974                 :             : }
    2975                 :             : 
    2976                 :             : /*
    2977                 :             :  * getTableData -
    2978                 :             :  *    set up dumpable objects representing the contents of tables
    2979                 :             :  */
    2980                 :             : static void
    2981                 :         182 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    2982                 :             : {
    2983                 :             :     int         i;
    2984                 :             : 
    2985         [ +  + ]:       52798 :     for (i = 0; i < numTables; i++)
    2986                 :             :     {
    2987   [ +  +  +  + ]:       52616 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    2988         [ +  + ]:        1013 :             (!relkind || tblinfo[i].relkind == relkind))
    2989                 :        6485 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    2990                 :             :     }
    2991                 :         182 : }
    2992                 :             : 
    2993                 :             : /*
    2994                 :             :  * Make a dumpable object for the data of this specific table
    2995                 :             :  *
    2996                 :             :  * Note: we make a TableDataInfo if and only if we are going to dump the
    2997                 :             :  * table data; the "dump" field in such objects isn't very interesting.
    2998                 :             :  */
    2999                 :             : static void
    3000                 :        6564 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    3001                 :             : {
    3002                 :             :     TableDataInfo *tdinfo;
    3003                 :             : 
    3004                 :             :     /*
    3005                 :             :      * Nothing to do if we already decided to dump the table.  This will
    3006                 :             :      * happen for "config" tables.
    3007                 :             :      */
    3008         [ +  + ]:        6564 :     if (tbinfo->dataObj != NULL)
    3009                 :           1 :         return;
    3010                 :             : 
    3011                 :             :     /* Skip property graphs (no data to dump) */
    3012         [ +  + ]:        6563 :     if (tbinfo->relkind == RELKIND_PROPGRAPH)
    3013                 :          92 :         return;
    3014                 :             :     /* Skip VIEWs (no data to dump) */
    3015         [ +  + ]:        6471 :     if (tbinfo->relkind == RELKIND_VIEW)
    3016                 :         520 :         return;
    3017                 :             :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    3018         [ +  + ]:        5951 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    3019         [ +  + ]:          40 :         (foreign_servers_include_oids.head == NULL ||
    3020         [ +  + ]:           4 :          !simple_oid_list_member(&foreign_servers_include_oids,
    3021                 :             :                                  tbinfo->foreign_server)))
    3022                 :          39 :         return;
    3023                 :             :     /* Skip partitioned tables (data in partitions) */
    3024         [ +  + ]:        5912 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    3025                 :         519 :         return;
    3026                 :             : 
    3027                 :             :     /* Don't dump data in unlogged tables, if so requested */
    3028         [ +  + ]:        5393 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    3029         [ +  + ]:          41 :         dopt->no_unlogged_table_data)
    3030                 :          18 :         return;
    3031                 :             : 
    3032                 :             :     /* Check that the data is not explicitly excluded */
    3033         [ +  + ]:        5375 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    3034                 :             :                                tbinfo->dobj.catId.oid))
    3035                 :           8 :         return;
    3036                 :             : 
    3037                 :             :     /* OK, let's dump it */
    3038                 :        5367 :     tdinfo = pg_malloc_object(TableDataInfo);
    3039                 :             : 
    3040         [ +  + ]:        5367 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    3041                 :         363 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    3042         [ +  + ]:        5004 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    3043                 :         399 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    3044                 :             :     else
    3045                 :        4605 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    3046                 :             : 
    3047                 :             :     /*
    3048                 :             :      * Note: use tableoid 0 so that this object won't be mistaken for
    3049                 :             :      * something that pg_depend entries apply to.
    3050                 :             :      */
    3051                 :        5367 :     tdinfo->dobj.catId.tableoid = 0;
    3052                 :        5367 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3053                 :        5367 :     AssignDumpId(&tdinfo->dobj);
    3054                 :        5367 :     tdinfo->dobj.name = tbinfo->dobj.name;
    3055                 :        5367 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    3056                 :        5367 :     tdinfo->tdtable = tbinfo;
    3057                 :        5367 :     tdinfo->filtercond = NULL;   /* might get set later */
    3058                 :        5367 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    3059                 :             : 
    3060                 :             :     /* A TableDataInfo contains data, of course */
    3061                 :        5367 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3062                 :             : 
    3063                 :        5367 :     tbinfo->dataObj = tdinfo;
    3064                 :             : 
    3065                 :             :     /*
    3066                 :             :      * Materialized view statistics must be restored after the data, because
    3067                 :             :      * REFRESH MATERIALIZED VIEW replaces the storage and resets the stats.
    3068                 :             :      *
    3069                 :             :      * The dependency is added here because the statistics objects are created
    3070                 :             :      * first.
    3071                 :             :      */
    3072   [ +  +  +  + ]:        5367 :     if (tbinfo->relkind == RELKIND_MATVIEW && tbinfo->stats != NULL)
    3073                 :             :     {
    3074                 :         286 :         tbinfo->stats->section = SECTION_POST_DATA;
    3075                 :         286 :         addObjectDependency(&tbinfo->stats->dobj, tdinfo->dobj.dumpId);
    3076                 :             :     }
    3077                 :             : 
    3078                 :             :     /* Make sure that we'll collect per-column info for this table. */
    3079                 :        5367 :     tbinfo->interesting = true;
    3080                 :             : }
    3081                 :             : 
    3082                 :             : /*
    3083                 :             :  * The refresh for a materialized view must be dependent on the refresh for
    3084                 :             :  * any materialized view that this one is dependent on.
    3085                 :             :  *
    3086                 :             :  * This must be called after all the objects are created, but before they are
    3087                 :             :  * sorted.
    3088                 :             :  */
    3089                 :             : static void
    3090                 :         146 : buildMatViewRefreshDependencies(Archive *fout)
    3091                 :             : {
    3092                 :             :     PQExpBuffer query;
    3093                 :             :     PGresult   *res;
    3094                 :             :     int         ntups,
    3095                 :             :                 i;
    3096                 :             :     int         i_classid,
    3097                 :             :                 i_objid,
    3098                 :             :                 i_refobjid;
    3099                 :             : 
    3100                 :         146 :     query = createPQExpBuffer();
    3101                 :             : 
    3102                 :         146 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    3103                 :             :                          "( "
    3104                 :             :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    3105                 :             :                          "FROM pg_depend d1 "
    3106                 :             :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    3107                 :             :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    3108                 :             :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    3109                 :             :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    3110                 :             :                          "AND d2.objid = r1.oid "
    3111                 :             :                          "AND d2.refobjid <> d1.objid "
    3112                 :             :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    3113                 :             :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3114                 :             :                          CppAsString2(RELKIND_VIEW) ") "
    3115                 :             :                          "WHERE d1.classid = 'pg_class'::regclass "
    3116                 :             :                          "UNION "
    3117                 :             :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    3118                 :             :                          "FROM w "
    3119                 :             :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    3120                 :             :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    3121                 :             :                          "AND d3.objid = r3.oid "
    3122                 :             :                          "AND d3.refobjid <> w.refobjid "
    3123                 :             :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    3124                 :             :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3125                 :             :                          CppAsString2(RELKIND_VIEW) ") "
    3126                 :             :                          ") "
    3127                 :             :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    3128                 :             :                          "FROM w "
    3129                 :             :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    3130                 :             : 
    3131                 :         146 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3132                 :             : 
    3133                 :         146 :     ntups = PQntuples(res);
    3134                 :             : 
    3135                 :         146 :     i_classid = PQfnumber(res, "classid");
    3136                 :         146 :     i_objid = PQfnumber(res, "objid");
    3137                 :         146 :     i_refobjid = PQfnumber(res, "refobjid");
    3138                 :             : 
    3139         [ +  + ]:         422 :     for (i = 0; i < ntups; i++)
    3140                 :             :     {
    3141                 :             :         CatalogId   objId;
    3142                 :             :         CatalogId   refobjId;
    3143                 :             :         DumpableObject *dobj;
    3144                 :             :         DumpableObject *refdobj;
    3145                 :             :         TableInfo  *tbinfo;
    3146                 :             :         TableInfo  *reftbinfo;
    3147                 :             : 
    3148                 :         276 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3149                 :         276 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3150                 :         276 :         refobjId.tableoid = objId.tableoid;
    3151                 :         276 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3152                 :             : 
    3153                 :         276 :         dobj = findObjectByCatalogId(objId);
    3154         [ -  + ]:         276 :         if (dobj == NULL)
    3155                 :          48 :             continue;
    3156                 :             : 
    3157                 :             :         Assert(dobj->objType == DO_TABLE);
    3158                 :         276 :         tbinfo = (TableInfo *) dobj;
    3159                 :             :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3160                 :         276 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3161         [ +  + ]:         276 :         if (dobj == NULL)
    3162                 :          48 :             continue;
    3163                 :             :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3164                 :             : 
    3165                 :         228 :         refdobj = findObjectByCatalogId(refobjId);
    3166         [ -  + ]:         228 :         if (refdobj == NULL)
    3167                 :           0 :             continue;
    3168                 :             : 
    3169                 :             :         Assert(refdobj->objType == DO_TABLE);
    3170                 :         228 :         reftbinfo = (TableInfo *) refdobj;
    3171                 :             :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3172                 :         228 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3173         [ -  + ]:         228 :         if (refdobj == NULL)
    3174                 :           0 :             continue;
    3175                 :             :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3176                 :             : 
    3177                 :         228 :         addObjectDependency(dobj, refdobj->dumpId);
    3178                 :             : 
    3179         [ +  + ]:         228 :         if (!reftbinfo->relispopulated)
    3180                 :          36 :             tbinfo->relispopulated = false;
    3181                 :             :     }
    3182                 :             : 
    3183                 :         146 :     PQclear(res);
    3184                 :             : 
    3185                 :         146 :     destroyPQExpBuffer(query);
    3186                 :         146 : }
    3187                 :             : 
    3188                 :             : /*
    3189                 :             :  * getTableDataFKConstraints -
    3190                 :             :  *    add dump-order dependencies reflecting foreign key constraints
    3191                 :             :  *
    3192                 :             :  * This code is executed only in a data-only dump --- in schema+data dumps
    3193                 :             :  * we handle foreign key issues by not creating the FK constraints until
    3194                 :             :  * after the data is loaded.  In a data-only dump, however, we want to
    3195                 :             :  * order the table data objects in such a way that a table's referenced
    3196                 :             :  * tables are restored first.  (In the presence of circular references or
    3197                 :             :  * self-references this may be impossible; we'll detect and complain about
    3198                 :             :  * that during the dependency sorting step.)
    3199                 :             :  */
    3200                 :             : static void
    3201                 :           7 : getTableDataFKConstraints(void)
    3202                 :             : {
    3203                 :             :     DumpableObject **dobjs;
    3204                 :             :     int         numObjs;
    3205                 :             :     int         i;
    3206                 :             : 
    3207                 :             :     /* Search through all the dumpable objects for FK constraints */
    3208                 :           7 :     getDumpableObjects(&dobjs, &numObjs);
    3209         [ +  + ]:       26824 :     for (i = 0; i < numObjs; i++)
    3210                 :             :     {
    3211         [ +  + ]:       26817 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3212                 :             :         {
    3213                 :           8 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3214                 :             :             TableInfo  *ftable;
    3215                 :             : 
    3216                 :             :             /* Not interesting unless both tables are to be dumped */
    3217         [ +  - ]:           8 :             if (cinfo->contable == NULL ||
    3218         [ +  + ]:           8 :                 cinfo->contable->dataObj == NULL)
    3219                 :           4 :                 continue;
    3220                 :           4 :             ftable = findTableByOid(cinfo->confrelid);
    3221         [ +  - ]:           4 :             if (ftable == NULL ||
    3222         [ -  + ]:           4 :                 ftable->dataObj == NULL)
    3223                 :           0 :                 continue;
    3224                 :             : 
    3225                 :             :             /*
    3226                 :             :              * Okay, make referencing table's TABLE_DATA object depend on the
    3227                 :             :              * referenced table's TABLE_DATA object.
    3228                 :             :              */
    3229                 :           4 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    3230                 :           4 :                                 ftable->dataObj->dobj.dumpId);
    3231                 :             :         }
    3232                 :             :     }
    3233                 :           7 :     free(dobjs);
    3234                 :           7 : }
    3235                 :             : 
    3236                 :             : 
    3237                 :             : /*
    3238                 :             :  * dumpDatabase:
    3239                 :             :  *  dump the database definition
    3240                 :             :  */
    3241                 :             : static void
    3242                 :          92 : dumpDatabase(Archive *fout)
    3243                 :             : {
    3244                 :          92 :     DumpOptions *dopt = fout->dopt;
    3245                 :          92 :     PQExpBuffer dbQry = createPQExpBuffer();
    3246                 :          92 :     PQExpBuffer delQry = createPQExpBuffer();
    3247                 :          92 :     PQExpBuffer creaQry = createPQExpBuffer();
    3248                 :          92 :     PQExpBuffer labelq = createPQExpBuffer();
    3249                 :          92 :     PGconn     *conn = GetConnection(fout);
    3250                 :             :     PGresult   *res;
    3251                 :             :     int         i_tableoid,
    3252                 :             :                 i_oid,
    3253                 :             :                 i_datname,
    3254                 :             :                 i_datdba,
    3255                 :             :                 i_encoding,
    3256                 :             :                 i_datlocprovider,
    3257                 :             :                 i_collate,
    3258                 :             :                 i_ctype,
    3259                 :             :                 i_datlocale,
    3260                 :             :                 i_daticurules,
    3261                 :             :                 i_frozenxid,
    3262                 :             :                 i_minmxid,
    3263                 :             :                 i_datacl,
    3264                 :             :                 i_acldefault,
    3265                 :             :                 i_datistemplate,
    3266                 :             :                 i_datconnlimit,
    3267                 :             :                 i_datcollversion,
    3268                 :             :                 i_tablespace;
    3269                 :             :     CatalogId   dbCatId;
    3270                 :             :     DumpId      dbDumpId;
    3271                 :             :     DumpableAcl dbdacl;
    3272                 :             :     const char *datname,
    3273                 :             :                *dba,
    3274                 :             :                *encoding,
    3275                 :             :                *datlocprovider,
    3276                 :             :                *collate,
    3277                 :             :                *ctype,
    3278                 :             :                *locale,
    3279                 :             :                *icurules,
    3280                 :             :                *datistemplate,
    3281                 :             :                *datconnlimit,
    3282                 :             :                *tablespace;
    3283                 :             :     uint32      frozenxid,
    3284                 :             :                 minmxid;
    3285                 :             :     char       *qdatname;
    3286                 :             : 
    3287                 :          92 :     pg_log_info("saving database definition");
    3288                 :             : 
    3289                 :             :     /*
    3290                 :             :      * Fetch the database-level properties for this database.
    3291                 :             :      */
    3292                 :          92 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3293                 :             :                          "datdba, "
    3294                 :             :                          "pg_encoding_to_char(encoding) AS encoding, "
    3295                 :             :                          "datcollate, datctype, datfrozenxid, "
    3296                 :             :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3297                 :             :                          "datistemplate, datconnlimit, ");
    3298                 :          92 :     appendPQExpBufferStr(dbQry, "datminmxid, ");
    3299         [ +  - ]:          92 :     if (fout->remoteVersion >= 170000)
    3300                 :          92 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3301         [ #  # ]:           0 :     else if (fout->remoteVersion >= 150000)
    3302                 :           0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3303                 :             :     else
    3304                 :           0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3305         [ +  - ]:          92 :     if (fout->remoteVersion >= 160000)
    3306                 :          92 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3307                 :             :     else
    3308                 :           0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3309                 :          92 :     appendPQExpBufferStr(dbQry,
    3310                 :             :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3311                 :             :                          "shobj_description(oid, 'pg_database') AS description "
    3312                 :             :                          "FROM pg_database "
    3313                 :             :                          "WHERE datname = current_database()");
    3314                 :             : 
    3315                 :          92 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3316                 :             : 
    3317                 :          92 :     i_tableoid = PQfnumber(res, "tableoid");
    3318                 :          92 :     i_oid = PQfnumber(res, "oid");
    3319                 :          92 :     i_datname = PQfnumber(res, "datname");
    3320                 :          92 :     i_datdba = PQfnumber(res, "datdba");
    3321                 :          92 :     i_encoding = PQfnumber(res, "encoding");
    3322                 :          92 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3323                 :          92 :     i_collate = PQfnumber(res, "datcollate");
    3324                 :          92 :     i_ctype = PQfnumber(res, "datctype");
    3325                 :          92 :     i_datlocale = PQfnumber(res, "datlocale");
    3326                 :          92 :     i_daticurules = PQfnumber(res, "daticurules");
    3327                 :          92 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3328                 :          92 :     i_minmxid = PQfnumber(res, "datminmxid");
    3329                 :          92 :     i_datacl = PQfnumber(res, "datacl");
    3330                 :          92 :     i_acldefault = PQfnumber(res, "acldefault");
    3331                 :          92 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3332                 :          92 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3333                 :          92 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3334                 :          92 :     i_tablespace = PQfnumber(res, "tablespace");
    3335                 :             : 
    3336                 :          92 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3337                 :          92 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3338                 :          92 :     datname = PQgetvalue(res, 0, i_datname);
    3339                 :          92 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3340                 :          92 :     encoding = PQgetvalue(res, 0, i_encoding);
    3341                 :          92 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3342                 :          92 :     collate = PQgetvalue(res, 0, i_collate);
    3343                 :          92 :     ctype = PQgetvalue(res, 0, i_ctype);
    3344         [ +  + ]:          92 :     if (!PQgetisnull(res, 0, i_datlocale))
    3345                 :          14 :         locale = PQgetvalue(res, 0, i_datlocale);
    3346                 :             :     else
    3347                 :          78 :         locale = NULL;
    3348         [ -  + ]:          92 :     if (!PQgetisnull(res, 0, i_daticurules))
    3349                 :           0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3350                 :             :     else
    3351                 :          92 :         icurules = NULL;
    3352                 :          92 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3353                 :          92 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3354                 :          92 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3355                 :          92 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3356                 :          92 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3357                 :          92 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3358                 :          92 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3359                 :             : 
    3360                 :          92 :     qdatname = pg_strdup(fmtId(datname));
    3361                 :             : 
    3362                 :             :     /*
    3363                 :             :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3364                 :             :      * to preserve that), as well as the encoding, locale, and tablespace
    3365                 :             :      * since those can't be altered later.  Other DB properties are left to
    3366                 :             :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3367                 :             :      * reconnecting to the target DB.
    3368                 :             :      *
    3369                 :             :      * For binary upgrade, we use the FILE_COPY strategy because testing has
    3370                 :             :      * shown it to be faster.  When the server is in binary upgrade mode, it
    3371                 :             :      * will also skip the checkpoints this strategy ordinarily performs.
    3372                 :             :      */
    3373         [ +  + ]:          92 :     if (dopt->binary_upgrade)
    3374                 :             :     {
    3375                 :          39 :         appendPQExpBuffer(creaQry,
    3376                 :             :                           "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3377                 :             :                           "OID = %u STRATEGY = FILE_COPY",
    3378                 :             :                           qdatname, dbCatId.oid);
    3379                 :             :     }
    3380                 :             :     else
    3381                 :             :     {
    3382                 :          53 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3383                 :             :                           qdatname);
    3384                 :             :     }
    3385         [ +  - ]:          92 :     if (strlen(encoding) > 0)
    3386                 :             :     {
    3387                 :          92 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3388                 :          92 :         appendStringLiteralAH(creaQry, encoding, fout);
    3389                 :             :     }
    3390                 :             : 
    3391                 :          92 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3392         [ +  + ]:          92 :     if (datlocprovider[0] == 'b')
    3393                 :          14 :         appendPQExpBufferStr(creaQry, "builtin");
    3394         [ +  - ]:          78 :     else if (datlocprovider[0] == 'c')
    3395                 :          78 :         appendPQExpBufferStr(creaQry, "libc");
    3396         [ #  # ]:           0 :     else if (datlocprovider[0] == 'i')
    3397                 :           0 :         appendPQExpBufferStr(creaQry, "icu");
    3398                 :             :     else
    3399                 :           0 :         pg_fatal("unrecognized locale provider: %s",
    3400                 :             :                  datlocprovider);
    3401                 :             : 
    3402   [ +  -  +  - ]:          92 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3403                 :             :     {
    3404                 :          92 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3405                 :          92 :         appendStringLiteralAH(creaQry, collate, fout);
    3406                 :             :     }
    3407                 :             :     else
    3408                 :             :     {
    3409         [ #  # ]:           0 :         if (strlen(collate) > 0)
    3410                 :             :         {
    3411                 :           0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3412                 :           0 :             appendStringLiteralAH(creaQry, collate, fout);
    3413                 :             :         }
    3414         [ #  # ]:           0 :         if (strlen(ctype) > 0)
    3415                 :             :         {
    3416                 :           0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3417                 :           0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3418                 :             :         }
    3419                 :             :     }
    3420         [ +  + ]:          92 :     if (locale)
    3421                 :             :     {
    3422         [ +  - ]:          14 :         if (datlocprovider[0] == 'b')
    3423                 :          14 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3424                 :             :         else
    3425                 :           0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3426                 :             : 
    3427                 :          14 :         appendStringLiteralAH(creaQry, locale, fout);
    3428                 :             :     }
    3429                 :             : 
    3430         [ -  + ]:          92 :     if (icurules)
    3431                 :             :     {
    3432                 :           0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3433                 :           0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3434                 :             :     }
    3435                 :             : 
    3436                 :             :     /*
    3437                 :             :      * For binary upgrade, carry over the collation version.  For normal
    3438                 :             :      * dump/restore, omit the version, so that it is computed upon restore.
    3439                 :             :      */
    3440         [ +  + ]:          92 :     if (dopt->binary_upgrade)
    3441                 :             :     {
    3442         [ +  - ]:          39 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3443                 :             :         {
    3444                 :          39 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3445                 :          39 :             appendStringLiteralAH(creaQry,
    3446                 :             :                                   PQgetvalue(res, 0, i_datcollversion),
    3447                 :             :                                   fout);
    3448                 :             :         }
    3449                 :             :     }
    3450                 :             : 
    3451                 :             :     /*
    3452                 :             :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3453                 :             :      * thing; the decision whether to specify a tablespace should be left till
    3454                 :             :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3455                 :             :      * label the DATABASE entry with the tablespace and let the normal
    3456                 :             :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3457                 :             :      * attention to default_tablespace, so that won't work.
    3458                 :             :      */
    3459   [ +  -  +  + ]:          92 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3460         [ +  - ]:           5 :         !dopt->outputNoTablespaces)
    3461                 :           5 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3462                 :             :                           fmtId(tablespace));
    3463                 :          92 :     appendPQExpBufferStr(creaQry, ";\n");
    3464                 :             : 
    3465                 :          92 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3466                 :             :                       qdatname);
    3467                 :             : 
    3468                 :          92 :     dbDumpId = createDumpId();
    3469                 :             : 
    3470                 :          92 :     ArchiveEntry(fout,
    3471                 :             :                  dbCatId,       /* catalog ID */
    3472                 :             :                  dbDumpId,      /* dump ID */
    3473                 :          92 :                  ARCHIVE_OPTS(.tag = datname,
    3474                 :             :                               .owner = dba,
    3475                 :             :                               .description = "DATABASE",
    3476                 :             :                               .section = SECTION_PRE_DATA,
    3477                 :             :                               .createStmt = creaQry->data,
    3478                 :             :                               .dropStmt = delQry->data));
    3479                 :             : 
    3480                 :             :     /* Compute correct tag for archive entry */
    3481                 :          92 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3482                 :             : 
    3483                 :             :     /* Dump DB comment if any */
    3484                 :             :     {
    3485                 :             :         /*
    3486                 :             :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3487                 :             :          * cannot use the dumpComment() code used for other database objects.
    3488                 :             :          * Be careful that the ArchiveEntry parameters match that function.
    3489                 :             :          */
    3490                 :          92 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3491                 :             : 
    3492   [ +  -  +  +  :          92 :         if (comment && *comment && !dopt->no_comments)
                   +  - ]
    3493                 :             :         {
    3494                 :          47 :             resetPQExpBuffer(dbQry);
    3495                 :             : 
    3496                 :             :             /*
    3497                 :             :              * Generates warning when loaded into a differently-named
    3498                 :             :              * database.
    3499                 :             :              */
    3500                 :          47 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3501                 :          47 :             appendStringLiteralAH(dbQry, comment, fout);
    3502                 :          47 :             appendPQExpBufferStr(dbQry, ";\n");
    3503                 :             : 
    3504                 :          47 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3505                 :          47 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3506                 :             :                                       .owner = dba,
    3507                 :             :                                       .description = "COMMENT",
    3508                 :             :                                       .section = SECTION_NONE,
    3509                 :             :                                       .createStmt = dbQry->data,
    3510                 :             :                                       .deps = &dbDumpId,
    3511                 :             :                                       .nDeps = 1));
    3512                 :             :         }
    3513                 :             :     }
    3514                 :             : 
    3515                 :             :     /* Dump DB security label, if enabled */
    3516         [ +  - ]:          92 :     if (!dopt->no_security_labels)
    3517                 :             :     {
    3518                 :             :         PGresult   *shres;
    3519                 :             :         PQExpBuffer seclabelQry;
    3520                 :             : 
    3521                 :          92 :         seclabelQry = createPQExpBuffer();
    3522                 :             : 
    3523                 :          92 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3524                 :          92 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3525                 :          92 :         resetPQExpBuffer(seclabelQry);
    3526                 :          92 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3527         [ -  + ]:          92 :         if (seclabelQry->len > 0)
    3528                 :           0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3529                 :           0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3530                 :             :                                       .owner = dba,
    3531                 :             :                                       .description = "SECURITY LABEL",
    3532                 :             :                                       .section = SECTION_NONE,
    3533                 :             :                                       .createStmt = seclabelQry->data,
    3534                 :             :                                       .deps = &dbDumpId,
    3535                 :             :                                       .nDeps = 1));
    3536                 :          92 :         destroyPQExpBuffer(seclabelQry);
    3537                 :          92 :         PQclear(shres);
    3538                 :             :     }
    3539                 :             : 
    3540                 :             :     /*
    3541                 :             :      * Dump ACL if any.  Note that we do not support initial privileges
    3542                 :             :      * (pg_init_privs) on databases.
    3543                 :             :      */
    3544                 :          92 :     dbdacl.privtype = 0;
    3545                 :          92 :     dbdacl.initprivs = NULL;
    3546                 :             : 
    3547                 :          92 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3548                 :             :             qdatname, NULL, NULL,
    3549                 :             :             NULL, dba, &dbdacl);
    3550                 :             : 
    3551                 :             :     /*
    3552                 :             :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3553                 :             :      * non-default database-level properties.  (The reason this must be
    3554                 :             :      * separate is that we cannot put any additional commands into the TOC
    3555                 :             :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3556                 :             :      * in an implicit transaction block, and the backend won't allow CREATE
    3557                 :             :      * DATABASE in that context.)
    3558                 :             :      */
    3559                 :          92 :     resetPQExpBuffer(creaQry);
    3560                 :          92 :     resetPQExpBuffer(delQry);
    3561                 :             : 
    3562   [ +  -  -  + ]:          92 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3563                 :           0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3564                 :             :                           qdatname, datconnlimit);
    3565                 :             : 
    3566         [ +  + ]:          92 :     if (strcmp(datistemplate, "t") == 0)
    3567                 :             :     {
    3568                 :          12 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3569                 :             :                           qdatname);
    3570                 :             : 
    3571                 :             :         /*
    3572                 :             :          * The backend won't accept DROP DATABASE on a template database.  We
    3573                 :             :          * can deal with that by removing the template marking before the DROP
    3574                 :             :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3575                 :             :          * since no such command is currently supported, fake it with a direct
    3576                 :             :          * UPDATE on pg_database.
    3577                 :             :          */
    3578                 :          12 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3579                 :             :                              "SET datistemplate = false WHERE datname = ");
    3580                 :          12 :         appendStringLiteralAH(delQry, datname, fout);
    3581                 :          12 :         appendPQExpBufferStr(delQry, ";\n");
    3582                 :             :     }
    3583                 :             : 
    3584                 :             :     /*
    3585                 :             :      * We do not restore pg_database.dathasloginevt because it is set
    3586                 :             :      * automatically on login event trigger creation.
    3587                 :             :      */
    3588                 :             : 
    3589                 :             :     /* Add database-specific SET options */
    3590                 :          92 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3591                 :             : 
    3592                 :             :     /*
    3593                 :             :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3594                 :             :      * entry, too, for lack of a better place.
    3595                 :             :      */
    3596         [ +  + ]:          92 :     if (dopt->binary_upgrade)
    3597                 :             :     {
    3598                 :          39 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3599                 :          39 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3600                 :             :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3601                 :             :                           "WHERE datname = ",
    3602                 :             :                           frozenxid, minmxid);
    3603                 :          39 :         appendStringLiteralAH(creaQry, datname, fout);
    3604                 :          39 :         appendPQExpBufferStr(creaQry, ";\n");
    3605                 :             :     }
    3606                 :             : 
    3607         [ +  + ]:          92 :     if (creaQry->len > 0)
    3608                 :          43 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3609                 :          43 :                      ARCHIVE_OPTS(.tag = datname,
    3610                 :             :                                   .owner = dba,
    3611                 :             :                                   .description = "DATABASE PROPERTIES",
    3612                 :             :                                   .section = SECTION_PRE_DATA,
    3613                 :             :                                   .createStmt = creaQry->data,
    3614                 :             :                                   .dropStmt = delQry->data,
    3615                 :             :                                   .deps = &dbDumpId));
    3616                 :             : 
    3617                 :             :     /*
    3618                 :             :      * pg_largeobject comes from the old system intact, so set its
    3619                 :             :      * relfrozenxids, relminmxids and relfilenode.
    3620                 :             :      *
    3621                 :             :      * pg_largeobject_metadata also comes from the old system intact for
    3622                 :             :      * upgrades from v16 and newer, so set its relfrozenxids, relminmxids, and
    3623                 :             :      * relfilenode, too.  pg_upgrade can't copy/link the files from older
    3624                 :             :      * versions because aclitem (needed by pg_largeobject_metadata.lomacl)
    3625                 :             :      * changed its storage format in v16.
    3626                 :             :      */
    3627         [ +  + ]:          92 :     if (dopt->binary_upgrade)
    3628                 :             :     {
    3629                 :             :         PGresult   *lo_res;
    3630                 :          39 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3631                 :          39 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3632                 :          39 :         PQExpBuffer lomOutQry = createPQExpBuffer();
    3633                 :          39 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3634                 :          39 :         PQExpBuffer lomHorizonQry = createPQExpBuffer();
    3635                 :             :         int         ii_relfrozenxid,
    3636                 :             :                     ii_relfilenode,
    3637                 :             :                     ii_oid,
    3638                 :             :                     ii_relminmxid;
    3639                 :             : 
    3640                 :          39 :         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3641                 :             :                           "FROM pg_catalog.pg_class\n"
    3642                 :             :                           "WHERE oid IN (%u, %u, %u, %u);\n",
    3643                 :             :                           LargeObjectRelationId, LargeObjectLOidPNIndexId,
    3644                 :             :                           LargeObjectMetadataRelationId, LargeObjectMetadataOidIndexId);
    3645                 :             : 
    3646                 :          39 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3647                 :             : 
    3648                 :          39 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3649                 :          39 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3650                 :          39 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3651                 :          39 :         ii_oid = PQfnumber(lo_res, "oid");
    3652                 :             : 
    3653                 :          39 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3654                 :          39 :         appendPQExpBufferStr(lomHorizonQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
    3655                 :          39 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3656                 :          39 :         appendPQExpBufferStr(lomOutQry, "\n-- For binary upgrade, preserve pg_largeobject_metadata and index relfilenodes\n");
    3657         [ +  + ]:         195 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3658                 :             :         {
    3659                 :             :             Oid         oid;
    3660                 :             :             RelFileNumber relfilenumber;
    3661                 :             :             PQExpBuffer horizonQry;
    3662                 :             :             PQExpBuffer outQry;
    3663                 :             : 
    3664                 :         156 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3665                 :         156 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3666                 :             : 
    3667   [ +  +  +  + ]:         156 :             if (oid == LargeObjectRelationId ||
    3668                 :             :                 oid == LargeObjectLOidPNIndexId)
    3669                 :             :             {
    3670                 :          78 :                 horizonQry = loHorizonQry;
    3671                 :          78 :                 outQry = loOutQry;
    3672                 :             :             }
    3673                 :             :             else
    3674                 :             :             {
    3675                 :          78 :                 horizonQry = lomHorizonQry;
    3676                 :          78 :                 outQry = lomOutQry;
    3677                 :             :             }
    3678                 :             : 
    3679                 :         156 :             appendPQExpBuffer(horizonQry, "UPDATE pg_catalog.pg_class\n"
    3680                 :             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3681                 :             :                               "WHERE oid = %u;\n",
    3682                 :         156 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3683                 :         156 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3684                 :         156 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3685                 :             : 
    3686   [ +  +  +  + ]:         156 :             if (oid == LargeObjectRelationId ||
    3687                 :             :                 oid == LargeObjectMetadataRelationId)
    3688                 :          78 :                 appendPQExpBuffer(outQry,
    3689                 :             :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3690                 :             :                                   relfilenumber);
    3691   [ +  +  +  - ]:          78 :             else if (oid == LargeObjectLOidPNIndexId ||
    3692                 :             :                      oid == LargeObjectMetadataOidIndexId)
    3693                 :          78 :                 appendPQExpBuffer(outQry,
    3694                 :             :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3695                 :             :                                   relfilenumber);
    3696                 :             :         }
    3697                 :             : 
    3698                 :          39 :         appendPQExpBufferStr(loOutQry,
    3699                 :             :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3700                 :          39 :         appendPQExpBufferStr(lomOutQry,
    3701                 :             :                              "TRUNCATE pg_catalog.pg_largeobject_metadata;\n");
    3702                 :             : 
    3703                 :          39 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3704                 :          39 :         appendPQExpBufferStr(lomOutQry, lomHorizonQry->data);
    3705                 :             : 
    3706                 :          39 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3707                 :          39 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3708                 :             :                                   .description = "pg_largeobject",
    3709                 :             :                                   .section = SECTION_PRE_DATA,
    3710                 :             :                                   .createStmt = loOutQry->data));
    3711                 :             : 
    3712         [ +  - ]:          39 :         if (fout->remoteVersion >= 160000)
    3713                 :          39 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3714                 :          39 :                          ARCHIVE_OPTS(.tag = "pg_largeobject_metadata",
    3715                 :             :                                       .description = "pg_largeobject_metadata",
    3716                 :             :                                       .section = SECTION_PRE_DATA,
    3717                 :             :                                       .createStmt = lomOutQry->data));
    3718                 :             : 
    3719                 :          39 :         PQclear(lo_res);
    3720                 :             : 
    3721                 :          39 :         destroyPQExpBuffer(loFrozenQry);
    3722                 :          39 :         destroyPQExpBuffer(loHorizonQry);
    3723                 :          39 :         destroyPQExpBuffer(lomHorizonQry);
    3724                 :          39 :         destroyPQExpBuffer(loOutQry);
    3725                 :          39 :         destroyPQExpBuffer(lomOutQry);
    3726                 :             :     }
    3727                 :             : 
    3728                 :          92 :     PQclear(res);
    3729                 :             : 
    3730                 :          92 :     pg_free(qdatname);
    3731                 :          92 :     destroyPQExpBuffer(dbQry);
    3732                 :          92 :     destroyPQExpBuffer(delQry);
    3733                 :          92 :     destroyPQExpBuffer(creaQry);
    3734                 :          92 :     destroyPQExpBuffer(labelq);
    3735                 :          92 : }
    3736                 :             : 
    3737                 :             : /*
    3738                 :             :  * Collect any database-specific or role-and-database-specific SET options
    3739                 :             :  * for this database, and append them to outbuf.
    3740                 :             :  */
    3741                 :             : static void
    3742                 :          92 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3743                 :             :                    const char *dbname, Oid dboid)
    3744                 :             : {
    3745                 :          92 :     PGconn     *conn = GetConnection(AH);
    3746                 :          92 :     PQExpBuffer buf = createPQExpBuffer();
    3747                 :             :     PGresult   *res;
    3748                 :             : 
    3749                 :             :     /* First collect database-specific options */
    3750                 :          92 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3751                 :             :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3752                 :             :                       dboid);
    3753                 :             : 
    3754                 :          92 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3755                 :             : 
    3756         [ +  + ]:         122 :     for (int i = 0; i < PQntuples(res); i++)
    3757                 :          30 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3758                 :             :                                "DATABASE", dbname, NULL, NULL,
    3759                 :             :                                outbuf);
    3760                 :             : 
    3761                 :          92 :     PQclear(res);
    3762                 :             : 
    3763                 :             :     /* Now look for role-and-database-specific options */
    3764                 :          92 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3765                 :             :                       "FROM pg_db_role_setting s, pg_roles r "
    3766                 :             :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3767                 :             :                       dboid);
    3768                 :             : 
    3769                 :          92 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3770                 :             : 
    3771         [ -  + ]:          92 :     for (int i = 0; i < PQntuples(res); i++)
    3772                 :           0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3773                 :           0 :                                "ROLE", PQgetvalue(res, i, 0),
    3774                 :             :                                "DATABASE", dbname,
    3775                 :             :                                outbuf);
    3776                 :             : 
    3777                 :          92 :     PQclear(res);
    3778                 :             : 
    3779                 :          92 :     destroyPQExpBuffer(buf);
    3780                 :          92 : }
    3781                 :             : 
    3782                 :             : /*
    3783                 :             :  * dumpEncoding: put the correct encoding into the archive
    3784                 :             :  */
    3785                 :             : static void
    3786                 :         191 : dumpEncoding(Archive *AH)
    3787                 :             : {
    3788                 :         191 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3789                 :         191 :     PQExpBuffer qry = createPQExpBuffer();
    3790                 :             : 
    3791                 :         191 :     pg_log_info("saving encoding = %s", encname);
    3792                 :             : 
    3793                 :         191 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3794                 :         191 :     appendStringLiteralAH(qry, encname, AH);
    3795                 :         191 :     appendPQExpBufferStr(qry, ";\n");
    3796                 :             : 
    3797                 :         191 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3798                 :         191 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3799                 :             :                               .description = "ENCODING",
    3800                 :             :                               .section = SECTION_PRE_DATA,
    3801                 :             :                               .createStmt = qry->data));
    3802                 :             : 
    3803                 :         191 :     destroyPQExpBuffer(qry);
    3804                 :         191 : }
    3805                 :             : 
    3806                 :             : 
    3807                 :             : /*
    3808                 :             :  * dumpStdStrings: put the correct escape string behavior into the archive
    3809                 :             :  */
    3810                 :             : static void
    3811                 :         191 : dumpStdStrings(Archive *AH)
    3812                 :             : {
    3813         [ +  - ]:         191 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3814                 :         191 :     PQExpBuffer qry = createPQExpBuffer();
    3815                 :             : 
    3816                 :         191 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3817                 :             :                 stdstrings);
    3818                 :             : 
    3819                 :         191 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3820                 :             :                       stdstrings);
    3821                 :             : 
    3822                 :         191 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3823                 :         191 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3824                 :             :                               .description = "STDSTRINGS",
    3825                 :             :                               .section = SECTION_PRE_DATA,
    3826                 :             :                               .createStmt = qry->data));
    3827                 :             : 
    3828                 :         191 :     destroyPQExpBuffer(qry);
    3829                 :         191 : }
    3830                 :             : 
    3831                 :             : /*
    3832                 :             :  * dumpSearchPath: record the active search_path in the archive
    3833                 :             :  */
    3834                 :             : static void
    3835                 :         191 : dumpSearchPath(Archive *AH)
    3836                 :             : {
    3837                 :         191 :     PQExpBuffer qry = createPQExpBuffer();
    3838                 :         191 :     PQExpBuffer path = createPQExpBuffer();
    3839                 :             :     PGresult   *res;
    3840                 :         191 :     char      **schemanames = NULL;
    3841                 :         191 :     int         nschemanames = 0;
    3842                 :             :     int         i;
    3843                 :             : 
    3844                 :             :     /*
    3845                 :             :      * We use the result of current_schemas(), not the search_path GUC,
    3846                 :             :      * because that might contain wildcards such as "$user", which won't
    3847                 :             :      * necessarily have the same value during restore.  Also, this way avoids
    3848                 :             :      * listing schemas that may appear in search_path but not actually exist,
    3849                 :             :      * which seems like a prudent exclusion.
    3850                 :             :      */
    3851                 :         191 :     res = ExecuteSqlQueryForSingleRow(AH,
    3852                 :             :                                       "SELECT pg_catalog.current_schemas(false)");
    3853                 :             : 
    3854         [ -  + ]:         191 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3855                 :           0 :         pg_fatal("could not parse result of current_schemas()");
    3856                 :             : 
    3857                 :             :     /*
    3858                 :             :      * We use set_config(), not a simple "SET search_path" command, because
    3859                 :             :      * the latter has less-clean behavior if the search path is empty.  While
    3860                 :             :      * that's likely to get fixed at some point, it seems like a good idea to
    3861                 :             :      * be as backwards-compatible as possible in what we put into archives.
    3862                 :             :      */
    3863         [ -  + ]:         191 :     for (i = 0; i < nschemanames; i++)
    3864                 :             :     {
    3865         [ #  # ]:           0 :         if (i > 0)
    3866                 :           0 :             appendPQExpBufferStr(path, ", ");
    3867                 :           0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3868                 :             :     }
    3869                 :             : 
    3870                 :         191 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3871                 :         191 :     appendStringLiteralAH(qry, path->data, AH);
    3872                 :         191 :     appendPQExpBufferStr(qry, ", false);\n");
    3873                 :             : 
    3874                 :         191 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3875                 :             : 
    3876                 :         191 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3877                 :         191 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3878                 :             :                               .description = "SEARCHPATH",
    3879                 :             :                               .section = SECTION_PRE_DATA,
    3880                 :             :                               .createStmt = qry->data));
    3881                 :             : 
    3882                 :             :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3883                 :         191 :     AH->searchpath = pg_strdup(qry->data);
    3884                 :             : 
    3885                 :         191 :     free(schemanames);
    3886                 :         191 :     PQclear(res);
    3887                 :         191 :     destroyPQExpBuffer(qry);
    3888                 :         191 :     destroyPQExpBuffer(path);
    3889                 :         191 : }
    3890                 :             : 
    3891                 :             : 
    3892                 :             : /*
    3893                 :             :  * getLOs:
    3894                 :             :  *  Collect schema-level data about large objects
    3895                 :             :  */
    3896                 :             : static void
    3897                 :         162 : getLOs(Archive *fout)
    3898                 :             : {
    3899                 :         162 :     DumpOptions *dopt = fout->dopt;
    3900                 :         162 :     PQExpBuffer loQry = createPQExpBuffer();
    3901                 :             :     PGresult   *res;
    3902                 :             :     int         ntups;
    3903                 :             :     int         i;
    3904                 :             :     int         n;
    3905                 :             :     int         i_oid;
    3906                 :             :     int         i_lomowner;
    3907                 :             :     int         i_lomacl;
    3908                 :             :     int         i_acldefault;
    3909                 :             : 
    3910                 :         162 :     pg_log_info("reading large objects");
    3911                 :             : 
    3912                 :             :     /*
    3913                 :             :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3914                 :             :      * with the same owner/ACL appear together.
    3915                 :             :      */
    3916                 :         162 :     appendPQExpBufferStr(loQry,
    3917                 :             :                          "SELECT oid, lomowner, lomacl, "
    3918                 :             :                          "acldefault('L', lomowner) AS acldefault "
    3919                 :             :                          "FROM pg_largeobject_metadata ");
    3920                 :             : 
    3921                 :             :     /*
    3922                 :             :      * For binary upgrades, we transfer pg_largeobject_metadata via COPY or by
    3923                 :             :      * copying/linking its files from the old cluster.  On such upgrades, we
    3924                 :             :      * only need to consider large objects that have comments or security
    3925                 :             :      * labels, since we still restore those objects via COMMENT/SECURITY LABEL
    3926                 :             :      * commands.
    3927                 :             :      */
    3928         [ +  + ]:         162 :     if (dopt->binary_upgrade)
    3929                 :          40 :         appendPQExpBufferStr(loQry,
    3930                 :             :                              "WHERE oid IN "
    3931                 :             :                              "(SELECT objoid FROM pg_description "
    3932                 :             :                              "WHERE classoid = " CppAsString2(LargeObjectRelationId) " "
    3933                 :             :                              "UNION SELECT objoid FROM pg_seclabel "
    3934                 :             :                              "WHERE classoid = " CppAsString2(LargeObjectRelationId) ") ");
    3935                 :             : 
    3936                 :         162 :     appendPQExpBufferStr(loQry,
    3937                 :             :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3938                 :             : 
    3939                 :         162 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3940                 :             : 
    3941                 :         162 :     i_oid = PQfnumber(res, "oid");
    3942                 :         162 :     i_lomowner = PQfnumber(res, "lomowner");
    3943                 :         162 :     i_lomacl = PQfnumber(res, "lomacl");
    3944                 :         162 :     i_acldefault = PQfnumber(res, "acldefault");
    3945                 :             : 
    3946                 :         162 :     ntups = PQntuples(res);
    3947                 :             : 
    3948                 :             :     /*
    3949                 :             :      * Group the blobs into suitably-sized groups that have the same owner and
    3950                 :             :      * ACL setting, and build a metadata and a data DumpableObject for each
    3951                 :             :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    3952                 :             :      * groups also share initprivs settings, since the DumpableObject only has
    3953                 :             :      * room for one.)  i is the index of the first tuple in the current group,
    3954                 :             :      * and n is the number of tuples we include in the group.
    3955                 :             :      */
    3956         [ +  + ]:         250 :     for (i = 0; i < ntups; i += n)
    3957                 :             :     {
    3958                 :          88 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3959                 :          88 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3960                 :          88 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    3961                 :             :         LoInfo     *loinfo;
    3962                 :             :         DumpableObject *lodata;
    3963                 :             :         char        namebuf[64];
    3964                 :             : 
    3965                 :             :         /* Scan to find first tuple not to be included in group */
    3966                 :          88 :         n = 1;
    3967   [ +  -  +  + ]:         102 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    3968                 :             :         {
    3969         [ +  - ]:          49 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    3970         [ +  + ]:          49 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    3971                 :             :                 break;
    3972                 :          14 :             n++;
    3973                 :             :         }
    3974                 :             : 
    3975                 :             :         /* Build the metadata DumpableObject */
    3976                 :          88 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    3977                 :             : 
    3978                 :          88 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    3979                 :          88 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    3980                 :          88 :         loinfo->dobj.catId.oid = thisoid;
    3981                 :          88 :         AssignDumpId(&loinfo->dobj);
    3982                 :             : 
    3983         [ +  + ]:          88 :         if (n > 1)
    3984                 :          10 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    3985                 :          10 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    3986                 :             :         else
    3987                 :          78 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    3988                 :          88 :         loinfo->dobj.name = pg_strdup(namebuf);
    3989                 :          88 :         loinfo->dacl.acl = pg_strdup(thisacl);
    3990                 :          88 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    3991                 :          88 :         loinfo->dacl.privtype = 0;
    3992                 :          88 :         loinfo->dacl.initprivs = NULL;
    3993                 :          88 :         loinfo->rolname = getRoleName(thisowner);
    3994                 :          88 :         loinfo->numlos = n;
    3995                 :          88 :         loinfo->looids[0] = thisoid;
    3996                 :             :         /* Collect OIDs of the remaining blobs in this group */
    3997         [ +  + ]:         102 :         for (int k = 1; k < n; k++)
    3998                 :             :         {
    3999                 :             :             CatalogId   extraID;
    4000                 :             : 
    4001                 :          14 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    4002                 :             : 
    4003                 :             :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    4004                 :          14 :             extraID.tableoid = LargeObjectRelationId;
    4005                 :          14 :             extraID.oid = loinfo->looids[k];
    4006                 :          14 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    4007                 :             :         }
    4008                 :             : 
    4009                 :             :         /* LOs have data */
    4010                 :          88 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    4011                 :             : 
    4012                 :             :         /* Mark whether LO group has a non-empty ACL */
    4013         [ +  + ]:          88 :         if (!PQgetisnull(res, i, i_lomacl))
    4014                 :          36 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    4015                 :             : 
    4016                 :             :         /*
    4017                 :             :          * In binary upgrade mode, pg_largeobject and pg_largeobject_metadata
    4018                 :             :          * are transferred via COPY or by copying/linking the files from the
    4019                 :             :          * old cluster.  Thus, we do not need to dump LO data, definitions, or
    4020                 :             :          * ACLs.
    4021                 :             :          */
    4022         [ +  + ]:          88 :         if (dopt->binary_upgrade)
    4023                 :           7 :             loinfo->dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL | DUMP_COMPONENT_DEFINITION);
    4024                 :             : 
    4025                 :             :         /*
    4026                 :             :          * Create a "BLOBS" data item for the group, too. This is just a
    4027                 :             :          * placeholder for sorting; it carries no data now.
    4028                 :             :          */
    4029                 :          88 :         lodata = pg_malloc_object(DumpableObject);
    4030                 :          88 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    4031                 :          88 :         lodata->catId = nilCatalogId;
    4032                 :          88 :         AssignDumpId(lodata);
    4033                 :          88 :         lodata->name = pg_strdup(namebuf);
    4034                 :          88 :         lodata->components |= DUMP_COMPONENT_DATA;
    4035                 :             :         /* Set up explicit dependency from data to metadata */
    4036                 :          88 :         lodata->dependencies = pg_malloc_object(DumpId);
    4037                 :          88 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    4038                 :          88 :         lodata->nDeps = lodata->allocDeps = 1;
    4039                 :             :     }
    4040                 :             : 
    4041                 :         162 :     PQclear(res);
    4042                 :         162 :     destroyPQExpBuffer(loQry);
    4043                 :         162 : }
    4044                 :             : 
    4045                 :             : /*
    4046                 :             :  * dumpLO
    4047                 :             :  *
    4048                 :             :  * dump the definition (metadata) of the given large object group
    4049                 :             :  */
    4050                 :             : static void
    4051                 :          88 : dumpLO(Archive *fout, const LoInfo *loinfo)
    4052                 :             : {
    4053                 :          88 :     PQExpBuffer cquery = createPQExpBuffer();
    4054                 :             : 
    4055                 :             :     /*
    4056                 :             :      * The "definition" is just a newline-separated list of OIDs.  We need to
    4057                 :             :      * put something into the dropStmt too, but it can just be a comment.
    4058                 :             :      */
    4059         [ +  + ]:         190 :     for (int i = 0; i < loinfo->numlos; i++)
    4060                 :         102 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    4061                 :             : 
    4062         [ +  + ]:          88 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4063                 :          81 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    4064                 :          81 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    4065                 :             :                                   .owner = loinfo->rolname,
    4066                 :             :                                   .description = "BLOB METADATA",
    4067                 :             :                                   .section = SECTION_DATA,
    4068                 :             :                                   .createStmt = cquery->data,
    4069                 :             :                                   .dropStmt = "-- dummy"));
    4070                 :             : 
    4071                 :             :     /*
    4072                 :             :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    4073                 :             :      * enough that it's okay to generate retail TOC entries for them.
    4074                 :             :      */
    4075         [ +  + ]:          88 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    4076                 :             :                              DUMP_COMPONENT_SECLABEL))
    4077                 :             :     {
    4078         [ +  + ]:         106 :         for (int i = 0; i < loinfo->numlos; i++)
    4079                 :             :         {
    4080                 :             :             CatalogId   catId;
    4081                 :             :             char        namebuf[32];
    4082                 :             : 
    4083                 :             :             /* Build identifying info for this blob */
    4084                 :          60 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    4085                 :          60 :             catId.oid = loinfo->looids[i];
    4086                 :          60 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    4087                 :             : 
    4088         [ +  - ]:          60 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4089                 :          60 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    4090                 :          60 :                             NULL, loinfo->rolname,
    4091                 :          60 :                             catId, 0, loinfo->dobj.dumpId);
    4092                 :             : 
    4093         [ +  + ]:          60 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4094                 :          10 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    4095                 :          10 :                              NULL, loinfo->rolname,
    4096                 :          10 :                              catId, 0, loinfo->dobj.dumpId);
    4097                 :             :         }
    4098                 :             :     }
    4099                 :             : 
    4100                 :             :     /*
    4101                 :             :      * Dump the ACLs if any (remember that all blobs in the group will have
    4102                 :             :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    4103                 :             :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    4104                 :             :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    4105                 :             :      * string to emit a mutated version for each blob.
    4106                 :             :      */
    4107         [ +  + ]:          88 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    4108                 :             :     {
    4109                 :             :         char        namebuf[32];
    4110                 :             : 
    4111                 :             :         /* Build identifying info for the first blob */
    4112                 :          35 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    4113                 :             : 
    4114         [ -  + ]:          35 :         if (loinfo->numlos > 1)
    4115                 :             :         {
    4116                 :             :             char        tagbuf[64];
    4117                 :             : 
    4118                 :           0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    4119                 :           0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    4120                 :             : 
    4121                 :           0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4122                 :             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4123                 :           0 :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    4124                 :             :         }
    4125                 :             :         else
    4126                 :             :         {
    4127                 :          35 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    4128                 :             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    4129                 :          35 :                     NULL, loinfo->rolname, &loinfo->dacl);
    4130                 :             :         }
    4131                 :             :     }
    4132                 :             : 
    4133                 :          88 :     destroyPQExpBuffer(cquery);
    4134                 :          88 : }
    4135                 :             : 
    4136                 :             : /*
    4137                 :             :  * dumpLOs:
    4138                 :             :  *  dump the data contents of the large objects in the given group
    4139                 :             :  */
    4140                 :             : static int
    4141                 :          77 : dumpLOs(Archive *fout, const void *arg)
    4142                 :             : {
    4143                 :          77 :     const LoInfo *loinfo = (const LoInfo *) arg;
    4144                 :          77 :     PGconn     *conn = GetConnection(fout);
    4145                 :             :     char        buf[LOBBUFSIZE];
    4146                 :             : 
    4147                 :          77 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    4148                 :             : 
    4149         [ +  + ]:         162 :     for (int i = 0; i < loinfo->numlos; i++)
    4150                 :             :     {
    4151                 :          85 :         Oid         loOid = loinfo->looids[i];
    4152                 :             :         int         loFd;
    4153                 :             :         int         cnt;
    4154                 :             : 
    4155                 :             :         /* Open the LO */
    4156                 :          85 :         loFd = lo_open(conn, loOid, INV_READ);
    4157         [ -  + ]:          85 :         if (loFd == -1)
    4158                 :           0 :             pg_fatal("could not open large object %u: %s",
    4159                 :             :                      loOid, PQerrorMessage(conn));
    4160                 :             : 
    4161                 :          85 :         StartLO(fout, loOid);
    4162                 :             : 
    4163                 :             :         /* Now read it in chunks, sending data to archive */
    4164                 :             :         do
    4165                 :             :         {
    4166                 :         133 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4167         [ -  + ]:         133 :             if (cnt < 0)
    4168                 :           0 :                 pg_fatal("error reading large object %u: %s",
    4169                 :             :                          loOid, PQerrorMessage(conn));
    4170                 :             : 
    4171                 :         133 :             WriteData(fout, buf, cnt);
    4172         [ +  + ]:         133 :         } while (cnt > 0);
    4173                 :             : 
    4174                 :          85 :         lo_close(conn, loFd);
    4175                 :             : 
    4176                 :          85 :         EndLO(fout, loOid);
    4177                 :             :     }
    4178                 :             : 
    4179                 :          77 :     return 1;
    4180                 :             : }
    4181                 :             : 
    4182                 :             : /*
    4183                 :             :  * getPolicies
    4184                 :             :  *    get information about all RLS policies on dumpable tables.
    4185                 :             :  */
    4186                 :             : void
    4187                 :         191 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4188                 :             : {
    4189                 :         191 :     DumpOptions *dopt = fout->dopt;
    4190                 :             :     PQExpBuffer query;
    4191                 :             :     PQExpBuffer tbloids;
    4192                 :             :     PGresult   *res;
    4193                 :             :     PolicyInfo *polinfo;
    4194                 :             :     int         i_oid;
    4195                 :             :     int         i_tableoid;
    4196                 :             :     int         i_polrelid;
    4197                 :             :     int         i_polname;
    4198                 :             :     int         i_polcmd;
    4199                 :             :     int         i_polpermissive;
    4200                 :             :     int         i_polroles;
    4201                 :             :     int         i_polqual;
    4202                 :             :     int         i_polwithcheck;
    4203                 :             :     int         i,
    4204                 :             :                 j,
    4205                 :             :                 ntups;
    4206                 :             : 
    4207                 :             :     /* Skip if --no-policies was specified */
    4208         [ +  + ]:         191 :     if (dopt->no_policies)
    4209                 :           1 :         return;
    4210                 :             : 
    4211                 :         190 :     query = createPQExpBuffer();
    4212                 :         190 :     tbloids = createPQExpBuffer();
    4213                 :             : 
    4214                 :             :     /*
    4215                 :             :      * Identify tables of interest, and check which ones have RLS enabled.
    4216                 :             :      */
    4217                 :         190 :     appendPQExpBufferChar(tbloids, '{');
    4218         [ +  + ]:       54888 :     for (i = 0; i < numTables; i++)
    4219                 :             :     {
    4220                 :       54698 :         TableInfo  *tbinfo = &tblinfo[i];
    4221                 :             : 
    4222                 :             :         /* Ignore row security on tables not to be dumped */
    4223         [ +  + ]:       54698 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4224                 :       47091 :             continue;
    4225                 :             : 
    4226                 :             :         /* It can't have RLS or policies if it's not a table */
    4227         [ +  + ]:        7607 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4228         [ +  + ]:        2167 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4229                 :        1540 :             continue;
    4230                 :             : 
    4231                 :             :         /* Add it to the list of table OIDs to be probed below */
    4232         [ +  + ]:        6067 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4233                 :        5942 :             appendPQExpBufferChar(tbloids, ',');
    4234                 :        6067 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4235                 :             : 
    4236                 :             :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4237         [ +  + ]:        6067 :         if (tbinfo->rowsec)
    4238                 :             :         {
    4239                 :          66 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4240                 :             : 
    4241                 :             :             /*
    4242                 :             :              * We represent RLS being enabled on a table by creating a
    4243                 :             :              * PolicyInfo object with null polname.
    4244                 :             :              *
    4245                 :             :              * Note: use tableoid 0 so that this object won't be mistaken for
    4246                 :             :              * something that pg_depend entries apply to.
    4247                 :             :              */
    4248                 :          66 :             polinfo = pg_malloc_object(PolicyInfo);
    4249                 :          66 :             polinfo->dobj.objType = DO_POLICY;
    4250                 :          66 :             polinfo->dobj.catId.tableoid = 0;
    4251                 :          66 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4252                 :          66 :             AssignDumpId(&polinfo->dobj);
    4253                 :          66 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4254                 :          66 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4255                 :          66 :             polinfo->poltable = tbinfo;
    4256                 :          66 :             polinfo->polname = NULL;
    4257                 :          66 :             polinfo->polcmd = '\0';
    4258                 :          66 :             polinfo->polpermissive = 0;
    4259                 :          66 :             polinfo->polroles = NULL;
    4260                 :          66 :             polinfo->polqual = NULL;
    4261                 :          66 :             polinfo->polwithcheck = NULL;
    4262                 :             :         }
    4263                 :             :     }
    4264                 :         190 :     appendPQExpBufferChar(tbloids, '}');
    4265                 :             : 
    4266                 :             :     /*
    4267                 :             :      * Now, read all RLS policies belonging to the tables of interest, and
    4268                 :             :      * create PolicyInfo objects for them.  (Note that we must filter the
    4269                 :             :      * results server-side not locally, because we dare not apply pg_get_expr
    4270                 :             :      * to tables we don't have lock on.)
    4271                 :             :      */
    4272                 :         190 :     pg_log_info("reading row-level security policies");
    4273                 :             : 
    4274                 :         190 :     printfPQExpBuffer(query,
    4275                 :             :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4276                 :         190 :     appendPQExpBufferStr(query, "pol.polpermissive, ");
    4277                 :         190 :     appendPQExpBuffer(query,
    4278                 :             :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4279                 :             :                       "   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, "
    4280                 :             :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4281                 :             :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4282                 :             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4283                 :             :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4284                 :             :                       tbloids->data);
    4285                 :             : 
    4286                 :         190 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4287                 :             : 
    4288                 :         190 :     ntups = PQntuples(res);
    4289         [ +  + ]:         190 :     if (ntups > 0)
    4290                 :             :     {
    4291                 :          46 :         i_oid = PQfnumber(res, "oid");
    4292                 :          46 :         i_tableoid = PQfnumber(res, "tableoid");
    4293                 :          46 :         i_polrelid = PQfnumber(res, "polrelid");
    4294                 :          46 :         i_polname = PQfnumber(res, "polname");
    4295                 :          46 :         i_polcmd = PQfnumber(res, "polcmd");
    4296                 :          46 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4297                 :          46 :         i_polroles = PQfnumber(res, "polroles");
    4298                 :          46 :         i_polqual = PQfnumber(res, "polqual");
    4299                 :          46 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4300                 :             : 
    4301                 :          46 :         polinfo = pg_malloc_array(PolicyInfo, ntups);
    4302                 :             : 
    4303         [ +  + ]:         337 :         for (j = 0; j < ntups; j++)
    4304                 :             :         {
    4305                 :         291 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4306                 :         291 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4307                 :             : 
    4308                 :         291 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4309                 :             : 
    4310                 :         291 :             polinfo[j].dobj.objType = DO_POLICY;
    4311                 :         291 :             polinfo[j].dobj.catId.tableoid =
    4312                 :         291 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4313                 :         291 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4314                 :         291 :             AssignDumpId(&polinfo[j].dobj);
    4315                 :         291 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4316                 :         291 :             polinfo[j].poltable = tbinfo;
    4317                 :         291 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4318                 :         291 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4319                 :             : 
    4320                 :         291 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4321                 :         291 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4322                 :             : 
    4323         [ +  + ]:         291 :             if (PQgetisnull(res, j, i_polroles))
    4324                 :         127 :                 polinfo[j].polroles = NULL;
    4325                 :             :             else
    4326                 :         164 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4327                 :             : 
    4328         [ +  + ]:         291 :             if (PQgetisnull(res, j, i_polqual))
    4329                 :          41 :                 polinfo[j].polqual = NULL;
    4330                 :             :             else
    4331                 :         250 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4332                 :             : 
    4333         [ +  + ]:         291 :             if (PQgetisnull(res, j, i_polwithcheck))
    4334                 :         153 :                 polinfo[j].polwithcheck = NULL;
    4335                 :             :             else
    4336                 :         138 :                 polinfo[j].polwithcheck
    4337                 :         138 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4338                 :             :         }
    4339                 :             :     }
    4340                 :             : 
    4341                 :         190 :     PQclear(res);
    4342                 :             : 
    4343                 :         190 :     destroyPQExpBuffer(query);
    4344                 :         190 :     destroyPQExpBuffer(tbloids);
    4345                 :             : }
    4346                 :             : 
    4347                 :             : /*
    4348                 :             :  * dumpPolicy
    4349                 :             :  *    dump the definition of the given policy
    4350                 :             :  */
    4351                 :             : static void
    4352                 :         357 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4353                 :             : {
    4354                 :         357 :     DumpOptions *dopt = fout->dopt;
    4355                 :         357 :     TableInfo  *tbinfo = polinfo->poltable;
    4356                 :             :     PQExpBuffer query;
    4357                 :             :     PQExpBuffer delqry;
    4358                 :             :     PQExpBuffer polprefix;
    4359                 :             :     char       *qtabname;
    4360                 :             :     const char *cmd;
    4361                 :             :     char       *tag;
    4362                 :             : 
    4363                 :             :     /* Do nothing if not dumping schema */
    4364         [ +  + ]:         357 :     if (!dopt->dumpSchema)
    4365                 :          56 :         return;
    4366                 :             : 
    4367                 :             :     /*
    4368                 :             :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4369                 :             :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4370                 :             :      * ROW LEVEL SECURITY.
    4371                 :             :      */
    4372         [ +  + ]:         301 :     if (polinfo->polname == NULL)
    4373                 :             :     {
    4374                 :          58 :         query = createPQExpBuffer();
    4375                 :             : 
    4376                 :          58 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4377                 :          58 :                           fmtQualifiedDumpable(tbinfo));
    4378                 :             : 
    4379                 :             :         /*
    4380                 :             :          * We must emit the ROW SECURITY object's dependency on its table
    4381                 :             :          * explicitly, because it will not match anything in pg_depend (unlike
    4382                 :             :          * the case for other PolicyInfo objects).
    4383                 :             :          */
    4384         [ +  - ]:          58 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4385                 :          58 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4386                 :          58 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4387                 :             :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4388                 :             :                                       .owner = tbinfo->rolname,
    4389                 :             :                                       .description = "ROW SECURITY",
    4390                 :             :                                       .section = SECTION_POST_DATA,
    4391                 :             :                                       .createStmt = query->data,
    4392                 :             :                                       .deps = &(tbinfo->dobj.dumpId),
    4393                 :             :                                       .nDeps = 1));
    4394                 :             : 
    4395                 :          58 :         destroyPQExpBuffer(query);
    4396                 :          58 :         return;
    4397                 :             :     }
    4398                 :             : 
    4399         [ +  + ]:         243 :     if (polinfo->polcmd == '*')
    4400                 :          81 :         cmd = "";
    4401         [ +  + ]:         162 :     else if (polinfo->polcmd == 'r')
    4402                 :          43 :         cmd = " FOR SELECT";
    4403         [ +  + ]:         119 :     else if (polinfo->polcmd == 'a')
    4404                 :          33 :         cmd = " FOR INSERT";
    4405         [ +  + ]:          86 :     else if (polinfo->polcmd == 'w')
    4406                 :          43 :         cmd = " FOR UPDATE";
    4407         [ +  - ]:          43 :     else if (polinfo->polcmd == 'd')
    4408                 :          43 :         cmd = " FOR DELETE";
    4409                 :             :     else
    4410                 :           0 :         pg_fatal("unexpected policy command type: %c",
    4411                 :             :                  polinfo->polcmd);
    4412                 :             : 
    4413                 :         243 :     query = createPQExpBuffer();
    4414                 :         243 :     delqry = createPQExpBuffer();
    4415                 :         243 :     polprefix = createPQExpBuffer();
    4416                 :             : 
    4417                 :         243 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4418                 :             : 
    4419                 :         243 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4420                 :             : 
    4421                 :         243 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4422         [ +  + ]:         243 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4423                 :             : 
    4424         [ +  + ]:         243 :     if (polinfo->polroles != NULL)
    4425                 :         132 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4426                 :             : 
    4427         [ +  + ]:         243 :     if (polinfo->polqual != NULL)
    4428                 :         210 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4429                 :             : 
    4430         [ +  + ]:         243 :     if (polinfo->polwithcheck != NULL)
    4431                 :         114 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4432                 :             : 
    4433                 :         243 :     appendPQExpBufferStr(query, ";\n");
    4434                 :             : 
    4435                 :         243 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4436                 :         243 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4437                 :             : 
    4438                 :         243 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4439                 :         243 :                       fmtId(polinfo->polname));
    4440                 :             : 
    4441                 :         243 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4442                 :             : 
    4443         [ +  - ]:         243 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4444                 :         243 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4445                 :         243 :                      ARCHIVE_OPTS(.tag = tag,
    4446                 :             :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4447                 :             :                                   .owner = tbinfo->rolname,
    4448                 :             :                                   .description = "POLICY",
    4449                 :             :                                   .section = SECTION_POST_DATA,
    4450                 :             :                                   .createStmt = query->data,
    4451                 :             :                                   .dropStmt = delqry->data));
    4452                 :             : 
    4453         [ +  + ]:         243 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4454                 :          33 :         dumpComment(fout, polprefix->data, qtabname,
    4455                 :          33 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4456                 :          33 :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4457                 :             : 
    4458                 :         243 :     pfree(tag);
    4459                 :         243 :     destroyPQExpBuffer(query);
    4460                 :         243 :     destroyPQExpBuffer(delqry);
    4461                 :         243 :     destroyPQExpBuffer(polprefix);
    4462                 :         243 :     pg_free(qtabname);
    4463                 :             : }
    4464                 :             : 
    4465                 :             : /*
    4466                 :             :  * getPublications
    4467                 :             :  *    get information about publications
    4468                 :             :  */
    4469                 :             : void
    4470                 :         191 : getPublications(Archive *fout)
    4471                 :             : {
    4472                 :         191 :     DumpOptions *dopt = fout->dopt;
    4473                 :             :     PQExpBuffer query;
    4474                 :             :     PGresult   *res;
    4475                 :             :     PublicationInfo *pubinfo;
    4476                 :             :     int         i_tableoid;
    4477                 :             :     int         i_oid;
    4478                 :             :     int         i_pubname;
    4479                 :             :     int         i_pubowner;
    4480                 :             :     int         i_puballtables;
    4481                 :             :     int         i_puballsequences;
    4482                 :             :     int         i_pubinsert;
    4483                 :             :     int         i_pubupdate;
    4484                 :             :     int         i_pubdelete;
    4485                 :             :     int         i_pubtruncate;
    4486                 :             :     int         i_pubviaroot;
    4487                 :             :     int         i_pubgencols;
    4488                 :             :     int         i,
    4489                 :             :                 ntups;
    4490                 :             : 
    4491         [ -  + ]:         191 :     if (dopt->no_publications)
    4492                 :           0 :         return;
    4493                 :             : 
    4494                 :         191 :     query = createPQExpBuffer();
    4495                 :             : 
    4496                 :             :     /* Get the publications. */
    4497                 :         191 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4498                 :             :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4499                 :             :                          "p.pubupdate, p.pubdelete, ");
    4500                 :             : 
    4501         [ +  - ]:         191 :     if (fout->remoteVersion >= 110000)
    4502                 :         191 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4503                 :             :     else
    4504                 :           0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4505                 :             : 
    4506         [ +  - ]:         191 :     if (fout->remoteVersion >= 130000)
    4507                 :         191 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4508                 :             :     else
    4509                 :           0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4510                 :             : 
    4511         [ +  - ]:         191 :     if (fout->remoteVersion >= 180000)
    4512                 :         191 :         appendPQExpBufferStr(query, "p.pubgencols, ");
    4513                 :             :     else
    4514                 :           0 :         appendPQExpBuffer(query, "'%c' AS pubgencols, ", PUBLISH_GENCOLS_NONE);
    4515                 :             : 
    4516         [ +  - ]:         191 :     if (fout->remoteVersion >= 190000)
    4517                 :         191 :         appendPQExpBufferStr(query, "p.puballsequences ");
    4518                 :             :     else
    4519                 :           0 :         appendPQExpBufferStr(query, "false AS puballsequences ");
    4520                 :             : 
    4521                 :         191 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4522                 :             : 
    4523                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4524                 :             : 
    4525                 :         191 :     ntups = PQntuples(res);
    4526                 :             : 
    4527         [ +  + ]:         191 :     if (ntups == 0)
    4528                 :         135 :         goto cleanup;
    4529                 :             : 
    4530                 :          56 :     i_tableoid = PQfnumber(res, "tableoid");
    4531                 :          56 :     i_oid = PQfnumber(res, "oid");
    4532                 :          56 :     i_pubname = PQfnumber(res, "pubname");
    4533                 :          56 :     i_pubowner = PQfnumber(res, "pubowner");
    4534                 :          56 :     i_puballtables = PQfnumber(res, "puballtables");
    4535                 :          56 :     i_puballsequences = PQfnumber(res, "puballsequences");
    4536                 :          56 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4537                 :          56 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4538                 :          56 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4539                 :          56 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4540                 :          56 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4541                 :          56 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4542                 :             : 
    4543                 :          56 :     pubinfo = pg_malloc_array(PublicationInfo, ntups);
    4544                 :             : 
    4545         [ +  + ]:         572 :     for (i = 0; i < ntups; i++)
    4546                 :             :     {
    4547                 :         516 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4548                 :         516 :         pubinfo[i].dobj.catId.tableoid =
    4549                 :         516 :             atooid(PQgetvalue(res, i, i_tableoid));
    4550                 :         516 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4551                 :         516 :         AssignDumpId(&pubinfo[i].dobj);
    4552                 :         516 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4553                 :         516 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4554                 :         516 :         pubinfo[i].puballtables =
    4555                 :         516 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4556                 :         516 :         pubinfo[i].puballsequences =
    4557                 :         516 :             (strcmp(PQgetvalue(res, i, i_puballsequences), "t") == 0);
    4558                 :         516 :         pubinfo[i].pubinsert =
    4559                 :         516 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4560                 :         516 :         pubinfo[i].pubupdate =
    4561                 :         516 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4562                 :         516 :         pubinfo[i].pubdelete =
    4563                 :         516 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4564                 :         516 :         pubinfo[i].pubtruncate =
    4565                 :         516 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4566                 :         516 :         pubinfo[i].pubviaroot =
    4567                 :         516 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4568                 :         516 :         pubinfo[i].pubgencols_type =
    4569                 :         516 :             *(PQgetvalue(res, i, i_pubgencols));
    4570                 :         516 :         pubinfo[i].except_tables = (SimplePtrList)
    4571                 :             :         {
    4572                 :             :             NULL, NULL
    4573                 :             :         };
    4574                 :             : 
    4575                 :             :         /* Decide whether we want to dump it */
    4576                 :         516 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4577                 :             : 
    4578                 :             :         /*
    4579                 :             :          * Get the list of tables for publications specified in the EXCEPT
    4580                 :             :          * TABLE clause.
    4581                 :             :          *
    4582                 :             :          * Although individual table entries in EXCEPT list could be stored in
    4583                 :             :          * PublicationRelInfo, dumpPublicationTable cannot be used to emit
    4584                 :             :          * them, because there is no ALTER PUBLICATION ... ADD command to add
    4585                 :             :          * individual table entries to the EXCEPT list.
    4586                 :             :          *
    4587                 :             :          * Therefore, the approach is to dump the complete EXCEPT list in a
    4588                 :             :          * single CREATE PUBLICATION statement. PublicationInfo is used to
    4589                 :             :          * collect this information, which is then emitted by
    4590                 :             :          * dumpPublication().
    4591                 :             :          */
    4592         [ +  - ]:         516 :         if (fout->remoteVersion >= 190000)
    4593                 :             :         {
    4594                 :             :             int         ntbls;
    4595                 :             :             PGresult   *res_tbls;
    4596                 :             : 
    4597                 :         516 :             resetPQExpBuffer(query);
    4598                 :         516 :             appendPQExpBuffer(query,
    4599                 :             :                               "SELECT prrelid\n"
    4600                 :             :                               "FROM pg_catalog.pg_publication_rel\n"
    4601                 :             :                               "WHERE prpubid = %u AND prexcept",
    4602                 :         516 :                               pubinfo[i].dobj.catId.oid);
    4603                 :             : 
    4604                 :         516 :             res_tbls = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4605                 :             : 
    4606                 :         516 :             ntbls = PQntuples(res_tbls);
    4607                 :             : 
    4608         [ +  + ]:         756 :             for (int j = 0; j < ntbls; j++)
    4609                 :             :             {
    4610                 :             :                 Oid         prrelid;
    4611                 :             :                 TableInfo  *tbinfo;
    4612                 :             : 
    4613                 :         240 :                 prrelid = atooid(PQgetvalue(res_tbls, j, 0));
    4614                 :             : 
    4615                 :         240 :                 tbinfo = findTableByOid(prrelid);
    4616                 :             : 
    4617         [ +  - ]:         240 :                 if (tbinfo != NULL)
    4618                 :         240 :                     simple_ptr_list_append(&pubinfo[i].except_tables, tbinfo);
    4619                 :             :             }
    4620                 :             : 
    4621                 :         516 :             PQclear(res_tbls);
    4622                 :             :         }
    4623                 :             :     }
    4624                 :             : 
    4625                 :          56 : cleanup:
    4626                 :         191 :     PQclear(res);
    4627                 :             : 
    4628                 :         191 :     destroyPQExpBuffer(query);
    4629                 :             : }
    4630                 :             : 
    4631                 :             : /*
    4632                 :             :  * dumpPublication
    4633                 :             :  *    dump the definition of the given publication
    4634                 :             :  */
    4635                 :             : static void
    4636                 :         416 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4637                 :             : {
    4638                 :         416 :     DumpOptions *dopt = fout->dopt;
    4639                 :             :     PQExpBuffer delq;
    4640                 :             :     PQExpBuffer query;
    4641                 :             :     char       *qpubname;
    4642                 :         416 :     bool        first = true;
    4643                 :             : 
    4644                 :             :     /* Do nothing if not dumping schema */
    4645         [ +  + ]:         416 :     if (!dopt->dumpSchema)
    4646                 :          60 :         return;
    4647                 :             : 
    4648                 :         356 :     delq = createPQExpBuffer();
    4649                 :         356 :     query = createPQExpBuffer();
    4650                 :             : 
    4651                 :         356 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4652                 :             : 
    4653                 :         356 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4654                 :             :                       qpubname);
    4655                 :             : 
    4656                 :         356 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4657                 :             :                       qpubname);
    4658                 :             : 
    4659         [ +  + ]:         356 :     if (pubinfo->puballtables)
    4660                 :             :     {
    4661                 :         166 :         int         n_except = 0;
    4662                 :             : 
    4663                 :         166 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4664                 :             : 
    4665                 :             :         /* Include EXCEPT (TABLE) clause if there are except_tables. */
    4666         [ +  + ]:         331 :         for (SimplePtrListCell *cell = pubinfo->except_tables.head; cell; cell = cell->next)
    4667                 :             :         {
    4668                 :         165 :             TableInfo  *tbinfo = (TableInfo *) cell->ptr;
    4669                 :             : 
    4670         [ +  + ]:         165 :             if (++n_except == 1)
    4671                 :          99 :                 appendPQExpBufferStr(query, " EXCEPT (");
    4672                 :             :             else
    4673                 :          66 :                 appendPQExpBufferStr(query, ", ");
    4674                 :         165 :             appendPQExpBuffer(query, "TABLE ONLY %s", fmtQualifiedDumpable(tbinfo));
    4675                 :             :         }
    4676         [ +  + ]:         166 :         if (n_except > 0)
    4677                 :          99 :             appendPQExpBufferChar(query, ')');
    4678                 :             : 
    4679         [ +  + ]:         166 :         if (pubinfo->puballsequences)
    4680                 :          33 :             appendPQExpBufferStr(query, ", ALL SEQUENCES");
    4681                 :             :     }
    4682         [ +  + ]:         190 :     else if (pubinfo->puballsequences)
    4683                 :          33 :         appendPQExpBufferStr(query, " FOR ALL SEQUENCES");
    4684                 :             : 
    4685                 :         356 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4686         [ +  + ]:         356 :     if (pubinfo->pubinsert)
    4687                 :             :     {
    4688                 :         290 :         appendPQExpBufferStr(query, "insert");
    4689                 :         290 :         first = false;
    4690                 :             :     }
    4691                 :             : 
    4692         [ +  + ]:         356 :     if (pubinfo->pubupdate)
    4693                 :             :     {
    4694         [ +  - ]:         290 :         if (!first)
    4695                 :         290 :             appendPQExpBufferStr(query, ", ");
    4696                 :             : 
    4697                 :         290 :         appendPQExpBufferStr(query, "update");
    4698                 :         290 :         first = false;
    4699                 :             :     }
    4700                 :             : 
    4701         [ +  + ]:         356 :     if (pubinfo->pubdelete)
    4702                 :             :     {
    4703         [ +  - ]:         290 :         if (!first)
    4704                 :         290 :             appendPQExpBufferStr(query, ", ");
    4705                 :             : 
    4706                 :         290 :         appendPQExpBufferStr(query, "delete");
    4707                 :         290 :         first = false;
    4708                 :             :     }
    4709                 :             : 
    4710         [ +  + ]:         356 :     if (pubinfo->pubtruncate)
    4711                 :             :     {
    4712         [ +  - ]:         290 :         if (!first)
    4713                 :         290 :             appendPQExpBufferStr(query, ", ");
    4714                 :             : 
    4715                 :         290 :         appendPQExpBufferStr(query, "truncate");
    4716                 :         290 :         first = false;
    4717                 :             :     }
    4718                 :             : 
    4719                 :         356 :     appendPQExpBufferChar(query, '\'');
    4720                 :             : 
    4721         [ +  + ]:         356 :     if (pubinfo->pubviaroot)
    4722                 :           5 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4723                 :             : 
    4724         [ +  + ]:         356 :     if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4725                 :          33 :         appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4726                 :             : 
    4727                 :         356 :     appendPQExpBufferStr(query, ");\n");
    4728                 :             : 
    4729         [ +  - ]:         356 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4730                 :         356 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4731                 :         356 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4732                 :             :                                   .owner = pubinfo->rolname,
    4733                 :             :                                   .description = "PUBLICATION",
    4734                 :             :                                   .section = SECTION_POST_DATA,
    4735                 :             :                                   .createStmt = query->data,
    4736                 :             :                                   .dropStmt = delq->data));
    4737                 :             : 
    4738         [ +  + ]:         356 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4739                 :          33 :         dumpComment(fout, "PUBLICATION", qpubname,
    4740                 :          33 :                     NULL, pubinfo->rolname,
    4741                 :          33 :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4742                 :             : 
    4743         [ -  + ]:         356 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4744                 :           0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4745                 :           0 :                      NULL, pubinfo->rolname,
    4746                 :           0 :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4747                 :             : 
    4748                 :         356 :     destroyPQExpBuffer(delq);
    4749                 :         356 :     destroyPQExpBuffer(query);
    4750                 :         356 :     pg_free(qpubname);
    4751                 :             : }
    4752                 :             : 
    4753                 :             : /*
    4754                 :             :  * getPublicationNamespaces
    4755                 :             :  *    get information about publication membership for dumpable schemas.
    4756                 :             :  */
    4757                 :             : void
    4758                 :         191 : getPublicationNamespaces(Archive *fout)
    4759                 :             : {
    4760                 :             :     PQExpBuffer query;
    4761                 :             :     PGresult   *res;
    4762                 :             :     PublicationSchemaInfo *pubsinfo;
    4763                 :         191 :     DumpOptions *dopt = fout->dopt;
    4764                 :             :     int         i_tableoid;
    4765                 :             :     int         i_oid;
    4766                 :             :     int         i_pnpubid;
    4767                 :             :     int         i_pnnspid;
    4768                 :             :     int         i,
    4769                 :             :                 j,
    4770                 :             :                 ntups;
    4771                 :             : 
    4772   [ +  -  -  + ]:         191 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4773                 :           0 :         return;
    4774                 :             : 
    4775                 :         191 :     query = createPQExpBuffer();
    4776                 :             : 
    4777                 :             :     /* Collect all publication membership info. */
    4778                 :         191 :     appendPQExpBufferStr(query,
    4779                 :             :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4780                 :             :                          "FROM pg_catalog.pg_publication_namespace");
    4781                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4782                 :             : 
    4783                 :         191 :     ntups = PQntuples(res);
    4784                 :             : 
    4785                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    4786                 :         191 :     i_oid = PQfnumber(res, "oid");
    4787                 :         191 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4788                 :         191 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4789                 :             : 
    4790                 :             :     /* this allocation may be more than we need */
    4791                 :         191 :     pubsinfo = pg_malloc_array(PublicationSchemaInfo, ntups);
    4792                 :         191 :     j = 0;
    4793                 :             : 
    4794         [ +  + ]:         322 :     for (i = 0; i < ntups; i++)
    4795                 :             :     {
    4796                 :         131 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4797                 :         131 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4798                 :             :         PublicationInfo *pubinfo;
    4799                 :             :         NamespaceInfo *nspinfo;
    4800                 :             : 
    4801                 :             :         /*
    4802                 :             :          * Ignore any entries for which we aren't interested in either the
    4803                 :             :          * publication or the rel.
    4804                 :             :          */
    4805                 :         131 :         pubinfo = findPublicationByOid(pnpubid);
    4806         [ -  + ]:         131 :         if (pubinfo == NULL)
    4807                 :           0 :             continue;
    4808                 :         131 :         nspinfo = findNamespaceByOid(pnnspid);
    4809         [ -  + ]:         131 :         if (nspinfo == NULL)
    4810                 :           0 :             continue;
    4811                 :             : 
    4812                 :             :         /* OK, make a DumpableObject for this relationship */
    4813                 :         131 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4814                 :         131 :         pubsinfo[j].dobj.catId.tableoid =
    4815                 :         131 :             atooid(PQgetvalue(res, i, i_tableoid));
    4816                 :         131 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4817                 :         131 :         AssignDumpId(&pubsinfo[j].dobj);
    4818                 :         131 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4819                 :         131 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4820                 :         131 :         pubsinfo[j].publication = pubinfo;
    4821                 :         131 :         pubsinfo[j].pubschema = nspinfo;
    4822                 :             : 
    4823                 :             :         /* Decide whether we want to dump it */
    4824                 :         131 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4825                 :             : 
    4826                 :         131 :         j++;
    4827                 :             :     }
    4828                 :             : 
    4829                 :         191 :     PQclear(res);
    4830                 :         191 :     destroyPQExpBuffer(query);
    4831                 :             : }
    4832                 :             : 
    4833                 :             : /*
    4834                 :             :  * getPublicationTables
    4835                 :             :  *    get information about publication membership for dumpable tables.
    4836                 :             :  */
    4837                 :             : void
    4838                 :         191 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4839                 :             : {
    4840                 :             :     PQExpBuffer query;
    4841                 :             :     PGresult   *res;
    4842                 :             :     PublicationRelInfo *pubrinfo;
    4843                 :         191 :     DumpOptions *dopt = fout->dopt;
    4844                 :             :     int         i_tableoid;
    4845                 :             :     int         i_oid;
    4846                 :             :     int         i_prpubid;
    4847                 :             :     int         i_prrelid;
    4848                 :             :     int         i_prrelqual;
    4849                 :             :     int         i_prattrs;
    4850                 :             :     int         i,
    4851                 :             :                 j,
    4852                 :             :                 ntups;
    4853                 :             : 
    4854         [ -  + ]:         191 :     if (dopt->no_publications)
    4855                 :           0 :         return;
    4856                 :             : 
    4857                 :         191 :     query = createPQExpBuffer();
    4858                 :             : 
    4859                 :             :     /* Collect all publication membership info. */
    4860         [ +  - ]:         191 :     if (fout->remoteVersion >= 150000)
    4861                 :             :     {
    4862                 :         191 :         appendPQExpBufferStr(query,
    4863                 :             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4864                 :             :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4865                 :             :                              "(CASE\n"
    4866                 :             :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4867                 :             :                              "    (SELECT array_agg(attname)\n"
    4868                 :             :                              "       FROM\n"
    4869                 :             :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4870                 :             :                              "         pg_catalog.pg_attribute\n"
    4871                 :             :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4872                 :             :                              "  ELSE NULL END) prattrs "
    4873                 :             :                              "FROM pg_catalog.pg_publication_rel pr");
    4874         [ +  - ]:         191 :         if (fout->remoteVersion >= 190000)
    4875                 :         191 :             appendPQExpBufferStr(query, " WHERE NOT pr.prexcept");
    4876                 :             :     }
    4877                 :             :     else
    4878                 :           0 :         appendPQExpBufferStr(query,
    4879                 :             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4880                 :             :                              "NULL AS prrelqual, NULL AS prattrs "
    4881                 :             :                              "FROM pg_catalog.pg_publication_rel");
    4882                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4883                 :             : 
    4884                 :         191 :     ntups = PQntuples(res);
    4885                 :             : 
    4886                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    4887                 :         191 :     i_oid = PQfnumber(res, "oid");
    4888                 :         191 :     i_prpubid = PQfnumber(res, "prpubid");
    4889                 :         191 :     i_prrelid = PQfnumber(res, "prrelid");
    4890                 :         191 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4891                 :         191 :     i_prattrs = PQfnumber(res, "prattrs");
    4892                 :             : 
    4893                 :             :     /* this allocation may be more than we need */
    4894                 :         191 :     pubrinfo = pg_malloc_array(PublicationRelInfo, ntups);
    4895                 :         191 :     j = 0;
    4896                 :             : 
    4897         [ +  + ]:         562 :     for (i = 0; i < ntups; i++)
    4898                 :             :     {
    4899                 :         371 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4900                 :         371 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4901                 :             :         PublicationInfo *pubinfo;
    4902                 :             :         TableInfo  *tbinfo;
    4903                 :             : 
    4904                 :             :         /*
    4905                 :             :          * Ignore any entries for which we aren't interested in either the
    4906                 :             :          * publication or the rel.
    4907                 :             :          */
    4908                 :         371 :         pubinfo = findPublicationByOid(prpubid);
    4909         [ -  + ]:         371 :         if (pubinfo == NULL)
    4910                 :           0 :             continue;
    4911                 :         371 :         tbinfo = findTableByOid(prrelid);
    4912         [ -  + ]:         371 :         if (tbinfo == NULL)
    4913                 :           0 :             continue;
    4914                 :             : 
    4915                 :             :         /* OK, make a DumpableObject for this relationship */
    4916                 :         371 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4917                 :         371 :         pubrinfo[j].dobj.catId.tableoid =
    4918                 :         371 :             atooid(PQgetvalue(res, i, i_tableoid));
    4919                 :         371 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4920                 :         371 :         AssignDumpId(&pubrinfo[j].dobj);
    4921                 :         371 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4922                 :         371 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4923                 :         371 :         pubrinfo[j].publication = pubinfo;
    4924                 :         371 :         pubrinfo[j].pubtable = tbinfo;
    4925         [ +  + ]:         371 :         if (PQgetisnull(res, i, i_prrelqual))
    4926                 :         206 :             pubrinfo[j].pubrelqual = NULL;
    4927                 :             :         else
    4928                 :         165 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4929                 :             : 
    4930         [ +  + ]:         371 :         if (!PQgetisnull(res, i, i_prattrs))
    4931                 :             :         {
    4932                 :             :             char      **attnames;
    4933                 :             :             int         nattnames;
    4934                 :             :             PQExpBuffer attribs;
    4935                 :             : 
    4936         [ -  + ]:         117 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4937                 :             :                               &attnames, &nattnames))
    4938                 :           0 :                 pg_fatal("could not parse %s array", "prattrs");
    4939                 :         117 :             attribs = createPQExpBuffer();
    4940         [ +  + ]:         337 :             for (int k = 0; k < nattnames; k++)
    4941                 :             :             {
    4942         [ +  + ]:         220 :                 if (k > 0)
    4943                 :         103 :                     appendPQExpBufferStr(attribs, ", ");
    4944                 :             : 
    4945                 :         220 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4946                 :             :             }
    4947                 :         117 :             pubrinfo[j].pubrattrs = attribs->data;
    4948                 :         117 :             free(attribs);      /* but not attribs->data */
    4949                 :         117 :             free(attnames);
    4950                 :             :         }
    4951                 :             :         else
    4952                 :         254 :             pubrinfo[j].pubrattrs = NULL;
    4953                 :             : 
    4954                 :             :         /* Decide whether we want to dump it */
    4955                 :         371 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    4956                 :             : 
    4957                 :         371 :         j++;
    4958                 :             :     }
    4959                 :             : 
    4960                 :         191 :     PQclear(res);
    4961                 :         191 :     destroyPQExpBuffer(query);
    4962                 :             : }
    4963                 :             : 
    4964                 :             : /*
    4965                 :             :  * dumpPublicationNamespace
    4966                 :             :  *    dump the definition of the given publication schema mapping.
    4967                 :             :  */
    4968                 :             : static void
    4969                 :         103 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    4970                 :             : {
    4971                 :         103 :     DumpOptions *dopt = fout->dopt;
    4972                 :         103 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    4973                 :         103 :     PublicationInfo *pubinfo = pubsinfo->publication;
    4974                 :             :     PQExpBuffer query;
    4975                 :             :     char       *tag;
    4976                 :             : 
    4977                 :             :     /* Do nothing if not dumping schema */
    4978         [ +  + ]:         103 :     if (!dopt->dumpSchema)
    4979                 :          12 :         return;
    4980                 :             : 
    4981                 :          91 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    4982                 :             : 
    4983                 :          91 :     query = createPQExpBuffer();
    4984                 :             : 
    4985                 :          91 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    4986                 :          91 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    4987                 :             : 
    4988                 :             :     /*
    4989                 :             :      * There is no point in creating drop query as the drop is done by schema
    4990                 :             :      * drop.
    4991                 :             :      */
    4992         [ +  - ]:          91 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4993                 :          91 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    4994                 :          91 :                      ARCHIVE_OPTS(.tag = tag,
    4995                 :             :                                   .namespace = schemainfo->dobj.name,
    4996                 :             :                                   .owner = pubinfo->rolname,
    4997                 :             :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    4998                 :             :                                   .section = SECTION_POST_DATA,
    4999                 :             :                                   .createStmt = query->data));
    5000                 :             : 
    5001                 :             :     /* These objects can't currently have comments or seclabels */
    5002                 :             : 
    5003                 :          91 :     pfree(tag);
    5004                 :          91 :     destroyPQExpBuffer(query);
    5005                 :             : }
    5006                 :             : 
    5007                 :             : /*
    5008                 :             :  * dumpPublicationTable
    5009                 :             :  *    dump the definition of the given publication table mapping
    5010                 :             :  */
    5011                 :             : static void
    5012                 :         298 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    5013                 :             : {
    5014                 :         298 :     DumpOptions *dopt = fout->dopt;
    5015                 :         298 :     PublicationInfo *pubinfo = pubrinfo->publication;
    5016                 :         298 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    5017                 :             :     PQExpBuffer query;
    5018                 :             :     char       *tag;
    5019                 :             : 
    5020                 :             :     /* Do nothing if not dumping schema */
    5021         [ +  + ]:         298 :     if (!dopt->dumpSchema)
    5022                 :          42 :         return;
    5023                 :             : 
    5024                 :         256 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    5025                 :             : 
    5026                 :         256 :     query = createPQExpBuffer();
    5027                 :             : 
    5028                 :         256 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    5029                 :         256 :                       fmtId(pubinfo->dobj.name));
    5030                 :         256 :     appendPQExpBuffer(query, " %s",
    5031                 :         256 :                       fmtQualifiedDumpable(tbinfo));
    5032                 :             : 
    5033         [ +  + ]:         256 :     if (pubrinfo->pubrattrs)
    5034                 :          81 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    5035                 :             : 
    5036         [ +  + ]:         256 :     if (pubrinfo->pubrelqual)
    5037                 :             :     {
    5038                 :             :         /*
    5039                 :             :          * It's necessary to add parentheses around the expression because
    5040                 :             :          * pg_get_expr won't supply the parentheses for things like WHERE
    5041                 :             :          * TRUE.
    5042                 :             :          */
    5043                 :         114 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    5044                 :             :     }
    5045                 :         256 :     appendPQExpBufferStr(query, ";\n");
    5046                 :             : 
    5047                 :             :     /*
    5048                 :             :      * There is no point in creating a drop query as the drop is done by table
    5049                 :             :      * drop.  (If you think to change this, see also _printTocEntry().)
    5050                 :             :      * Although this object doesn't really have ownership as such, set the
    5051                 :             :      * owner field anyway to ensure that the command is run by the correct
    5052                 :             :      * role at restore time.
    5053                 :             :      */
    5054         [ +  - ]:         256 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5055                 :         256 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    5056                 :         256 :                      ARCHIVE_OPTS(.tag = tag,
    5057                 :             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    5058                 :             :                                   .owner = pubinfo->rolname,
    5059                 :             :                                   .description = "PUBLICATION TABLE",
    5060                 :             :                                   .section = SECTION_POST_DATA,
    5061                 :             :                                   .createStmt = query->data));
    5062                 :             : 
    5063                 :             :     /* These objects can't currently have comments or seclabels */
    5064                 :             : 
    5065                 :         256 :     pfree(tag);
    5066                 :         256 :     destroyPQExpBuffer(query);
    5067                 :             : }
    5068                 :             : 
    5069                 :             : /*
    5070                 :             :  * Is the currently connected user a superuser?
    5071                 :             :  */
    5072                 :             : static bool
    5073                 :         190 : is_superuser(Archive *fout)
    5074                 :             : {
    5075                 :         190 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    5076                 :             :     const char *val;
    5077                 :             : 
    5078                 :         190 :     val = PQparameterStatus(AH->connection, "is_superuser");
    5079                 :             : 
    5080   [ +  -  +  + ]:         190 :     if (val && strcmp(val, "on") == 0)
    5081                 :         187 :         return true;
    5082                 :             : 
    5083                 :           3 :     return false;
    5084                 :             : }
    5085                 :             : 
    5086                 :             : /*
    5087                 :             :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    5088                 :             :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    5089                 :             :  * the setting query is effective only where available.
    5090                 :             :  */
    5091                 :             : static void
    5092                 :         225 : set_restrict_relation_kind(Archive *AH, const char *value)
    5093                 :             : {
    5094                 :         225 :     PQExpBuffer query = createPQExpBuffer();
    5095                 :             :     PGresult   *res;
    5096                 :             : 
    5097                 :         225 :     appendPQExpBuffer(query,
    5098                 :             :                       "SELECT set_config(name, '%s', false) "
    5099                 :             :                       "FROM pg_settings "
    5100                 :             :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    5101                 :             :                       value);
    5102                 :         225 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    5103                 :             : 
    5104                 :         225 :     PQclear(res);
    5105                 :         225 :     destroyPQExpBuffer(query);
    5106                 :         225 : }
    5107                 :             : 
    5108                 :             : /*
    5109                 :             :  * getSubscriptions
    5110                 :             :  *    get information about subscriptions
    5111                 :             :  */
    5112                 :             : void
    5113                 :         191 : getSubscriptions(Archive *fout)
    5114                 :             : {
    5115                 :         191 :     DumpOptions *dopt = fout->dopt;
    5116                 :             :     PQExpBuffer query;
    5117                 :             :     PGresult   *res;
    5118                 :             :     SubscriptionInfo *subinfo;
    5119                 :             :     int         i_tableoid;
    5120                 :             :     int         i_oid;
    5121                 :             :     int         i_subname;
    5122                 :             :     int         i_subowner;
    5123                 :             :     int         i_subbinary;
    5124                 :             :     int         i_substream;
    5125                 :             :     int         i_subtwophasestate;
    5126                 :             :     int         i_subdisableonerr;
    5127                 :             :     int         i_subpasswordrequired;
    5128                 :             :     int         i_subrunasowner;
    5129                 :             :     int         i_subservername;
    5130                 :             :     int         i_subconninfo;
    5131                 :             :     int         i_subslotname;
    5132                 :             :     int         i_subsynccommit;
    5133                 :             :     int         i_subwalrcvtimeout;
    5134                 :             :     int         i_subpublications;
    5135                 :             :     int         i_suborigin;
    5136                 :             :     int         i_suboriginremotelsn;
    5137                 :             :     int         i_subenabled;
    5138                 :             :     int         i_subfailover;
    5139                 :             :     int         i_subretaindeadtuples;
    5140                 :             :     int         i_submaxretention;
    5141                 :             :     int         i,
    5142                 :             :                 ntups;
    5143                 :             : 
    5144         [ +  + ]:         191 :     if (dopt->no_subscriptions)
    5145                 :           1 :         return;
    5146                 :             : 
    5147         [ +  + ]:         190 :     if (!is_superuser(fout))
    5148                 :             :     {
    5149                 :             :         int         n;
    5150                 :             : 
    5151                 :           3 :         res = ExecuteSqlQuery(fout,
    5152                 :             :                               "SELECT count(*) FROM pg_subscription "
    5153                 :             :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    5154                 :             :                               "                 WHERE datname = current_database())",
    5155                 :             :                               PGRES_TUPLES_OK);
    5156                 :           3 :         n = atoi(PQgetvalue(res, 0, 0));
    5157         [ +  + ]:           3 :         if (n > 0)
    5158                 :           2 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    5159                 :           3 :         PQclear(res);
    5160                 :           3 :         return;
    5161                 :             :     }
    5162                 :             : 
    5163                 :         187 :     query = createPQExpBuffer();
    5164                 :             : 
    5165                 :             :     /* Get the subscriptions in current database. */
    5166                 :         187 :     appendPQExpBufferStr(query,
    5167                 :             :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    5168                 :             :                          " s.subowner,\n"
    5169                 :             :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    5170                 :             :                          " s.subpublications,\n");
    5171                 :             : 
    5172         [ +  - ]:         187 :     if (fout->remoteVersion >= 140000)
    5173                 :         187 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    5174                 :             :     else
    5175                 :           0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    5176                 :             : 
    5177         [ +  - ]:         187 :     if (fout->remoteVersion >= 140000)
    5178                 :         187 :         appendPQExpBufferStr(query, " s.substream,\n");
    5179                 :             :     else
    5180                 :           0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    5181                 :             : 
    5182         [ +  - ]:         187 :     if (fout->remoteVersion >= 150000)
    5183                 :         187 :         appendPQExpBufferStr(query,
    5184                 :             :                              " s.subtwophasestate,\n"
    5185                 :             :                              " s.subdisableonerr,\n");
    5186                 :             :     else
    5187                 :           0 :         appendPQExpBuffer(query,
    5188                 :             :                           " '%c' AS subtwophasestate,\n"
    5189                 :             :                           " false AS subdisableonerr,\n",
    5190                 :             :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    5191                 :             : 
    5192         [ +  - ]:         187 :     if (fout->remoteVersion >= 160000)
    5193                 :         187 :         appendPQExpBufferStr(query,
    5194                 :             :                              " s.subpasswordrequired,\n"
    5195                 :             :                              " s.subrunasowner,\n"
    5196                 :             :                              " s.suborigin,\n");
    5197                 :             :     else
    5198                 :           0 :         appendPQExpBuffer(query,
    5199                 :             :                           " 't' AS subpasswordrequired,\n"
    5200                 :             :                           " 't' AS subrunasowner,\n"
    5201                 :             :                           " '%s' AS suborigin,\n",
    5202                 :             :                           LOGICALREP_ORIGIN_ANY);
    5203                 :             : 
    5204   [ +  +  +  - ]:         187 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5205                 :          40 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    5206                 :             :                              " s.subenabled,\n");
    5207                 :             :     else
    5208                 :         147 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    5209                 :             :                              " false AS subenabled,\n");
    5210                 :             : 
    5211         [ +  - ]:         187 :     if (fout->remoteVersion >= 170000)
    5212                 :         187 :         appendPQExpBufferStr(query,
    5213                 :             :                              " s.subfailover,\n");
    5214                 :             :     else
    5215                 :           0 :         appendPQExpBufferStr(query,
    5216                 :             :                              " false AS subfailover,\n");
    5217                 :             : 
    5218         [ +  - ]:         187 :     if (fout->remoteVersion >= 190000)
    5219                 :         187 :         appendPQExpBufferStr(query,
    5220                 :             :                              " s.subretaindeadtuples,\n");
    5221                 :             :     else
    5222                 :           0 :         appendPQExpBufferStr(query,
    5223                 :             :                              " false AS subretaindeadtuples,\n");
    5224                 :             : 
    5225         [ +  - ]:         187 :     if (fout->remoteVersion >= 190000)
    5226                 :         187 :         appendPQExpBufferStr(query,
    5227                 :             :                              " s.submaxretention,\n");
    5228                 :             :     else
    5229                 :           0 :         appendPQExpBufferStr(query, " 0 AS submaxretention,\n");
    5230                 :             : 
    5231         [ +  - ]:         187 :     if (fout->remoteVersion >= 190000)
    5232                 :         187 :         appendPQExpBufferStr(query,
    5233                 :             :                              " s.subwalrcvtimeout,\n");
    5234                 :             :     else
    5235                 :           0 :         appendPQExpBufferStr(query,
    5236                 :             :                              " '-1' AS subwalrcvtimeout,\n");
    5237                 :             : 
    5238         [ +  - ]:         187 :     if (fout->remoteVersion >= 190000)
    5239                 :         187 :         appendPQExpBufferStr(query, " fs.srvname AS subservername\n");
    5240                 :             :     else
    5241                 :           0 :         appendPQExpBufferStr(query, " NULL AS subservername\n");
    5242                 :             : 
    5243                 :         187 :     appendPQExpBufferStr(query,
    5244                 :             :                          "FROM pg_subscription s\n");
    5245                 :             : 
    5246         [ +  - ]:         187 :     if (fout->remoteVersion >= 190000)
    5247                 :         187 :         appendPQExpBufferStr(query,
    5248                 :             :                              "LEFT JOIN pg_catalog.pg_foreign_server fs \n"
    5249                 :             :                              "    ON fs.oid = s.subserver \n");
    5250                 :             : 
    5251   [ +  +  +  - ]:         187 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5252                 :          40 :         appendPQExpBufferStr(query,
    5253                 :             :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    5254                 :             :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    5255                 :             : 
    5256                 :         187 :     appendPQExpBufferStr(query,
    5257                 :             :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    5258                 :             :                          "                   WHERE datname = current_database())");
    5259                 :             : 
    5260                 :         187 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5261                 :             : 
    5262                 :         187 :     ntups = PQntuples(res);
    5263                 :             : 
    5264                 :             :     /*
    5265                 :             :      * Get subscription fields. We don't include subskiplsn in the dump as
    5266                 :             :      * after restoring the dump this value may no longer be relevant.
    5267                 :             :      */
    5268                 :         187 :     i_tableoid = PQfnumber(res, "tableoid");
    5269                 :         187 :     i_oid = PQfnumber(res, "oid");
    5270                 :         187 :     i_subname = PQfnumber(res, "subname");
    5271                 :         187 :     i_subowner = PQfnumber(res, "subowner");
    5272                 :         187 :     i_subenabled = PQfnumber(res, "subenabled");
    5273                 :         187 :     i_subbinary = PQfnumber(res, "subbinary");
    5274                 :         187 :     i_substream = PQfnumber(res, "substream");
    5275                 :         187 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5276                 :         187 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5277                 :         187 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5278                 :         187 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    5279                 :         187 :     i_subfailover = PQfnumber(res, "subfailover");
    5280                 :         187 :     i_subretaindeadtuples = PQfnumber(res, "subretaindeadtuples");
    5281                 :         187 :     i_submaxretention = PQfnumber(res, "submaxretention");
    5282                 :         187 :     i_subservername = PQfnumber(res, "subservername");
    5283                 :         187 :     i_subconninfo = PQfnumber(res, "subconninfo");
    5284                 :         187 :     i_subslotname = PQfnumber(res, "subslotname");
    5285                 :         187 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    5286                 :         187 :     i_subwalrcvtimeout = PQfnumber(res, "subwalrcvtimeout");
    5287                 :         187 :     i_subpublications = PQfnumber(res, "subpublications");
    5288                 :         187 :     i_suborigin = PQfnumber(res, "suborigin");
    5289                 :         187 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5290                 :             : 
    5291                 :         187 :     subinfo = pg_malloc_array(SubscriptionInfo, ntups);
    5292                 :             : 
    5293         [ +  + ]:         324 :     for (i = 0; i < ntups; i++)
    5294                 :             :     {
    5295                 :         137 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5296                 :         137 :         subinfo[i].dobj.catId.tableoid =
    5297                 :         137 :             atooid(PQgetvalue(res, i, i_tableoid));
    5298                 :         137 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5299                 :         137 :         AssignDumpId(&subinfo[i].dobj);
    5300                 :         137 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5301                 :         137 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5302                 :             : 
    5303                 :         137 :         subinfo[i].subenabled =
    5304                 :         137 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5305         [ +  - ]:         137 :         if (PQgetisnull(res, i, i_subservername))
    5306                 :         137 :             subinfo[i].subservername = NULL;
    5307                 :             :         else
    5308                 :           0 :             subinfo[i].subservername = pg_strdup(PQgetvalue(res, i, i_subservername));
    5309                 :         137 :         subinfo[i].subbinary =
    5310                 :         137 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5311                 :         137 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5312                 :         137 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5313                 :         137 :         subinfo[i].subdisableonerr =
    5314                 :         137 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5315                 :         137 :         subinfo[i].subpasswordrequired =
    5316                 :         137 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5317                 :         137 :         subinfo[i].subrunasowner =
    5318                 :         137 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5319                 :         137 :         subinfo[i].subfailover =
    5320                 :         137 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5321                 :         137 :         subinfo[i].subretaindeadtuples =
    5322                 :         137 :             (strcmp(PQgetvalue(res, i, i_subretaindeadtuples), "t") == 0);
    5323                 :         137 :         subinfo[i].submaxretention =
    5324                 :         137 :             atoi(PQgetvalue(res, i, i_submaxretention));
    5325         [ -  + ]:         137 :         if (PQgetisnull(res, i, i_subconninfo))
    5326                 :           0 :             subinfo[i].subconninfo = NULL;
    5327                 :             :         else
    5328                 :         137 :             subinfo[i].subconninfo =
    5329                 :         137 :                 pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5330         [ -  + ]:         137 :         if (PQgetisnull(res, i, i_subslotname))
    5331                 :           0 :             subinfo[i].subslotname = NULL;
    5332                 :             :         else
    5333                 :         137 :             subinfo[i].subslotname =
    5334                 :         137 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5335                 :         274 :         subinfo[i].subsynccommit =
    5336                 :         137 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5337                 :         274 :         subinfo[i].subwalrcvtimeout =
    5338                 :         137 :             pg_strdup(PQgetvalue(res, i, i_subwalrcvtimeout));
    5339                 :         274 :         subinfo[i].subpublications =
    5340                 :         137 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5341                 :         137 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5342         [ +  + ]:         137 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5343                 :         136 :             subinfo[i].suboriginremotelsn = NULL;
    5344                 :             :         else
    5345                 :           1 :             subinfo[i].suboriginremotelsn =
    5346                 :           1 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5347                 :             : 
    5348                 :             :         /* Decide whether we want to dump it */
    5349                 :         137 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5350                 :             :     }
    5351                 :         187 :     PQclear(res);
    5352                 :             : 
    5353                 :         187 :     destroyPQExpBuffer(query);
    5354                 :             : }
    5355                 :             : 
    5356                 :             : /*
    5357                 :             :  * getSubscriptionRelations
    5358                 :             :  *    Get information about subscription membership for dumpable relations. This
    5359                 :             :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5360                 :             :  */
    5361                 :             : void
    5362                 :         191 : getSubscriptionRelations(Archive *fout)
    5363                 :             : {
    5364                 :         191 :     DumpOptions *dopt = fout->dopt;
    5365                 :         191 :     SubscriptionInfo *subinfo = NULL;
    5366                 :             :     SubRelInfo *subrinfo;
    5367                 :             :     PGresult   *res;
    5368                 :             :     int         i_srsubid;
    5369                 :             :     int         i_srrelid;
    5370                 :             :     int         i_srsubstate;
    5371                 :             :     int         i_srsublsn;
    5372                 :             :     int         ntups;
    5373                 :         191 :     Oid         last_srsubid = InvalidOid;
    5374                 :             : 
    5375   [ +  +  +  + ]:         191 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5376         [ -  + ]:          40 :         fout->remoteVersion < 170000)
    5377                 :         151 :         return;
    5378                 :             : 
    5379                 :          40 :     res = ExecuteSqlQuery(fout,
    5380                 :             :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5381                 :             :                           "FROM pg_catalog.pg_subscription_rel "
    5382                 :             :                           "ORDER BY srsubid",
    5383                 :             :                           PGRES_TUPLES_OK);
    5384                 :          40 :     ntups = PQntuples(res);
    5385         [ +  + ]:          40 :     if (ntups == 0)
    5386                 :          39 :         goto cleanup;
    5387                 :             : 
    5388                 :             :     /* Get pg_subscription_rel attributes */
    5389                 :           1 :     i_srsubid = PQfnumber(res, "srsubid");
    5390                 :           1 :     i_srrelid = PQfnumber(res, "srrelid");
    5391                 :           1 :     i_srsubstate = PQfnumber(res, "srsubstate");
    5392                 :           1 :     i_srsublsn = PQfnumber(res, "srsublsn");
    5393                 :             : 
    5394                 :           1 :     subrinfo = pg_malloc_array(SubRelInfo, ntups);
    5395         [ +  + ]:           4 :     for (int i = 0; i < ntups; i++)
    5396                 :             :     {
    5397                 :           3 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5398                 :           3 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    5399                 :             :         TableInfo  *tblinfo;
    5400                 :             : 
    5401                 :             :         /*
    5402                 :             :          * If we switched to a new subscription, check if the subscription
    5403                 :             :          * exists.
    5404                 :             :          */
    5405         [ +  + ]:           3 :         if (cur_srsubid != last_srsubid)
    5406                 :             :         {
    5407                 :           2 :             subinfo = findSubscriptionByOid(cur_srsubid);
    5408         [ -  + ]:           2 :             if (subinfo == NULL)
    5409                 :           0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5410                 :             : 
    5411                 :           2 :             last_srsubid = cur_srsubid;
    5412                 :             :         }
    5413                 :             : 
    5414                 :           3 :         tblinfo = findTableByOid(relid);
    5415         [ -  + ]:           3 :         if (tblinfo == NULL)
    5416                 :           0 :             pg_fatal("failed sanity check, relation with OID %u not found",
    5417                 :             :                      relid);
    5418                 :             : 
    5419                 :             :         /* OK, make a DumpableObject for this relationship */
    5420                 :           3 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5421                 :           3 :         subrinfo[i].dobj.catId.tableoid = relid;
    5422                 :           3 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    5423                 :           3 :         AssignDumpId(&subrinfo[i].dobj);
    5424                 :           3 :         subrinfo[i].dobj.namespace = tblinfo->dobj.namespace;
    5425                 :           3 :         subrinfo[i].dobj.name = tblinfo->dobj.name;
    5426                 :           3 :         subrinfo[i].subinfo = subinfo;
    5427                 :           3 :         subrinfo[i].tblinfo = tblinfo;
    5428                 :           3 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5429         [ +  + ]:           3 :         if (PQgetisnull(res, i, i_srsublsn))
    5430                 :           1 :             subrinfo[i].srsublsn = NULL;
    5431                 :             :         else
    5432                 :           2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5433                 :             : 
    5434                 :             :         /* Decide whether we want to dump it */
    5435                 :           3 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    5436                 :             :     }
    5437                 :             : 
    5438                 :           1 : cleanup:
    5439                 :          40 :     PQclear(res);
    5440                 :             : }
    5441                 :             : 
    5442                 :             : /*
    5443                 :             :  * dumpSubscriptionTable
    5444                 :             :  *    Dump the definition of the given subscription table mapping. This will be
    5445                 :             :  *    used only in binary-upgrade mode for PG17 or later versions.
    5446                 :             :  */
    5447                 :             : static void
    5448                 :           3 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5449                 :             : {
    5450                 :           3 :     DumpOptions *dopt = fout->dopt;
    5451                 :           3 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5452                 :             :     PQExpBuffer query;
    5453                 :             :     char       *tag;
    5454                 :             : 
    5455                 :             :     /* Do nothing if not dumping schema */
    5456         [ -  + ]:           3 :     if (!dopt->dumpSchema)
    5457                 :           0 :         return;
    5458                 :             : 
    5459                 :             :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5460                 :             : 
    5461                 :           3 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->tblinfo->dobj.name);
    5462                 :             : 
    5463                 :           3 :     query = createPQExpBuffer();
    5464                 :             : 
    5465         [ +  - ]:           3 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5466                 :             :     {
    5467                 :             :         /*
    5468                 :             :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5469                 :             :          * to pg_subscription_rel table. This will be used only in
    5470                 :             :          * binary-upgrade mode.
    5471                 :             :          */
    5472                 :           3 :         appendPQExpBufferStr(query,
    5473                 :             :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5474                 :           3 :         appendPQExpBufferStr(query,
    5475                 :             :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5476                 :           3 :         appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5477                 :           3 :         appendPQExpBuffer(query,
    5478                 :             :                           ", %u, '%c'",
    5479                 :           3 :                           subrinfo->tblinfo->dobj.catId.oid,
    5480                 :           3 :                           subrinfo->srsubstate);
    5481                 :             : 
    5482   [ +  +  +  - ]:           3 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5483                 :           2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5484                 :             :         else
    5485                 :           1 :             appendPQExpBufferStr(query, ", NULL");
    5486                 :             : 
    5487                 :           3 :         appendPQExpBufferStr(query, ");\n");
    5488                 :             :     }
    5489                 :             : 
    5490                 :             :     /*
    5491                 :             :      * There is no point in creating a drop query as the drop is done by table
    5492                 :             :      * drop.  (If you think to change this, see also _printTocEntry().)
    5493                 :             :      * Although this object doesn't really have ownership as such, set the
    5494                 :             :      * owner field anyway to ensure that the command is run by the correct
    5495                 :             :      * role at restore time.
    5496                 :             :      */
    5497         [ +  - ]:           3 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5498                 :           3 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5499                 :           3 :                      ARCHIVE_OPTS(.tag = tag,
    5500                 :             :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5501                 :             :                                   .owner = subinfo->rolname,
    5502                 :             :                                   .description = "SUBSCRIPTION TABLE",
    5503                 :             :                                   .section = SECTION_POST_DATA,
    5504                 :             :                                   .createStmt = query->data));
    5505                 :             : 
    5506                 :             :     /* These objects can't currently have comments or seclabels */
    5507                 :             : 
    5508                 :           3 :     pfree(tag);
    5509                 :           3 :     destroyPQExpBuffer(query);
    5510                 :             : }
    5511                 :             : 
    5512                 :             : /*
    5513                 :             :  * dumpSubscription
    5514                 :             :  *    dump the definition of the given subscription
    5515                 :             :  */
    5516                 :             : static void
    5517                 :         116 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5518                 :             : {
    5519                 :         116 :     DumpOptions *dopt = fout->dopt;
    5520                 :             :     PQExpBuffer delq;
    5521                 :             :     PQExpBuffer query;
    5522                 :             :     PQExpBuffer publications;
    5523                 :             :     char       *qsubname;
    5524                 :         116 :     char      **pubnames = NULL;
    5525                 :         116 :     int         npubnames = 0;
    5526                 :             :     int         i;
    5527                 :             : 
    5528                 :             :     /* Do nothing if not dumping schema */
    5529         [ +  + ]:         116 :     if (!dopt->dumpSchema)
    5530                 :          18 :         return;
    5531                 :             : 
    5532                 :          98 :     delq = createPQExpBuffer();
    5533                 :          98 :     query = createPQExpBuffer();
    5534                 :             : 
    5535                 :          98 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5536                 :             : 
    5537                 :          98 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5538                 :             :                       qsubname);
    5539                 :             : 
    5540                 :          98 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s ",
    5541                 :             :                       qsubname);
    5542         [ -  + ]:          98 :     if (subinfo->subservername)
    5543                 :             :     {
    5544                 :           0 :         appendPQExpBuffer(query, "SERVER %s", fmtId(subinfo->subservername));
    5545                 :             :     }
    5546                 :             :     else
    5547                 :             :     {
    5548                 :          98 :         appendPQExpBufferStr(query, "CONNECTION ");
    5549                 :          98 :         appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5550                 :             :     }
    5551                 :             : 
    5552                 :             :     /* Build list of quoted publications and append them to query. */
    5553         [ -  + ]:          98 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5554                 :           0 :         pg_fatal("could not parse %s array", "subpublications");
    5555                 :             : 
    5556                 :          98 :     publications = createPQExpBuffer();
    5557         [ +  + ]:         196 :     for (i = 0; i < npubnames; i++)
    5558                 :             :     {
    5559         [ -  + ]:          98 :         if (i > 0)
    5560                 :           0 :             appendPQExpBufferStr(publications, ", ");
    5561                 :             : 
    5562                 :          98 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5563                 :             :     }
    5564                 :             : 
    5565                 :          98 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5566         [ +  - ]:          98 :     if (subinfo->subslotname)
    5567                 :          98 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5568                 :             :     else
    5569                 :           0 :         appendPQExpBufferStr(query, "NONE");
    5570                 :             : 
    5571         [ -  + ]:          98 :     if (subinfo->subbinary)
    5572                 :           0 :         appendPQExpBufferStr(query, ", binary = true");
    5573                 :             : 
    5574         [ +  + ]:          98 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5575                 :          32 :         appendPQExpBufferStr(query, ", streaming = on");
    5576         [ +  + ]:          66 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5577                 :          34 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5578                 :             :     else
    5579                 :          32 :         appendPQExpBufferStr(query, ", streaming = off");
    5580                 :             : 
    5581         [ -  + ]:          98 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5582                 :           0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5583                 :             : 
    5584         [ -  + ]:          98 :     if (subinfo->subdisableonerr)
    5585                 :           0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5586                 :             : 
    5587         [ -  + ]:          98 :     if (!subinfo->subpasswordrequired)
    5588                 :           0 :         appendPQExpBufferStr(query, ", password_required = false");
    5589                 :             : 
    5590         [ -  + ]:          98 :     if (subinfo->subrunasowner)
    5591                 :           0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5592                 :             : 
    5593         [ +  + ]:          98 :     if (subinfo->subfailover)
    5594                 :           1 :         appendPQExpBufferStr(query, ", failover = true");
    5595                 :             : 
    5596         [ +  + ]:          98 :     if (subinfo->subretaindeadtuples)
    5597                 :           1 :         appendPQExpBufferStr(query, ", retain_dead_tuples = true");
    5598                 :             : 
    5599         [ -  + ]:          98 :     if (subinfo->submaxretention)
    5600                 :           0 :         appendPQExpBuffer(query, ", max_retention_duration = %d", subinfo->submaxretention);
    5601                 :             : 
    5602         [ -  + ]:          98 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5603                 :           0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5604                 :             : 
    5605         [ -  + ]:          98 :     if (strcmp(subinfo->subwalrcvtimeout, "-1") != 0)
    5606                 :           0 :         appendPQExpBuffer(query, ", wal_receiver_timeout = %s", fmtId(subinfo->subwalrcvtimeout));
    5607                 :             : 
    5608         [ +  + ]:          98 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5609                 :          32 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5610                 :             : 
    5611                 :          98 :     appendPQExpBufferStr(query, ");\n");
    5612                 :             : 
    5613                 :             :     /*
    5614                 :             :      * In binary-upgrade mode, we allow the replication to continue after the
    5615                 :             :      * upgrade.
    5616                 :             :      */
    5617   [ +  +  +  - ]:          98 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5618                 :             :     {
    5619         [ +  + ]:           5 :         if (subinfo->suboriginremotelsn)
    5620                 :             :         {
    5621                 :             :             /*
    5622                 :             :              * Preserve the remote_lsn for the subscriber's replication
    5623                 :             :              * origin. This value is required to start the replication from
    5624                 :             :              * the position before the upgrade. This value will be stale if
    5625                 :             :              * the publisher gets upgraded before the subscriber node.
    5626                 :             :              * However, this shouldn't be a problem as the upgrade of the
    5627                 :             :              * publisher ensures that all the transactions were replicated
    5628                 :             :              * before upgrading it.
    5629                 :             :              */
    5630                 :           1 :             appendPQExpBufferStr(query,
    5631                 :             :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5632                 :           1 :             appendPQExpBufferStr(query,
    5633                 :             :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5634                 :           1 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5635                 :           1 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5636                 :             :         }
    5637                 :             : 
    5638         [ +  + ]:           5 :         if (subinfo->subenabled)
    5639                 :             :         {
    5640                 :             :             /*
    5641                 :             :              * Enable the subscription to allow the replication to continue
    5642                 :             :              * after the upgrade.
    5643                 :             :              */
    5644                 :           1 :             appendPQExpBufferStr(query,
    5645                 :             :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5646                 :           1 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5647                 :             :         }
    5648                 :             :     }
    5649                 :             : 
    5650         [ +  - ]:          98 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5651                 :          98 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5652                 :          98 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5653                 :             :                                   .owner = subinfo->rolname,
    5654                 :             :                                   .description = "SUBSCRIPTION",
    5655                 :             :                                   .section = SECTION_POST_DATA,
    5656                 :             :                                   .createStmt = query->data,
    5657                 :             :                                   .dropStmt = delq->data));
    5658                 :             : 
    5659         [ +  + ]:          98 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5660                 :          32 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5661                 :          32 :                     NULL, subinfo->rolname,
    5662                 :          32 :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5663                 :             : 
    5664         [ -  + ]:          98 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5665                 :           0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5666                 :           0 :                      NULL, subinfo->rolname,
    5667                 :           0 :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5668                 :             : 
    5669                 :          98 :     destroyPQExpBuffer(publications);
    5670                 :          98 :     free(pubnames);
    5671                 :             : 
    5672                 :          98 :     destroyPQExpBuffer(delq);
    5673                 :          98 :     destroyPQExpBuffer(query);
    5674                 :          98 :     pg_free(qsubname);
    5675                 :             : }
    5676                 :             : 
    5677                 :             : /*
    5678                 :             :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5679                 :             :  * the object needs.
    5680                 :             :  */
    5681                 :             : static void
    5682                 :        5411 : append_depends_on_extension(Archive *fout,
    5683                 :             :                             PQExpBuffer create,
    5684                 :             :                             const DumpableObject *dobj,
    5685                 :             :                             const char *catalog,
    5686                 :             :                             const char *keyword,
    5687                 :             :                             const char *objname)
    5688                 :             : {
    5689         [ +  + ]:        5411 :     if (dobj->depends_on_ext)
    5690                 :             :     {
    5691                 :             :         char       *nm;
    5692                 :             :         PGresult   *res;
    5693                 :             :         PQExpBuffer query;
    5694                 :             :         int         ntups;
    5695                 :             :         int         i_extname;
    5696                 :             :         int         i;
    5697                 :             : 
    5698                 :             :         /* dodge fmtId() non-reentrancy */
    5699                 :          42 :         nm = pg_strdup(objname);
    5700                 :             : 
    5701                 :          42 :         query = createPQExpBuffer();
    5702                 :          42 :         appendPQExpBuffer(query,
    5703                 :             :                           "SELECT e.extname "
    5704                 :             :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5705                 :             :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5706                 :             :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5707                 :             :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5708                 :             :                           catalog,
    5709                 :          42 :                           dobj->catId.oid);
    5710                 :          42 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5711                 :          42 :         ntups = PQntuples(res);
    5712                 :          42 :         i_extname = PQfnumber(res, "extname");
    5713         [ +  + ]:          84 :         for (i = 0; i < ntups; i++)
    5714                 :             :         {
    5715                 :          42 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5716                 :             :                               keyword, nm,
    5717                 :          42 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5718                 :             :         }
    5719                 :             : 
    5720                 :          42 :         PQclear(res);
    5721                 :          42 :         destroyPQExpBuffer(query);
    5722                 :          42 :         pg_free(nm);
    5723                 :             :     }
    5724                 :        5411 : }
    5725                 :             : 
    5726                 :             : static Oid
    5727                 :           0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5728                 :             : {
    5729                 :             :     /*
    5730                 :             :      * If the old version didn't assign an array type, but the new version
    5731                 :             :      * does, we must select an unused type OID to assign.  This currently only
    5732                 :             :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5733                 :             :      *
    5734                 :             :      * Note: local state here is kind of ugly, but we must have some, since we
    5735                 :             :      * mustn't choose the same unused OID more than once.
    5736                 :             :      */
    5737                 :             :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5738                 :             :     PGresult   *res;
    5739                 :             :     bool        is_dup;
    5740                 :             : 
    5741                 :             :     do
    5742                 :             :     {
    5743                 :           0 :         ++next_possible_free_oid;
    5744                 :           0 :         printfPQExpBuffer(upgrade_query,
    5745                 :             :                           "SELECT EXISTS(SELECT 1 "
    5746                 :             :                           "FROM pg_catalog.pg_type "
    5747                 :             :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5748                 :             :                           next_possible_free_oid);
    5749                 :           0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5750                 :           0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5751                 :           0 :         PQclear(res);
    5752         [ #  # ]:           0 :     } while (is_dup);
    5753                 :             : 
    5754                 :           0 :     return next_possible_free_oid;
    5755                 :             : }
    5756                 :             : 
    5757                 :             : static void
    5758                 :        1017 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5759                 :             :                                          PQExpBuffer upgrade_buffer,
    5760                 :             :                                          Oid pg_type_oid,
    5761                 :             :                                          bool force_array_type,
    5762                 :             :                                          bool include_multirange_type)
    5763                 :             : {
    5764                 :        1017 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5765                 :             :     PGresult   *res;
    5766                 :             :     Oid         pg_type_array_oid;
    5767                 :             :     Oid         pg_type_multirange_oid;
    5768                 :             :     Oid         pg_type_multirange_array_oid;
    5769                 :             :     TypeInfo   *tinfo;
    5770                 :             : 
    5771                 :        1017 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5772                 :        1017 :     appendPQExpBuffer(upgrade_buffer,
    5773                 :             :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5774                 :             :                       pg_type_oid);
    5775                 :             : 
    5776                 :        1017 :     tinfo = findTypeByOid(pg_type_oid);
    5777         [ +  - ]:        1017 :     if (tinfo)
    5778                 :        1017 :         pg_type_array_oid = tinfo->typarray;
    5779                 :             :     else
    5780                 :           0 :         pg_type_array_oid = InvalidOid;
    5781                 :             : 
    5782   [ +  +  -  + ]:        1017 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5783                 :           0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5784                 :             : 
    5785         [ +  + ]:        1017 :     if (OidIsValid(pg_type_array_oid))
    5786                 :             :     {
    5787                 :        1015 :         appendPQExpBufferStr(upgrade_buffer,
    5788                 :             :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5789                 :        1015 :         appendPQExpBuffer(upgrade_buffer,
    5790                 :             :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5791                 :             :                           pg_type_array_oid);
    5792                 :             :     }
    5793                 :             : 
    5794                 :             :     /*
    5795                 :             :      * Pre-set the multirange type oid and its own array type oid.
    5796                 :             :      */
    5797         [ +  + ]:        1017 :     if (include_multirange_type)
    5798                 :             :     {
    5799         [ +  - ]:           9 :         if (fout->remoteVersion >= 140000)
    5800                 :             :         {
    5801                 :           9 :             printfPQExpBuffer(upgrade_query,
    5802                 :             :                               "SELECT t.oid, t.typarray "
    5803                 :             :                               "FROM pg_catalog.pg_type t "
    5804                 :             :                               "JOIN pg_catalog.pg_range r "
    5805                 :             :                               "ON t.oid = r.rngmultitypid "
    5806                 :             :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5807                 :             :                               pg_type_oid);
    5808                 :             : 
    5809                 :           9 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5810                 :             : 
    5811                 :           9 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5812                 :           9 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5813                 :             : 
    5814                 :           9 :             PQclear(res);
    5815                 :             :         }
    5816                 :             :         else
    5817                 :             :         {
    5818                 :           0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5819                 :           0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5820                 :             :         }
    5821                 :             : 
    5822                 :           9 :         appendPQExpBufferStr(upgrade_buffer,
    5823                 :             :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5824                 :           9 :         appendPQExpBuffer(upgrade_buffer,
    5825                 :             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5826                 :             :                           pg_type_multirange_oid);
    5827                 :           9 :         appendPQExpBufferStr(upgrade_buffer,
    5828                 :             :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5829                 :           9 :         appendPQExpBuffer(upgrade_buffer,
    5830                 :             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5831                 :             :                           pg_type_multirange_array_oid);
    5832                 :             :     }
    5833                 :             : 
    5834                 :        1017 :     destroyPQExpBuffer(upgrade_query);
    5835                 :        1017 : }
    5836                 :             : 
    5837                 :             : static void
    5838                 :         952 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5839                 :             :                                     PQExpBuffer upgrade_buffer,
    5840                 :             :                                     const TableInfo *tbinfo)
    5841                 :             : {
    5842                 :         952 :     Oid         pg_type_oid = tbinfo->reltype;
    5843                 :             : 
    5844         [ +  + ]:         952 :     if (OidIsValid(pg_type_oid))
    5845                 :         937 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5846                 :             :                                                  pg_type_oid, false, false);
    5847                 :         952 : }
    5848                 :             : 
    5849                 :             : /*
    5850                 :             :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5851                 :             :  */
    5852                 :             : static int
    5853                 :       13815 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5854                 :             : {
    5855                 :       13815 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5856                 :       13815 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5857                 :             : 
    5858                 :       13815 :     return pg_cmp_u32(v1.oid, v2.oid);
    5859                 :             : }
    5860                 :             : 
    5861                 :             : /*
    5862                 :             :  * collectBinaryUpgradeClassOids
    5863                 :             :  *
    5864                 :             :  * Construct a table of pg_class information required for
    5865                 :             :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5866                 :             :  * lookup.
    5867                 :             :  */
    5868                 :             : static void
    5869                 :          40 : collectBinaryUpgradeClassOids(Archive *fout)
    5870                 :             : {
    5871                 :             :     PGresult   *res;
    5872                 :             :     const char *query;
    5873                 :             : 
    5874                 :          40 :     query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5875                 :             :         "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5876                 :             :         "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5877                 :             :         "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5878                 :             :         "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5879                 :             :         "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5880                 :             :         "ORDER BY c.oid;";
    5881                 :             : 
    5882                 :          40 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5883                 :             : 
    5884                 :          40 :     nbinaryUpgradeClassOids = PQntuples(res);
    5885                 :          40 :     binaryUpgradeClassOids =
    5886                 :          40 :         pg_malloc_array(BinaryUpgradeClassOidItem, nbinaryUpgradeClassOids);
    5887                 :             : 
    5888         [ +  + ]:       20127 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5889                 :             :     {
    5890                 :       20087 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5891                 :       20087 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5892                 :       20087 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5893                 :       20087 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5894                 :       20087 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5895                 :       20087 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5896                 :       20087 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5897                 :             :     }
    5898                 :             : 
    5899                 :          40 :     PQclear(res);
    5900                 :          40 : }
    5901                 :             : 
    5902                 :             : static void
    5903                 :        1375 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5904                 :             :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5905                 :             : {
    5906                 :        1375 :     BinaryUpgradeClassOidItem key = {0};
    5907                 :             :     BinaryUpgradeClassOidItem *entry;
    5908                 :             : 
    5909                 :             :     Assert(binaryUpgradeClassOids);
    5910                 :             : 
    5911                 :             :     /*
    5912                 :             :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5913                 :             :      * toast table and toast table's index if any.
    5914                 :             :      *
    5915                 :             :      * One complexity is that the current table definition might not require
    5916                 :             :      * the creation of a TOAST table, but the old database might have a TOAST
    5917                 :             :      * table that was created earlier, before some wide columns were dropped.
    5918                 :             :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5919                 :             :      * by the new backend, so we can copy the files during binary upgrade
    5920                 :             :      * without worrying about this case.
    5921                 :             :      */
    5922                 :        1375 :     key.oid = pg_class_oid;
    5923                 :        1375 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5924                 :             :                     sizeof(BinaryUpgradeClassOidItem),
    5925                 :             :                     BinaryUpgradeClassOidItemCmp);
    5926                 :             : 
    5927                 :        1375 :     appendPQExpBufferStr(upgrade_buffer,
    5928                 :             :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5929                 :             : 
    5930         [ +  + ]:        1375 :     if (entry->relkind != RELKIND_INDEX &&
    5931         [ +  + ]:        1066 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5932                 :             :     {
    5933                 :        1036 :         appendPQExpBuffer(upgrade_buffer,
    5934                 :             :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5935                 :             :                           pg_class_oid);
    5936                 :             : 
    5937                 :             :         /*
    5938                 :             :          * Not every relation has storage. Also, in a pre-v12 database,
    5939                 :             :          * partitioned tables have a relfilenumber, which should not be
    5940                 :             :          * preserved when upgrading.
    5941                 :             :          */
    5942         [ +  + ]:        1036 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5943         [ +  - ]:         849 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5944                 :         849 :             appendPQExpBuffer(upgrade_buffer,
    5945                 :             :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5946                 :             :                               entry->relfilenumber);
    5947                 :             : 
    5948                 :             :         /*
    5949                 :             :          * In a pre-v12 database, partitioned tables might be marked as having
    5950                 :             :          * toast tables, but we should ignore them if so.
    5951                 :             :          */
    5952         [ +  + ]:        1036 :         if (OidIsValid(entry->toast_oid) &&
    5953         [ +  - ]:         296 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5954                 :             :         {
    5955                 :         296 :             appendPQExpBuffer(upgrade_buffer,
    5956                 :             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    5957                 :             :                               entry->toast_oid);
    5958                 :         296 :             appendPQExpBuffer(upgrade_buffer,
    5959                 :             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    5960                 :             :                               entry->toast_relfilenumber);
    5961                 :             : 
    5962                 :             :             /* every toast table has an index */
    5963                 :         296 :             appendPQExpBuffer(upgrade_buffer,
    5964                 :             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5965                 :             :                               entry->toast_index_oid);
    5966                 :         296 :             appendPQExpBuffer(upgrade_buffer,
    5967                 :             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5968                 :             :                               entry->toast_index_relfilenumber);
    5969                 :             :         }
    5970                 :             :     }
    5971                 :             :     else
    5972                 :             :     {
    5973                 :             :         /* Preserve the OID and relfilenumber of the index */
    5974                 :         339 :         appendPQExpBuffer(upgrade_buffer,
    5975                 :             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5976                 :             :                           pg_class_oid);
    5977                 :         339 :         appendPQExpBuffer(upgrade_buffer,
    5978                 :             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5979                 :             :                           entry->relfilenumber);
    5980                 :             :     }
    5981                 :             : 
    5982                 :        1375 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    5983                 :        1375 : }
    5984                 :             : 
    5985                 :             : /*
    5986                 :             :  * If the DumpableObject is a member of an extension, add a suitable
    5987                 :             :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    5988                 :             :  *
    5989                 :             :  * For somewhat historical reasons, objname should already be quoted,
    5990                 :             :  * but not objnamespace (if any).
    5991                 :             :  */
    5992                 :             : static void
    5993                 :        1620 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    5994                 :             :                                 const DumpableObject *dobj,
    5995                 :             :                                 const char *objtype,
    5996                 :             :                                 const char *objname,
    5997                 :             :                                 const char *objnamespace)
    5998                 :             : {
    5999                 :        1620 :     DumpableObject *extobj = NULL;
    6000                 :             :     int         i;
    6001                 :             : 
    6002         [ +  + ]:        1620 :     if (!dobj->ext_member)
    6003                 :        1598 :         return;
    6004                 :             : 
    6005                 :             :     /*
    6006                 :             :      * Find the parent extension.  We could avoid this search if we wanted to
    6007                 :             :      * add a link field to DumpableObject, but the space costs of that would
    6008                 :             :      * be considerable.  We assume that member objects could only have a
    6009                 :             :      * direct dependency on their own extension, not any others.
    6010                 :             :      */
    6011         [ +  - ]:          22 :     for (i = 0; i < dobj->nDeps; i++)
    6012                 :             :     {
    6013                 :          22 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    6014   [ +  -  +  - ]:          22 :         if (extobj && extobj->objType == DO_EXTENSION)
    6015                 :          22 :             break;
    6016                 :           0 :         extobj = NULL;
    6017                 :             :     }
    6018         [ -  + ]:          22 :     if (extobj == NULL)
    6019                 :           0 :         pg_fatal("could not find parent extension for %s %s",
    6020                 :             :                  objtype, objname);
    6021                 :             : 
    6022                 :          22 :     appendPQExpBufferStr(upgrade_buffer,
    6023                 :             :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    6024                 :          22 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    6025                 :          22 :                       fmtId(extobj->name),
    6026                 :             :                       objtype);
    6027   [ +  +  +  - ]:          22 :     if (objnamespace && *objnamespace)
    6028                 :          19 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    6029                 :          22 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    6030                 :             : }
    6031                 :             : 
    6032                 :             : /*
    6033                 :             :  * getNamespaces:
    6034                 :             :  *    get information about all namespaces in the system catalogs
    6035                 :             :  */
    6036                 :             : void
    6037                 :         192 : getNamespaces(Archive *fout)
    6038                 :             : {
    6039                 :             :     PGresult   *res;
    6040                 :             :     int         ntups;
    6041                 :             :     int         i;
    6042                 :             :     PQExpBuffer query;
    6043                 :             :     NamespaceInfo *nsinfo;
    6044                 :             :     int         i_tableoid;
    6045                 :             :     int         i_oid;
    6046                 :             :     int         i_nspname;
    6047                 :             :     int         i_nspowner;
    6048                 :             :     int         i_nspacl;
    6049                 :             :     int         i_acldefault;
    6050                 :             : 
    6051                 :         192 :     query = createPQExpBuffer();
    6052                 :             : 
    6053                 :             :     /*
    6054                 :             :      * we fetch all namespaces including system ones, so that every object we
    6055                 :             :      * read in can be linked to a containing namespace.
    6056                 :             :      */
    6057                 :         192 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    6058                 :             :                          "n.nspowner, "
    6059                 :             :                          "n.nspacl, "
    6060                 :             :                          "acldefault('n', n.nspowner) AS acldefault "
    6061                 :             :                          "FROM pg_namespace n");
    6062                 :             : 
    6063                 :         192 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6064                 :             : 
    6065                 :         192 :     ntups = PQntuples(res);
    6066                 :             : 
    6067                 :         192 :     nsinfo = pg_malloc_array(NamespaceInfo, ntups);
    6068                 :             : 
    6069                 :         192 :     i_tableoid = PQfnumber(res, "tableoid");
    6070                 :         192 :     i_oid = PQfnumber(res, "oid");
    6071                 :         192 :     i_nspname = PQfnumber(res, "nspname");
    6072                 :         192 :     i_nspowner = PQfnumber(res, "nspowner");
    6073                 :         192 :     i_nspacl = PQfnumber(res, "nspacl");
    6074                 :         192 :     i_acldefault = PQfnumber(res, "acldefault");
    6075                 :             : 
    6076         [ +  + ]:        1888 :     for (i = 0; i < ntups; i++)
    6077                 :             :     {
    6078                 :             :         const char *nspowner;
    6079                 :             : 
    6080                 :        1696 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    6081                 :        1696 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6082                 :        1696 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6083                 :        1696 :         AssignDumpId(&nsinfo[i].dobj);
    6084                 :        1696 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    6085                 :        1696 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    6086                 :        1696 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6087                 :        1696 :         nsinfo[i].dacl.privtype = 0;
    6088                 :        1696 :         nsinfo[i].dacl.initprivs = NULL;
    6089                 :        1696 :         nspowner = PQgetvalue(res, i, i_nspowner);
    6090                 :        1696 :         nsinfo[i].nspowner = atooid(nspowner);
    6091                 :        1696 :         nsinfo[i].rolname = getRoleName(nspowner);
    6092                 :             : 
    6093                 :             :         /* Decide whether to dump this namespace */
    6094                 :        1696 :         selectDumpableNamespace(&nsinfo[i], fout);
    6095                 :             : 
    6096                 :             :         /* Mark whether namespace has an ACL */
    6097         [ +  + ]:        1696 :         if (!PQgetisnull(res, i, i_nspacl))
    6098                 :         861 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6099                 :             : 
    6100                 :             :         /*
    6101                 :             :          * We ignore any pg_init_privs.initprivs entry for the public schema
    6102                 :             :          * and assume a predetermined default, for several reasons.  First,
    6103                 :             :          * dropping and recreating the schema removes its pg_init_privs entry,
    6104                 :             :          * but an empty destination database starts with this ACL nonetheless.
    6105                 :             :          * Second, we support dump/reload of public schema ownership changes.
    6106                 :             :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    6107                 :             :          * initprivs continues to reflect the initial owner.  Hence,
    6108                 :             :          * synthesize the value that nspacl will have after the restore's
    6109                 :             :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    6110                 :             :          * match the source's ACL, even if the latter was an initdb-default
    6111                 :             :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    6112                 :             :          * system object ACLs that the DBA had not customized.  We've made the
    6113                 :             :          * public schema depart from that, because changing its ACL so easily
    6114                 :             :          * breaks applications.
    6115                 :             :          */
    6116         [ +  + ]:        1696 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    6117                 :             :         {
    6118                 :         188 :             PQExpBuffer aclarray = createPQExpBuffer();
    6119                 :         188 :             PQExpBuffer aclitem = createPQExpBuffer();
    6120                 :             : 
    6121                 :             :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    6122                 :         188 :             appendPQExpBufferChar(aclarray, '{');
    6123                 :         188 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6124                 :         188 :             appendPQExpBufferStr(aclitem, "=UC/");
    6125                 :         188 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6126                 :         188 :             appendPGArray(aclarray, aclitem->data);
    6127                 :         188 :             resetPQExpBuffer(aclitem);
    6128                 :         188 :             appendPQExpBufferStr(aclitem, "=U/");
    6129                 :         188 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    6130                 :         188 :             appendPGArray(aclarray, aclitem->data);
    6131                 :         188 :             appendPQExpBufferChar(aclarray, '}');
    6132                 :             : 
    6133                 :         188 :             nsinfo[i].dacl.privtype = 'i';
    6134                 :         188 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    6135                 :         188 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6136                 :             : 
    6137                 :         188 :             destroyPQExpBuffer(aclarray);
    6138                 :         188 :             destroyPQExpBuffer(aclitem);
    6139                 :             :         }
    6140                 :             :     }
    6141                 :             : 
    6142                 :         192 :     PQclear(res);
    6143                 :         192 :     destroyPQExpBuffer(query);
    6144                 :         192 : }
    6145                 :             : 
    6146                 :             : /*
    6147                 :             :  * findNamespace:
    6148                 :             :  *      given a namespace OID, look up the info read by getNamespaces
    6149                 :             :  */
    6150                 :             : static NamespaceInfo *
    6151                 :      626220 : findNamespace(Oid nsoid)
    6152                 :             : {
    6153                 :             :     NamespaceInfo *nsinfo;
    6154                 :             : 
    6155                 :      626220 :     nsinfo = findNamespaceByOid(nsoid);
    6156         [ -  + ]:      626220 :     if (nsinfo == NULL)
    6157                 :           0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    6158                 :      626220 :     return nsinfo;
    6159                 :             : }
    6160                 :             : 
    6161                 :             : /*
    6162                 :             :  * getExtensions:
    6163                 :             :  *    read all extensions in the system catalogs and return them in the
    6164                 :             :  * ExtensionInfo* structure
    6165                 :             :  *
    6166                 :             :  *  numExtensions is set to the number of extensions read in
    6167                 :             :  */
    6168                 :             : ExtensionInfo *
    6169                 :         192 : getExtensions(Archive *fout, int *numExtensions)
    6170                 :             : {
    6171                 :         192 :     DumpOptions *dopt = fout->dopt;
    6172                 :             :     PGresult   *res;
    6173                 :             :     int         ntups;
    6174                 :             :     int         i;
    6175                 :             :     PQExpBuffer query;
    6176                 :         192 :     ExtensionInfo *extinfo = NULL;
    6177                 :             :     int         i_tableoid;
    6178                 :             :     int         i_oid;
    6179                 :             :     int         i_extname;
    6180                 :             :     int         i_nspname;
    6181                 :             :     int         i_extrelocatable;
    6182                 :             :     int         i_extversion;
    6183                 :             :     int         i_extconfig;
    6184                 :             :     int         i_extcondition;
    6185                 :             : 
    6186                 :         192 :     query = createPQExpBuffer();
    6187                 :             : 
    6188                 :         192 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    6189                 :             :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    6190                 :             :                          "FROM pg_extension x "
    6191                 :             :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    6192                 :             : 
    6193                 :         192 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6194                 :             : 
    6195                 :         192 :     ntups = PQntuples(res);
    6196         [ -  + ]:         192 :     if (ntups == 0)
    6197                 :           0 :         goto cleanup;
    6198                 :             : 
    6199                 :         192 :     extinfo = pg_malloc_array(ExtensionInfo, ntups);
    6200                 :             : 
    6201                 :         192 :     i_tableoid = PQfnumber(res, "tableoid");
    6202                 :         192 :     i_oid = PQfnumber(res, "oid");
    6203                 :         192 :     i_extname = PQfnumber(res, "extname");
    6204                 :         192 :     i_nspname = PQfnumber(res, "nspname");
    6205                 :         192 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    6206                 :         192 :     i_extversion = PQfnumber(res, "extversion");
    6207                 :         192 :     i_extconfig = PQfnumber(res, "extconfig");
    6208                 :         192 :     i_extcondition = PQfnumber(res, "extcondition");
    6209                 :             : 
    6210         [ +  + ]:         415 :     for (i = 0; i < ntups; i++)
    6211                 :             :     {
    6212                 :         223 :         extinfo[i].dobj.objType = DO_EXTENSION;
    6213                 :         223 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6214                 :         223 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6215                 :         223 :         AssignDumpId(&extinfo[i].dobj);
    6216                 :         223 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    6217                 :         223 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    6218                 :         223 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    6219                 :         223 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    6220                 :         223 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    6221                 :         223 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    6222                 :             : 
    6223                 :             :         /* Decide whether we want to dump it */
    6224                 :         223 :         selectDumpableExtension(&(extinfo[i]), dopt);
    6225                 :             :     }
    6226                 :             : 
    6227                 :         192 : cleanup:
    6228                 :         192 :     PQclear(res);
    6229                 :         192 :     destroyPQExpBuffer(query);
    6230                 :             : 
    6231                 :         192 :     *numExtensions = ntups;
    6232                 :             : 
    6233                 :         192 :     return extinfo;
    6234                 :             : }
    6235                 :             : 
    6236                 :             : /*
    6237                 :             :  * getTypes:
    6238                 :             :  *    get information about all types in the system catalogs
    6239                 :             :  *
    6240                 :             :  * NB: this must run after getFuncs() because we assume we can do
    6241                 :             :  * findFuncByOid().
    6242                 :             :  */
    6243                 :             : void
    6244                 :         191 : getTypes(Archive *fout)
    6245                 :             : {
    6246                 :             :     PGresult   *res;
    6247                 :             :     int         ntups;
    6248                 :             :     int         i;
    6249                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    6250                 :             :     TypeInfo   *tyinfo;
    6251                 :             :     ShellTypeInfo *stinfo;
    6252                 :             :     int         i_tableoid;
    6253                 :             :     int         i_oid;
    6254                 :             :     int         i_typname;
    6255                 :             :     int         i_typnamespace;
    6256                 :             :     int         i_typacl;
    6257                 :             :     int         i_acldefault;
    6258                 :             :     int         i_typowner;
    6259                 :             :     int         i_typelem;
    6260                 :             :     int         i_typrelid;
    6261                 :             :     int         i_typrelkind;
    6262                 :             :     int         i_typtype;
    6263                 :             :     int         i_typisdefined;
    6264                 :             :     int         i_isarray;
    6265                 :             :     int         i_typarray;
    6266                 :             : 
    6267                 :             :     /*
    6268                 :             :      * we include even the built-in types because those may be used as array
    6269                 :             :      * elements by user-defined types
    6270                 :             :      *
    6271                 :             :      * we filter out the built-in types when we dump out the types
    6272                 :             :      *
    6273                 :             :      * same approach for undefined (shell) types and array types
    6274                 :             :      *
    6275                 :             :      * Note: as of 8.3 we can reliably detect whether a type is an
    6276                 :             :      * auto-generated array type by checking the element type's typarray.
    6277                 :             :      * (Before that the test is capable of generating false positives.) We
    6278                 :             :      * still check for name beginning with '_', though, so as to avoid the
    6279                 :             :      * cost of the subselect probe for all standard types.  This would have to
    6280                 :             :      * be revisited if the backend ever allows renaming of array types.
    6281                 :             :      */
    6282                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    6283                 :             :                          "typnamespace, typacl, "
    6284                 :             :                          "acldefault('T', typowner) AS acldefault, "
    6285                 :             :                          "typowner, "
    6286                 :             :                          "typelem, typrelid, typarray, "
    6287                 :             :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    6288                 :             :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    6289                 :             :                          "typtype, typisdefined, "
    6290                 :             :                          "typname[0] = '_' AND typelem != 0 AND "
    6291                 :             :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    6292                 :             :                          "FROM pg_type");
    6293                 :             : 
    6294                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6295                 :             : 
    6296                 :         191 :     ntups = PQntuples(res);
    6297                 :             : 
    6298                 :         191 :     tyinfo = pg_malloc_array(TypeInfo, ntups);
    6299                 :             : 
    6300                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    6301                 :         191 :     i_oid = PQfnumber(res, "oid");
    6302                 :         191 :     i_typname = PQfnumber(res, "typname");
    6303                 :         191 :     i_typnamespace = PQfnumber(res, "typnamespace");
    6304                 :         191 :     i_typacl = PQfnumber(res, "typacl");
    6305                 :         191 :     i_acldefault = PQfnumber(res, "acldefault");
    6306                 :         191 :     i_typowner = PQfnumber(res, "typowner");
    6307                 :         191 :     i_typelem = PQfnumber(res, "typelem");
    6308                 :         191 :     i_typrelid = PQfnumber(res, "typrelid");
    6309                 :         191 :     i_typrelkind = PQfnumber(res, "typrelkind");
    6310                 :         191 :     i_typtype = PQfnumber(res, "typtype");
    6311                 :         191 :     i_typisdefined = PQfnumber(res, "typisdefined");
    6312                 :         191 :     i_isarray = PQfnumber(res, "isarray");
    6313                 :         191 :     i_typarray = PQfnumber(res, "typarray");
    6314                 :             : 
    6315         [ +  + ]:      148169 :     for (i = 0; i < ntups; i++)
    6316                 :             :     {
    6317                 :      147978 :         tyinfo[i].dobj.objType = DO_TYPE;
    6318                 :      147978 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6319                 :      147978 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6320                 :      147978 :         AssignDumpId(&tyinfo[i].dobj);
    6321                 :      147978 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6322                 :      295956 :         tyinfo[i].dobj.namespace =
    6323                 :      147978 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6324                 :      147978 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6325                 :      147978 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6326                 :      147978 :         tyinfo[i].dacl.privtype = 0;
    6327                 :      147978 :         tyinfo[i].dacl.initprivs = NULL;
    6328                 :      147978 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    6329                 :      147978 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6330                 :      147978 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6331                 :      147978 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6332                 :      147978 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6333                 :      147978 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6334                 :      147978 :         tyinfo[i].shellType = NULL;
    6335                 :             : 
    6336         [ +  + ]:      147978 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6337                 :      147923 :             tyinfo[i].isDefined = true;
    6338                 :             :         else
    6339                 :          55 :             tyinfo[i].isDefined = false;
    6340                 :             : 
    6341         [ +  + ]:      147978 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6342                 :       71192 :             tyinfo[i].isArray = true;
    6343                 :             :         else
    6344                 :       76786 :             tyinfo[i].isArray = false;
    6345                 :             : 
    6346                 :      147978 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6347                 :             : 
    6348         [ +  + ]:      147978 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6349                 :        1291 :             tyinfo[i].isMultirange = true;
    6350                 :             :         else
    6351                 :      146687 :             tyinfo[i].isMultirange = false;
    6352                 :             : 
    6353                 :             :         /* Decide whether we want to dump it */
    6354                 :      147978 :         selectDumpableType(&tyinfo[i], fout);
    6355                 :             : 
    6356                 :             :         /* Mark whether type has an ACL */
    6357         [ +  + ]:      147978 :         if (!PQgetisnull(res, i, i_typacl))
    6358                 :         217 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6359                 :             : 
    6360                 :             :         /*
    6361                 :             :          * If it's a domain, fetch info about its constraints, if any
    6362                 :             :          */
    6363                 :      147978 :         tyinfo[i].nDomChecks = 0;
    6364                 :      147978 :         tyinfo[i].domChecks = NULL;
    6365                 :      147978 :         tyinfo[i].notnull = NULL;
    6366         [ +  + ]:      147978 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6367         [ +  + ]:       16336 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6368                 :         181 :             getDomainConstraints(fout, &(tyinfo[i]));
    6369                 :             : 
    6370                 :             :         /*
    6371                 :             :          * If it's a base type, make a DumpableObject representing a shell
    6372                 :             :          * definition of the type.  We will need to dump that ahead of the I/O
    6373                 :             :          * functions for the type.  Similarly, range types need a shell
    6374                 :             :          * definition in case they have a canonicalize function.
    6375                 :             :          *
    6376                 :             :          * Note: the shell type doesn't have a catId.  You might think it
    6377                 :             :          * should copy the base type's catId, but then it might capture the
    6378                 :             :          * pg_depend entries for the type, which we don't want.
    6379                 :             :          */
    6380         [ +  + ]:      147978 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6381         [ +  + ]:       16336 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6382         [ +  + ]:        7950 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6383                 :             :         {
    6384                 :        8521 :             stinfo = pg_malloc_object(ShellTypeInfo);
    6385                 :        8521 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6386                 :        8521 :             stinfo->dobj.catId = nilCatalogId;
    6387                 :        8521 :             AssignDumpId(&stinfo->dobj);
    6388                 :        8521 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6389                 :        8521 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6390                 :        8521 :             stinfo->baseType = &(tyinfo[i]);
    6391                 :        8521 :             tyinfo[i].shellType = stinfo;
    6392                 :             : 
    6393                 :             :             /*
    6394                 :             :              * Initially mark the shell type as not to be dumped.  We'll only
    6395                 :             :              * dump it if the I/O or canonicalize functions need to be dumped;
    6396                 :             :              * this is taken care of while sorting dependencies.
    6397                 :             :              */
    6398                 :        8521 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6399                 :             :         }
    6400                 :             :     }
    6401                 :             : 
    6402                 :         191 :     PQclear(res);
    6403                 :             : 
    6404                 :         191 :     destroyPQExpBuffer(query);
    6405                 :         191 : }
    6406                 :             : 
    6407                 :             : /*
    6408                 :             :  * getOperators:
    6409                 :             :  *    get information about all operators in the system catalogs
    6410                 :             :  */
    6411                 :             : void
    6412                 :         191 : getOperators(Archive *fout)
    6413                 :             : {
    6414                 :             :     PGresult   *res;
    6415                 :             :     int         ntups;
    6416                 :             :     int         i;
    6417                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    6418                 :             :     OprInfo    *oprinfo;
    6419                 :             :     int         i_tableoid;
    6420                 :             :     int         i_oid;
    6421                 :             :     int         i_oprname;
    6422                 :             :     int         i_oprnamespace;
    6423                 :             :     int         i_oprowner;
    6424                 :             :     int         i_oprkind;
    6425                 :             :     int         i_oprleft;
    6426                 :             :     int         i_oprright;
    6427                 :             :     int         i_oprcode;
    6428                 :             : 
    6429                 :             :     /*
    6430                 :             :      * find all operators, including builtin operators; we filter out
    6431                 :             :      * system-defined operators at dump-out time.
    6432                 :             :      */
    6433                 :             : 
    6434                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6435                 :             :                          "oprnamespace, "
    6436                 :             :                          "oprowner, "
    6437                 :             :                          "oprkind, "
    6438                 :             :                          "oprleft, "
    6439                 :             :                          "oprright, "
    6440                 :             :                          "oprcode::oid AS oprcode "
    6441                 :             :                          "FROM pg_operator");
    6442                 :             : 
    6443                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6444                 :             : 
    6445                 :         191 :     ntups = PQntuples(res);
    6446                 :             : 
    6447                 :         191 :     oprinfo = pg_malloc_array(OprInfo, ntups);
    6448                 :             : 
    6449                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    6450                 :         191 :     i_oid = PQfnumber(res, "oid");
    6451                 :         191 :     i_oprname = PQfnumber(res, "oprname");
    6452                 :         191 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6453                 :         191 :     i_oprowner = PQfnumber(res, "oprowner");
    6454                 :         191 :     i_oprkind = PQfnumber(res, "oprkind");
    6455                 :         191 :     i_oprleft = PQfnumber(res, "oprleft");
    6456                 :         191 :     i_oprright = PQfnumber(res, "oprright");
    6457                 :         191 :     i_oprcode = PQfnumber(res, "oprcode");
    6458                 :             : 
    6459         [ +  + ]:      154091 :     for (i = 0; i < ntups; i++)
    6460                 :             :     {
    6461                 :      153900 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6462                 :      153900 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6463                 :      153900 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6464                 :      153900 :         AssignDumpId(&oprinfo[i].dobj);
    6465                 :      153900 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6466                 :      307800 :         oprinfo[i].dobj.namespace =
    6467                 :      153900 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6468                 :      153900 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6469                 :      153900 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6470                 :      153900 :         oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
    6471                 :      153900 :         oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
    6472                 :      153900 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6473                 :             : 
    6474                 :             :         /* Decide whether we want to dump it */
    6475                 :      153900 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6476                 :             :     }
    6477                 :             : 
    6478                 :         191 :     PQclear(res);
    6479                 :             : 
    6480                 :         191 :     destroyPQExpBuffer(query);
    6481                 :         191 : }
    6482                 :             : 
    6483                 :             : /*
    6484                 :             :  * getCollations:
    6485                 :             :  *    get information about all collations in the system catalogs
    6486                 :             :  */
    6487                 :             : void
    6488                 :         191 : getCollations(Archive *fout)
    6489                 :             : {
    6490                 :             :     PGresult   *res;
    6491                 :             :     int         ntups;
    6492                 :             :     int         i;
    6493                 :             :     PQExpBuffer query;
    6494                 :             :     CollInfo   *collinfo;
    6495                 :             :     int         i_tableoid;
    6496                 :             :     int         i_oid;
    6497                 :             :     int         i_collname;
    6498                 :             :     int         i_collnamespace;
    6499                 :             :     int         i_collowner;
    6500                 :             :     int         i_collencoding;
    6501                 :             : 
    6502                 :         191 :     query = createPQExpBuffer();
    6503                 :             : 
    6504                 :             :     /*
    6505                 :             :      * find all collations, including builtin collations; we filter out
    6506                 :             :      * system-defined collations at dump-out time.
    6507                 :             :      */
    6508                 :             : 
    6509                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6510                 :             :                          "collnamespace, "
    6511                 :             :                          "collowner, "
    6512                 :             :                          "collencoding "
    6513                 :             :                          "FROM pg_collation");
    6514                 :             : 
    6515                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6516                 :             : 
    6517                 :         191 :     ntups = PQntuples(res);
    6518                 :             : 
    6519                 :         191 :     collinfo = pg_malloc_array(CollInfo, ntups);
    6520                 :             : 
    6521                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    6522                 :         191 :     i_oid = PQfnumber(res, "oid");
    6523                 :         191 :     i_collname = PQfnumber(res, "collname");
    6524                 :         191 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6525                 :         191 :     i_collowner = PQfnumber(res, "collowner");
    6526                 :         191 :     i_collencoding = PQfnumber(res, "collencoding");
    6527                 :             : 
    6528         [ +  + ]:      168388 :     for (i = 0; i < ntups; i++)
    6529                 :             :     {
    6530                 :      168197 :         collinfo[i].dobj.objType = DO_COLLATION;
    6531                 :      168197 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6532                 :      168197 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6533                 :      168197 :         AssignDumpId(&collinfo[i].dobj);
    6534                 :      168197 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6535                 :      336394 :         collinfo[i].dobj.namespace =
    6536                 :      168197 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6537                 :      168197 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6538                 :      168197 :         collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
    6539                 :             : 
    6540                 :             :         /* Decide whether we want to dump it */
    6541                 :      168197 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6542                 :             :     }
    6543                 :             : 
    6544                 :         191 :     PQclear(res);
    6545                 :             : 
    6546                 :         191 :     destroyPQExpBuffer(query);
    6547                 :         191 : }
    6548                 :             : 
    6549                 :             : /*
    6550                 :             :  * getConversions:
    6551                 :             :  *    get information about all conversions in the system catalogs
    6552                 :             :  */
    6553                 :             : void
    6554                 :         191 : getConversions(Archive *fout)
    6555                 :             : {
    6556                 :             :     PGresult   *res;
    6557                 :             :     int         ntups;
    6558                 :             :     int         i;
    6559                 :             :     PQExpBuffer query;
    6560                 :             :     ConvInfo   *convinfo;
    6561                 :             :     int         i_tableoid;
    6562                 :             :     int         i_oid;
    6563                 :             :     int         i_conname;
    6564                 :             :     int         i_connamespace;
    6565                 :             :     int         i_conowner;
    6566                 :             : 
    6567                 :         191 :     query = createPQExpBuffer();
    6568                 :             : 
    6569                 :             :     /*
    6570                 :             :      * find all conversions, including builtin conversions; we filter out
    6571                 :             :      * system-defined conversions at dump-out time.
    6572                 :             :      */
    6573                 :             : 
    6574                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6575                 :             :                          "connamespace, "
    6576                 :             :                          "conowner "
    6577                 :             :                          "FROM pg_conversion");
    6578                 :             : 
    6579                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6580                 :             : 
    6581                 :         191 :     ntups = PQntuples(res);
    6582                 :             : 
    6583                 :         191 :     convinfo = pg_malloc_array(ConvInfo, ntups);
    6584                 :             : 
    6585                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    6586                 :         191 :     i_oid = PQfnumber(res, "oid");
    6587                 :         191 :     i_conname = PQfnumber(res, "conname");
    6588                 :         191 :     i_connamespace = PQfnumber(res, "connamespace");
    6589                 :         191 :     i_conowner = PQfnumber(res, "conowner");
    6590                 :             : 
    6591         [ +  + ]:       18957 :     for (i = 0; i < ntups; i++)
    6592                 :             :     {
    6593                 :       18766 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6594                 :       18766 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6595                 :       18766 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6596                 :       18766 :         AssignDumpId(&convinfo[i].dobj);
    6597                 :       18766 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6598                 :       37532 :         convinfo[i].dobj.namespace =
    6599                 :       18766 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6600                 :       18766 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6601                 :             : 
    6602                 :             :         /* Decide whether we want to dump it */
    6603                 :       18766 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6604                 :             :     }
    6605                 :             : 
    6606                 :         191 :     PQclear(res);
    6607                 :             : 
    6608                 :         191 :     destroyPQExpBuffer(query);
    6609                 :         191 : }
    6610                 :             : 
    6611                 :             : /*
    6612                 :             :  * getAccessMethods:
    6613                 :             :  *    get information about all user-defined access methods
    6614                 :             :  */
    6615                 :             : void
    6616                 :         191 : getAccessMethods(Archive *fout)
    6617                 :             : {
    6618                 :             :     PGresult   *res;
    6619                 :             :     int         ntups;
    6620                 :             :     int         i;
    6621                 :             :     PQExpBuffer query;
    6622                 :             :     AccessMethodInfo *aminfo;
    6623                 :             :     int         i_tableoid;
    6624                 :             :     int         i_oid;
    6625                 :             :     int         i_amname;
    6626                 :             :     int         i_amhandler;
    6627                 :             :     int         i_amtype;
    6628                 :             : 
    6629                 :         191 :     query = createPQExpBuffer();
    6630                 :             : 
    6631                 :             :     /*
    6632                 :             :      * Select all access methods from pg_am table.
    6633                 :             :      */
    6634                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
    6635                 :         191 :     appendPQExpBufferStr(query,
    6636                 :             :                          "amtype, "
    6637                 :             :                          "amhandler::pg_catalog.regproc AS amhandler ");
    6638                 :         191 :     appendPQExpBufferStr(query, "FROM pg_am");
    6639                 :             : 
    6640                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6641                 :             : 
    6642                 :         191 :     ntups = PQntuples(res);
    6643                 :             : 
    6644                 :         191 :     aminfo = pg_malloc_array(AccessMethodInfo, ntups);
    6645                 :             : 
    6646                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    6647                 :         191 :     i_oid = PQfnumber(res, "oid");
    6648                 :         191 :     i_amname = PQfnumber(res, "amname");
    6649                 :         191 :     i_amhandler = PQfnumber(res, "amhandler");
    6650                 :         191 :     i_amtype = PQfnumber(res, "amtype");
    6651                 :             : 
    6652         [ +  + ]:        1656 :     for (i = 0; i < ntups; i++)
    6653                 :             :     {
    6654                 :        1465 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6655                 :        1465 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6656                 :        1465 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6657                 :        1465 :         AssignDumpId(&aminfo[i].dobj);
    6658                 :        1465 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6659                 :        1465 :         aminfo[i].dobj.namespace = NULL;
    6660                 :        1465 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6661                 :        1465 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6662                 :             : 
    6663                 :             :         /* Decide whether we want to dump it */
    6664                 :        1465 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6665                 :             :     }
    6666                 :             : 
    6667                 :         191 :     PQclear(res);
    6668                 :             : 
    6669                 :         191 :     destroyPQExpBuffer(query);
    6670                 :         191 : }
    6671                 :             : 
    6672                 :             : 
    6673                 :             : /*
    6674                 :             :  * getOpclasses:
    6675                 :             :  *    get information about all opclasses in the system catalogs
    6676                 :             :  */
    6677                 :             : void
    6678                 :         191 : getOpclasses(Archive *fout)
    6679                 :             : {
    6680                 :             :     PGresult   *res;
    6681                 :             :     int         ntups;
    6682                 :             :     int         i;
    6683                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    6684                 :             :     OpclassInfo *opcinfo;
    6685                 :             :     int         i_tableoid;
    6686                 :             :     int         i_oid;
    6687                 :             :     int         i_opcmethod;
    6688                 :             :     int         i_opcname;
    6689                 :             :     int         i_opcnamespace;
    6690                 :             :     int         i_opcowner;
    6691                 :             : 
    6692                 :             :     /*
    6693                 :             :      * find all opclasses, including builtin opclasses; we filter out
    6694                 :             :      * system-defined opclasses at dump-out time.
    6695                 :             :      */
    6696                 :             : 
    6697                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
    6698                 :             :                          "opcnamespace, "
    6699                 :             :                          "opcowner "
    6700                 :             :                          "FROM pg_opclass");
    6701                 :             : 
    6702                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6703                 :             : 
    6704                 :         191 :     ntups = PQntuples(res);
    6705                 :             : 
    6706                 :         191 :     opcinfo = pg_malloc_array(OpclassInfo, ntups);
    6707                 :             : 
    6708                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    6709                 :         191 :     i_oid = PQfnumber(res, "oid");
    6710                 :         191 :     i_opcmethod = PQfnumber(res, "opcmethod");
    6711                 :         191 :     i_opcname = PQfnumber(res, "opcname");
    6712                 :         191 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6713                 :         191 :     i_opcowner = PQfnumber(res, "opcowner");
    6714                 :             : 
    6715         [ +  + ]:       34545 :     for (i = 0; i < ntups; i++)
    6716                 :             :     {
    6717                 :       34354 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6718                 :       34354 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6719                 :       34354 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6720                 :       34354 :         AssignDumpId(&opcinfo[i].dobj);
    6721                 :       34354 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6722                 :       68708 :         opcinfo[i].dobj.namespace =
    6723                 :       34354 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6724                 :       34354 :         opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
    6725                 :       34354 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6726                 :             : 
    6727                 :             :         /* Decide whether we want to dump it */
    6728                 :       34354 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6729                 :             :     }
    6730                 :             : 
    6731                 :         191 :     PQclear(res);
    6732                 :             : 
    6733                 :         191 :     destroyPQExpBuffer(query);
    6734                 :         191 : }
    6735                 :             : 
    6736                 :             : /*
    6737                 :             :  * getOpfamilies:
    6738                 :             :  *    get information about all opfamilies in the system catalogs
    6739                 :             :  */
    6740                 :             : void
    6741                 :         191 : getOpfamilies(Archive *fout)
    6742                 :             : {
    6743                 :             :     PGresult   *res;
    6744                 :             :     int         ntups;
    6745                 :             :     int         i;
    6746                 :             :     PQExpBuffer query;
    6747                 :             :     OpfamilyInfo *opfinfo;
    6748                 :             :     int         i_tableoid;
    6749                 :             :     int         i_oid;
    6750                 :             :     int         i_opfmethod;
    6751                 :             :     int         i_opfname;
    6752                 :             :     int         i_opfnamespace;
    6753                 :             :     int         i_opfowner;
    6754                 :             : 
    6755                 :         191 :     query = createPQExpBuffer();
    6756                 :             : 
    6757                 :             :     /*
    6758                 :             :      * find all opfamilies, including builtin opfamilies; we filter out
    6759                 :             :      * system-defined opfamilies at dump-out time.
    6760                 :             :      */
    6761                 :             : 
    6762                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
    6763                 :             :                          "opfnamespace, "
    6764                 :             :                          "opfowner "
    6765                 :             :                          "FROM pg_opfamily");
    6766                 :             : 
    6767                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6768                 :             : 
    6769                 :         191 :     ntups = PQntuples(res);
    6770                 :             : 
    6771                 :         191 :     opfinfo = pg_malloc_array(OpfamilyInfo, ntups);
    6772                 :             : 
    6773                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    6774                 :         191 :     i_oid = PQfnumber(res, "oid");
    6775                 :         191 :     i_opfname = PQfnumber(res, "opfname");
    6776                 :         191 :     i_opfmethod = PQfnumber(res, "opfmethod");
    6777                 :         191 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6778                 :         191 :     i_opfowner = PQfnumber(res, "opfowner");
    6779                 :             : 
    6780         [ +  + ]:       28604 :     for (i = 0; i < ntups; i++)
    6781                 :             :     {
    6782                 :       28413 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6783                 :       28413 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6784                 :       28413 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6785                 :       28413 :         AssignDumpId(&opfinfo[i].dobj);
    6786                 :       28413 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6787                 :       56826 :         opfinfo[i].dobj.namespace =
    6788                 :       28413 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6789                 :       28413 :         opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
    6790                 :       28413 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6791                 :             : 
    6792                 :             :         /* Decide whether we want to dump it */
    6793                 :       28413 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6794                 :             :     }
    6795                 :             : 
    6796                 :         191 :     PQclear(res);
    6797                 :             : 
    6798                 :         191 :     destroyPQExpBuffer(query);
    6799                 :         191 : }
    6800                 :             : 
    6801                 :             : /*
    6802                 :             :  * getAggregates:
    6803                 :             :  *    get information about all user-defined aggregates in the system catalogs
    6804                 :             :  */
    6805                 :             : void
    6806                 :         191 : getAggregates(Archive *fout)
    6807                 :             : {
    6808                 :         191 :     DumpOptions *dopt = fout->dopt;
    6809                 :             :     PGresult   *res;
    6810                 :             :     int         ntups;
    6811                 :             :     int         i;
    6812                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    6813                 :             :     AggInfo    *agginfo;
    6814                 :             :     int         i_tableoid;
    6815                 :             :     int         i_oid;
    6816                 :             :     int         i_aggname;
    6817                 :             :     int         i_aggnamespace;
    6818                 :             :     int         i_pronargs;
    6819                 :             :     int         i_proargtypes;
    6820                 :             :     int         i_proowner;
    6821                 :             :     int         i_aggacl;
    6822                 :             :     int         i_acldefault;
    6823                 :             :     const char *agg_check;
    6824                 :             : 
    6825                 :             :     /*
    6826                 :             :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6827                 :             :      * rationale behind the filtering logic.
    6828                 :             :      */
    6829                 :         382 :     agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6830         [ +  - ]:         191 :                  : "p.proisagg");
    6831                 :             : 
    6832                 :         191 :     appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6833                 :             :                       "p.proname AS aggname, "
    6834                 :             :                       "p.pronamespace AS aggnamespace, "
    6835                 :             :                       "p.pronargs, p.proargtypes, "
    6836                 :             :                       "p.proowner, "
    6837                 :             :                       "p.proacl AS aggacl, "
    6838                 :             :                       "acldefault('f', p.proowner) AS acldefault "
    6839                 :             :                       "FROM pg_proc p "
    6840                 :             :                       "LEFT JOIN pg_init_privs pip ON "
    6841                 :             :                       "(p.oid = pip.objoid "
    6842                 :             :                       "AND pip.classoid = 'pg_proc'::regclass "
    6843                 :             :                       "AND pip.objsubid = 0) "
    6844                 :             :                       "WHERE %s AND ("
    6845                 :             :                       "p.pronamespace != "
    6846                 :             :                       "(SELECT oid FROM pg_namespace "
    6847                 :             :                       "WHERE nspname = 'pg_catalog') OR "
    6848                 :             :                       "p.proacl IS DISTINCT FROM pip.initprivs",
    6849                 :             :                       agg_check);
    6850         [ +  + ]:         191 :     if (dopt->binary_upgrade)
    6851                 :          40 :         appendPQExpBufferStr(query,
    6852                 :             :                              " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6853                 :             :                              "classid = 'pg_proc'::regclass AND "
    6854                 :             :                              "objid = p.oid AND "
    6855                 :             :                              "refclassid = 'pg_extension'::regclass AND "
    6856                 :             :                              "deptype = 'e')");
    6857                 :         191 :     appendPQExpBufferChar(query, ')');
    6858                 :             : 
    6859                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6860                 :             : 
    6861                 :         191 :     ntups = PQntuples(res);
    6862                 :             : 
    6863                 :         191 :     agginfo = pg_malloc_array(AggInfo, ntups);
    6864                 :             : 
    6865                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    6866                 :         191 :     i_oid = PQfnumber(res, "oid");
    6867                 :         191 :     i_aggname = PQfnumber(res, "aggname");
    6868                 :         191 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6869                 :         191 :     i_pronargs = PQfnumber(res, "pronargs");
    6870                 :         191 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6871                 :         191 :     i_proowner = PQfnumber(res, "proowner");
    6872                 :         191 :     i_aggacl = PQfnumber(res, "aggacl");
    6873                 :         191 :     i_acldefault = PQfnumber(res, "acldefault");
    6874                 :             : 
    6875         [ +  + ]:         593 :     for (i = 0; i < ntups; i++)
    6876                 :             :     {
    6877                 :         402 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6878                 :         402 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6879                 :         402 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6880                 :         402 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6881                 :         402 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6882                 :         804 :         agginfo[i].aggfn.dobj.namespace =
    6883                 :         402 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6884                 :         402 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6885                 :         402 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6886                 :         402 :         agginfo[i].aggfn.dacl.privtype = 0;
    6887                 :         402 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6888                 :         402 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6889                 :         402 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6890                 :         402 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6891                 :         402 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6892         [ +  + ]:         402 :         if (agginfo[i].aggfn.nargs == 0)
    6893                 :          56 :             agginfo[i].aggfn.argtypes = NULL;
    6894                 :             :         else
    6895                 :             :         {
    6896                 :         346 :             agginfo[i].aggfn.argtypes = pg_malloc_array(Oid, agginfo[i].aggfn.nargs);
    6897                 :         346 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6898                 :         346 :                           agginfo[i].aggfn.argtypes,
    6899                 :         346 :                           agginfo[i].aggfn.nargs);
    6900                 :             :         }
    6901                 :         402 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6902                 :             : 
    6903                 :             :         /* Decide whether we want to dump it */
    6904                 :         402 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6905                 :             : 
    6906                 :             :         /* Mark whether aggregate has an ACL */
    6907         [ +  + ]:         402 :         if (!PQgetisnull(res, i, i_aggacl))
    6908                 :          25 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6909                 :             :     }
    6910                 :             : 
    6911                 :         191 :     PQclear(res);
    6912                 :             : 
    6913                 :         191 :     destroyPQExpBuffer(query);
    6914                 :         191 : }
    6915                 :             : 
    6916                 :             : /*
    6917                 :             :  * getFuncs:
    6918                 :             :  *    get information about all user-defined functions in the system catalogs
    6919                 :             :  */
    6920                 :             : void
    6921                 :         191 : getFuncs(Archive *fout)
    6922                 :             : {
    6923                 :         191 :     DumpOptions *dopt = fout->dopt;
    6924                 :             :     PGresult   *res;
    6925                 :             :     int         ntups;
    6926                 :             :     int         i;
    6927                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    6928                 :             :     FuncInfo   *finfo;
    6929                 :             :     int         i_tableoid;
    6930                 :             :     int         i_oid;
    6931                 :             :     int         i_proname;
    6932                 :             :     int         i_pronamespace;
    6933                 :             :     int         i_proowner;
    6934                 :             :     int         i_prolang;
    6935                 :             :     int         i_pronargs;
    6936                 :             :     int         i_proargtypes;
    6937                 :             :     int         i_prorettype;
    6938                 :             :     int         i_proacl;
    6939                 :             :     int         i_acldefault;
    6940                 :             :     const char *not_agg_check;
    6941                 :             : 
    6942                 :             :     /*
    6943                 :             :      * Find all interesting functions.  This is a bit complicated:
    6944                 :             :      *
    6945                 :             :      * 1. Always exclude aggregates; those are handled elsewhere.
    6946                 :             :      *
    6947                 :             :      * 2. Always exclude functions that are internally dependent on something
    6948                 :             :      * else, since presumably those will be created as a result of creating
    6949                 :             :      * the something else.  This currently acts only to suppress constructor
    6950                 :             :      * functions for range types.  Note this is OK only because the
    6951                 :             :      * constructors don't have any dependencies the range type doesn't have;
    6952                 :             :      * otherwise we might not get creation ordering correct.
    6953                 :             :      *
    6954                 :             :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    6955                 :             :      * they're members of extensions and we are in binary-upgrade mode then
    6956                 :             :      * include them, since we want to dump extension members individually in
    6957                 :             :      * that mode.  Also, if they are used by casts or transforms then we need
    6958                 :             :      * to gather the information about them, though they won't be dumped if
    6959                 :             :      * they are built-in.  Also, include functions in pg_catalog if they have
    6960                 :             :      * an ACL different from what's shown in pg_init_privs (so we have to join
    6961                 :             :      * to pg_init_privs; annoying).
    6962                 :             :      */
    6963                 :         382 :     not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    6964         [ +  - ]:         191 :                      : "NOT p.proisagg");
    6965                 :             : 
    6966                 :         191 :     appendPQExpBuffer(query,
    6967                 :             :                       "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    6968                 :             :                       "p.pronargs, p.proargtypes, p.prorettype, "
    6969                 :             :                       "p.proacl, "
    6970                 :             :                       "acldefault('f', p.proowner) AS acldefault, "
    6971                 :             :                       "p.pronamespace, "
    6972                 :             :                       "p.proowner "
    6973                 :             :                       "FROM pg_proc p "
    6974                 :             :                       "LEFT JOIN pg_init_privs pip ON "
    6975                 :             :                       "(p.oid = pip.objoid "
    6976                 :             :                       "AND pip.classoid = 'pg_proc'::regclass "
    6977                 :             :                       "AND pip.objsubid = 0) "
    6978                 :             :                       "WHERE %s"
    6979                 :             :                       "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6980                 :             :                       "WHERE classid = 'pg_proc'::regclass AND "
    6981                 :             :                       "objid = p.oid AND deptype = 'i')"
    6982                 :             :                       "\n  AND ("
    6983                 :             :                       "\n  pronamespace != "
    6984                 :             :                       "(SELECT oid FROM pg_namespace "
    6985                 :             :                       "WHERE nspname = 'pg_catalog')"
    6986                 :             :                       "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6987                 :             :                       "\n  WHERE pg_cast.oid > %u "
    6988                 :             :                       "\n  AND p.oid = pg_cast.castfunc)"
    6989                 :             :                       "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6990                 :             :                       "\n  WHERE pg_transform.oid > %u AND "
    6991                 :             :                       "\n  (p.oid = pg_transform.trffromsql"
    6992                 :             :                       "\n  OR p.oid = pg_transform.trftosql))",
    6993                 :             :                       not_agg_check,
    6994                 :             :                       g_last_builtin_oid,
    6995                 :             :                       g_last_builtin_oid);
    6996         [ +  + ]:         191 :     if (dopt->binary_upgrade)
    6997                 :          40 :         appendPQExpBufferStr(query,
    6998                 :             :                              "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6999                 :             :                              "classid = 'pg_proc'::regclass AND "
    7000                 :             :                              "objid = p.oid AND "
    7001                 :             :                              "refclassid = 'pg_extension'::regclass AND "
    7002                 :             :                              "deptype = 'e')");
    7003                 :         191 :     appendPQExpBufferStr(query,
    7004                 :             :                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    7005                 :         191 :     appendPQExpBufferChar(query, ')');
    7006                 :             : 
    7007                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7008                 :             : 
    7009                 :         191 :     ntups = PQntuples(res);
    7010                 :             : 
    7011                 :         191 :     finfo = pg_malloc0_array(FuncInfo, ntups);
    7012                 :             : 
    7013                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    7014                 :         191 :     i_oid = PQfnumber(res, "oid");
    7015                 :         191 :     i_proname = PQfnumber(res, "proname");
    7016                 :         191 :     i_pronamespace = PQfnumber(res, "pronamespace");
    7017                 :         191 :     i_proowner = PQfnumber(res, "proowner");
    7018                 :         191 :     i_prolang = PQfnumber(res, "prolang");
    7019                 :         191 :     i_pronargs = PQfnumber(res, "pronargs");
    7020                 :         191 :     i_proargtypes = PQfnumber(res, "proargtypes");
    7021                 :         191 :     i_prorettype = PQfnumber(res, "prorettype");
    7022                 :         191 :     i_proacl = PQfnumber(res, "proacl");
    7023                 :         191 :     i_acldefault = PQfnumber(res, "acldefault");
    7024                 :             : 
    7025         [ +  + ]:        5144 :     for (i = 0; i < ntups; i++)
    7026                 :             :     {
    7027                 :        4953 :         finfo[i].dobj.objType = DO_FUNC;
    7028                 :        4953 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7029                 :        4953 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7030                 :        4953 :         AssignDumpId(&finfo[i].dobj);
    7031                 :        4953 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    7032                 :        9906 :         finfo[i].dobj.namespace =
    7033                 :        4953 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    7034                 :        4953 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    7035                 :        4953 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7036                 :        4953 :         finfo[i].dacl.privtype = 0;
    7037                 :        4953 :         finfo[i].dacl.initprivs = NULL;
    7038                 :        4953 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    7039                 :        4953 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    7040                 :        4953 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    7041                 :        4953 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    7042         [ +  + ]:        4953 :         if (finfo[i].nargs == 0)
    7043                 :        1121 :             finfo[i].argtypes = NULL;
    7044                 :             :         else
    7045                 :             :         {
    7046                 :        3832 :             finfo[i].argtypes = pg_malloc_array(Oid, finfo[i].nargs);
    7047                 :        3832 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    7048                 :        3832 :                           finfo[i].argtypes, finfo[i].nargs);
    7049                 :             :         }
    7050                 :        4953 :         finfo[i].postponed_def = false; /* might get set during sort */
    7051                 :             : 
    7052                 :             :         /* Decide whether we want to dump it */
    7053                 :        4953 :         selectDumpableObject(&(finfo[i].dobj), fout);
    7054                 :             : 
    7055                 :             :         /* Mark whether function has an ACL */
    7056         [ +  + ]:        4953 :         if (!PQgetisnull(res, i, i_proacl))
    7057                 :         146 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7058                 :             :     }
    7059                 :             : 
    7060                 :         191 :     PQclear(res);
    7061                 :             : 
    7062                 :         191 :     destroyPQExpBuffer(query);
    7063                 :         191 : }
    7064                 :             : 
    7065                 :             : /*
    7066                 :             :  * getRelationStatistics
    7067                 :             :  *    register the statistics object as a dependent of the relation.
    7068                 :             :  *
    7069                 :             :  * reltuples is passed as a string to avoid complexities in converting from/to
    7070                 :             :  * floating point.
    7071                 :             :  */
    7072                 :             : static RelStatsInfo *
    7073                 :       10566 : getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
    7074                 :             :                       char *reltuples, int32 relallvisible,
    7075                 :             :                       int32 relallfrozen, char relkind,
    7076                 :             :                       char **indAttNames, int nindAttNames)
    7077                 :             : {
    7078         [ +  + ]:       10566 :     if (!fout->dopt->dumpStatistics)
    7079                 :        6580 :         return NULL;
    7080                 :             : 
    7081   [ +  +  +  + ]:        3986 :     if ((relkind == RELKIND_RELATION) ||
    7082         [ +  + ]:        1659 :         (relkind == RELKIND_PARTITIONED_TABLE) ||
    7083         [ +  + ]:        1001 :         (relkind == RELKIND_INDEX) ||
    7084         [ +  + ]:         667 :         (relkind == RELKIND_PARTITIONED_INDEX) ||
    7085         [ +  + ]:         337 :         (relkind == RELKIND_MATVIEW ||
    7086                 :             :          relkind == RELKIND_FOREIGN_TABLE))
    7087                 :             :     {
    7088                 :        3684 :         RelStatsInfo *info = pg_malloc0_object(RelStatsInfo);
    7089                 :        3684 :         DumpableObject *dobj = &info->dobj;
    7090                 :             : 
    7091                 :        3684 :         dobj->objType = DO_REL_STATS;
    7092                 :        3684 :         dobj->catId.tableoid = 0;
    7093                 :        3684 :         dobj->catId.oid = 0;
    7094                 :        3684 :         AssignDumpId(dobj);
    7095                 :        3684 :         dobj->dependencies = pg_malloc_object(DumpId);
    7096                 :        3684 :         dobj->dependencies[0] = rel->dumpId;
    7097                 :        3684 :         dobj->nDeps = 1;
    7098                 :        3684 :         dobj->allocDeps = 1;
    7099                 :        3684 :         dobj->components |= DUMP_COMPONENT_STATISTICS;
    7100                 :        3684 :         dobj->name = pg_strdup(rel->name);
    7101                 :        3684 :         dobj->namespace = rel->namespace;
    7102                 :        3684 :         info->relid = rel->catId.oid;
    7103                 :        3684 :         info->relpages = relpages;
    7104                 :        3684 :         info->reltuples = pstrdup(reltuples);
    7105                 :        3684 :         info->relallvisible = relallvisible;
    7106                 :        3684 :         info->relallfrozen = relallfrozen;
    7107                 :        3684 :         info->relkind = relkind;
    7108                 :        3684 :         info->indAttNames = indAttNames;
    7109                 :        3684 :         info->nindAttNames = nindAttNames;
    7110                 :             : 
    7111                 :             :         /*
    7112                 :             :          * Ordinarily, stats go in SECTION_DATA for tables and
    7113                 :             :          * SECTION_POST_DATA for indexes.
    7114                 :             :          *
    7115                 :             :          * However, the section may be updated later for materialized view
    7116                 :             :          * stats. REFRESH MATERIALIZED VIEW replaces the storage and resets
    7117                 :             :          * the stats, so the stats must be restored after the data. Also, the
    7118                 :             :          * materialized view definition may be postponed to SECTION_POST_DATA
    7119                 :             :          * (see repairMatViewBoundaryMultiLoop()).
    7120                 :             :          */
    7121      [ +  +  - ]:        3684 :         switch (info->relkind)
    7122                 :             :         {
    7123                 :        2692 :             case RELKIND_RELATION:
    7124                 :             :             case RELKIND_PARTITIONED_TABLE:
    7125                 :             :             case RELKIND_MATVIEW:
    7126                 :             :             case RELKIND_FOREIGN_TABLE:
    7127                 :        2692 :                 info->section = SECTION_DATA;
    7128                 :        2692 :                 break;
    7129                 :         992 :             case RELKIND_INDEX:
    7130                 :             :             case RELKIND_PARTITIONED_INDEX:
    7131                 :         992 :                 info->section = SECTION_POST_DATA;
    7132                 :         992 :                 break;
    7133                 :           0 :             default:
    7134                 :           0 :                 pg_fatal("cannot dump statistics for relation kind \"%c\"",
    7135                 :             :                          info->relkind);
    7136                 :             :         }
    7137                 :             : 
    7138                 :        3684 :         return info;
    7139                 :             :     }
    7140                 :         302 :     return NULL;
    7141                 :             : }
    7142                 :             : 
    7143                 :             : /*
    7144                 :             :  * getTables
    7145                 :             :  *    read all the tables (no indexes) in the system catalogs,
    7146                 :             :  *    and return them as an array of TableInfo structures
    7147                 :             :  *
    7148                 :             :  * *numTables is set to the number of tables read in
    7149                 :             :  */
    7150                 :             : TableInfo *
    7151                 :         192 : getTables(Archive *fout, int *numTables)
    7152                 :             : {
    7153                 :         192 :     DumpOptions *dopt = fout->dopt;
    7154                 :             :     PGresult   *res;
    7155                 :             :     int         ntups;
    7156                 :             :     int         i;
    7157                 :         192 :     PQExpBuffer query = createPQExpBuffer();
    7158                 :             :     TableInfo  *tblinfo;
    7159                 :             :     int         i_reltableoid;
    7160                 :             :     int         i_reloid;
    7161                 :             :     int         i_relname;
    7162                 :             :     int         i_relnamespace;
    7163                 :             :     int         i_relkind;
    7164                 :             :     int         i_reltype;
    7165                 :             :     int         i_relowner;
    7166                 :             :     int         i_relchecks;
    7167                 :             :     int         i_relhasindex;
    7168                 :             :     int         i_relhasrules;
    7169                 :             :     int         i_relpages;
    7170                 :             :     int         i_reltuples;
    7171                 :             :     int         i_relallvisible;
    7172                 :             :     int         i_relallfrozen;
    7173                 :             :     int         i_toastpages;
    7174                 :             :     int         i_owning_tab;
    7175                 :             :     int         i_owning_col;
    7176                 :             :     int         i_reltablespace;
    7177                 :             :     int         i_relhasoids;
    7178                 :             :     int         i_relhastriggers;
    7179                 :             :     int         i_relpersistence;
    7180                 :             :     int         i_relispopulated;
    7181                 :             :     int         i_relreplident;
    7182                 :             :     int         i_relrowsec;
    7183                 :             :     int         i_relforcerowsec;
    7184                 :             :     int         i_relfrozenxid;
    7185                 :             :     int         i_toastfrozenxid;
    7186                 :             :     int         i_toastoid;
    7187                 :             :     int         i_relminmxid;
    7188                 :             :     int         i_toastminmxid;
    7189                 :             :     int         i_reloptions;
    7190                 :             :     int         i_checkoption;
    7191                 :             :     int         i_toastreloptions;
    7192                 :             :     int         i_reloftype;
    7193                 :             :     int         i_foreignserver;
    7194                 :             :     int         i_amname;
    7195                 :             :     int         i_is_identity_sequence;
    7196                 :             :     int         i_relacl;
    7197                 :             :     int         i_acldefault;
    7198                 :             :     int         i_ispartition;
    7199                 :             : 
    7200                 :             :     /*
    7201                 :             :      * Find all the tables and table-like objects.
    7202                 :             :      *
    7203                 :             :      * We must fetch all tables in this phase because otherwise we cannot
    7204                 :             :      * correctly identify inherited columns, owned sequences, etc.
    7205                 :             :      *
    7206                 :             :      * We include system catalogs, so that we can work if a user table is
    7207                 :             :      * defined to inherit from a system catalog (pretty weird, but...)
    7208                 :             :      *
    7209                 :             :      * Note: in this phase we should collect only a minimal amount of
    7210                 :             :      * information about each table, basically just enough to decide if it is
    7211                 :             :      * interesting.  In particular, since we do not yet have lock on any user
    7212                 :             :      * table, we MUST NOT invoke any server-side data collection functions
    7213                 :             :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    7214                 :             :      * wrong answers if any concurrent DDL is happening.
    7215                 :             :      */
    7216                 :             : 
    7217                 :         192 :     appendPQExpBufferStr(query,
    7218                 :             :                          "SELECT c.tableoid, c.oid, c.relname, "
    7219                 :             :                          "c.relnamespace, c.relkind, c.reltype, "
    7220                 :             :                          "c.relowner, "
    7221                 :             :                          "c.relchecks, "
    7222                 :             :                          "c.relhasindex, c.relhasrules, c.relpages, "
    7223                 :             :                          "c.reltuples, c.relallvisible, ");
    7224                 :             : 
    7225         [ +  - ]:         192 :     if (fout->remoteVersion >= 180000)
    7226                 :         192 :         appendPQExpBufferStr(query, "c.relallfrozen, ");
    7227                 :             :     else
    7228                 :           0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7229                 :             : 
    7230                 :         192 :     appendPQExpBufferStr(query,
    7231                 :             :                          "c.relhastriggers, c.relpersistence, "
    7232                 :             :                          "c.reloftype, "
    7233                 :             :                          "c.relacl, "
    7234                 :             :                          "acldefault(CASE"
    7235                 :             :                          " WHEN c.relkind = " CppAsString2(RELKIND_PROPGRAPH));
    7236                 :             :     /* 19beta1 didn't support acldefault('g'), so we'll fix that below */
    7237                 :         192 :     appendPQExpBufferStr(query,
    7238         [ +  - ]:         192 :                          fout->remoteVersion >= 200000 ?
    7239                 :             :                          " THEN 'g'::\"char\"" :
    7240                 :             :                          " THEN NULL");
    7241                 :         192 :     appendPQExpBufferStr(query,
    7242                 :             :                          " WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    7243                 :             :                          " THEN 's'::\"char\""
    7244                 :             :                          " ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    7245                 :             :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    7246                 :             :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    7247                 :             :                          "ELSE 0 END AS foreignserver, "
    7248                 :             :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    7249                 :             :                          "tc.oid AS toid, "
    7250                 :             :                          "tc.relpages AS toastpages, "
    7251                 :             :                          "tc.reloptions AS toast_reloptions, "
    7252                 :             :                          "d.refobjid AS owning_tab, "
    7253                 :             :                          "d.refobjsubid AS owning_col, "
    7254                 :             :                          "tsp.spcname AS reltablespace, ");
    7255                 :             : 
    7256         [ +  - ]:         192 :     if (fout->remoteVersion >= 120000)
    7257                 :         192 :         appendPQExpBufferStr(query,
    7258                 :             :                              "false AS relhasoids, ");
    7259                 :             :     else
    7260                 :           0 :         appendPQExpBufferStr(query,
    7261                 :             :                              "c.relhasoids, ");
    7262                 :             : 
    7263                 :         192 :     appendPQExpBufferStr(query,
    7264                 :             :                          "c.relispopulated, ");
    7265                 :             : 
    7266                 :         192 :     appendPQExpBufferStr(query,
    7267                 :             :                          "c.relreplident, ");
    7268                 :             : 
    7269                 :         192 :     appendPQExpBufferStr(query,
    7270                 :             :                          "c.relrowsecurity, c.relforcerowsecurity, ");
    7271                 :             : 
    7272                 :         192 :     appendPQExpBufferStr(query,
    7273                 :             :                          "c.relminmxid, tc.relminmxid AS tminmxid, ");
    7274                 :             : 
    7275                 :         192 :     appendPQExpBufferStr(query,
    7276                 :             :                          "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    7277                 :             :                          "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    7278                 :             :                          "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    7279                 :             : 
    7280                 :         192 :     appendPQExpBufferStr(query,
    7281                 :             :                          "am.amname, ");
    7282                 :             : 
    7283                 :         192 :     appendPQExpBufferStr(query,
    7284                 :             :                          "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    7285                 :             : 
    7286                 :         192 :     appendPQExpBufferStr(query,
    7287                 :             :                          "c.relispartition AS ispartition ");
    7288                 :             : 
    7289                 :             :     /*
    7290                 :             :      * Left join to pg_depend to pick up dependency info linking sequences to
    7291                 :             :      * their owning column, if any (note this dependency is AUTO except for
    7292                 :             :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    7293                 :             :      * collect the spcname.
    7294                 :             :      */
    7295                 :         192 :     appendPQExpBufferStr(query,
    7296                 :             :                          "\nFROM pg_class c\n"
    7297                 :             :                          "LEFT JOIN pg_depend d ON "
    7298                 :             :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    7299                 :             :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    7300                 :             :                          "d.objsubid = 0 AND "
    7301                 :             :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    7302                 :             :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    7303                 :             : 
    7304                 :             :     /*
    7305                 :             :      * Left join to pg_am to pick up the amname.
    7306                 :             :      */
    7307                 :         192 :     appendPQExpBufferStr(query,
    7308                 :             :                          "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    7309                 :             : 
    7310                 :             :     /*
    7311                 :             :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    7312                 :             :      * that versions 10 and 11 have them, but later versions do not, so
    7313                 :             :      * emitting them causes the upgrade to fail.
    7314                 :             :      */
    7315                 :         192 :     appendPQExpBufferStr(query,
    7316                 :             :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    7317                 :             :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    7318                 :             :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    7319                 :             : 
    7320                 :             :     /*
    7321                 :             :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    7322                 :             :      * relkinds are possible in older servers, but it's not worth the trouble
    7323                 :             :      * to emit a version-dependent list.
    7324                 :             :      *
    7325                 :             :      * Composite-type table entries won't be dumped as such, but we have to
    7326                 :             :      * make a DumpableObject for them so that we can track dependencies of the
    7327                 :             :      * composite type (pg_depend entries for columns of the composite type
    7328                 :             :      * link to the pg_class entry not the pg_type entry).
    7329                 :             :      */
    7330                 :         192 :     appendPQExpBufferStr(query,
    7331                 :             :                          "WHERE c.relkind IN ("
    7332                 :             :                          CppAsString2(RELKIND_RELATION) ", "
    7333                 :             :                          CppAsString2(RELKIND_SEQUENCE) ", "
    7334                 :             :                          CppAsString2(RELKIND_VIEW) ", "
    7335                 :             :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    7336                 :             :                          CppAsString2(RELKIND_MATVIEW) ", "
    7337                 :             :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    7338                 :             :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
    7339                 :             :                          CppAsString2(RELKIND_PROPGRAPH) ")\n"
    7340                 :             :                          "ORDER BY c.oid");
    7341                 :             : 
    7342                 :         192 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7343                 :             : 
    7344                 :         192 :     ntups = PQntuples(res);
    7345                 :             : 
    7346                 :         192 :     *numTables = ntups;
    7347                 :             : 
    7348                 :             :     /*
    7349                 :             :      * Extract data from result and lock dumpable tables.  We do the locking
    7350                 :             :      * before anything else, to minimize the window wherein a table could
    7351                 :             :      * disappear under us.
    7352                 :             :      *
    7353                 :             :      * Note that we have to save info about all tables here, even when dumping
    7354                 :             :      * only one, because we don't yet know which tables might be inheritance
    7355                 :             :      * ancestors of the target table.
    7356                 :             :      */
    7357                 :         192 :     tblinfo = pg_malloc0_array(TableInfo, ntups);
    7358                 :             : 
    7359                 :         192 :     i_reltableoid = PQfnumber(res, "tableoid");
    7360                 :         192 :     i_reloid = PQfnumber(res, "oid");
    7361                 :         192 :     i_relname = PQfnumber(res, "relname");
    7362                 :         192 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7363                 :         192 :     i_relkind = PQfnumber(res, "relkind");
    7364                 :         192 :     i_reltype = PQfnumber(res, "reltype");
    7365                 :         192 :     i_relowner = PQfnumber(res, "relowner");
    7366                 :         192 :     i_relchecks = PQfnumber(res, "relchecks");
    7367                 :         192 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7368                 :         192 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7369                 :         192 :     i_relpages = PQfnumber(res, "relpages");
    7370                 :         192 :     i_reltuples = PQfnumber(res, "reltuples");
    7371                 :         192 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7372                 :         192 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7373                 :         192 :     i_toastpages = PQfnumber(res, "toastpages");
    7374                 :         192 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7375                 :         192 :     i_owning_col = PQfnumber(res, "owning_col");
    7376                 :         192 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7377                 :         192 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7378                 :         192 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7379                 :         192 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7380                 :         192 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7381                 :         192 :     i_relreplident = PQfnumber(res, "relreplident");
    7382                 :         192 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7383                 :         192 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7384                 :         192 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7385                 :         192 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7386                 :         192 :     i_toastoid = PQfnumber(res, "toid");
    7387                 :         192 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7388                 :         192 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7389                 :         192 :     i_reloptions = PQfnumber(res, "reloptions");
    7390                 :         192 :     i_checkoption = PQfnumber(res, "checkoption");
    7391                 :         192 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7392                 :         192 :     i_reloftype = PQfnumber(res, "reloftype");
    7393                 :         192 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7394                 :         192 :     i_amname = PQfnumber(res, "amname");
    7395                 :         192 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7396                 :         192 :     i_relacl = PQfnumber(res, "relacl");
    7397                 :         192 :     i_acldefault = PQfnumber(res, "acldefault");
    7398                 :         192 :     i_ispartition = PQfnumber(res, "ispartition");
    7399                 :             : 
    7400         [ +  + ]:         192 :     if (dopt->lockWaitTimeout)
    7401                 :             :     {
    7402                 :             :         /*
    7403                 :             :          * Arrange to fail instead of waiting forever for a table lock.
    7404                 :             :          *
    7405                 :             :          * NB: this coding assumes that the only queries issued within the
    7406                 :             :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    7407                 :             :          * applied to other things too.
    7408                 :             :          */
    7409                 :           2 :         resetPQExpBuffer(query);
    7410                 :           2 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    7411                 :           2 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7412                 :           2 :         ExecuteSqlStatement(fout, query->data);
    7413                 :             :     }
    7414                 :             : 
    7415                 :         192 :     resetPQExpBuffer(query);
    7416                 :             : 
    7417         [ +  + ]:       55480 :     for (i = 0; i < ntups; i++)
    7418                 :             :     {
    7419                 :       55288 :         int32       relallvisible = atoi(PQgetvalue(res, i, i_relallvisible));
    7420                 :       55288 :         int32       relallfrozen = atoi(PQgetvalue(res, i, i_relallfrozen));
    7421                 :             : 
    7422                 :       55288 :         tblinfo[i].dobj.objType = DO_TABLE;
    7423                 :       55288 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7424                 :       55288 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7425                 :       55288 :         AssignDumpId(&tblinfo[i].dobj);
    7426                 :       55288 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7427                 :      110576 :         tblinfo[i].dobj.namespace =
    7428                 :       55288 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7429                 :       55288 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7430                 :             :         /* acldefault computed below */
    7431                 :       55288 :         tblinfo[i].dacl.privtype = 0;
    7432                 :       55288 :         tblinfo[i].dacl.initprivs = NULL;
    7433                 :       55288 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7434                 :       55288 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7435                 :       55288 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7436                 :       55288 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7437                 :       55288 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7438                 :       55288 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7439                 :       55288 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7440         [ +  + ]:       55288 :         if (PQgetisnull(res, i, i_toastpages))
    7441                 :       44892 :             tblinfo[i].toastpages = 0;
    7442                 :             :         else
    7443                 :       10396 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7444         [ +  + ]:       55288 :         if (PQgetisnull(res, i, i_owning_tab))
    7445                 :             :         {
    7446                 :       54864 :             tblinfo[i].owning_tab = InvalidOid;
    7447                 :       54864 :             tblinfo[i].owning_col = 0;
    7448                 :             :         }
    7449                 :             :         else
    7450                 :             :         {
    7451                 :         424 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7452                 :         424 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7453                 :             :         }
    7454                 :       55288 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7455                 :       55288 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7456                 :       55288 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7457                 :       55288 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7458                 :       55288 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7459                 :       55288 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7460                 :       55288 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7461                 :       55288 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7462                 :       55288 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7463                 :       55288 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7464                 :       55288 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7465                 :       55288 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7466                 :       55288 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7467                 :       55288 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7468         [ +  + ]:       55288 :         if (PQgetisnull(res, i, i_checkoption))
    7469                 :       55239 :             tblinfo[i].checkoption = NULL;
    7470                 :             :         else
    7471                 :          49 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7472                 :       55288 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7473                 :       55288 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7474                 :       55288 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7475         [ +  + ]:       55288 :         if (PQgetisnull(res, i, i_amname))
    7476                 :       33568 :             tblinfo[i].amname = NULL;
    7477                 :             :         else
    7478                 :       21720 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7479                 :       55288 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7480                 :       55288 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7481                 :             : 
    7482         [ +  + ]:       55288 :         if (tblinfo[i].relkind == RELKIND_PROPGRAPH &&
    7483         [ -  + ]:         147 :             !(fout->remoteVersion >= 200000))
    7484                 :           0 :         {
    7485                 :           0 :             PQExpBuffer aclarray = createPQExpBuffer();
    7486                 :           0 :             PQExpBuffer aclitem = createPQExpBuffer();
    7487                 :             : 
    7488                 :             :             /* Standard ACL as of v19 is {owner=r/owner} */
    7489                 :           0 :             appendPQExpBufferChar(aclarray, '{');
    7490                 :           0 :             quoteAclUserName(aclitem, tblinfo[i].rolname);
    7491                 :           0 :             appendPQExpBufferStr(aclitem, "=r/");
    7492                 :           0 :             quoteAclUserName(aclitem, tblinfo[i].rolname);
    7493                 :           0 :             appendPGArray(aclarray, aclitem->data);
    7494                 :           0 :             appendPQExpBufferChar(aclarray, '}');
    7495                 :             : 
    7496                 :           0 :             tblinfo[i].dacl.acldefault = pstrdup(aclarray->data);
    7497                 :             : 
    7498                 :           0 :             destroyPQExpBuffer(aclarray);
    7499                 :           0 :             destroyPQExpBuffer(aclitem);
    7500                 :             :         }
    7501                 :             :         else
    7502                 :       55288 :             tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7503                 :             : 
    7504                 :             :         /* other fields were zeroed above */
    7505                 :             : 
    7506                 :             :         /*
    7507                 :             :          * Decide whether we want to dump this table.
    7508                 :             :          */
    7509         [ +  + ]:       55288 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7510                 :         186 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7511                 :             :         else
    7512                 :       55102 :             selectDumpableTable(&tblinfo[i], fout);
    7513                 :             : 
    7514                 :             :         /*
    7515                 :             :          * Now, consider the table "interesting" if we need to dump its
    7516                 :             :          * definition, data or its statistics.  Later on, we'll skip a lot of
    7517                 :             :          * data collection for uninteresting tables.
    7518                 :             :          *
    7519                 :             :          * Note: the "interesting" flag will also be set by flagInhTables for
    7520                 :             :          * parents of interesting tables, so that we collect necessary
    7521                 :             :          * inheritance info even when the parents are not themselves being
    7522                 :             :          * dumped.  This is the main reason why we need an "interesting" flag
    7523                 :             :          * that's separate from the components-to-dump bitmask.
    7524                 :             :          */
    7525                 :       55288 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7526                 :             :                                   (DUMP_COMPONENT_DEFINITION |
    7527                 :             :                                    DUMP_COMPONENT_DATA |
    7528                 :       55288 :                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7529                 :             : 
    7530                 :       55288 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7531                 :       55288 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7532                 :             : 
    7533                 :             :         /* Tables have data */
    7534                 :       55288 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7535                 :             : 
    7536                 :             :         /* Mark whether table has an ACL */
    7537         [ +  + ]:       55288 :         if (!PQgetisnull(res, i, i_relacl))
    7538                 :       44645 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7539                 :       55288 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7540                 :             : 
    7541                 :             :         /* Add statistics */
    7542         [ +  + ]:       55288 :         if (tblinfo[i].interesting)
    7543                 :             :         {
    7544                 :             :             RelStatsInfo *stats;
    7545                 :             : 
    7546                 :       15440 :             stats = getRelationStatistics(fout, &tblinfo[i].dobj,
    7547                 :        7720 :                                           tblinfo[i].relpages,
    7548                 :             :                                           PQgetvalue(res, i, i_reltuples),
    7549                 :             :                                           relallvisible, relallfrozen,
    7550                 :        7720 :                                           tblinfo[i].relkind, NULL, 0);
    7551         [ +  + ]:        7720 :             if (tblinfo[i].relkind == RELKIND_MATVIEW)
    7552                 :         425 :                 tblinfo[i].stats = stats;
    7553                 :             :         }
    7554                 :             : 
    7555                 :             :         /*
    7556                 :             :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7557                 :             :          * in schema before we get around to dumping them.
    7558                 :             :          *
    7559                 :             :          * Note that we don't explicitly lock parents of the target tables; we
    7560                 :             :          * assume our lock on the child is enough to prevent schema
    7561                 :             :          * alterations to parent tables.
    7562                 :             :          *
    7563                 :             :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7564                 :             :          * plain or partitioned tables, but the backend doesn't presently
    7565                 :             :          * allow that.
    7566                 :             :          *
    7567                 :             :          * We only need to lock the table for certain components; see
    7568                 :             :          * pg_dump.h
    7569                 :             :          */
    7570         [ +  + ]:       55288 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7571         [ +  + ]:        7720 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7572         [ +  + ]:        2202 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7573                 :             :         {
    7574                 :             :             /*
    7575                 :             :              * Tables are locked in batches.  When dumping from a remote
    7576                 :             :              * server this can save a significant amount of time by reducing
    7577                 :             :              * the number of round trips.
    7578                 :             :              */
    7579         [ +  + ]:        6153 :             if (query->len == 0)
    7580                 :         127 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7581                 :         127 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7582                 :             :             else
    7583                 :             :             {
    7584                 :        6026 :                 appendPQExpBuffer(query, ", %s",
    7585                 :        6026 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7586                 :             : 
    7587                 :             :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7588         [ -  + ]:        6026 :                 if (query->len >= 100000)
    7589                 :             :                 {
    7590                 :             :                     /* Lock another batch of tables. */
    7591                 :           0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7592                 :           0 :                     ExecuteSqlStatement(fout, query->data);
    7593                 :           0 :                     resetPQExpBuffer(query);
    7594                 :             :                 }
    7595                 :             :             }
    7596                 :             :         }
    7597                 :             :     }
    7598                 :             : 
    7599         [ +  + ]:         192 :     if (query->len != 0)
    7600                 :             :     {
    7601                 :             :         /* Lock the tables in the last batch. */
    7602                 :         127 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7603                 :         127 :         ExecuteSqlStatement(fout, query->data);
    7604                 :             :     }
    7605                 :             : 
    7606         [ +  + ]:         191 :     if (dopt->lockWaitTimeout)
    7607                 :             :     {
    7608                 :           2 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7609                 :             :     }
    7610                 :             : 
    7611                 :         191 :     PQclear(res);
    7612                 :             : 
    7613                 :         191 :     destroyPQExpBuffer(query);
    7614                 :             : 
    7615                 :         191 :     return tblinfo;
    7616                 :             : }
    7617                 :             : 
    7618                 :             : /*
    7619                 :             :  * getOwnedSeqs
    7620                 :             :  *    identify owned sequences and mark them as dumpable if owning table is
    7621                 :             :  *
    7622                 :             :  * We used to do this in getTables(), but it's better to do it after the
    7623                 :             :  * index used by findTableByOid() has been set up.
    7624                 :             :  */
    7625                 :             : void
    7626                 :         191 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7627                 :             : {
    7628                 :             :     int         i;
    7629                 :             : 
    7630                 :             :     /*
    7631                 :             :      * Force sequences that are "owned" by table columns to be dumped whenever
    7632                 :             :      * their owning table is being dumped.
    7633                 :             :      */
    7634         [ +  + ]:       55184 :     for (i = 0; i < numTables; i++)
    7635                 :             :     {
    7636                 :       54993 :         TableInfo  *seqinfo = &tblinfo[i];
    7637                 :             :         TableInfo  *owning_tab;
    7638                 :             : 
    7639         [ +  + ]:       54993 :         if (!OidIsValid(seqinfo->owning_tab))
    7640                 :       54572 :             continue;           /* not an owned sequence */
    7641                 :             : 
    7642                 :         421 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7643         [ -  + ]:         421 :         if (owning_tab == NULL)
    7644                 :           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7645                 :             :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7646                 :             : 
    7647                 :             :         /*
    7648                 :             :          * For an identity sequence, dump exactly the same components for the
    7649                 :             :          * sequence as for the owning table.  This is important because we
    7650                 :             :          * treat the identity sequence as an integral part of the table.  For
    7651                 :             :          * example, there is not any DDL command that allows creation of such
    7652                 :             :          * a sequence independently of the table.
    7653                 :             :          *
    7654                 :             :          * For other owned sequences such as serial sequences, we need to dump
    7655                 :             :          * the components that are being dumped for the table and any
    7656                 :             :          * components that the sequence is explicitly marked with.
    7657                 :             :          *
    7658                 :             :          * We can't simply use the set of components which are being dumped
    7659                 :             :          * for the table as the table might be in an extension (and only the
    7660                 :             :          * non-extension components, eg: ACLs if changed, security labels, and
    7661                 :             :          * policies, are being dumped) while the sequence is not (and
    7662                 :             :          * therefore the definition and other components should also be
    7663                 :             :          * dumped).
    7664                 :             :          *
    7665                 :             :          * If the sequence is part of the extension then it should be properly
    7666                 :             :          * marked by checkExtensionMembership() and this will be a no-op as
    7667                 :             :          * the table will be equivalently marked.
    7668                 :             :          */
    7669         [ +  + ]:         421 :         if (seqinfo->is_identity_sequence)
    7670                 :         202 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7671                 :             :         else
    7672                 :         219 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7673                 :             : 
    7674                 :             :         /* Make sure that necessary data is available if we're dumping it */
    7675         [ +  + ]:         421 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7676                 :             :         {
    7677                 :         325 :             seqinfo->interesting = true;
    7678                 :         325 :             owning_tab->interesting = true;
    7679                 :             :         }
    7680                 :             :     }
    7681                 :         191 : }
    7682                 :             : 
    7683                 :             : /*
    7684                 :             :  * getInherits
    7685                 :             :  *    read all the inheritance information
    7686                 :             :  * from the system catalogs return them in the InhInfo* structure
    7687                 :             :  *
    7688                 :             :  * numInherits is set to the number of pairs read in
    7689                 :             :  */
    7690                 :             : InhInfo *
    7691                 :         191 : getInherits(Archive *fout, int *numInherits)
    7692                 :             : {
    7693                 :             :     PGresult   *res;
    7694                 :             :     int         ntups;
    7695                 :             :     int         i;
    7696                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    7697                 :             :     InhInfo    *inhinfo;
    7698                 :             : 
    7699                 :             :     int         i_inhrelid;
    7700                 :             :     int         i_inhparent;
    7701                 :             : 
    7702                 :             :     /* find all the inheritance information */
    7703                 :         191 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7704                 :             : 
    7705                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7706                 :             : 
    7707                 :         191 :     ntups = PQntuples(res);
    7708                 :             : 
    7709                 :         191 :     *numInherits = ntups;
    7710                 :             : 
    7711                 :         191 :     inhinfo = pg_malloc_array(InhInfo, ntups);
    7712                 :             : 
    7713                 :         191 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7714                 :         191 :     i_inhparent = PQfnumber(res, "inhparent");
    7715                 :             : 
    7716         [ +  + ]:        3819 :     for (i = 0; i < ntups; i++)
    7717                 :             :     {
    7718                 :        3628 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7719                 :        3628 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7720                 :             :     }
    7721                 :             : 
    7722                 :         191 :     PQclear(res);
    7723                 :             : 
    7724                 :         191 :     destroyPQExpBuffer(query);
    7725                 :             : 
    7726                 :         191 :     return inhinfo;
    7727                 :             : }
    7728                 :             : 
    7729                 :             : /*
    7730                 :             :  * getPartitioningInfo
    7731                 :             :  *    get information about partitioning
    7732                 :             :  *
    7733                 :             :  * For the most part, we only collect partitioning info about tables we
    7734                 :             :  * intend to dump.  However, this function has to consider all partitioned
    7735                 :             :  * tables in the database, because we need to know about parents of partitions
    7736                 :             :  * we are going to dump even if the parents themselves won't be dumped.
    7737                 :             :  *
    7738                 :             :  * Specifically, what we need to know is whether each partitioned table
    7739                 :             :  * has an "unsafe" partitioning scheme that requires us to force
    7740                 :             :  * load-via-partition-root mode for its children.  Currently the only case
    7741                 :             :  * for which we force that is hash partitioning on enum columns, since the
    7742                 :             :  * hash codes depend on enum value OIDs which won't be replicated across
    7743                 :             :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7744                 :             :  * might be necessary, but we expect users to cope with them.
    7745                 :             :  */
    7746                 :             : void
    7747                 :         191 : getPartitioningInfo(Archive *fout)
    7748                 :             : {
    7749                 :             :     PQExpBuffer query;
    7750                 :             :     PGresult   *res;
    7751                 :             :     int         ntups;
    7752                 :             : 
    7753                 :             :     /* hash partitioning didn't exist before v11 */
    7754         [ -  + ]:         191 :     if (fout->remoteVersion < 110000)
    7755                 :           0 :         return;
    7756                 :             :     /* needn't bother if not dumping data */
    7757         [ +  + ]:         191 :     if (!fout->dopt->dumpData)
    7758                 :          45 :         return;
    7759                 :             : 
    7760                 :         146 :     query = createPQExpBuffer();
    7761                 :             : 
    7762                 :             :     /*
    7763                 :             :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7764                 :             :      * appears among the partition opclasses.  We needn't check partstrat.
    7765                 :             :      *
    7766                 :             :      * Note that this query may well retrieve info about tables we aren't
    7767                 :             :      * going to dump and hence have no lock on.  That's okay since we need not
    7768                 :             :      * invoke any unsafe server-side functions.
    7769                 :             :      */
    7770                 :         146 :     appendPQExpBufferStr(query,
    7771                 :             :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7772                 :             :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7773                 :             :                          "ON c.opcmethod = a.oid\n"
    7774                 :             :                          "WHERE opcname = 'enum_ops' "
    7775                 :             :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7776                 :             :                          "AND amname = 'hash') = ANY(partclass)");
    7777                 :             : 
    7778                 :         146 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7779                 :             : 
    7780                 :         146 :     ntups = PQntuples(res);
    7781                 :             : 
    7782         [ +  + ]:         191 :     for (int i = 0; i < ntups; i++)
    7783                 :             :     {
    7784                 :          45 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7785                 :             :         TableInfo  *tbinfo;
    7786                 :             : 
    7787                 :          45 :         tbinfo = findTableByOid(tabrelid);
    7788         [ -  + ]:          45 :         if (tbinfo == NULL)
    7789                 :           0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7790                 :             :                      tabrelid);
    7791                 :          45 :         tbinfo->unsafe_partitions = true;
    7792                 :             :     }
    7793                 :             : 
    7794                 :         146 :     PQclear(res);
    7795                 :             : 
    7796                 :         146 :     destroyPQExpBuffer(query);
    7797                 :             : }
    7798                 :             : 
    7799                 :             : /*
    7800                 :             :  * getIndexes
    7801                 :             :  *    get information about every index on a dumpable table
    7802                 :             :  *
    7803                 :             :  * Note: index data is not returned directly to the caller, but it
    7804                 :             :  * does get entered into the DumpableObject tables.
    7805                 :             :  */
    7806                 :             : void
    7807                 :         191 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7808                 :             : {
    7809                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    7810                 :         191 :     PQExpBuffer tbloids = createPQExpBuffer();
    7811                 :             :     PGresult   *res;
    7812                 :             :     int         ntups;
    7813                 :             :     int         curtblindx;
    7814                 :             :     IndxInfo   *indxinfo;
    7815                 :             :     int         i_tableoid,
    7816                 :             :                 i_oid,
    7817                 :             :                 i_indrelid,
    7818                 :             :                 i_indexname,
    7819                 :             :                 i_relpages,
    7820                 :             :                 i_reltuples,
    7821                 :             :                 i_relallvisible,
    7822                 :             :                 i_relallfrozen,
    7823                 :             :                 i_parentidx,
    7824                 :             :                 i_indexdef,
    7825                 :             :                 i_indnkeyatts,
    7826                 :             :                 i_indnatts,
    7827                 :             :                 i_indkey,
    7828                 :             :                 i_indisclustered,
    7829                 :             :                 i_indisreplident,
    7830                 :             :                 i_indnullsnotdistinct,
    7831                 :             :                 i_contype,
    7832                 :             :                 i_conname,
    7833                 :             :                 i_condeferrable,
    7834                 :             :                 i_condeferred,
    7835                 :             :                 i_conperiod,
    7836                 :             :                 i_contableoid,
    7837                 :             :                 i_conoid,
    7838                 :             :                 i_condef,
    7839                 :             :                 i_indattnames,
    7840                 :             :                 i_tablespace,
    7841                 :             :                 i_indreloptions,
    7842                 :             :                 i_indstatcols,
    7843                 :             :                 i_indstatvals;
    7844                 :             : 
    7845                 :             :     /*
    7846                 :             :      * We want to perform just one query against pg_index.  However, we
    7847                 :             :      * mustn't try to select every row of the catalog and then sort it out on
    7848                 :             :      * the client side, because some of the server-side functions we need
    7849                 :             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7850                 :             :      * build an array of the OIDs of tables we care about (and now have lock
    7851                 :             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7852                 :             :      */
    7853                 :         191 :     appendPQExpBufferChar(tbloids, '{');
    7854         [ +  + ]:       55184 :     for (int i = 0; i < numTables; i++)
    7855                 :             :     {
    7856                 :       54993 :         TableInfo  *tbinfo = &tblinfo[i];
    7857                 :             : 
    7858         [ +  + ]:       54993 :         if (!tbinfo->hasindex)
    7859                 :       39181 :             continue;
    7860                 :             : 
    7861                 :             :         /*
    7862                 :             :          * We can ignore indexes of uninteresting tables.
    7863                 :             :          */
    7864         [ +  + ]:       15812 :         if (!tbinfo->interesting)
    7865                 :       13615 :             continue;
    7866                 :             : 
    7867                 :             :         /* OK, we need info for this table */
    7868         [ +  + ]:        2197 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7869                 :        2115 :             appendPQExpBufferChar(tbloids, ',');
    7870                 :        2197 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    7871                 :             :     }
    7872                 :         191 :     appendPQExpBufferChar(tbloids, '}');
    7873                 :             : 
    7874                 :         191 :     appendPQExpBufferStr(query,
    7875                 :             :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    7876                 :             :                          "t.relname AS indexname, "
    7877                 :             :                          "t.relpages, t.reltuples, t.relallvisible, ");
    7878                 :             : 
    7879         [ +  - ]:         191 :     if (fout->remoteVersion >= 180000)
    7880                 :         191 :         appendPQExpBufferStr(query, "t.relallfrozen, ");
    7881                 :             :     else
    7882                 :           0 :         appendPQExpBufferStr(query, "0 AS relallfrozen, ");
    7883                 :             : 
    7884                 :         191 :     appendPQExpBufferStr(query,
    7885                 :             :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7886                 :             :                          "i.indkey, i.indisclustered, "
    7887                 :             :                          "c.contype, c.conname, "
    7888                 :             :                          "c.condeferrable, c.condeferred, "
    7889                 :             :                          "c.tableoid AS contableoid, "
    7890                 :             :                          "c.oid AS conoid, "
    7891                 :             :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    7892                 :             :                          "CASE WHEN i.indexprs IS NOT NULL THEN "
    7893                 :             :                          "(SELECT pg_catalog.array_agg(attname ORDER BY attnum)"
    7894                 :             :                          "  FROM pg_catalog.pg_attribute "
    7895                 :             :                          "  WHERE attrelid = i.indexrelid) "
    7896                 :             :                          "ELSE NULL END AS indattnames, "
    7897                 :             :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7898                 :             :                          "t.reloptions AS indreloptions, ");
    7899                 :             : 
    7900                 :             : 
    7901                 :         191 :     appendPQExpBufferStr(query,
    7902                 :             :                          "i.indisreplident, ");
    7903                 :             : 
    7904         [ +  - ]:         191 :     if (fout->remoteVersion >= 110000)
    7905                 :         191 :         appendPQExpBufferStr(query,
    7906                 :             :                              "inh.inhparent AS parentidx, "
    7907                 :             :                              "i.indnkeyatts AS indnkeyatts, "
    7908                 :             :                              "i.indnatts AS indnatts, "
    7909                 :             :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    7910                 :             :                              "  FROM pg_catalog.pg_attribute "
    7911                 :             :                              "  WHERE attrelid = i.indexrelid AND "
    7912                 :             :                              "    attstattarget >= 0) AS indstatcols, "
    7913                 :             :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    7914                 :             :                              "  FROM pg_catalog.pg_attribute "
    7915                 :             :                              "  WHERE attrelid = i.indexrelid AND "
    7916                 :             :                              "    attstattarget >= 0) AS indstatvals, ");
    7917                 :             :     else
    7918                 :           0 :         appendPQExpBufferStr(query,
    7919                 :             :                              "0 AS parentidx, "
    7920                 :             :                              "i.indnatts AS indnkeyatts, "
    7921                 :             :                              "i.indnatts AS indnatts, "
    7922                 :             :                              "'' AS indstatcols, "
    7923                 :             :                              "'' AS indstatvals, ");
    7924                 :             : 
    7925         [ +  - ]:         191 :     if (fout->remoteVersion >= 150000)
    7926                 :         191 :         appendPQExpBufferStr(query,
    7927                 :             :                              "i.indnullsnotdistinct, ");
    7928                 :             :     else
    7929                 :           0 :         appendPQExpBufferStr(query,
    7930                 :             :                              "false AS indnullsnotdistinct, ");
    7931                 :             : 
    7932         [ +  - ]:         191 :     if (fout->remoteVersion >= 180000)
    7933                 :         191 :         appendPQExpBufferStr(query,
    7934                 :             :                              "c.conperiod ");
    7935                 :             :     else
    7936                 :           0 :         appendPQExpBufferStr(query,
    7937                 :             :                              "NULL AS conperiod ");
    7938                 :             : 
    7939                 :             :     /*
    7940                 :             :      * The point of the messy-looking outer join is to find a constraint that
    7941                 :             :      * is related by an internal dependency link to the index. If we find one,
    7942                 :             :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    7943                 :             :      * index won't have more than one internal dependency.
    7944                 :             :      *
    7945                 :             :      * Note: the check on conrelid is redundant, but useful because that
    7946                 :             :      * column is indexed while conindid is not.
    7947                 :             :      */
    7948         [ +  - ]:         191 :     if (fout->remoteVersion >= 110000)
    7949                 :             :     {
    7950                 :         191 :         appendPQExpBuffer(query,
    7951                 :             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7952                 :             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7953                 :             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7954                 :             :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    7955                 :             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7956                 :             :                           "ON (i.indrelid = c.conrelid AND "
    7957                 :             :                           "i.indexrelid = c.conindid AND "
    7958                 :             :                           "c.contype IN ('p','u','x')) "
    7959                 :             :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    7960                 :             :                           "ON (inh.inhrelid = indexrelid) "
    7961                 :             :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    7962                 :             :                           "AND i.indisready "
    7963                 :             :                           "ORDER BY i.indrelid, indexname",
    7964                 :             :                           tbloids->data);
    7965                 :             :     }
    7966                 :             :     else
    7967                 :             :     {
    7968                 :             :         /*
    7969                 :             :          * the test on indisready is necessary in 9.2, and harmless in
    7970                 :             :          * earlier/later versions
    7971                 :             :          */
    7972                 :           0 :         appendPQExpBuffer(query,
    7973                 :             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7974                 :             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7975                 :             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7976                 :             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7977                 :             :                           "ON (i.indrelid = c.conrelid AND "
    7978                 :             :                           "i.indexrelid = c.conindid AND "
    7979                 :             :                           "c.contype IN ('p','u','x')) "
    7980                 :             :                           "WHERE i.indisvalid AND i.indisready "
    7981                 :             :                           "ORDER BY i.indrelid, indexname",
    7982                 :             :                           tbloids->data);
    7983                 :             :     }
    7984                 :             : 
    7985                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7986                 :             : 
    7987                 :         191 :     ntups = PQntuples(res);
    7988                 :             : 
    7989                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    7990                 :         191 :     i_oid = PQfnumber(res, "oid");
    7991                 :         191 :     i_indrelid = PQfnumber(res, "indrelid");
    7992                 :         191 :     i_indexname = PQfnumber(res, "indexname");
    7993                 :         191 :     i_relpages = PQfnumber(res, "relpages");
    7994                 :         191 :     i_reltuples = PQfnumber(res, "reltuples");
    7995                 :         191 :     i_relallvisible = PQfnumber(res, "relallvisible");
    7996                 :         191 :     i_relallfrozen = PQfnumber(res, "relallfrozen");
    7997                 :         191 :     i_parentidx = PQfnumber(res, "parentidx");
    7998                 :         191 :     i_indexdef = PQfnumber(res, "indexdef");
    7999                 :         191 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    8000                 :         191 :     i_indnatts = PQfnumber(res, "indnatts");
    8001                 :         191 :     i_indkey = PQfnumber(res, "indkey");
    8002                 :         191 :     i_indisclustered = PQfnumber(res, "indisclustered");
    8003                 :         191 :     i_indisreplident = PQfnumber(res, "indisreplident");
    8004                 :         191 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    8005                 :         191 :     i_contype = PQfnumber(res, "contype");
    8006                 :         191 :     i_conname = PQfnumber(res, "conname");
    8007                 :         191 :     i_condeferrable = PQfnumber(res, "condeferrable");
    8008                 :         191 :     i_condeferred = PQfnumber(res, "condeferred");
    8009                 :         191 :     i_conperiod = PQfnumber(res, "conperiod");
    8010                 :         191 :     i_contableoid = PQfnumber(res, "contableoid");
    8011                 :         191 :     i_conoid = PQfnumber(res, "conoid");
    8012                 :         191 :     i_condef = PQfnumber(res, "condef");
    8013                 :         191 :     i_indattnames = PQfnumber(res, "indattnames");
    8014                 :         191 :     i_tablespace = PQfnumber(res, "tablespace");
    8015                 :         191 :     i_indreloptions = PQfnumber(res, "indreloptions");
    8016                 :         191 :     i_indstatcols = PQfnumber(res, "indstatcols");
    8017                 :         191 :     i_indstatvals = PQfnumber(res, "indstatvals");
    8018                 :             : 
    8019                 :         191 :     indxinfo = pg_malloc_array(IndxInfo, ntups);
    8020                 :             : 
    8021                 :             :     /*
    8022                 :             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8023                 :             :      * j is handled by the inner loop.
    8024                 :             :      */
    8025                 :         191 :     curtblindx = -1;
    8026         [ +  + ]:        2376 :     for (int j = 0; j < ntups;)
    8027                 :             :     {
    8028                 :        2185 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    8029                 :        2185 :         TableInfo  *tbinfo = NULL;
    8030                 :             :         int         numinds;
    8031                 :             : 
    8032                 :             :         /* Count rows for this table */
    8033         [ +  + ]:        2846 :         for (numinds = 1; numinds < ntups - j; numinds++)
    8034         [ +  + ]:        2764 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    8035                 :        2103 :                 break;
    8036                 :             : 
    8037                 :             :         /*
    8038                 :             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8039                 :             :          * order.
    8040                 :             :          */
    8041         [ +  - ]:       26239 :         while (++curtblindx < numTables)
    8042                 :             :         {
    8043                 :       26239 :             tbinfo = &tblinfo[curtblindx];
    8044         [ +  + ]:       26239 :             if (tbinfo->dobj.catId.oid == indrelid)
    8045                 :        2185 :                 break;
    8046                 :             :         }
    8047         [ -  + ]:        2185 :         if (curtblindx >= numTables)
    8048                 :           0 :             pg_fatal("unrecognized table OID %u", indrelid);
    8049                 :             :         /* cross-check that we only got requested tables */
    8050         [ +  - ]:        2185 :         if (!tbinfo->hasindex ||
    8051         [ -  + ]:        2185 :             !tbinfo->interesting)
    8052                 :           0 :             pg_fatal("unexpected index data for table \"%s\"",
    8053                 :             :                      tbinfo->dobj.name);
    8054                 :             : 
    8055                 :             :         /* Save data for this table */
    8056                 :        2185 :         tbinfo->indexes = indxinfo + j;
    8057                 :        2185 :         tbinfo->numIndexes = numinds;
    8058                 :             : 
    8059         [ +  + ]:        5031 :         for (int c = 0; c < numinds; c++, j++)
    8060                 :             :         {
    8061                 :             :             char        contype;
    8062                 :             :             char        indexkind;
    8063                 :        2846 :             char      **indAttNames = NULL;
    8064                 :        2846 :             int         nindAttNames = 0;
    8065                 :             :             RelStatsInfo *relstats;
    8066                 :        2846 :             int32       relpages = atoi(PQgetvalue(res, j, i_relpages));
    8067                 :        2846 :             int32       relallvisible = atoi(PQgetvalue(res, j, i_relallvisible));
    8068                 :        2846 :             int32       relallfrozen = atoi(PQgetvalue(res, j, i_relallfrozen));
    8069                 :             : 
    8070                 :        2846 :             indxinfo[j].dobj.objType = DO_INDEX;
    8071                 :        2846 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8072                 :        2846 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8073                 :        2846 :             AssignDumpId(&indxinfo[j].dobj);
    8074                 :        2846 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    8075                 :        2846 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    8076                 :        2846 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8077                 :        2846 :             indxinfo[j].indextable = tbinfo;
    8078                 :        2846 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    8079                 :        2846 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    8080                 :        2846 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    8081                 :        2846 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    8082                 :        2846 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    8083                 :        2846 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    8084                 :        2846 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    8085                 :        2846 :             indxinfo[j].indkeys = pg_malloc_array(Oid, indxinfo[j].indnattrs);
    8086                 :        2846 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    8087                 :        2846 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    8088                 :        2846 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    8089                 :        2846 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    8090                 :        2846 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    8091                 :        2846 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    8092                 :        2846 :             indxinfo[j].partattaches = (SimplePtrList)
    8093                 :             :             {
    8094                 :             :                 NULL, NULL
    8095                 :             :             };
    8096                 :             : 
    8097         [ +  + ]:        2846 :             if (indxinfo[j].parentidx == 0)
    8098                 :        2236 :                 indexkind = RELKIND_INDEX;
    8099                 :             :             else
    8100                 :         610 :                 indexkind = RELKIND_PARTITIONED_INDEX;
    8101                 :             : 
    8102         [ +  + ]:        2846 :             if (!PQgetisnull(res, j, i_indattnames))
    8103                 :             :             {
    8104         [ -  + ]:         162 :                 if (!parsePGArray(PQgetvalue(res, j, i_indattnames),
    8105                 :             :                                   &indAttNames, &nindAttNames))
    8106                 :           0 :                     pg_fatal("could not parse %s array", "indattnames");
    8107                 :             :             }
    8108                 :             : 
    8109                 :        2846 :             relstats = getRelationStatistics(fout, &indxinfo[j].dobj, relpages,
    8110                 :             :                                              PQgetvalue(res, j, i_reltuples),
    8111                 :             :                                              relallvisible, relallfrozen, indexkind,
    8112                 :             :                                              indAttNames, nindAttNames);
    8113                 :             : 
    8114                 :        2846 :             contype = *(PQgetvalue(res, j, i_contype));
    8115   [ +  +  +  +  :        2846 :             if (contype == 'p' || contype == 'u' || contype == 'x')
                   +  + ]
    8116                 :        1714 :             {
    8117                 :             :                 /*
    8118                 :             :                  * If we found a constraint matching the index, create an
    8119                 :             :                  * entry for it.
    8120                 :             :                  */
    8121                 :             :                 ConstraintInfo *constrinfo;
    8122                 :             : 
    8123                 :        1714 :                 constrinfo = pg_malloc_object(ConstraintInfo);
    8124                 :        1714 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    8125                 :        1714 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8126                 :        1714 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8127                 :        1714 :                 AssignDumpId(&constrinfo->dobj);
    8128                 :        1714 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    8129                 :        1714 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8130                 :        1714 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    8131                 :        1714 :                 constrinfo->contable = tbinfo;
    8132                 :        1714 :                 constrinfo->condomain = NULL;
    8133                 :        1714 :                 constrinfo->contype = contype;
    8134         [ +  + ]:        1714 :                 if (contype == 'x')
    8135                 :          10 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8136                 :             :                 else
    8137                 :        1704 :                     constrinfo->condef = NULL;
    8138                 :        1714 :                 constrinfo->confrelid = InvalidOid;
    8139                 :        1714 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    8140                 :        1714 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    8141                 :        1714 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    8142                 :        1714 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    8143                 :        1714 :                 constrinfo->conislocal = true;
    8144                 :        1714 :                 constrinfo->separate = true;
    8145                 :             : 
    8146                 :        1714 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    8147         [ +  + ]:        1714 :                 if (relstats != NULL)
    8148                 :         589 :                     addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    8149                 :             :             }
    8150                 :             :             else
    8151                 :             :             {
    8152                 :             :                 /* Plain secondary index */
    8153                 :        1132 :                 indxinfo[j].indexconstraint = 0;
    8154                 :             :             }
    8155                 :             :         }
    8156                 :             :     }
    8157                 :             : 
    8158                 :         191 :     PQclear(res);
    8159                 :             : 
    8160                 :         191 :     destroyPQExpBuffer(query);
    8161                 :         191 :     destroyPQExpBuffer(tbloids);
    8162                 :         191 : }
    8163                 :             : 
    8164                 :             : /*
    8165                 :             :  * getExtendedStatistics
    8166                 :             :  *    get information about extended-statistics objects.
    8167                 :             :  *
    8168                 :             :  * Note: extended statistics data is not returned directly to the caller, but
    8169                 :             :  * it does get entered into the DumpableObject tables.
    8170                 :             :  */
    8171                 :             : void
    8172                 :         191 : getExtendedStatistics(Archive *fout)
    8173                 :             : {
    8174                 :             :     PQExpBuffer query;
    8175                 :             :     PGresult   *res;
    8176                 :             :     StatsExtInfo *statsextinfo;
    8177                 :             :     int         ntups;
    8178                 :             :     int         i_tableoid;
    8179                 :             :     int         i_oid;
    8180                 :             :     int         i_stxname;
    8181                 :             :     int         i_stxnamespace;
    8182                 :             :     int         i_stxowner;
    8183                 :             :     int         i_stxrelid;
    8184                 :             :     int         i_stattarget;
    8185                 :             :     int         i;
    8186                 :             : 
    8187                 :         191 :     query = createPQExpBuffer();
    8188                 :             : 
    8189         [ -  + ]:         191 :     if (fout->remoteVersion < 130000)
    8190                 :           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8191                 :             :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    8192                 :             :                              "FROM pg_catalog.pg_statistic_ext");
    8193                 :             :     else
    8194                 :         191 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    8195                 :             :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    8196                 :             :                              "FROM pg_catalog.pg_statistic_ext");
    8197                 :             : 
    8198                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8199                 :             : 
    8200                 :         191 :     ntups = PQntuples(res);
    8201                 :             : 
    8202                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    8203                 :         191 :     i_oid = PQfnumber(res, "oid");
    8204                 :         191 :     i_stxname = PQfnumber(res, "stxname");
    8205                 :         191 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    8206                 :         191 :     i_stxowner = PQfnumber(res, "stxowner");
    8207                 :         191 :     i_stxrelid = PQfnumber(res, "stxrelid");
    8208                 :         191 :     i_stattarget = PQfnumber(res, "stxstattarget");
    8209                 :             : 
    8210                 :         191 :     statsextinfo = pg_malloc_array(StatsExtInfo, ntups);
    8211                 :             : 
    8212         [ +  + ]:         411 :     for (i = 0; i < ntups; i++)
    8213                 :             :     {
    8214                 :         220 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    8215                 :         220 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8216                 :         220 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8217                 :         220 :         AssignDumpId(&statsextinfo[i].dobj);
    8218                 :         220 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    8219                 :         440 :         statsextinfo[i].dobj.namespace =
    8220                 :         220 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    8221                 :         220 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    8222                 :         440 :         statsextinfo[i].stattable =
    8223                 :         220 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    8224         [ +  + ]:         220 :         if (PQgetisnull(res, i, i_stattarget))
    8225                 :         172 :             statsextinfo[i].stattarget = -1;
    8226                 :             :         else
    8227                 :          48 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    8228                 :             : 
    8229                 :             :         /* Decide whether we want to dump it */
    8230                 :         220 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    8231                 :             : 
    8232         [ +  + ]:         220 :         if (fout->dopt->dumpStatistics)
    8233                 :         164 :             statsextinfo[i].dobj.components |= DUMP_COMPONENT_STATISTICS;
    8234                 :             :     }
    8235                 :             : 
    8236                 :         191 :     PQclear(res);
    8237                 :         191 :     destroyPQExpBuffer(query);
    8238                 :         191 : }
    8239                 :             : 
    8240                 :             : /*
    8241                 :             :  * getConstraints
    8242                 :             :  *
    8243                 :             :  * Get info about constraints on dumpable tables.
    8244                 :             :  *
    8245                 :             :  * Currently handles foreign keys only.
    8246                 :             :  * Unique and primary key constraints are handled with indexes,
    8247                 :             :  * while check constraints are processed in getTableAttrs().
    8248                 :             :  */
    8249                 :             : void
    8250                 :         191 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    8251                 :             : {
    8252                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    8253                 :         191 :     PQExpBuffer tbloids = createPQExpBuffer();
    8254                 :             :     PGresult   *res;
    8255                 :             :     int         ntups;
    8256                 :             :     int         curtblindx;
    8257                 :         191 :     TableInfo  *tbinfo = NULL;
    8258                 :             :     ConstraintInfo *constrinfo;
    8259                 :             :     int         i_contableoid,
    8260                 :             :                 i_conoid,
    8261                 :             :                 i_conrelid,
    8262                 :             :                 i_conname,
    8263                 :             :                 i_confrelid,
    8264                 :             :                 i_conindid,
    8265                 :             :                 i_condef;
    8266                 :             : 
    8267                 :             :     /*
    8268                 :             :      * We want to perform just one query against pg_constraint.  However, we
    8269                 :             :      * mustn't try to select every row of the catalog and then sort it out on
    8270                 :             :      * the client side, because some of the server-side functions we need
    8271                 :             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8272                 :             :      * build an array of the OIDs of tables we care about (and now have lock
    8273                 :             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8274                 :             :      */
    8275                 :         191 :     appendPQExpBufferChar(tbloids, '{');
    8276         [ +  + ]:       55184 :     for (int i = 0; i < numTables; i++)
    8277                 :             :     {
    8278                 :       54993 :         TableInfo  *tinfo = &tblinfo[i];
    8279                 :             : 
    8280         [ +  + ]:       54993 :         if (!(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8281                 :       47328 :             continue;
    8282                 :             : 
    8283                 :             :         /* OK, we need info for this table */
    8284         [ +  + ]:        7665 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8285                 :        7537 :             appendPQExpBufferChar(tbloids, ',');
    8286                 :        7665 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    8287                 :             :     }
    8288                 :         191 :     appendPQExpBufferChar(tbloids, '}');
    8289                 :             : 
    8290                 :         191 :     appendPQExpBufferStr(query,
    8291                 :             :                          "SELECT c.tableoid, c.oid, "
    8292                 :             :                          "conrelid, conname, confrelid, ");
    8293         [ +  - ]:         191 :     if (fout->remoteVersion >= 110000)
    8294                 :         191 :         appendPQExpBufferStr(query, "conindid, ");
    8295                 :             :     else
    8296                 :           0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    8297                 :         191 :     appendPQExpBuffer(query,
    8298                 :             :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    8299                 :             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8300                 :             :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    8301                 :             :                       "WHERE contype = 'f' ",
    8302                 :             :                       tbloids->data);
    8303         [ +  - ]:         191 :     if (fout->remoteVersion >= 110000)
    8304                 :         191 :         appendPQExpBufferStr(query,
    8305                 :             :                              "AND conparentid = 0 ");
    8306                 :         191 :     appendPQExpBufferStr(query,
    8307                 :             :                          "ORDER BY conrelid, conname");
    8308                 :             : 
    8309                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8310                 :             : 
    8311                 :         191 :     ntups = PQntuples(res);
    8312                 :             : 
    8313                 :         191 :     i_contableoid = PQfnumber(res, "tableoid");
    8314                 :         191 :     i_conoid = PQfnumber(res, "oid");
    8315                 :         191 :     i_conrelid = PQfnumber(res, "conrelid");
    8316                 :         191 :     i_conname = PQfnumber(res, "conname");
    8317                 :         191 :     i_confrelid = PQfnumber(res, "confrelid");
    8318                 :         191 :     i_conindid = PQfnumber(res, "conindid");
    8319                 :         191 :     i_condef = PQfnumber(res, "condef");
    8320                 :             : 
    8321                 :         191 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8322                 :             : 
    8323                 :         191 :     curtblindx = -1;
    8324         [ +  + ]:         428 :     for (int j = 0; j < ntups; j++)
    8325                 :             :     {
    8326                 :         237 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    8327                 :             :         TableInfo  *reftable;
    8328                 :             : 
    8329                 :             :         /*
    8330                 :             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8331                 :             :          * order.
    8332                 :             :          */
    8333   [ +  +  +  + ]:         237 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    8334                 :             :         {
    8335         [ +  - ]:       16524 :             while (++curtblindx < numTables)
    8336                 :             :             {
    8337                 :       16524 :                 tbinfo = &tblinfo[curtblindx];
    8338         [ +  + ]:       16524 :                 if (tbinfo->dobj.catId.oid == conrelid)
    8339                 :         197 :                     break;
    8340                 :             :             }
    8341         [ -  + ]:         197 :             if (curtblindx >= numTables)
    8342                 :           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    8343                 :             :         }
    8344                 :             : 
    8345                 :         237 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8346                 :         237 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8347                 :         237 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8348                 :         237 :         AssignDumpId(&constrinfo[j].dobj);
    8349                 :         237 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8350                 :         237 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8351                 :         237 :         constrinfo[j].contable = tbinfo;
    8352                 :         237 :         constrinfo[j].condomain = NULL;
    8353                 :         237 :         constrinfo[j].contype = 'f';
    8354                 :         237 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8355                 :         237 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8356                 :         237 :         constrinfo[j].conindex = 0;
    8357                 :         237 :         constrinfo[j].condeferrable = false;
    8358                 :         237 :         constrinfo[j].condeferred = false;
    8359                 :         237 :         constrinfo[j].conislocal = true;
    8360                 :         237 :         constrinfo[j].separate = true;
    8361                 :             : 
    8362                 :             :         /*
    8363                 :             :          * Restoring an FK that points to a partitioned table requires that
    8364                 :             :          * all partition indexes have been attached beforehand. Ensure that
    8365                 :             :          * happens by making the constraint depend on each index partition
    8366                 :             :          * attach object.
    8367                 :             :          */
    8368                 :         237 :         reftable = findTableByOid(constrinfo[j].confrelid);
    8369   [ +  -  +  + ]:         237 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    8370                 :             :         {
    8371                 :          30 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    8372                 :             : 
    8373         [ +  - ]:          30 :             if (indexOid != InvalidOid)
    8374                 :             :             {
    8375         [ +  - ]:          30 :                 for (int k = 0; k < reftable->numIndexes; k++)
    8376                 :             :                 {
    8377                 :             :                     IndxInfo   *refidx;
    8378                 :             : 
    8379                 :             :                     /* not our index? */
    8380         [ -  + ]:          30 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    8381                 :           0 :                         continue;
    8382                 :             : 
    8383                 :          30 :                     refidx = &reftable->indexes[k];
    8384                 :          30 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    8385                 :          30 :                     break;
    8386                 :             :                 }
    8387                 :             :             }
    8388                 :             :         }
    8389                 :             :     }
    8390                 :             : 
    8391                 :         191 :     PQclear(res);
    8392                 :             : 
    8393                 :         191 :     destroyPQExpBuffer(query);
    8394                 :         191 :     destroyPQExpBuffer(tbloids);
    8395                 :         191 : }
    8396                 :             : 
    8397                 :             : /*
    8398                 :             :  * addConstrChildIdxDeps
    8399                 :             :  *
    8400                 :             :  * Recursive subroutine for getConstraints
    8401                 :             :  *
    8402                 :             :  * Given an object representing a foreign key constraint and an index on the
    8403                 :             :  * partitioned table it references, mark the constraint object as dependent
    8404                 :             :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    8405                 :             :  * drilling down to their partitions if any.  This ensures that the FK is not
    8406                 :             :  * restored until the index is fully marked valid.
    8407                 :             :  */
    8408                 :             : static void
    8409                 :          55 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    8410                 :             : {
    8411                 :             :     SimplePtrListCell *cell;
    8412                 :             : 
    8413                 :             :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    8414                 :             : 
    8415         [ +  + ]:         185 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    8416                 :             :     {
    8417                 :         130 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    8418                 :             : 
    8419                 :         130 :         addObjectDependency(dobj, attach->dobj.dumpId);
    8420                 :             : 
    8421         [ +  + ]:         130 :         if (attach->partitionIdx->partattaches.head != NULL)
    8422                 :          25 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    8423                 :             :     }
    8424                 :          55 : }
    8425                 :             : 
    8426                 :             : /*
    8427                 :             :  * getDomainConstraints
    8428                 :             :  *
    8429                 :             :  * Get info about constraints on a domain.
    8430                 :             :  */
    8431                 :             : static void
    8432                 :         181 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8433                 :             : {
    8434                 :             :     ConstraintInfo *constrinfo;
    8435                 :         181 :     PQExpBuffer query = createPQExpBuffer();
    8436                 :             :     PGresult   *res;
    8437                 :             :     int         i_tableoid,
    8438                 :             :                 i_oid,
    8439                 :             :                 i_conname,
    8440                 :             :                 i_consrc,
    8441                 :             :                 i_convalidated,
    8442                 :             :                 i_contype;
    8443                 :             :     int         ntups;
    8444                 :             : 
    8445         [ +  + ]:         181 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8446                 :             :     {
    8447                 :             :         /*
    8448                 :             :          * Set up query for constraint-specific details.  For servers 17 and
    8449                 :             :          * up, domains have constraints of type 'n' as well as 'c', otherwise
    8450                 :             :          * just the latter.
    8451                 :             :          */
    8452                 :          46 :         appendPQExpBuffer(query,
    8453                 :             :                           "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8454                 :             :                           "SELECT tableoid, oid, conname, "
    8455                 :             :                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8456                 :             :                           "convalidated, contype "
    8457                 :             :                           "FROM pg_catalog.pg_constraint "
    8458                 :             :                           "WHERE contypid = $1 AND contype IN (%s) "
    8459                 :             :                           "ORDER BY conname",
    8460         [ -  + ]:          46 :                           fout->remoteVersion < 170000 ? "'c'" : "'c', 'n'");
    8461                 :             : 
    8462                 :          46 :         ExecuteSqlStatement(fout, query->data);
    8463                 :             : 
    8464                 :          46 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8465                 :             :     }
    8466                 :             : 
    8467                 :         181 :     printfPQExpBuffer(query,
    8468                 :             :                       "EXECUTE getDomainConstraints('%u')",
    8469                 :             :                       tyinfo->dobj.catId.oid);
    8470                 :             : 
    8471                 :         181 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8472                 :             : 
    8473                 :         181 :     ntups = PQntuples(res);
    8474                 :             : 
    8475                 :         181 :     i_tableoid = PQfnumber(res, "tableoid");
    8476                 :         181 :     i_oid = PQfnumber(res, "oid");
    8477                 :         181 :     i_conname = PQfnumber(res, "conname");
    8478                 :         181 :     i_consrc = PQfnumber(res, "consrc");
    8479                 :         181 :     i_convalidated = PQfnumber(res, "convalidated");
    8480                 :         181 :     i_contype = PQfnumber(res, "contype");
    8481                 :             : 
    8482                 :         181 :     constrinfo = pg_malloc_array(ConstraintInfo, ntups);
    8483                 :         181 :     tyinfo->domChecks = constrinfo;
    8484                 :             : 
    8485                 :             :     /* 'i' tracks result rows; 'j' counts CHECK constraints */
    8486         [ +  + ]:         373 :     for (int i = 0, j = 0; i < ntups; i++)
    8487                 :             :     {
    8488                 :         192 :         bool        validated = PQgetvalue(res, i, i_convalidated)[0] == 't';
    8489                 :         192 :         char        contype = (PQgetvalue(res, i, i_contype))[0];
    8490                 :             :         ConstraintInfo *constraint;
    8491                 :             : 
    8492         [ +  + ]:         192 :         if (contype == CONSTRAINT_CHECK)
    8493                 :             :         {
    8494                 :         136 :             constraint = &constrinfo[j++];
    8495                 :         136 :             tyinfo->nDomChecks++;
    8496                 :             :         }
    8497                 :             :         else
    8498                 :             :         {
    8499                 :             :             Assert(contype == CONSTRAINT_NOTNULL);
    8500                 :             :             Assert(tyinfo->notnull == NULL);
    8501                 :             :             /* use last item in array for the not-null constraint */
    8502                 :          56 :             tyinfo->notnull = &(constrinfo[ntups - 1]);
    8503                 :          56 :             constraint = tyinfo->notnull;
    8504                 :             :         }
    8505                 :             : 
    8506                 :         192 :         constraint->dobj.objType = DO_CONSTRAINT;
    8507                 :         192 :         constraint->dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8508                 :         192 :         constraint->dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8509                 :         192 :         AssignDumpId(&(constraint->dobj));
    8510                 :         192 :         constraint->dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8511                 :         192 :         constraint->dobj.namespace = tyinfo->dobj.namespace;
    8512                 :         192 :         constraint->contable = NULL;
    8513                 :         192 :         constraint->condomain = tyinfo;
    8514                 :         192 :         constraint->contype = contype;
    8515                 :         192 :         constraint->condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8516                 :         192 :         constraint->confrelid = InvalidOid;
    8517                 :         192 :         constraint->conindex = 0;
    8518                 :         192 :         constraint->condeferrable = false;
    8519                 :         192 :         constraint->condeferred = false;
    8520                 :         192 :         constraint->conislocal = true;
    8521                 :             : 
    8522                 :         192 :         constraint->separate = !validated;
    8523                 :             : 
    8524                 :             :         /*
    8525                 :             :          * Make the domain depend on the constraint, ensuring it won't be
    8526                 :             :          * output till any constraint dependencies are OK.  If the constraint
    8527                 :             :          * has not been validated, it's going to be dumped after the domain
    8528                 :             :          * anyway, so this doesn't matter.
    8529                 :             :          */
    8530         [ +  + ]:         192 :         if (validated)
    8531                 :         187 :             addObjectDependency(&tyinfo->dobj, constraint->dobj.dumpId);
    8532                 :             :     }
    8533                 :             : 
    8534                 :         181 :     PQclear(res);
    8535                 :             : 
    8536                 :         181 :     destroyPQExpBuffer(query);
    8537                 :         181 : }
    8538                 :             : 
    8539                 :             : /*
    8540                 :             :  * getRules
    8541                 :             :  *    get basic information about every rule in the system
    8542                 :             :  */
    8543                 :             : void
    8544                 :         191 : getRules(Archive *fout)
    8545                 :             : {
    8546                 :             :     PGresult   *res;
    8547                 :             :     int         ntups;
    8548                 :             :     int         i;
    8549                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    8550                 :             :     RuleInfo   *ruleinfo;
    8551                 :             :     int         i_tableoid;
    8552                 :             :     int         i_oid;
    8553                 :             :     int         i_rulename;
    8554                 :             :     int         i_ruletable;
    8555                 :             :     int         i_ev_type;
    8556                 :             :     int         i_is_instead;
    8557                 :             :     int         i_ev_enabled;
    8558                 :             : 
    8559                 :         191 :     appendPQExpBufferStr(query, "SELECT "
    8560                 :             :                          "tableoid, oid, rulename, "
    8561                 :             :                          "ev_class AS ruletable, ev_type, is_instead, "
    8562                 :             :                          "ev_enabled "
    8563                 :             :                          "FROM pg_rewrite "
    8564                 :             :                          "ORDER BY oid");
    8565                 :             : 
    8566                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8567                 :             : 
    8568                 :         191 :     ntups = PQntuples(res);
    8569                 :             : 
    8570                 :         191 :     ruleinfo = pg_malloc_array(RuleInfo, ntups);
    8571                 :             : 
    8572                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    8573                 :         191 :     i_oid = PQfnumber(res, "oid");
    8574                 :         191 :     i_rulename = PQfnumber(res, "rulename");
    8575                 :         191 :     i_ruletable = PQfnumber(res, "ruletable");
    8576                 :         191 :     i_ev_type = PQfnumber(res, "ev_type");
    8577                 :         191 :     i_is_instead = PQfnumber(res, "is_instead");
    8578                 :         191 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8579                 :             : 
    8580         [ +  + ]:       32907 :     for (i = 0; i < ntups; i++)
    8581                 :             :     {
    8582                 :             :         Oid         ruletableoid;
    8583                 :             : 
    8584                 :       32716 :         ruleinfo[i].dobj.objType = DO_RULE;
    8585                 :       32716 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8586                 :       32716 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8587                 :       32716 :         AssignDumpId(&ruleinfo[i].dobj);
    8588                 :       32716 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8589                 :       32716 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8590                 :       32716 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8591         [ -  + ]:       32716 :         if (ruleinfo[i].ruletable == NULL)
    8592                 :           0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8593                 :             :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8594                 :       32716 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8595                 :       32716 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8596                 :       32716 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8597                 :       32716 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8598                 :       32716 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8599         [ +  - ]:       32716 :         if (ruleinfo[i].ruletable)
    8600                 :             :         {
    8601                 :             :             /*
    8602                 :             :              * If the table is a view or materialized view, force its ON
    8603                 :             :              * SELECT rule to be sorted before the view itself --- this
    8604                 :             :              * ensures that any dependencies for the rule affect the table's
    8605                 :             :              * positioning. Other rules are forced to appear after their
    8606                 :             :              * table.
    8607                 :             :              */
    8608         [ +  + ]:       32716 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8609         [ +  + ]:         726 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8610   [ +  +  +  - ]:       32485 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8611                 :             :             {
    8612                 :       32061 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8613                 :       32061 :                                     ruleinfo[i].dobj.dumpId);
    8614                 :             :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8615                 :       32061 :                 ruleinfo[i].separate = false;
    8616                 :             :             }
    8617                 :             :             else
    8618                 :             :             {
    8619                 :         655 :                 addObjectDependency(&ruleinfo[i].dobj,
    8620                 :         655 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8621                 :         655 :                 ruleinfo[i].separate = true;
    8622                 :             :             }
    8623                 :             :         }
    8624                 :             :         else
    8625                 :           0 :             ruleinfo[i].separate = true;
    8626                 :             :     }
    8627                 :             : 
    8628                 :         191 :     PQclear(res);
    8629                 :             : 
    8630                 :         191 :     destroyPQExpBuffer(query);
    8631                 :         191 : }
    8632                 :             : 
    8633                 :             : /*
    8634                 :             :  * getTriggers
    8635                 :             :  *    get information about every trigger on a dumpable table
    8636                 :             :  *
    8637                 :             :  * Note: trigger data is not returned directly to the caller, but it
    8638                 :             :  * does get entered into the DumpableObject tables.
    8639                 :             :  */
    8640                 :             : void
    8641                 :         191 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8642                 :             : {
    8643                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    8644                 :         191 :     PQExpBuffer tbloids = createPQExpBuffer();
    8645                 :             :     PGresult   *res;
    8646                 :             :     int         ntups;
    8647                 :             :     int         curtblindx;
    8648                 :             :     TriggerInfo *tginfo;
    8649                 :             :     int         i_tableoid,
    8650                 :             :                 i_oid,
    8651                 :             :                 i_tgrelid,
    8652                 :             :                 i_tgname,
    8653                 :             :                 i_tgenabled,
    8654                 :             :                 i_tgispartition,
    8655                 :             :                 i_tgdef;
    8656                 :             : 
    8657                 :             :     /*
    8658                 :             :      * We want to perform just one query against pg_trigger.  However, we
    8659                 :             :      * mustn't try to select every row of the catalog and then sort it out on
    8660                 :             :      * the client side, because some of the server-side functions we need
    8661                 :             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8662                 :             :      * build an array of the OIDs of tables we care about (and now have lock
    8663                 :             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8664                 :             :      */
    8665                 :         191 :     appendPQExpBufferChar(tbloids, '{');
    8666         [ +  + ]:       55184 :     for (int i = 0; i < numTables; i++)
    8667                 :             :     {
    8668                 :       54993 :         TableInfo  *tbinfo = &tblinfo[i];
    8669                 :             : 
    8670         [ +  + ]:       54993 :         if (!tbinfo->hastriggers ||
    8671         [ +  + ]:        1260 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8672                 :       54033 :             continue;
    8673                 :             : 
    8674                 :             :         /* OK, we need info for this table */
    8675         [ +  + ]:         960 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8676                 :         906 :             appendPQExpBufferChar(tbloids, ',');
    8677                 :         960 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8678                 :             :     }
    8679                 :         191 :     appendPQExpBufferChar(tbloids, '}');
    8680                 :             : 
    8681         [ +  - ]:         191 :     if (fout->remoteVersion >= 150000)
    8682                 :             :     {
    8683                 :             :         /*
    8684                 :             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8685                 :             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8686                 :             :          * under-parenthesization.
    8687                 :             :          *
    8688                 :             :          * NB: We need to see partition triggers in case the tgenabled flag
    8689                 :             :          * has been changed from the parent.
    8690                 :             :          */
    8691                 :         191 :         appendPQExpBuffer(query,
    8692                 :             :                           "SELECT t.tgrelid, t.tgname, "
    8693                 :             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8694                 :             :                           "t.tgenabled, t.tableoid, t.oid, "
    8695                 :             :                           "t.tgparentid <> 0 AS tgispartition\n"
    8696                 :             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8697                 :             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8698                 :             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8699                 :             :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8700                 :             :                           "OR t.tgenabled != u.tgenabled) "
    8701                 :             :                           "ORDER BY t.tgrelid, t.tgname",
    8702                 :             :                           tbloids->data);
    8703                 :             :     }
    8704         [ #  # ]:           0 :     else if (fout->remoteVersion >= 130000)
    8705                 :             :     {
    8706                 :             :         /*
    8707                 :             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8708                 :             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8709                 :             :          * under-parenthesization.
    8710                 :             :          *
    8711                 :             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8712                 :             :          * tgenabled flag has been changed from the parent.
    8713                 :             :          */
    8714                 :           0 :         appendPQExpBuffer(query,
    8715                 :             :                           "SELECT t.tgrelid, t.tgname, "
    8716                 :             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8717                 :             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8718                 :             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8719                 :             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8720                 :             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8721                 :             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8722                 :             :                           "ORDER BY t.tgrelid, t.tgname",
    8723                 :             :                           tbloids->data);
    8724                 :             :     }
    8725         [ #  # ]:           0 :     else if (fout->remoteVersion >= 110000)
    8726                 :             :     {
    8727                 :             :         /*
    8728                 :             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8729                 :             :          * tgenabled flag has been changed from the parent. No tgparentid in
    8730                 :             :          * version 11-12, so we have to match them via pg_depend.
    8731                 :             :          *
    8732                 :             :          * See above about pretty=true in pg_get_triggerdef.
    8733                 :             :          */
    8734                 :           0 :         appendPQExpBuffer(query,
    8735                 :             :                           "SELECT t.tgrelid, t.tgname, "
    8736                 :             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8737                 :             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8738                 :             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8739                 :             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8740                 :             :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8741                 :             :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8742                 :             :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8743                 :             :                           " d.objid = t.oid "
    8744                 :             :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8745                 :             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8746                 :             :                           "ORDER BY t.tgrelid, t.tgname",
    8747                 :             :                           tbloids->data);
    8748                 :             :     }
    8749                 :             :     else
    8750                 :             :     {
    8751                 :             :         /* See above about pretty=true in pg_get_triggerdef */
    8752                 :           0 :         appendPQExpBuffer(query,
    8753                 :             :                           "SELECT t.tgrelid, t.tgname, "
    8754                 :             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8755                 :             :                           "t.tgenabled, false as tgispartition, "
    8756                 :             :                           "t.tableoid, t.oid "
    8757                 :             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8758                 :             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8759                 :             :                           "WHERE NOT tgisinternal "
    8760                 :             :                           "ORDER BY t.tgrelid, t.tgname",
    8761                 :             :                           tbloids->data);
    8762                 :             :     }
    8763                 :             : 
    8764                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8765                 :             : 
    8766                 :         191 :     ntups = PQntuples(res);
    8767                 :             : 
    8768                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    8769                 :         191 :     i_oid = PQfnumber(res, "oid");
    8770                 :         191 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8771                 :         191 :     i_tgname = PQfnumber(res, "tgname");
    8772                 :         191 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8773                 :         191 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8774                 :         191 :     i_tgdef = PQfnumber(res, "tgdef");
    8775                 :             : 
    8776                 :         191 :     tginfo = pg_malloc_array(TriggerInfo, ntups);
    8777                 :             : 
    8778                 :             :     /*
    8779                 :             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8780                 :             :      * j is handled by the inner loop.
    8781                 :             :      */
    8782                 :         191 :     curtblindx = -1;
    8783         [ +  + ]:         509 :     for (int j = 0; j < ntups;)
    8784                 :             :     {
    8785                 :         318 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8786                 :         318 :         TableInfo  *tbinfo = NULL;
    8787                 :             :         int         numtrigs;
    8788                 :             : 
    8789                 :             :         /* Count rows for this table */
    8790         [ +  + ]:         535 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8791         [ +  + ]:         481 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8792                 :         264 :                 break;
    8793                 :             : 
    8794                 :             :         /*
    8795                 :             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8796                 :             :          * order.
    8797                 :             :          */
    8798         [ +  - ]:       18307 :         while (++curtblindx < numTables)
    8799                 :             :         {
    8800                 :       18307 :             tbinfo = &tblinfo[curtblindx];
    8801         [ +  + ]:       18307 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8802                 :         318 :                 break;
    8803                 :             :         }
    8804         [ -  + ]:         318 :         if (curtblindx >= numTables)
    8805                 :           0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8806                 :             : 
    8807                 :             :         /* Save data for this table */
    8808                 :         318 :         tbinfo->triggers = tginfo + j;
    8809                 :         318 :         tbinfo->numTriggers = numtrigs;
    8810                 :             : 
    8811         [ +  + ]:         853 :         for (int c = 0; c < numtrigs; c++, j++)
    8812                 :             :         {
    8813                 :         535 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8814                 :         535 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8815                 :         535 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8816                 :         535 :             AssignDumpId(&tginfo[j].dobj);
    8817                 :         535 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8818                 :         535 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8819                 :         535 :             tginfo[j].tgtable = tbinfo;
    8820                 :         535 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8821                 :         535 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8822                 :         535 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8823                 :             :         }
    8824                 :             :     }
    8825                 :             : 
    8826                 :         191 :     PQclear(res);
    8827                 :             : 
    8828                 :         191 :     destroyPQExpBuffer(query);
    8829                 :         191 :     destroyPQExpBuffer(tbloids);
    8830                 :         191 : }
    8831                 :             : 
    8832                 :             : /*
    8833                 :             :  * getEventTriggers
    8834                 :             :  *    get information about event triggers
    8835                 :             :  */
    8836                 :             : void
    8837                 :         191 : getEventTriggers(Archive *fout)
    8838                 :             : {
    8839                 :             :     int         i;
    8840                 :             :     PQExpBuffer query;
    8841                 :             :     PGresult   *res;
    8842                 :             :     EventTriggerInfo *evtinfo;
    8843                 :             :     int         i_tableoid,
    8844                 :             :                 i_oid,
    8845                 :             :                 i_evtname,
    8846                 :             :                 i_evtevent,
    8847                 :             :                 i_evtowner,
    8848                 :             :                 i_evttags,
    8849                 :             :                 i_evtfname,
    8850                 :             :                 i_evtenabled;
    8851                 :             :     int         ntups;
    8852                 :             : 
    8853                 :         191 :     query = createPQExpBuffer();
    8854                 :             : 
    8855                 :         191 :     appendPQExpBufferStr(query,
    8856                 :             :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8857                 :             :                          "evtevent, evtowner, "
    8858                 :             :                          "array_to_string(array("
    8859                 :             :                          "select quote_literal(x) "
    8860                 :             :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    8861                 :             :                          "e.evtfoid::regproc as evtfname "
    8862                 :             :                          "FROM pg_event_trigger e "
    8863                 :             :                          "ORDER BY e.oid");
    8864                 :             : 
    8865                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8866                 :             : 
    8867                 :         191 :     ntups = PQntuples(res);
    8868                 :             : 
    8869                 :         191 :     evtinfo = pg_malloc_array(EventTriggerInfo, ntups);
    8870                 :             : 
    8871                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    8872                 :         191 :     i_oid = PQfnumber(res, "oid");
    8873                 :         191 :     i_evtname = PQfnumber(res, "evtname");
    8874                 :         191 :     i_evtevent = PQfnumber(res, "evtevent");
    8875                 :         191 :     i_evtowner = PQfnumber(res, "evtowner");
    8876                 :         191 :     i_evttags = PQfnumber(res, "evttags");
    8877                 :         191 :     i_evtfname = PQfnumber(res, "evtfname");
    8878                 :         191 :     i_evtenabled = PQfnumber(res, "evtenabled");
    8879                 :             : 
    8880         [ +  + ]:         246 :     for (i = 0; i < ntups; i++)
    8881                 :             :     {
    8882                 :          55 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    8883                 :          55 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8884                 :          55 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8885                 :          55 :         AssignDumpId(&evtinfo[i].dobj);
    8886                 :          55 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    8887                 :          55 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    8888                 :          55 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    8889                 :          55 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    8890                 :          55 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    8891                 :          55 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    8892                 :          55 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    8893                 :             : 
    8894                 :             :         /* Decide whether we want to dump it */
    8895                 :          55 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    8896                 :             :     }
    8897                 :             : 
    8898                 :         191 :     PQclear(res);
    8899                 :             : 
    8900                 :         191 :     destroyPQExpBuffer(query);
    8901                 :         191 : }
    8902                 :             : 
    8903                 :             : /*
    8904                 :             :  * getProcLangs
    8905                 :             :  *    get basic information about every procedural language in the system
    8906                 :             :  *
    8907                 :             :  * NB: this must run after getFuncs() because we assume we can do
    8908                 :             :  * findFuncByOid().
    8909                 :             :  */
    8910                 :             : void
    8911                 :         191 : getProcLangs(Archive *fout)
    8912                 :             : {
    8913                 :             :     PGresult   *res;
    8914                 :             :     int         ntups;
    8915                 :             :     int         i;
    8916                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    8917                 :             :     ProcLangInfo *planginfo;
    8918                 :             :     int         i_tableoid;
    8919                 :             :     int         i_oid;
    8920                 :             :     int         i_lanname;
    8921                 :             :     int         i_lanpltrusted;
    8922                 :             :     int         i_lanplcallfoid;
    8923                 :             :     int         i_laninline;
    8924                 :             :     int         i_lanvalidator;
    8925                 :             :     int         i_lanacl;
    8926                 :             :     int         i_acldefault;
    8927                 :             :     int         i_lanowner;
    8928                 :             : 
    8929                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8930                 :             :                          "lanname, lanpltrusted, lanplcallfoid, "
    8931                 :             :                          "laninline, lanvalidator, "
    8932                 :             :                          "lanacl, "
    8933                 :             :                          "acldefault('l', lanowner) AS acldefault, "
    8934                 :             :                          "lanowner "
    8935                 :             :                          "FROM pg_language "
    8936                 :             :                          "WHERE lanispl "
    8937                 :             :                          "ORDER BY oid");
    8938                 :             : 
    8939                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8940                 :             : 
    8941                 :         191 :     ntups = PQntuples(res);
    8942                 :             : 
    8943                 :         191 :     planginfo = pg_malloc_array(ProcLangInfo, ntups);
    8944                 :             : 
    8945                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    8946                 :         191 :     i_oid = PQfnumber(res, "oid");
    8947                 :         191 :     i_lanname = PQfnumber(res, "lanname");
    8948                 :         191 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    8949                 :         191 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    8950                 :         191 :     i_laninline = PQfnumber(res, "laninline");
    8951                 :         191 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    8952                 :         191 :     i_lanacl = PQfnumber(res, "lanacl");
    8953                 :         191 :     i_acldefault = PQfnumber(res, "acldefault");
    8954                 :         191 :     i_lanowner = PQfnumber(res, "lanowner");
    8955                 :             : 
    8956         [ +  + ]:         430 :     for (i = 0; i < ntups; i++)
    8957                 :             :     {
    8958                 :         239 :         planginfo[i].dobj.objType = DO_PROCLANG;
    8959                 :         239 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8960                 :         239 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8961                 :         239 :         AssignDumpId(&planginfo[i].dobj);
    8962                 :             : 
    8963                 :         239 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    8964                 :         239 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    8965                 :         239 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    8966                 :         239 :         planginfo[i].dacl.privtype = 0;
    8967                 :         239 :         planginfo[i].dacl.initprivs = NULL;
    8968                 :         239 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    8969                 :         239 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    8970                 :         239 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    8971                 :         239 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    8972                 :         239 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    8973                 :             : 
    8974                 :             :         /* Decide whether we want to dump it */
    8975                 :         239 :         selectDumpableProcLang(&(planginfo[i]), fout);
    8976                 :             : 
    8977                 :             :         /* Mark whether language has an ACL */
    8978         [ +  + ]:         239 :         if (!PQgetisnull(res, i, i_lanacl))
    8979                 :          48 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    8980                 :             :     }
    8981                 :             : 
    8982                 :         191 :     PQclear(res);
    8983                 :             : 
    8984                 :         191 :     destroyPQExpBuffer(query);
    8985                 :         191 : }
    8986                 :             : 
    8987                 :             : /*
    8988                 :             :  * getCasts
    8989                 :             :  *    get basic information about most casts in the system
    8990                 :             :  *
    8991                 :             :  * Skip casts from a range to its multirange, since we'll create those
    8992                 :             :  * automatically.
    8993                 :             :  */
    8994                 :             : void
    8995                 :         191 : getCasts(Archive *fout)
    8996                 :             : {
    8997                 :             :     PGresult   *res;
    8998                 :             :     int         ntups;
    8999                 :             :     int         i;
    9000                 :         191 :     PQExpBuffer query = createPQExpBuffer();
    9001                 :             :     CastInfo   *castinfo;
    9002                 :             :     int         i_tableoid;
    9003                 :             :     int         i_oid;
    9004                 :             :     int         i_castsource;
    9005                 :             :     int         i_casttarget;
    9006                 :             :     int         i_castfunc;
    9007                 :             :     int         i_castcontext;
    9008                 :             :     int         i_castmethod;
    9009                 :             : 
    9010         [ +  - ]:         191 :     if (fout->remoteVersion >= 140000)
    9011                 :             :     {
    9012                 :         191 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9013                 :             :                              "castsource, casttarget, castfunc, castcontext, "
    9014                 :             :                              "castmethod "
    9015                 :             :                              "FROM pg_cast c "
    9016                 :             :                              "WHERE NOT EXISTS ( "
    9017                 :             :                              "SELECT 1 FROM pg_range r "
    9018                 :             :                              "WHERE c.castsource = r.rngtypid "
    9019                 :             :                              "AND c.casttarget = r.rngmultitypid "
    9020                 :             :                              ") "
    9021                 :             :                              "ORDER BY 3,4");
    9022                 :             :     }
    9023                 :             :     else
    9024                 :             :     {
    9025                 :           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9026                 :             :                              "castsource, casttarget, castfunc, castcontext, "
    9027                 :             :                              "castmethod "
    9028                 :             :                              "FROM pg_cast ORDER BY 3,4");
    9029                 :             :     }
    9030                 :             : 
    9031                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9032                 :             : 
    9033                 :         191 :     ntups = PQntuples(res);
    9034                 :             : 
    9035                 :         191 :     castinfo = pg_malloc_array(CastInfo, ntups);
    9036                 :             : 
    9037                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    9038                 :         191 :     i_oid = PQfnumber(res, "oid");
    9039                 :         191 :     i_castsource = PQfnumber(res, "castsource");
    9040                 :         191 :     i_casttarget = PQfnumber(res, "casttarget");
    9041                 :         191 :     i_castfunc = PQfnumber(res, "castfunc");
    9042                 :         191 :     i_castcontext = PQfnumber(res, "castcontext");
    9043                 :         191 :     i_castmethod = PQfnumber(res, "castmethod");
    9044                 :             : 
    9045         [ +  + ]:       46694 :     for (i = 0; i < ntups; i++)
    9046                 :             :     {
    9047                 :             :         PQExpBufferData namebuf;
    9048                 :             :         TypeInfo   *sTypeInfo;
    9049                 :             :         TypeInfo   *tTypeInfo;
    9050                 :             : 
    9051                 :       46503 :         castinfo[i].dobj.objType = DO_CAST;
    9052                 :       46503 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9053                 :       46503 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9054                 :       46503 :         AssignDumpId(&castinfo[i].dobj);
    9055                 :       46503 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    9056                 :       46503 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    9057                 :       46503 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    9058                 :       46503 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    9059                 :       46503 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    9060                 :             : 
    9061                 :             :         /*
    9062                 :             :          * Try to name cast as concatenation of typnames.  This is only used
    9063                 :             :          * for purposes of sorting.  If we fail to find either type, the name
    9064                 :             :          * will be an empty string.
    9065                 :             :          */
    9066                 :       46503 :         initPQExpBuffer(&namebuf);
    9067                 :       46503 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    9068                 :       46503 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    9069   [ +  -  +  - ]:       46503 :         if (sTypeInfo && tTypeInfo)
    9070                 :       46503 :             appendPQExpBuffer(&namebuf, "%s %s",
    9071                 :             :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    9072                 :       46503 :         castinfo[i].dobj.name = namebuf.data;
    9073                 :             : 
    9074                 :             :         /* Decide whether we want to dump it */
    9075                 :       46503 :         selectDumpableCast(&(castinfo[i]), fout);
    9076                 :             :     }
    9077                 :             : 
    9078                 :         191 :     PQclear(res);
    9079                 :             : 
    9080                 :         191 :     destroyPQExpBuffer(query);
    9081                 :         191 : }
    9082                 :             : 
    9083                 :             : static char *
    9084                 :          93 : get_language_name(Archive *fout, Oid langid)
    9085                 :             : {
    9086                 :             :     PQExpBuffer query;
    9087                 :             :     PGresult   *res;
    9088                 :             :     char       *lanname;
    9089                 :             : 
    9090                 :          93 :     query = createPQExpBuffer();
    9091                 :          93 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    9092                 :          93 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    9093                 :          93 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    9094                 :          93 :     destroyPQExpBuffer(query);
    9095                 :          93 :     PQclear(res);
    9096                 :             : 
    9097                 :          93 :     return lanname;
    9098                 :             : }
    9099                 :             : 
    9100                 :             : /*
    9101                 :             :  * getTransforms
    9102                 :             :  *    get basic information about every transform in the system
    9103                 :             :  */
    9104                 :             : void
    9105                 :         191 : getTransforms(Archive *fout)
    9106                 :             : {
    9107                 :             :     PGresult   *res;
    9108                 :             :     int         ntups;
    9109                 :             :     int         i;
    9110                 :             :     PQExpBuffer query;
    9111                 :             :     TransformInfo *transforminfo;
    9112                 :             :     int         i_tableoid;
    9113                 :             :     int         i_oid;
    9114                 :             :     int         i_trftype;
    9115                 :             :     int         i_trflang;
    9116                 :             :     int         i_trffromsql;
    9117                 :             :     int         i_trftosql;
    9118                 :             : 
    9119                 :         191 :     query = createPQExpBuffer();
    9120                 :             : 
    9121                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    9122                 :             :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    9123                 :             :                          "FROM pg_transform "
    9124                 :             :                          "ORDER BY 3,4");
    9125                 :             : 
    9126                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9127                 :             : 
    9128                 :         191 :     ntups = PQntuples(res);
    9129                 :             : 
    9130                 :         191 :     transforminfo = pg_malloc_array(TransformInfo, ntups);
    9131                 :             : 
    9132                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
    9133                 :         191 :     i_oid = PQfnumber(res, "oid");
    9134                 :         191 :     i_trftype = PQfnumber(res, "trftype");
    9135                 :         191 :     i_trflang = PQfnumber(res, "trflang");
    9136                 :         191 :     i_trffromsql = PQfnumber(res, "trffromsql");
    9137                 :         191 :     i_trftosql = PQfnumber(res, "trftosql");
    9138                 :             : 
    9139         [ +  + ]:         246 :     for (i = 0; i < ntups; i++)
    9140                 :             :     {
    9141                 :             :         PQExpBufferData namebuf;
    9142                 :             :         TypeInfo   *typeInfo;
    9143                 :             :         char       *lanname;
    9144                 :             : 
    9145                 :          55 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    9146                 :          55 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9147                 :          55 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9148                 :          55 :         AssignDumpId(&transforminfo[i].dobj);
    9149                 :          55 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    9150                 :          55 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    9151                 :          55 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    9152                 :          55 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    9153                 :             : 
    9154                 :             :         /*
    9155                 :             :          * Try to name transform as concatenation of type and language name.
    9156                 :             :          * This is only used for purposes of sorting.  If we fail to find
    9157                 :             :          * either, the name will be an empty string.
    9158                 :             :          */
    9159                 :          55 :         initPQExpBuffer(&namebuf);
    9160                 :          55 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    9161                 :          55 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    9162   [ +  -  +  - ]:          55 :         if (typeInfo && lanname)
    9163                 :          55 :             appendPQExpBuffer(&namebuf, "%s %s",
    9164                 :             :                               typeInfo->dobj.name, lanname);
    9165                 :          55 :         transforminfo[i].dobj.name = namebuf.data;
    9166                 :          55 :         free(lanname);
    9167                 :             : 
    9168                 :             :         /* Decide whether we want to dump it */
    9169                 :          55 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    9170                 :             :     }
    9171                 :             : 
    9172                 :         191 :     PQclear(res);
    9173                 :             : 
    9174                 :         191 :     destroyPQExpBuffer(query);
    9175                 :         191 : }
    9176                 :             : 
    9177                 :             : /*
    9178                 :             :  * getTableAttrs -
    9179                 :             :  *    for each interesting table, read info about its attributes
    9180                 :             :  *    (names, types, default values, CHECK constraints, etc)
    9181                 :             :  *
    9182                 :             :  *  modifies tblinfo
    9183                 :             :  */
    9184                 :             : void
    9185                 :         191 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    9186                 :             : {
    9187                 :         191 :     DumpOptions *dopt = fout->dopt;
    9188                 :         191 :     PQExpBuffer q = createPQExpBuffer();
    9189                 :         191 :     PQExpBuffer tbloids = createPQExpBuffer();
    9190                 :         191 :     PQExpBuffer checkoids = createPQExpBuffer();
    9191                 :         191 :     PQExpBuffer invalidnotnulloids = NULL;
    9192                 :             :     PGresult   *res;
    9193                 :             :     int         ntups;
    9194                 :             :     int         curtblindx;
    9195                 :             :     int         i_attrelid;
    9196                 :             :     int         i_attnum;
    9197                 :             :     int         i_attname;
    9198                 :             :     int         i_atttypname;
    9199                 :             :     int         i_attstattarget;
    9200                 :             :     int         i_attstorage;
    9201                 :             :     int         i_typstorage;
    9202                 :             :     int         i_attidentity;
    9203                 :             :     int         i_attgenerated;
    9204                 :             :     int         i_attisdropped;
    9205                 :             :     int         i_attlen;
    9206                 :             :     int         i_attalign;
    9207                 :             :     int         i_attislocal;
    9208                 :             :     int         i_notnull_name;
    9209                 :             :     int         i_notnull_comment;
    9210                 :             :     int         i_notnull_noinherit;
    9211                 :             :     int         i_notnull_islocal;
    9212                 :             :     int         i_notnull_invalidoid;
    9213                 :             :     int         i_attoptions;
    9214                 :             :     int         i_attcollation;
    9215                 :             :     int         i_attcompression;
    9216                 :             :     int         i_attfdwoptions;
    9217                 :             :     int         i_attmissingval;
    9218                 :             :     int         i_atthasdef;
    9219                 :             : 
    9220                 :             :     /*
    9221                 :             :      * We want to perform just one query against pg_attribute, and then just
    9222                 :             :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    9223                 :             :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    9224                 :             :      * mustn't try to select every row of those catalogs and then sort it out
    9225                 :             :      * on the client side, because some of the server-side functions we need
    9226                 :             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    9227                 :             :      * build an array of the OIDs of tables we care about (and now have lock
    9228                 :             :      * on!), and use a WHERE clause to constrain which rows are selected.
    9229                 :             :      */
    9230                 :         191 :     appendPQExpBufferChar(tbloids, '{');
    9231                 :         191 :     appendPQExpBufferChar(checkoids, '{');
    9232         [ +  + ]:       55184 :     for (int i = 0; i < numTables; i++)
    9233                 :             :     {
    9234                 :       54993 :         TableInfo  *tbinfo = &tblinfo[i];
    9235                 :             : 
    9236                 :             :         /* Don't bother to collect info for sequences */
    9237         [ +  + ]:       54993 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    9238                 :         647 :             continue;
    9239                 :             : 
    9240                 :             :         /*
    9241                 :             :          * Don't bother with uninteresting tables, either.  For binary
    9242                 :             :          * upgrades, this is bypassed for pg_largeobject_metadata and
    9243                 :             :          * pg_shdepend so that the columns names are collected for the
    9244                 :             :          * corresponding COPY commands.  Restoring the data for those catalogs
    9245                 :             :          * is faster than restoring the equivalent set of large object
    9246                 :             :          * commands.
    9247                 :             :          */
    9248         [ +  + ]:       54346 :         if (!tbinfo->interesting &&
    9249         [ +  + ]:       47043 :             !(fout->dopt->binary_upgrade &&
    9250         [ +  + ]:        9458 :               (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9251         [ +  + ]:        9418 :                tbinfo->dobj.catId.oid == SharedDependRelationId)))
    9252                 :       46963 :             continue;
    9253                 :             : 
    9254                 :             :         /* OK, we need info for this table */
    9255         [ +  + ]:        7383 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    9256                 :        7234 :             appendPQExpBufferChar(tbloids, ',');
    9257                 :        7383 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9258                 :             : 
    9259         [ +  + ]:        7383 :         if (tbinfo->ncheck > 0)
    9260                 :             :         {
    9261                 :             :             /* Also make a list of the ones with check constraints */
    9262         [ +  + ]:         548 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    9263                 :         476 :                 appendPQExpBufferChar(checkoids, ',');
    9264                 :         548 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    9265                 :             :         }
    9266                 :             :     }
    9267                 :         191 :     appendPQExpBufferChar(tbloids, '}');
    9268                 :         191 :     appendPQExpBufferChar(checkoids, '}');
    9269                 :             : 
    9270                 :             :     /*
    9271                 :             :      * Find all the user attributes and their types.
    9272                 :             :      *
    9273                 :             :      * Since we only want to dump COLLATE clauses for attributes whose
    9274                 :             :      * collation is different from their type's default, we use a CASE here to
    9275                 :             :      * suppress uninteresting attcollations cheaply.
    9276                 :             :      */
    9277                 :         191 :     appendPQExpBufferStr(q,
    9278                 :             :                          "SELECT\n"
    9279                 :             :                          "a.attrelid,\n"
    9280                 :             :                          "a.attnum,\n"
    9281                 :             :                          "a.attname,\n"
    9282                 :             :                          "a.attstattarget,\n"
    9283                 :             :                          "a.attstorage,\n"
    9284                 :             :                          "t.typstorage,\n"
    9285                 :             :                          "a.atthasdef,\n"
    9286                 :             :                          "a.attisdropped,\n"
    9287                 :             :                          "a.attlen,\n"
    9288                 :             :                          "a.attalign,\n"
    9289                 :             :                          "a.attislocal,\n"
    9290                 :             :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    9291                 :             :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    9292                 :             :                          "CASE WHEN a.attcollation <> t.typcollation "
    9293                 :             :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    9294                 :             :                          "pg_catalog.array_to_string(ARRAY("
    9295                 :             :                          "SELECT pg_catalog.quote_ident(option_name) || "
    9296                 :             :                          "' ' || pg_catalog.quote_literal(option_value) "
    9297                 :             :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    9298                 :             :                          "ORDER BY option_name"
    9299                 :             :                          "), E',\n    ') AS attfdwoptions,\n");
    9300                 :             : 
    9301                 :             :     /*
    9302                 :             :      * Find out any NOT NULL markings for each column.  In 18 and up we read
    9303                 :             :      * pg_constraint to obtain the constraint name, and for valid constraints
    9304                 :             :      * also pg_description to obtain its comment.  notnull_noinherit is set
    9305                 :             :      * according to the NO INHERIT property.  For versions prior to 18, we
    9306                 :             :      * store an empty string as the name when a constraint is marked as
    9307                 :             :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    9308                 :             :      * without a name); also, such cases are never NO INHERIT.
    9309                 :             :      *
    9310                 :             :      * For invalid constraints, we need to store their OIDs for processing
    9311                 :             :      * elsewhere, so we bring the pg_constraint.oid value when the constraint
    9312                 :             :      * is invalid, and NULL otherwise.  Their comments are handled not here
    9313                 :             :      * but by collectComments, because they're their own dumpable object.
    9314                 :             :      *
    9315                 :             :      * We track in notnull_islocal whether the constraint was defined directly
    9316                 :             :      * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    9317                 :             :      * might modify this later.
    9318                 :             :      */
    9319         [ +  - ]:         191 :     if (fout->remoteVersion >= 180000)
    9320                 :         191 :         appendPQExpBufferStr(q,
    9321                 :             :                              "co.conname AS notnull_name,\n"
    9322                 :             :                              "CASE WHEN co.convalidated THEN pt.description"
    9323                 :             :                              " ELSE NULL END AS notnull_comment,\n"
    9324                 :             :                              "CASE WHEN NOT co.convalidated THEN co.oid "
    9325                 :             :                              "ELSE NULL END AS notnull_invalidoid,\n"
    9326                 :             :                              "co.connoinherit AS notnull_noinherit,\n"
    9327                 :             :                              "co.conislocal AS notnull_islocal,\n");
    9328                 :             :     else
    9329                 :           0 :         appendPQExpBufferStr(q,
    9330                 :             :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    9331                 :             :                              "NULL AS notnull_comment,\n"
    9332                 :             :                              "NULL AS notnull_invalidoid,\n"
    9333                 :             :                              "false AS notnull_noinherit,\n"
    9334                 :             :                              "CASE WHEN a.attislocal THEN true\n"
    9335                 :             :                              "     WHEN a.attnotnull AND NOT a.attislocal THEN true\n"
    9336                 :             :                              "     ELSE false\n"
    9337                 :             :                              "END AS notnull_islocal,\n");
    9338                 :             : 
    9339         [ +  - ]:         191 :     if (fout->remoteVersion >= 140000)
    9340                 :         191 :         appendPQExpBufferStr(q,
    9341                 :             :                              "a.attcompression AS attcompression,\n");
    9342                 :             :     else
    9343                 :           0 :         appendPQExpBufferStr(q,
    9344                 :             :                              "'' AS attcompression,\n");
    9345                 :             : 
    9346                 :         191 :     appendPQExpBufferStr(q,
    9347                 :             :                          "a.attidentity,\n");
    9348                 :             : 
    9349         [ +  - ]:         191 :     if (fout->remoteVersion >= 110000)
    9350                 :         191 :         appendPQExpBufferStr(q,
    9351                 :             :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    9352                 :             :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    9353                 :             :     else
    9354                 :           0 :         appendPQExpBufferStr(q,
    9355                 :             :                              "NULL AS attmissingval,\n");
    9356                 :             : 
    9357         [ +  - ]:         191 :     if (fout->remoteVersion >= 120000)
    9358                 :         191 :         appendPQExpBufferStr(q,
    9359                 :             :                              "a.attgenerated\n");
    9360                 :             :     else
    9361                 :           0 :         appendPQExpBufferStr(q,
    9362                 :             :                              "'' AS attgenerated\n");
    9363                 :             : 
    9364                 :             :     /* need left join to pg_type to not fail on dropped columns ... */
    9365                 :         191 :     appendPQExpBuffer(q,
    9366                 :             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9367                 :             :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    9368                 :             :                       "LEFT JOIN pg_catalog.pg_type t "
    9369                 :             :                       "ON (a.atttypid = t.oid)\n",
    9370                 :             :                       tbloids->data);
    9371                 :             : 
    9372                 :             :     /*
    9373                 :             :      * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    9374                 :             :      * entries and pg_description to get their comments.
    9375                 :             :      */
    9376         [ +  - ]:         191 :     if (fout->remoteVersion >= 180000)
    9377                 :         191 :         appendPQExpBufferStr(q,
    9378                 :             :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    9379                 :             :                              "(a.attrelid = co.conrelid\n"
    9380                 :             :                              "   AND co.contype = 'n' AND "
    9381                 :             :                              "co.conkey = array[a.attnum])\n"
    9382                 :             :                              " LEFT JOIN pg_catalog.pg_description pt ON "
    9383                 :             :                              "(pt.classoid = co.tableoid AND pt.objoid = co.oid)\n");
    9384                 :             : 
    9385                 :         191 :     appendPQExpBufferStr(q,
    9386                 :             :                          "WHERE a.attnum > 0::pg_catalog.int2\n");
    9387                 :             : 
    9388                 :             :     /*
    9389                 :             :      * For binary upgrades from <v12, be sure to pick up
    9390                 :             :      * pg_largeobject_metadata's oid column.
    9391                 :             :      */
    9392   [ +  +  -  + ]:         191 :     if (fout->dopt->binary_upgrade && fout->remoteVersion < 120000)
    9393                 :           0 :         appendPQExpBufferStr(q,
    9394                 :             :                              "OR (a.attnum = -2::pg_catalog.int2 AND src.tbloid = "
    9395                 :             :                              CppAsString2(LargeObjectMetadataRelationId) ")\n");
    9396                 :             : 
    9397                 :         191 :     appendPQExpBufferStr(q,
    9398                 :             :                          "ORDER BY a.attrelid, a.attnum");
    9399                 :             : 
    9400                 :         191 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9401                 :             : 
    9402                 :         191 :     ntups = PQntuples(res);
    9403                 :             : 
    9404                 :         191 :     i_attrelid = PQfnumber(res, "attrelid");
    9405                 :         191 :     i_attnum = PQfnumber(res, "attnum");
    9406                 :         191 :     i_attname = PQfnumber(res, "attname");
    9407                 :         191 :     i_atttypname = PQfnumber(res, "atttypname");
    9408                 :         191 :     i_attstattarget = PQfnumber(res, "attstattarget");
    9409                 :         191 :     i_attstorage = PQfnumber(res, "attstorage");
    9410                 :         191 :     i_typstorage = PQfnumber(res, "typstorage");
    9411                 :         191 :     i_attidentity = PQfnumber(res, "attidentity");
    9412                 :         191 :     i_attgenerated = PQfnumber(res, "attgenerated");
    9413                 :         191 :     i_attisdropped = PQfnumber(res, "attisdropped");
    9414                 :         191 :     i_attlen = PQfnumber(res, "attlen");
    9415                 :         191 :     i_attalign = PQfnumber(res, "attalign");
    9416                 :         191 :     i_attislocal = PQfnumber(res, "attislocal");
    9417                 :         191 :     i_notnull_name = PQfnumber(res, "notnull_name");
    9418                 :         191 :     i_notnull_comment = PQfnumber(res, "notnull_comment");
    9419                 :         191 :     i_notnull_invalidoid = PQfnumber(res, "notnull_invalidoid");
    9420                 :         191 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9421                 :         191 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9422                 :         191 :     i_attoptions = PQfnumber(res, "attoptions");
    9423                 :         191 :     i_attcollation = PQfnumber(res, "attcollation");
    9424                 :         191 :     i_attcompression = PQfnumber(res, "attcompression");
    9425                 :         191 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9426                 :         191 :     i_attmissingval = PQfnumber(res, "attmissingval");
    9427                 :         191 :     i_atthasdef = PQfnumber(res, "atthasdef");
    9428                 :             : 
    9429                 :             :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9430                 :         191 :     resetPQExpBuffer(tbloids);
    9431                 :         191 :     appendPQExpBufferChar(tbloids, '{');
    9432                 :             : 
    9433                 :             :     /*
    9434                 :             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    9435                 :             :      * r is handled by the inner loop.
    9436                 :             :      */
    9437                 :         191 :     curtblindx = -1;
    9438         [ +  + ]:        7316 :     for (int r = 0; r < ntups;)
    9439                 :             :     {
    9440                 :        7125 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9441                 :        7125 :         TableInfo  *tbinfo = NULL;
    9442                 :             :         int         numatts;
    9443                 :             :         bool        hasdefaults;
    9444                 :             : 
    9445                 :             :         /* Count rows for this table */
    9446         [ +  + ]:       26559 :         for (numatts = 1; numatts < ntups - r; numatts++)
    9447         [ +  + ]:       26413 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9448                 :        6979 :                 break;
    9449                 :             : 
    9450                 :             :         /*
    9451                 :             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9452                 :             :          * order.
    9453                 :             :          */
    9454         [ +  - ]:       38198 :         while (++curtblindx < numTables)
    9455                 :             :         {
    9456                 :       38198 :             tbinfo = &tblinfo[curtblindx];
    9457         [ +  + ]:       38198 :             if (tbinfo->dobj.catId.oid == attrelid)
    9458                 :        7125 :                 break;
    9459                 :             :         }
    9460         [ -  + ]:        7125 :         if (curtblindx >= numTables)
    9461                 :           0 :             pg_fatal("unrecognized table OID %u", attrelid);
    9462                 :             :         /* cross-check that we only got requested tables */
    9463         [ +  - ]:        7125 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9464         [ +  + ]:        7125 :             (!tbinfo->interesting &&
    9465         [ +  - ]:          80 :              !(fout->dopt->binary_upgrade &&
    9466         [ +  + ]:          80 :                (tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId ||
    9467         [ -  + ]:          40 :                 tbinfo->dobj.catId.oid == SharedDependRelationId))))
    9468                 :           0 :             pg_fatal("unexpected column data for table \"%s\"",
    9469                 :             :                      tbinfo->dobj.name);
    9470                 :             : 
    9471                 :             :         /* Save data for this table */
    9472                 :        7125 :         tbinfo->numatts = numatts;
    9473                 :        7125 :         tbinfo->attnames = pg_malloc_array(char *, numatts);
    9474                 :        7125 :         tbinfo->atttypnames = pg_malloc_array(char *, numatts);
    9475                 :        7125 :         tbinfo->attstattarget = pg_malloc_array(int, numatts);
    9476                 :        7125 :         tbinfo->attstorage = pg_malloc_array(char, numatts);
    9477                 :        7125 :         tbinfo->typstorage = pg_malloc_array(char, numatts);
    9478                 :        7125 :         tbinfo->attidentity = pg_malloc_array(char, numatts);
    9479                 :        7125 :         tbinfo->attgenerated = pg_malloc_array(char, numatts);
    9480                 :        7125 :         tbinfo->attisdropped = pg_malloc_array(bool, numatts);
    9481                 :        7125 :         tbinfo->attlen = pg_malloc_array(int, numatts);
    9482                 :        7125 :         tbinfo->attalign = pg_malloc_array(char, numatts);
    9483                 :        7125 :         tbinfo->attislocal = pg_malloc_array(bool, numatts);
    9484                 :        7125 :         tbinfo->attoptions = pg_malloc_array(char *, numatts);
    9485                 :        7125 :         tbinfo->attcollation = pg_malloc_array(Oid, numatts);
    9486                 :        7125 :         tbinfo->attcompression = pg_malloc_array(char, numatts);
    9487                 :        7125 :         tbinfo->attfdwoptions = pg_malloc_array(char *, numatts);
    9488                 :        7125 :         tbinfo->attmissingval = pg_malloc_array(char *, numatts);
    9489                 :        7125 :         tbinfo->notnull_constrs = pg_malloc_array(char *, numatts);
    9490                 :        7125 :         tbinfo->notnull_comment = pg_malloc_array(char *, numatts);
    9491                 :        7125 :         tbinfo->notnull_invalid = pg_malloc_array(bool, numatts);
    9492                 :        7125 :         tbinfo->notnull_noinh = pg_malloc_array(bool, numatts);
    9493                 :        7125 :         tbinfo->notnull_islocal = pg_malloc_array(bool, numatts);
    9494                 :        7125 :         tbinfo->attrdefs = pg_malloc_array(AttrDefInfo *, numatts);
    9495                 :        7125 :         hasdefaults = false;
    9496                 :             : 
    9497         [ +  + ]:       33684 :         for (int j = 0; j < numatts; j++, r++)
    9498                 :             :         {
    9499         [ -  + ]:       26559 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)) &&
    9500   [ #  #  #  # ]:           0 :                 !(fout->dopt->binary_upgrade && fout->remoteVersion < 120000 &&
    9501         [ #  # ]:           0 :                   tbinfo->dobj.catId.oid == LargeObjectMetadataRelationId))
    9502                 :           0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    9503                 :             :                          tbinfo->dobj.name);
    9504                 :       26559 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9505                 :       26559 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9506         [ +  + ]:       26559 :             if (PQgetisnull(res, r, i_attstattarget))
    9507                 :       26516 :                 tbinfo->attstattarget[j] = -1;
    9508                 :             :             else
    9509                 :          43 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9510                 :       26559 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9511                 :       26559 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9512                 :       26559 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9513                 :       26559 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9514   [ +  +  +  + ]:       26559 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9515                 :       26559 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9516                 :       26559 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9517                 :       26559 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9518                 :       26559 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9519                 :             : 
    9520                 :             :             /* Handle not-null constraint name and flags */
    9521                 :       26559 :             determineNotNullFlags(fout, res, r,
    9522                 :             :                                   tbinfo, j,
    9523                 :             :                                   i_notnull_name,
    9524                 :             :                                   i_notnull_comment,
    9525                 :             :                                   i_notnull_invalidoid,
    9526                 :             :                                   i_notnull_noinherit,
    9527                 :             :                                   i_notnull_islocal,
    9528                 :             :                                   &invalidnotnulloids);
    9529                 :             : 
    9530                 :       26559 :             tbinfo->notnull_comment[j] = PQgetisnull(res, r, i_notnull_comment) ?
    9531         [ +  + ]:       26559 :                 NULL : pg_strdup(PQgetvalue(res, r, i_notnull_comment));
    9532                 :       26559 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9533                 :       26559 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9534                 :       26559 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9535                 :       26559 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9536                 :       26559 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9537                 :       26559 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9538         [ +  + ]:       26559 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9539                 :        1376 :                 hasdefaults = true;
    9540                 :             :         }
    9541                 :             : 
    9542         [ +  + ]:        7125 :         if (hasdefaults)
    9543                 :             :         {
    9544                 :             :             /* Collect OIDs of interesting tables that have defaults */
    9545         [ +  + ]:        1026 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9546                 :         955 :                 appendPQExpBufferChar(tbloids, ',');
    9547                 :        1026 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9548                 :             :         }
    9549                 :             :     }
    9550                 :             : 
    9551                 :             :     /* If invalidnotnulloids has any data, finalize it */
    9552         [ +  + ]:         191 :     if (invalidnotnulloids != NULL)
    9553                 :          46 :         appendPQExpBufferChar(invalidnotnulloids, '}');
    9554                 :             : 
    9555                 :         191 :     PQclear(res);
    9556                 :             : 
    9557                 :             :     /*
    9558                 :             :      * Now get info about column defaults.  This is skipped for a data-only
    9559                 :             :      * dump, as it is only needed for table schemas.
    9560                 :             :      */
    9561   [ +  +  +  + ]:         191 :     if (dopt->dumpSchema && tbloids->len > 1)
    9562                 :             :     {
    9563                 :             :         AttrDefInfo *attrdefs;
    9564                 :             :         int         numDefaults;
    9565                 :          62 :         TableInfo  *tbinfo = NULL;
    9566                 :             : 
    9567                 :          62 :         pg_log_info("finding table default expressions");
    9568                 :             : 
    9569                 :          62 :         appendPQExpBufferChar(tbloids, '}');
    9570                 :             : 
    9571                 :          62 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9572                 :             :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9573                 :             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9574                 :             :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9575                 :             :                           "ORDER BY a.adrelid, a.adnum",
    9576                 :             :                           tbloids->data);
    9577                 :             : 
    9578                 :          62 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9579                 :             : 
    9580                 :          62 :         numDefaults = PQntuples(res);
    9581                 :          62 :         attrdefs = pg_malloc_array(AttrDefInfo, numDefaults);
    9582                 :             : 
    9583                 :          62 :         curtblindx = -1;
    9584         [ +  + ]:        1329 :         for (int j = 0; j < numDefaults; j++)
    9585                 :             :         {
    9586                 :        1267 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9587                 :        1267 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9588                 :        1267 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9589                 :        1267 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9590                 :        1267 :             char       *adsrc = PQgetvalue(res, j, 4);
    9591                 :             : 
    9592                 :             :             /*
    9593                 :             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9594                 :             :              * OID order.
    9595                 :             :              */
    9596   [ +  +  +  + ]:        1267 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9597                 :             :             {
    9598         [ +  - ]:       20961 :                 while (++curtblindx < numTables)
    9599                 :             :                 {
    9600                 :       20961 :                     tbinfo = &tblinfo[curtblindx];
    9601         [ +  + ]:       20961 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9602                 :         951 :                         break;
    9603                 :             :                 }
    9604         [ -  + ]:         951 :                 if (curtblindx >= numTables)
    9605                 :           0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9606                 :             :             }
    9607                 :             : 
    9608   [ +  -  -  + ]:        1267 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9609                 :           0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9610                 :             :                          adnum, tbinfo->dobj.name);
    9611                 :             : 
    9612                 :             :             /*
    9613                 :             :              * dropped columns shouldn't have defaults, but just in case,
    9614                 :             :              * ignore 'em
    9615                 :             :              */
    9616         [ -  + ]:        1267 :             if (tbinfo->attisdropped[adnum - 1])
    9617                 :           0 :                 continue;
    9618                 :             : 
    9619                 :        1267 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9620                 :        1267 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9621                 :        1267 :             attrdefs[j].dobj.catId.oid = adoid;
    9622                 :        1267 :             AssignDumpId(&attrdefs[j].dobj);
    9623                 :        1267 :             attrdefs[j].adtable = tbinfo;
    9624                 :        1267 :             attrdefs[j].adnum = adnum;
    9625                 :        1267 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9626                 :             : 
    9627                 :        1267 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9628                 :        1267 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9629                 :             : 
    9630                 :        1267 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9631                 :             : 
    9632                 :             :             /*
    9633                 :             :              * Figure out whether the default/generation expression should be
    9634                 :             :              * dumped as part of the main CREATE TABLE (or similar) command or
    9635                 :             :              * as a separate ALTER TABLE (or similar) command. The preference
    9636                 :             :              * is to put it into the CREATE command, but in some cases that's
    9637                 :             :              * not possible.
    9638                 :             :              */
    9639         [ +  + ]:        1267 :             if (tbinfo->attgenerated[adnum - 1])
    9640                 :             :             {
    9641                 :             :                 /*
    9642                 :             :                  * Column generation expressions cannot be dumped separately,
    9643                 :             :                  * because there is no syntax for it.  By setting separate to
    9644                 :             :                  * false here we prevent the "default" from being processed as
    9645                 :             :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9646                 :             :                  * it as not to be dumped at all, if possible (that is, if it
    9647                 :             :                  * can be inherited from a parent).
    9648                 :             :                  */
    9649                 :         722 :                 attrdefs[j].separate = false;
    9650                 :             :             }
    9651         [ +  + ]:         545 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9652                 :             :             {
    9653                 :             :                 /*
    9654                 :             :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9655                 :             :                  * TABLE commands.
    9656                 :             :                  */
    9657                 :          34 :                 attrdefs[j].separate = true;
    9658                 :             :             }
    9659         [ +  + ]:         511 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9660                 :             :             {
    9661                 :             :                 /* column will be suppressed, print default separately */
    9662                 :           4 :                 attrdefs[j].separate = true;
    9663                 :             :             }
    9664                 :             :             else
    9665                 :             :             {
    9666                 :         507 :                 attrdefs[j].separate = false;
    9667                 :             :             }
    9668                 :             : 
    9669         [ +  + ]:        1267 :             if (!attrdefs[j].separate)
    9670                 :             :             {
    9671                 :             :                 /*
    9672                 :             :                  * Mark the default as needing to appear before the table, so
    9673                 :             :                  * that any dependencies it has must be emitted before the
    9674                 :             :                  * CREATE TABLE.  If this is not possible, we'll change to
    9675                 :             :                  * "separate" mode while sorting dependencies.
    9676                 :             :                  */
    9677                 :        1229 :                 addObjectDependency(&tbinfo->dobj,
    9678                 :        1229 :                                     attrdefs[j].dobj.dumpId);
    9679                 :             :             }
    9680                 :             : 
    9681                 :        1267 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9682                 :             :         }
    9683                 :             : 
    9684                 :          62 :         PQclear(res);
    9685                 :             :     }
    9686                 :             : 
    9687                 :             :     /*
    9688                 :             :      * Get info about NOT NULL NOT VALID constraints.  This is skipped for a
    9689                 :             :      * data-only dump, as it is only needed for table schemas.
    9690                 :             :      */
    9691   [ +  +  +  + ]:         191 :     if (dopt->dumpSchema && invalidnotnulloids)
    9692                 :             :     {
    9693                 :             :         ConstraintInfo *constrs;
    9694                 :             :         int         numConstrs;
    9695                 :             :         int         i_tableoid;
    9696                 :             :         int         i_oid;
    9697                 :             :         int         i_conrelid;
    9698                 :             :         int         i_conname;
    9699                 :             :         int         i_consrc;
    9700                 :             :         int         i_conislocal;
    9701                 :             : 
    9702                 :          39 :         pg_log_info("finding invalid not-null constraints");
    9703                 :             : 
    9704                 :          39 :         resetPQExpBuffer(q);
    9705                 :          39 :         appendPQExpBuffer(q,
    9706                 :             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9707                 :             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9708                 :             :                           "conislocal, convalidated "
    9709                 :             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(conoid)\n"
    9710                 :             :                           "JOIN pg_catalog.pg_constraint c ON (src.conoid = c.oid)\n"
    9711                 :             :                           "ORDER BY c.conrelid, c.conname",
    9712                 :          39 :                           invalidnotnulloids->data);
    9713                 :             : 
    9714                 :          39 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9715                 :             : 
    9716                 :          39 :         numConstrs = PQntuples(res);
    9717                 :          39 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9718                 :             : 
    9719                 :          39 :         i_tableoid = PQfnumber(res, "tableoid");
    9720                 :          39 :         i_oid = PQfnumber(res, "oid");
    9721                 :          39 :         i_conrelid = PQfnumber(res, "conrelid");
    9722                 :          39 :         i_conname = PQfnumber(res, "conname");
    9723                 :          39 :         i_consrc = PQfnumber(res, "consrc");
    9724                 :          39 :         i_conislocal = PQfnumber(res, "conislocal");
    9725                 :             : 
    9726                 :             :         /* As above, this loop iterates once per table, not once per row */
    9727                 :          39 :         curtblindx = -1;
    9728         [ +  + ]:         108 :         for (int j = 0; j < numConstrs;)
    9729                 :             :         {
    9730                 :          69 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9731                 :          69 :             TableInfo  *tbinfo = NULL;
    9732                 :             :             int         numcons;
    9733                 :             : 
    9734                 :             :             /* Count rows for this table */
    9735         [ +  + ]:          69 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9736         [ +  - ]:          30 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9737                 :          30 :                     break;
    9738                 :             : 
    9739                 :             :             /*
    9740                 :             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9741                 :             :              * OID order.
    9742                 :             :              */
    9743         [ +  - ]:       14309 :             while (++curtblindx < numTables)
    9744                 :             :             {
    9745                 :       14309 :                 tbinfo = &tblinfo[curtblindx];
    9746         [ +  + ]:       14309 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9747                 :          69 :                     break;
    9748                 :             :             }
    9749         [ -  + ]:          69 :             if (curtblindx >= numTables)
    9750                 :           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9751                 :             : 
    9752         [ +  + ]:         138 :             for (int c = 0; c < numcons; c++, j++)
    9753                 :             :             {
    9754                 :          69 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9755                 :          69 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9756                 :          69 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9757                 :          69 :                 AssignDumpId(&constrs[j].dobj);
    9758                 :          69 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9759                 :          69 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9760                 :          69 :                 constrs[j].contable = tbinfo;
    9761                 :          69 :                 constrs[j].condomain = NULL;
    9762                 :          69 :                 constrs[j].contype = 'n';
    9763                 :          69 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9764                 :          69 :                 constrs[j].confrelid = InvalidOid;
    9765                 :          69 :                 constrs[j].conindex = 0;
    9766                 :          69 :                 constrs[j].condeferrable = false;
    9767                 :          69 :                 constrs[j].condeferred = false;
    9768                 :          69 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9769                 :             : 
    9770                 :             :                 /*
    9771                 :             :                  * All invalid not-null constraints must be dumped separately,
    9772                 :             :                  * because CREATE TABLE would not create them as invalid, and
    9773                 :             :                  * also because they must be created after potentially
    9774                 :             :                  * violating data has been loaded.
    9775                 :             :                  */
    9776                 :          69 :                 constrs[j].separate = true;
    9777                 :             : 
    9778                 :          69 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9779                 :             :             }
    9780                 :             :         }
    9781                 :          39 :         PQclear(res);
    9782                 :             :     }
    9783                 :             : 
    9784                 :             :     /*
    9785                 :             :      * Get info about table CHECK constraints.  This is skipped for a
    9786                 :             :      * data-only dump, as it is only needed for table schemas.
    9787                 :             :      */
    9788   [ +  +  +  + ]:         191 :     if (dopt->dumpSchema && checkoids->len > 2)
    9789                 :             :     {
    9790                 :             :         ConstraintInfo *constrs;
    9791                 :             :         int         numConstrs;
    9792                 :             :         int         i_tableoid;
    9793                 :             :         int         i_oid;
    9794                 :             :         int         i_conrelid;
    9795                 :             :         int         i_conname;
    9796                 :             :         int         i_consrc;
    9797                 :             :         int         i_conislocal;
    9798                 :             :         int         i_convalidated;
    9799                 :             : 
    9800                 :          63 :         pg_log_info("finding table check constraints");
    9801                 :             : 
    9802                 :          63 :         resetPQExpBuffer(q);
    9803                 :          63 :         appendPQExpBuffer(q,
    9804                 :             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9805                 :             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9806                 :             :                           "conislocal, convalidated "
    9807                 :             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9808                 :             :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9809                 :             :                           "WHERE contype = 'c' "
    9810                 :             :                           "ORDER BY c.conrelid, c.conname",
    9811                 :             :                           checkoids->data);
    9812                 :             : 
    9813                 :          63 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9814                 :             : 
    9815                 :          63 :         numConstrs = PQntuples(res);
    9816                 :          63 :         constrs = pg_malloc_array(ConstraintInfo, numConstrs);
    9817                 :             : 
    9818                 :          63 :         i_tableoid = PQfnumber(res, "tableoid");
    9819                 :          63 :         i_oid = PQfnumber(res, "oid");
    9820                 :          63 :         i_conrelid = PQfnumber(res, "conrelid");
    9821                 :          63 :         i_conname = PQfnumber(res, "conname");
    9822                 :          63 :         i_consrc = PQfnumber(res, "consrc");
    9823                 :          63 :         i_conislocal = PQfnumber(res, "conislocal");
    9824                 :          63 :         i_convalidated = PQfnumber(res, "convalidated");
    9825                 :             : 
    9826                 :             :         /* As above, this loop iterates once per table, not once per row */
    9827                 :          63 :         curtblindx = -1;
    9828         [ +  + ]:         556 :         for (int j = 0; j < numConstrs;)
    9829                 :             :         {
    9830                 :         493 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9831                 :         493 :             TableInfo  *tbinfo = NULL;
    9832                 :             :             int         numcons;
    9833                 :             : 
    9834                 :             :             /* Count rows for this table */
    9835         [ +  + ]:         632 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9836         [ +  + ]:         569 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9837                 :         430 :                     break;
    9838                 :             : 
    9839                 :             :             /*
    9840                 :             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9841                 :             :              * OID order.
    9842                 :             :              */
    9843         [ +  - ]:       20236 :             while (++curtblindx < numTables)
    9844                 :             :             {
    9845                 :       20236 :                 tbinfo = &tblinfo[curtblindx];
    9846         [ +  + ]:       20236 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9847                 :         493 :                     break;
    9848                 :             :             }
    9849         [ -  + ]:         493 :             if (curtblindx >= numTables)
    9850                 :           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9851                 :             : 
    9852         [ -  + ]:         493 :             if (numcons != tbinfo->ncheck)
    9853                 :             :             {
    9854                 :           0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    9855                 :             :                                       "expected %d check constraints on table \"%s\" but found %d",
    9856                 :             :                                       tbinfo->ncheck),
    9857                 :             :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
    9858                 :           0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
    9859                 :           0 :                 exit_nicely(1);
    9860                 :             :             }
    9861                 :             : 
    9862                 :         493 :             tbinfo->checkexprs = constrs + j;
    9863                 :             : 
    9864         [ +  + ]:        1125 :             for (int c = 0; c < numcons; c++, j++)
    9865                 :             :             {
    9866                 :         632 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
    9867                 :             : 
    9868                 :         632 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9869                 :         632 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9870                 :         632 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9871                 :         632 :                 AssignDumpId(&constrs[j].dobj);
    9872                 :         632 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9873                 :         632 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9874                 :         632 :                 constrs[j].contable = tbinfo;
    9875                 :         632 :                 constrs[j].condomain = NULL;
    9876                 :         632 :                 constrs[j].contype = 'c';
    9877                 :         632 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9878                 :         632 :                 constrs[j].confrelid = InvalidOid;
    9879                 :         632 :                 constrs[j].conindex = 0;
    9880                 :         632 :                 constrs[j].condeferrable = false;
    9881                 :         632 :                 constrs[j].condeferred = false;
    9882                 :         632 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9883                 :             : 
    9884                 :             :                 /*
    9885                 :             :                  * An unvalidated constraint needs to be dumped separately, so
    9886                 :             :                  * that potentially-violating existing data is loaded before
    9887                 :             :                  * the constraint.
    9888                 :             :                  */
    9889                 :         632 :                 constrs[j].separate = !validated;
    9890                 :             : 
    9891                 :         632 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9892                 :             : 
    9893                 :             :                 /*
    9894                 :             :                  * Mark the constraint as needing to appear before the table
    9895                 :             :                  * --- this is so that any other dependencies of the
    9896                 :             :                  * constraint will be emitted before we try to create the
    9897                 :             :                  * table.  If the constraint is to be dumped separately, it
    9898                 :             :                  * will be dumped after data is loaded anyway, so don't do it.
    9899                 :             :                  * (There's an automatic dependency in the opposite direction
    9900                 :             :                  * anyway, so don't need to add one manually here.)
    9901                 :             :                  */
    9902         [ +  + ]:         632 :                 if (!constrs[j].separate)
    9903                 :         567 :                     addObjectDependency(&tbinfo->dobj,
    9904                 :         567 :                                         constrs[j].dobj.dumpId);
    9905                 :             : 
    9906                 :             :                 /*
    9907                 :             :                  * We will detect later whether the constraint must be split
    9908                 :             :                  * out from the table definition.
    9909                 :             :                  */
    9910                 :             :             }
    9911                 :             :         }
    9912                 :             : 
    9913                 :          63 :         PQclear(res);
    9914                 :             :     }
    9915                 :             : 
    9916                 :         191 :     destroyPQExpBuffer(q);
    9917                 :         191 :     destroyPQExpBuffer(tbloids);
    9918                 :         191 :     destroyPQExpBuffer(checkoids);
    9919                 :         191 : }
    9920                 :             : 
    9921                 :             : /*
    9922                 :             :  * Based on the getTableAttrs query's row corresponding to one column, set
    9923                 :             :  * the name and flags to handle a not-null constraint for that column in
    9924                 :             :  * the tbinfo struct.
    9925                 :             :  *
    9926                 :             :  * Result row 'r' is for tbinfo's attribute 'j'.
    9927                 :             :  *
    9928                 :             :  * There are four possibilities:
    9929                 :             :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
    9930                 :             :  *    (the constraint name) remains NULL.
    9931                 :             :  * 2) The column has a constraint with no name (this is the case when
    9932                 :             :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
    9933                 :             :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
    9934                 :             :  * 3) The column has an invalid not-null constraint.  This must be treated
    9935                 :             :  *    as a separate object (because it must be created after the table data
    9936                 :             :  *    is loaded).  So we add its OID to invalidnotnulloids for processing
    9937                 :             :  *    elsewhere and do nothing further with it here.  We distinguish this
    9938                 :             :  *    case because the "notnull_invalidoid" column has been set to a non-NULL
    9939                 :             :  *    value, which is the constraint OID.  Valid constraints have a null OID.
    9940                 :             :  * 4) The column has a constraint with a known name; in that case
    9941                 :             :  *    notnull_constrs carries that name and dumpTableSchema will print
    9942                 :             :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
    9943                 :             :  *    (table_column_not_null) and there's no comment on the constraint,
    9944                 :             :  *    there's no need to print that name in the dump, so notnull_constrs
    9945                 :             :  *    is set to the empty string and it behaves as case 2.
    9946                 :             :  *
    9947                 :             :  * In a child table that inherits from a parent already containing NOT NULL
    9948                 :             :  * constraints and the columns in the child don't have their own NOT NULL
    9949                 :             :  * declarations, we suppress printing constraints in the child: the
    9950                 :             :  * constraints are acquired at the point where the child is attached to the
    9951                 :             :  * parent.  This is tracked in ->notnull_islocal; for servers pre-18 this is
    9952                 :             :  * set not here but in flagInhAttrs.  That flag is also used when the
    9953                 :             :  * constraint was validated in a child but all its parent have it as NOT
    9954                 :             :  * VALID.
    9955                 :             :  *
    9956                 :             :  * Any of these constraints might have the NO INHERIT bit.  If so we set
    9957                 :             :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
    9958                 :             :  *
    9959                 :             :  * In case 4 above, the name comparison is a bit of a hack; it actually fails
    9960                 :             :  * to do the right thing in all but the trivial case.  However, the downside
    9961                 :             :  * of getting it wrong is simply that the name is printed rather than
    9962                 :             :  * suppressed, so it's not a big deal.
    9963                 :             :  *
    9964                 :             :  * invalidnotnulloids is expected to be given as NULL; if any invalid not-null
    9965                 :             :  * constraints are found, it is initialized and filled with the array of
    9966                 :             :  * OIDs of such constraints, for later processing.
    9967                 :             :  */
    9968                 :             : static void
    9969                 :       26559 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
    9970                 :             :                       TableInfo *tbinfo, int j,
    9971                 :             :                       int i_notnull_name,
    9972                 :             :                       int i_notnull_comment,
    9973                 :             :                       int i_notnull_invalidoid,
    9974                 :             :                       int i_notnull_noinherit,
    9975                 :             :                       int i_notnull_islocal,
    9976                 :             :                       PQExpBuffer *invalidnotnulloids)
    9977                 :             : {
    9978                 :       26559 :     DumpOptions *dopt = fout->dopt;
    9979                 :             : 
    9980                 :             :     /*
    9981                 :             :      * If this not-null constraint is not valid, list its OID in
    9982                 :             :      * invalidnotnulloids and do nothing further.  It'll be processed
    9983                 :             :      * elsewhere later.
    9984                 :             :      *
    9985                 :             :      * Because invalid not-null constraints are rare, we don't want to malloc
    9986                 :             :      * invalidnotnulloids until we're sure we're going it need it, which
    9987                 :             :      * happens here.
    9988                 :             :      */
    9989         [ +  + ]:       26559 :     if (!PQgetisnull(res, r, i_notnull_invalidoid))
    9990                 :             :     {
    9991                 :          76 :         char       *constroid = PQgetvalue(res, r, i_notnull_invalidoid);
    9992                 :             : 
    9993         [ +  + ]:          76 :         if (*invalidnotnulloids == NULL)
    9994                 :             :         {
    9995                 :          46 :             *invalidnotnulloids = createPQExpBuffer();
    9996                 :          46 :             appendPQExpBufferChar(*invalidnotnulloids, '{');
    9997                 :          46 :             appendPQExpBufferStr(*invalidnotnulloids, constroid);
    9998                 :             :         }
    9999                 :             :         else
   10000                 :          30 :             appendPQExpBuffer(*invalidnotnulloids, ",%s", constroid);
   10001                 :             : 
   10002                 :             :         /*
   10003                 :             :          * Track when a parent constraint is invalid for the cases where a
   10004                 :             :          * child constraint has been validated independenly.
   10005                 :             :          */
   10006                 :          76 :         tbinfo->notnull_invalid[j] = true;
   10007                 :             : 
   10008                 :             :         /* nothing else to do */
   10009                 :          76 :         tbinfo->notnull_constrs[j] = NULL;
   10010                 :          76 :         return;
   10011                 :             :     }
   10012                 :             : 
   10013                 :             :     /*
   10014                 :             :      * notnull_noinh is straight from the query result. notnull_islocal also,
   10015                 :             :      * though flagInhAttrs may change that one later.
   10016                 :             :      */
   10017                 :       26483 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
   10018                 :       26483 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
   10019                 :       26483 :     tbinfo->notnull_invalid[j] = false;
   10020                 :             : 
   10021                 :             :     /*
   10022                 :             :      * Determine a constraint name to use.  If the column is not marked not-
   10023                 :             :      * null, we set NULL which cues ... to do nothing.  An empty string says
   10024                 :             :      * to print an unnamed NOT NULL, and anything else is a constraint name to
   10025                 :             :      * use.
   10026                 :             :      */
   10027         [ -  + ]:       26483 :     if (fout->remoteVersion < 180000)
   10028                 :             :     {
   10029                 :             :         /*
   10030                 :             :          * < 18 doesn't have not-null names, so an unnamed constraint is
   10031                 :             :          * sufficient.
   10032                 :             :          */
   10033         [ #  # ]:           0 :         if (PQgetisnull(res, r, i_notnull_name))
   10034                 :           0 :             tbinfo->notnull_constrs[j] = NULL;
   10035                 :             :         else
   10036                 :           0 :             tbinfo->notnull_constrs[j] = "";
   10037                 :             :     }
   10038                 :             :     else
   10039                 :             :     {
   10040         [ +  + ]:       26483 :         if (PQgetisnull(res, r, i_notnull_name))
   10041                 :       23512 :             tbinfo->notnull_constrs[j] = NULL;
   10042                 :             :         else
   10043                 :             :         {
   10044                 :             :             /*
   10045                 :             :              * In binary upgrade of inheritance child tables, must have a
   10046                 :             :              * constraint name that we can UPDATE later; same if there's a
   10047                 :             :              * comment on the constraint.
   10048                 :             :              */
   10049         [ +  + ]:        2971 :             if ((dopt->binary_upgrade &&
   10050         [ +  + ]:         373 :                  !tbinfo->ispartition &&
   10051   [ +  +  +  + ]:        3235 :                  !tbinfo->notnull_islocal[j]) ||
   10052                 :        2950 :                 !PQgetisnull(res, r, i_notnull_comment))
   10053                 :             :             {
   10054                 :          70 :                 tbinfo->notnull_constrs[j] =
   10055                 :          70 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
   10056                 :             :             }
   10057                 :             :             else
   10058                 :             :             {
   10059                 :             :                 char       *default_name;
   10060                 :             : 
   10061                 :             :                 /* XXX should match ChooseConstraintName better */
   10062                 :        2901 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
   10063                 :        2901 :                                         tbinfo->attnames[j]);
   10064         [ +  + ]:        2901 :                 if (strcmp(default_name,
   10065                 :        2901 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
   10066                 :        1937 :                     tbinfo->notnull_constrs[j] = "";
   10067                 :             :                 else
   10068                 :             :                 {
   10069                 :         964 :                     tbinfo->notnull_constrs[j] =
   10070                 :         964 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
   10071                 :             :                 }
   10072                 :        2901 :                 pfree(default_name);
   10073                 :             :             }
   10074                 :             :         }
   10075                 :             :     }
   10076                 :             : }
   10077                 :             : 
   10078                 :             : /*
   10079                 :             :  * Test whether a column should be printed as part of table's CREATE TABLE.
   10080                 :             :  * Column number is zero-based.
   10081                 :             :  *
   10082                 :             :  * Normally this is always true, but it's false for dropped columns, as well
   10083                 :             :  * as those that were inherited without any local definition.  (If we print
   10084                 :             :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
   10085                 :             :  * For partitions, it's always true, because we want the partitions to be
   10086                 :             :  * created independently and ATTACH PARTITION used afterwards.
   10087                 :             :  *
   10088                 :             :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
   10089                 :             :  * attisdropped state later, so as to keep control of the physical column
   10090                 :             :  * order.
   10091                 :             :  *
   10092                 :             :  * This function exists because there are scattered nonobvious places that
   10093                 :             :  * must be kept in sync with this decision.
   10094                 :             :  */
   10095                 :             : bool
   10096                 :       42930 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
   10097                 :             : {
   10098         [ +  + ]:       42930 :     if (dopt->binary_upgrade)
   10099                 :        6618 :         return true;
   10100         [ +  + ]:       36312 :     if (tbinfo->attisdropped[colno])
   10101                 :         738 :         return false;
   10102   [ +  +  +  + ]:       35574 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
   10103                 :             : }
   10104                 :             : 
   10105                 :             : 
   10106                 :             : /*
   10107                 :             :  * getTSParsers:
   10108                 :             :  *    get information about all text search parsers in the system catalogs
   10109                 :             :  */
   10110                 :             : void
   10111                 :         191 : getTSParsers(Archive *fout)
   10112                 :             : {
   10113                 :             :     PGresult   *res;
   10114                 :             :     int         ntups;
   10115                 :             :     int         i;
   10116                 :             :     PQExpBuffer query;
   10117                 :             :     TSParserInfo *prsinfo;
   10118                 :             :     int         i_tableoid;
   10119                 :             :     int         i_oid;
   10120                 :             :     int         i_prsname;
   10121                 :             :     int         i_prsnamespace;
   10122                 :             :     int         i_prsstart;
   10123                 :             :     int         i_prstoken;
   10124                 :             :     int         i_prsend;
   10125                 :             :     int         i_prsheadline;
   10126                 :             :     int         i_prslextype;
   10127                 :             : 
   10128                 :         191 :     query = createPQExpBuffer();
   10129                 :             : 
   10130                 :             :     /*
   10131                 :             :      * find all text search objects, including builtin ones; we filter out
   10132                 :             :      * system-defined objects at dump-out time.
   10133                 :             :      */
   10134                 :             : 
   10135                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
   10136                 :             :                          "prsstart::oid, prstoken::oid, "
   10137                 :             :                          "prsend::oid, prsheadline::oid, prslextype::oid "
   10138                 :             :                          "FROM pg_ts_parser");
   10139                 :             : 
   10140                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10141                 :             : 
   10142                 :         191 :     ntups = PQntuples(res);
   10143                 :             : 
   10144                 :         191 :     prsinfo = pg_malloc_array(TSParserInfo, ntups);
   10145                 :             : 
   10146                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
   10147                 :         191 :     i_oid = PQfnumber(res, "oid");
   10148                 :         191 :     i_prsname = PQfnumber(res, "prsname");
   10149                 :         191 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
   10150                 :         191 :     i_prsstart = PQfnumber(res, "prsstart");
   10151                 :         191 :     i_prstoken = PQfnumber(res, "prstoken");
   10152                 :         191 :     i_prsend = PQfnumber(res, "prsend");
   10153                 :         191 :     i_prsheadline = PQfnumber(res, "prsheadline");
   10154                 :         191 :     i_prslextype = PQfnumber(res, "prslextype");
   10155                 :             : 
   10156         [ +  + ]:         430 :     for (i = 0; i < ntups; i++)
   10157                 :             :     {
   10158                 :         239 :         prsinfo[i].dobj.objType = DO_TSPARSER;
   10159                 :         239 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10160                 :         239 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10161                 :         239 :         AssignDumpId(&prsinfo[i].dobj);
   10162                 :         239 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
   10163                 :         478 :         prsinfo[i].dobj.namespace =
   10164                 :         239 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
   10165                 :         239 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
   10166                 :         239 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
   10167                 :         239 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
   10168                 :         239 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
   10169                 :         239 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
   10170                 :             : 
   10171                 :             :         /* Decide whether we want to dump it */
   10172                 :         239 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
   10173                 :             :     }
   10174                 :             : 
   10175                 :         191 :     PQclear(res);
   10176                 :             : 
   10177                 :         191 :     destroyPQExpBuffer(query);
   10178                 :         191 : }
   10179                 :             : 
   10180                 :             : /*
   10181                 :             :  * getTSDictionaries:
   10182                 :             :  *    get information about all text search dictionaries in the system catalogs
   10183                 :             :  */
   10184                 :             : void
   10185                 :         191 : getTSDictionaries(Archive *fout)
   10186                 :             : {
   10187                 :             :     PGresult   *res;
   10188                 :             :     int         ntups;
   10189                 :             :     int         i;
   10190                 :             :     PQExpBuffer query;
   10191                 :             :     TSDictInfo *dictinfo;
   10192                 :             :     int         i_tableoid;
   10193                 :             :     int         i_oid;
   10194                 :             :     int         i_dictname;
   10195                 :             :     int         i_dictnamespace;
   10196                 :             :     int         i_dictowner;
   10197                 :             :     int         i_dicttemplate;
   10198                 :             :     int         i_dictinitoption;
   10199                 :             : 
   10200                 :         191 :     query = createPQExpBuffer();
   10201                 :             : 
   10202                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
   10203                 :             :                          "dictnamespace, dictowner, "
   10204                 :             :                          "dicttemplate, dictinitoption "
   10205                 :             :                          "FROM pg_ts_dict");
   10206                 :             : 
   10207                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10208                 :             : 
   10209                 :         191 :     ntups = PQntuples(res);
   10210                 :             : 
   10211                 :         191 :     dictinfo = pg_malloc_array(TSDictInfo, ntups);
   10212                 :             : 
   10213                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
   10214                 :         191 :     i_oid = PQfnumber(res, "oid");
   10215                 :         191 :     i_dictname = PQfnumber(res, "dictname");
   10216                 :         191 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
   10217                 :         191 :     i_dictowner = PQfnumber(res, "dictowner");
   10218                 :         191 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
   10219                 :         191 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
   10220                 :             : 
   10221         [ +  + ]:        6414 :     for (i = 0; i < ntups; i++)
   10222                 :             :     {
   10223                 :        6223 :         dictinfo[i].dobj.objType = DO_TSDICT;
   10224                 :        6223 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10225                 :        6223 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10226                 :        6223 :         AssignDumpId(&dictinfo[i].dobj);
   10227                 :        6223 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
   10228                 :       12446 :         dictinfo[i].dobj.namespace =
   10229                 :        6223 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
   10230                 :        6223 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
   10231                 :        6223 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
   10232         [ +  + ]:        6223 :         if (PQgetisnull(res, i, i_dictinitoption))
   10233                 :         239 :             dictinfo[i].dictinitoption = NULL;
   10234                 :             :         else
   10235                 :        5984 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
   10236                 :             : 
   10237                 :             :         /* Decide whether we want to dump it */
   10238                 :        6223 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
   10239                 :             :     }
   10240                 :             : 
   10241                 :         191 :     PQclear(res);
   10242                 :             : 
   10243                 :         191 :     destroyPQExpBuffer(query);
   10244                 :         191 : }
   10245                 :             : 
   10246                 :             : /*
   10247                 :             :  * getTSTemplates:
   10248                 :             :  *    get information about all text search templates in the system catalogs
   10249                 :             :  */
   10250                 :             : void
   10251                 :         191 : getTSTemplates(Archive *fout)
   10252                 :             : {
   10253                 :             :     PGresult   *res;
   10254                 :             :     int         ntups;
   10255                 :             :     int         i;
   10256                 :             :     PQExpBuffer query;
   10257                 :             :     TSTemplateInfo *tmplinfo;
   10258                 :             :     int         i_tableoid;
   10259                 :             :     int         i_oid;
   10260                 :             :     int         i_tmplname;
   10261                 :             :     int         i_tmplnamespace;
   10262                 :             :     int         i_tmplinit;
   10263                 :             :     int         i_tmpllexize;
   10264                 :             : 
   10265                 :         191 :     query = createPQExpBuffer();
   10266                 :             : 
   10267                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
   10268                 :             :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
   10269                 :             :                          "FROM pg_ts_template");
   10270                 :             : 
   10271                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10272                 :             : 
   10273                 :         191 :     ntups = PQntuples(res);
   10274                 :             : 
   10275                 :         191 :     tmplinfo = pg_malloc_array(TSTemplateInfo, ntups);
   10276                 :             : 
   10277                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
   10278                 :         191 :     i_oid = PQfnumber(res, "oid");
   10279                 :         191 :     i_tmplname = PQfnumber(res, "tmplname");
   10280                 :         191 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
   10281                 :         191 :     i_tmplinit = PQfnumber(res, "tmplinit");
   10282                 :         191 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
   10283                 :             : 
   10284         [ +  + ]:        1194 :     for (i = 0; i < ntups; i++)
   10285                 :             :     {
   10286                 :        1003 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
   10287                 :        1003 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10288                 :        1003 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10289                 :        1003 :         AssignDumpId(&tmplinfo[i].dobj);
   10290                 :        1003 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
   10291                 :        2006 :         tmplinfo[i].dobj.namespace =
   10292                 :        1003 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
   10293                 :        1003 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
   10294                 :        1003 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
   10295                 :             : 
   10296                 :             :         /* Decide whether we want to dump it */
   10297                 :        1003 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
   10298                 :             :     }
   10299                 :             : 
   10300                 :         191 :     PQclear(res);
   10301                 :             : 
   10302                 :         191 :     destroyPQExpBuffer(query);
   10303                 :         191 : }
   10304                 :             : 
   10305                 :             : /*
   10306                 :             :  * getTSConfigurations:
   10307                 :             :  *    get information about all text search configurations
   10308                 :             :  */
   10309                 :             : void
   10310                 :         191 : getTSConfigurations(Archive *fout)
   10311                 :             : {
   10312                 :             :     PGresult   *res;
   10313                 :             :     int         ntups;
   10314                 :             :     int         i;
   10315                 :             :     PQExpBuffer query;
   10316                 :             :     TSConfigInfo *cfginfo;
   10317                 :             :     int         i_tableoid;
   10318                 :             :     int         i_oid;
   10319                 :             :     int         i_cfgname;
   10320                 :             :     int         i_cfgnamespace;
   10321                 :             :     int         i_cfgowner;
   10322                 :             :     int         i_cfgparser;
   10323                 :             : 
   10324                 :         191 :     query = createPQExpBuffer();
   10325                 :             : 
   10326                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
   10327                 :             :                          "cfgnamespace, cfgowner, cfgparser "
   10328                 :             :                          "FROM pg_ts_config");
   10329                 :             : 
   10330                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10331                 :             : 
   10332                 :         191 :     ntups = PQntuples(res);
   10333                 :             : 
   10334                 :         191 :     cfginfo = pg_malloc_array(TSConfigInfo, ntups);
   10335                 :             : 
   10336                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
   10337                 :         191 :     i_oid = PQfnumber(res, "oid");
   10338                 :         191 :     i_cfgname = PQfnumber(res, "cfgname");
   10339                 :         191 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
   10340                 :         191 :     i_cfgowner = PQfnumber(res, "cfgowner");
   10341                 :         191 :     i_cfgparser = PQfnumber(res, "cfgparser");
   10342                 :             : 
   10343         [ +  + ]:        6379 :     for (i = 0; i < ntups; i++)
   10344                 :             :     {
   10345                 :        6188 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
   10346                 :        6188 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10347                 :        6188 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10348                 :        6188 :         AssignDumpId(&cfginfo[i].dobj);
   10349                 :        6188 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
   10350                 :       12376 :         cfginfo[i].dobj.namespace =
   10351                 :        6188 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
   10352                 :        6188 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
   10353                 :        6188 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
   10354                 :             : 
   10355                 :             :         /* Decide whether we want to dump it */
   10356                 :        6188 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
   10357                 :             :     }
   10358                 :             : 
   10359                 :         191 :     PQclear(res);
   10360                 :             : 
   10361                 :         191 :     destroyPQExpBuffer(query);
   10362                 :         191 : }
   10363                 :             : 
   10364                 :             : /*
   10365                 :             :  * getForeignDataWrappers:
   10366                 :             :  *    get information about all foreign-data wrappers in the system catalogs
   10367                 :             :  */
   10368                 :             : void
   10369                 :         191 : getForeignDataWrappers(Archive *fout)
   10370                 :             : {
   10371                 :             :     PGresult   *res;
   10372                 :             :     int         ntups;
   10373                 :             :     int         i;
   10374                 :             :     PQExpBuffer query;
   10375                 :             :     FdwInfo    *fdwinfo;
   10376                 :             :     int         i_tableoid;
   10377                 :             :     int         i_oid;
   10378                 :             :     int         i_fdwname;
   10379                 :             :     int         i_fdwowner;
   10380                 :             :     int         i_fdwhandler;
   10381                 :             :     int         i_fdwvalidator;
   10382                 :             :     int         i_fdwconnection;
   10383                 :             :     int         i_fdwacl;
   10384                 :             :     int         i_acldefault;
   10385                 :             :     int         i_fdwoptions;
   10386                 :             : 
   10387                 :         191 :     query = createPQExpBuffer();
   10388                 :             : 
   10389                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
   10390                 :             :                          "fdwowner, "
   10391                 :             :                          "fdwhandler::pg_catalog.regproc, "
   10392                 :             :                          "fdwvalidator::pg_catalog.regproc, ");
   10393                 :             : 
   10394         [ +  - ]:         191 :     if (fout->remoteVersion >= 190000)
   10395                 :         191 :         appendPQExpBufferStr(query, "fdwconnection::pg_catalog.regproc, ");
   10396                 :             :     else
   10397                 :           0 :         appendPQExpBufferStr(query, "'-' AS fdwconnection, ");
   10398                 :             : 
   10399                 :         191 :     appendPQExpBufferStr(query,
   10400                 :             :                          "fdwacl, "
   10401                 :             :                          "acldefault('F', fdwowner) AS acldefault, "
   10402                 :             :                          "array_to_string(ARRAY("
   10403                 :             :                          "SELECT quote_ident(option_name) || ' ' || "
   10404                 :             :                          "quote_literal(option_value) "
   10405                 :             :                          "FROM pg_options_to_table(fdwoptions) "
   10406                 :             :                          "ORDER BY option_name"
   10407                 :             :                          "), E',\n    ') AS fdwoptions "
   10408                 :             :                          "FROM pg_foreign_data_wrapper");
   10409                 :             : 
   10410                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10411                 :             : 
   10412                 :         191 :     ntups = PQntuples(res);
   10413                 :             : 
   10414                 :         191 :     fdwinfo = pg_malloc_array(FdwInfo, ntups);
   10415                 :             : 
   10416                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
   10417                 :         191 :     i_oid = PQfnumber(res, "oid");
   10418                 :         191 :     i_fdwname = PQfnumber(res, "fdwname");
   10419                 :         191 :     i_fdwowner = PQfnumber(res, "fdwowner");
   10420                 :         191 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
   10421                 :         191 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
   10422                 :         191 :     i_fdwconnection = PQfnumber(res, "fdwconnection");
   10423                 :         191 :     i_fdwacl = PQfnumber(res, "fdwacl");
   10424                 :         191 :     i_acldefault = PQfnumber(res, "acldefault");
   10425                 :         191 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
   10426                 :             : 
   10427         [ +  + ]:         265 :     for (i = 0; i < ntups; i++)
   10428                 :             :     {
   10429                 :          74 :         fdwinfo[i].dobj.objType = DO_FDW;
   10430                 :          74 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10431                 :          74 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10432                 :          74 :         AssignDumpId(&fdwinfo[i].dobj);
   10433                 :          74 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
   10434                 :          74 :         fdwinfo[i].dobj.namespace = NULL;
   10435                 :          74 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
   10436                 :          74 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10437                 :          74 :         fdwinfo[i].dacl.privtype = 0;
   10438                 :          74 :         fdwinfo[i].dacl.initprivs = NULL;
   10439                 :          74 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
   10440                 :          74 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
   10441                 :          74 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
   10442                 :          74 :         fdwinfo[i].fdwconnection = pg_strdup(PQgetvalue(res, i, i_fdwconnection));
   10443                 :          74 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
   10444                 :             : 
   10445                 :             :         /* Decide whether we want to dump it */
   10446                 :          74 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
   10447                 :             : 
   10448                 :             :         /* Mark whether FDW has an ACL */
   10449         [ +  + ]:          74 :         if (!PQgetisnull(res, i, i_fdwacl))
   10450                 :          48 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10451                 :             :     }
   10452                 :             : 
   10453                 :         191 :     PQclear(res);
   10454                 :             : 
   10455                 :         191 :     destroyPQExpBuffer(query);
   10456                 :         191 : }
   10457                 :             : 
   10458                 :             : /*
   10459                 :             :  * getForeignServers:
   10460                 :             :  *    get information about all foreign servers in the system catalogs
   10461                 :             :  */
   10462                 :             : void
   10463                 :         191 : getForeignServers(Archive *fout)
   10464                 :             : {
   10465                 :             :     PGresult   *res;
   10466                 :             :     int         ntups;
   10467                 :             :     int         i;
   10468                 :             :     PQExpBuffer query;
   10469                 :             :     ForeignServerInfo *srvinfo;
   10470                 :             :     int         i_tableoid;
   10471                 :             :     int         i_oid;
   10472                 :             :     int         i_srvname;
   10473                 :             :     int         i_srvowner;
   10474                 :             :     int         i_srvfdw;
   10475                 :             :     int         i_srvtype;
   10476                 :             :     int         i_srvversion;
   10477                 :             :     int         i_srvacl;
   10478                 :             :     int         i_acldefault;
   10479                 :             :     int         i_srvoptions;
   10480                 :             : 
   10481                 :         191 :     query = createPQExpBuffer();
   10482                 :             : 
   10483                 :         191 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
   10484                 :             :                          "srvowner, "
   10485                 :             :                          "srvfdw, srvtype, srvversion, srvacl, "
   10486                 :             :                          "acldefault('S', srvowner) AS acldefault, "
   10487                 :             :                          "array_to_string(ARRAY("
   10488                 :             :                          "SELECT quote_ident(option_name) || ' ' || "
   10489                 :             :                          "quote_literal(option_value) "
   10490                 :             :                          "FROM pg_options_to_table(srvoptions) "
   10491                 :             :                          "ORDER BY option_name"
   10492                 :             :                          "), E',\n    ') AS srvoptions "
   10493                 :             :                          "FROM pg_foreign_server");
   10494                 :             : 
   10495                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10496                 :             : 
   10497                 :         191 :     ntups = PQntuples(res);
   10498                 :             : 
   10499                 :         191 :     srvinfo = pg_malloc_array(ForeignServerInfo, ntups);
   10500                 :             : 
   10501                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
   10502                 :         191 :     i_oid = PQfnumber(res, "oid");
   10503                 :         191 :     i_srvname = PQfnumber(res, "srvname");
   10504                 :         191 :     i_srvowner = PQfnumber(res, "srvowner");
   10505                 :         191 :     i_srvfdw = PQfnumber(res, "srvfdw");
   10506                 :         191 :     i_srvtype = PQfnumber(res, "srvtype");
   10507                 :         191 :     i_srvversion = PQfnumber(res, "srvversion");
   10508                 :         191 :     i_srvacl = PQfnumber(res, "srvacl");
   10509                 :         191 :     i_acldefault = PQfnumber(res, "acldefault");
   10510                 :         191 :     i_srvoptions = PQfnumber(res, "srvoptions");
   10511                 :             : 
   10512         [ +  + ]:         269 :     for (i = 0; i < ntups; i++)
   10513                 :             :     {
   10514                 :          78 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
   10515                 :          78 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10516                 :          78 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10517                 :          78 :         AssignDumpId(&srvinfo[i].dobj);
   10518                 :          78 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
   10519                 :          78 :         srvinfo[i].dobj.namespace = NULL;
   10520                 :          78 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
   10521                 :          78 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10522                 :          78 :         srvinfo[i].dacl.privtype = 0;
   10523                 :          78 :         srvinfo[i].dacl.initprivs = NULL;
   10524                 :          78 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
   10525                 :          78 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
   10526                 :          78 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
   10527                 :          78 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
   10528                 :          78 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
   10529                 :             : 
   10530                 :             :         /* Decide whether we want to dump it */
   10531                 :          78 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
   10532                 :             : 
   10533                 :             :         /* Servers have user mappings */
   10534                 :          78 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
   10535                 :             : 
   10536                 :             :         /* Mark whether server has an ACL */
   10537         [ +  + ]:          78 :         if (!PQgetisnull(res, i, i_srvacl))
   10538                 :          48 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10539                 :             :     }
   10540                 :             : 
   10541                 :         191 :     PQclear(res);
   10542                 :             : 
   10543                 :         191 :     destroyPQExpBuffer(query);
   10544                 :         191 : }
   10545                 :             : 
   10546                 :             : /*
   10547                 :             :  * getDefaultACLs:
   10548                 :             :  *    get information about all default ACL information in the system catalogs
   10549                 :             :  */
   10550                 :             : void
   10551                 :         191 : getDefaultACLs(Archive *fout)
   10552                 :             : {
   10553                 :         191 :     DumpOptions *dopt = fout->dopt;
   10554                 :             :     DefaultACLInfo *daclinfo;
   10555                 :             :     PQExpBuffer query;
   10556                 :             :     PGresult   *res;
   10557                 :             :     int         i_oid;
   10558                 :             :     int         i_tableoid;
   10559                 :             :     int         i_defaclrole;
   10560                 :             :     int         i_defaclnamespace;
   10561                 :             :     int         i_defaclobjtype;
   10562                 :             :     int         i_defaclacl;
   10563                 :             :     int         i_acldefault;
   10564                 :             :     int         i,
   10565                 :             :                 ntups;
   10566                 :             : 
   10567                 :         191 :     query = createPQExpBuffer();
   10568                 :             : 
   10569                 :             :     /*
   10570                 :             :      * Global entries (with defaclnamespace=0) replace the hard-wired default
   10571                 :             :      * ACL for their object type.  We should dump them as deltas from the
   10572                 :             :      * default ACL, since that will be used as a starting point for
   10573                 :             :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
   10574                 :             :      * non-global entries can only add privileges not revoke them.  We must
   10575                 :             :      * dump those as-is (i.e., as deltas from an empty ACL).
   10576                 :             :      *
   10577                 :             :      * We can use defaclobjtype as the object type for acldefault(), except
   10578                 :             :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
   10579                 :             :      * 's'.
   10580                 :             :      */
   10581                 :         191 :     appendPQExpBufferStr(query,
   10582                 :             :                          "SELECT oid, tableoid, "
   10583                 :             :                          "defaclrole, "
   10584                 :             :                          "defaclnamespace, "
   10585                 :             :                          "defaclobjtype, "
   10586                 :             :                          "defaclacl, "
   10587                 :             :                          "CASE WHEN defaclnamespace = 0 THEN "
   10588                 :             :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
   10589                 :             :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
   10590                 :             :                          "defaclrole) ELSE '{}' END AS acldefault "
   10591                 :             :                          "FROM pg_default_acl");
   10592                 :             : 
   10593                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10594                 :             : 
   10595                 :         191 :     ntups = PQntuples(res);
   10596                 :             : 
   10597                 :         191 :     daclinfo = pg_malloc_array(DefaultACLInfo, ntups);
   10598                 :             : 
   10599                 :         191 :     i_oid = PQfnumber(res, "oid");
   10600                 :         191 :     i_tableoid = PQfnumber(res, "tableoid");
   10601                 :         191 :     i_defaclrole = PQfnumber(res, "defaclrole");
   10602                 :         191 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10603                 :         191 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10604                 :         191 :     i_defaclacl = PQfnumber(res, "defaclacl");
   10605                 :         191 :     i_acldefault = PQfnumber(res, "acldefault");
   10606                 :             : 
   10607         [ +  + ]:         397 :     for (i = 0; i < ntups; i++)
   10608                 :             :     {
   10609                 :         206 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10610                 :             : 
   10611                 :         206 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10612                 :         206 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10613                 :         206 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10614                 :         206 :         AssignDumpId(&daclinfo[i].dobj);
   10615                 :             :         /* cheesy ... is it worth coming up with a better object name? */
   10616                 :         206 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10617                 :             : 
   10618         [ +  + ]:         206 :         if (nspid != InvalidOid)
   10619                 :          96 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10620                 :             :         else
   10621                 :         110 :             daclinfo[i].dobj.namespace = NULL;
   10622                 :             : 
   10623                 :         206 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10624                 :         206 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10625                 :         206 :         daclinfo[i].dacl.privtype = 0;
   10626                 :         206 :         daclinfo[i].dacl.initprivs = NULL;
   10627                 :         206 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10628                 :         206 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10629                 :             : 
   10630                 :             :         /* Default ACLs are ACLs, of course */
   10631                 :         206 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10632                 :             : 
   10633                 :             :         /* Decide whether we want to dump it */
   10634                 :         206 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10635                 :             :     }
   10636                 :             : 
   10637                 :         191 :     PQclear(res);
   10638                 :             : 
   10639                 :         191 :     destroyPQExpBuffer(query);
   10640                 :         191 : }
   10641                 :             : 
   10642                 :             : /*
   10643                 :             :  * getRoleName -- look up the name of a role, given its OID
   10644                 :             :  *
   10645                 :             :  * In current usage, we don't expect failures, so error out for a bad OID.
   10646                 :             :  */
   10647                 :             : static const char *
   10648                 :      628063 : getRoleName(const char *roleoid_str)
   10649                 :             : {
   10650                 :      628063 :     Oid         roleoid = atooid(roleoid_str);
   10651                 :             : 
   10652                 :             :     /*
   10653                 :             :      * Do binary search to find the appropriate item.
   10654                 :             :      */
   10655         [ +  - ]:      628063 :     if (nrolenames > 0)
   10656                 :             :     {
   10657                 :      628063 :         RoleNameItem *low = &rolenames[0];
   10658                 :      628063 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10659                 :             : 
   10660         [ +  - ]:     2512433 :         while (low <= high)
   10661                 :             :         {
   10662                 :     2512433 :             RoleNameItem *middle = low + (high - low) / 2;
   10663                 :             : 
   10664         [ +  + ]:     2512433 :             if (roleoid < middle->roleoid)
   10665                 :     1882984 :                 high = middle - 1;
   10666         [ +  + ]:      629449 :             else if (roleoid > middle->roleoid)
   10667                 :        1386 :                 low = middle + 1;
   10668                 :             :             else
   10669                 :      628063 :                 return middle->rolename; /* found a match */
   10670                 :             :         }
   10671                 :             :     }
   10672                 :             : 
   10673                 :           0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10674                 :             :     return NULL;                /* keep compiler quiet */
   10675                 :             : }
   10676                 :             : 
   10677                 :             : /*
   10678                 :             :  * collectRoleNames --
   10679                 :             :  *
   10680                 :             :  * Construct a table of all known roles.
   10681                 :             :  * The table is sorted by OID for speed in lookup.
   10682                 :             :  */
   10683                 :             : static void
   10684                 :         192 : collectRoleNames(Archive *fout)
   10685                 :             : {
   10686                 :             :     PGresult   *res;
   10687                 :             :     const char *query;
   10688                 :             :     int         i;
   10689                 :             : 
   10690                 :         192 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10691                 :             : 
   10692                 :         192 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10693                 :             : 
   10694                 :         192 :     nrolenames = PQntuples(res);
   10695                 :             : 
   10696                 :         192 :     rolenames = pg_malloc_array(RoleNameItem, nrolenames);
   10697                 :             : 
   10698         [ +  + ]:        3702 :     for (i = 0; i < nrolenames; i++)
   10699                 :             :     {
   10700                 :        3510 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10701                 :        3510 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10702                 :             :     }
   10703                 :             : 
   10704                 :         192 :     PQclear(res);
   10705                 :         192 : }
   10706                 :             : 
   10707                 :             : /*
   10708                 :             :  * getAdditionalACLs
   10709                 :             :  *
   10710                 :             :  * We have now created all the DumpableObjects, and collected the ACL data
   10711                 :             :  * that appears in the directly-associated catalog entries.  However, there's
   10712                 :             :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10713                 :             :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10714                 :             :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10715                 :             :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10716                 :             :  * information into the relevant DumpableObjects.
   10717                 :             :  */
   10718                 :             : static void
   10719                 :         189 : getAdditionalACLs(Archive *fout)
   10720                 :             : {
   10721                 :         189 :     PQExpBuffer query = createPQExpBuffer();
   10722                 :             :     PGresult   *res;
   10723                 :             :     int         ntups,
   10724                 :             :                 i;
   10725                 :             : 
   10726                 :             :     /* Check for per-column ACLs */
   10727                 :         189 :     appendPQExpBufferStr(query,
   10728                 :             :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10729                 :             :                          "WHERE attacl IS NOT NULL");
   10730                 :             : 
   10731                 :         189 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10732                 :             : 
   10733                 :         189 :     ntups = PQntuples(res);
   10734         [ +  + ]:         557 :     for (i = 0; i < ntups; i++)
   10735                 :             :     {
   10736                 :         368 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10737                 :             :         TableInfo  *tblinfo;
   10738                 :             : 
   10739                 :         368 :         tblinfo = findTableByOid(relid);
   10740                 :             :         /* OK to ignore tables we haven't got a DumpableObject for */
   10741         [ +  - ]:         368 :         if (tblinfo)
   10742                 :             :         {
   10743                 :         368 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10744                 :         368 :             tblinfo->hascolumnACLs = true;
   10745                 :             :         }
   10746                 :             :     }
   10747                 :         189 :     PQclear(res);
   10748                 :             : 
   10749                 :             :     /* Fetch initial-privileges data */
   10750                 :         189 :     printfPQExpBuffer(query,
   10751                 :             :                       "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10752                 :             :                       "FROM pg_init_privs");
   10753                 :             : 
   10754                 :         189 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10755                 :             : 
   10756                 :         189 :     ntups = PQntuples(res);
   10757         [ +  + ]:       48314 :     for (i = 0; i < ntups; i++)
   10758                 :             :     {
   10759                 :       48125 :         Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10760                 :       48125 :         Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10761                 :       48125 :         int         objsubid = atoi(PQgetvalue(res, i, 2));
   10762                 :       48125 :         char        privtype = *(PQgetvalue(res, i, 3));
   10763                 :       48125 :         char       *initprivs = PQgetvalue(res, i, 4);
   10764                 :             :         CatalogId   objId;
   10765                 :             :         DumpableObject *dobj;
   10766                 :             : 
   10767                 :       48125 :         objId.tableoid = classoid;
   10768                 :       48125 :         objId.oid = objoid;
   10769                 :       48125 :         dobj = findObjectByCatalogId(objId);
   10770                 :             :         /* OK to ignore entries we haven't got a DumpableObject for */
   10771         [ +  + ]:       48125 :         if (dobj)
   10772                 :             :         {
   10773                 :             :             /* Cope with sub-object initprivs */
   10774         [ +  + ]:       35131 :             if (objsubid != 0)
   10775                 :             :             {
   10776         [ +  - ]:        4560 :                 if (dobj->objType == DO_TABLE)
   10777                 :             :                 {
   10778                 :             :                     /* For a column initprivs, set the table's ACL flags */
   10779                 :        4560 :                     dobj->components |= DUMP_COMPONENT_ACL;
   10780                 :        4560 :                     ((TableInfo *) dobj)->hascolumnACLs = true;
   10781                 :             :                 }
   10782                 :             :                 else
   10783                 :           0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10784                 :             :                                    classoid, objoid, objsubid);
   10785                 :        4745 :                 continue;
   10786                 :             :             }
   10787                 :             : 
   10788                 :             :             /*
   10789                 :             :              * We ignore any pg_init_privs.initprivs entry for the public
   10790                 :             :              * schema, as explained in getNamespaces().
   10791                 :             :              */
   10792         [ +  + ]:       30571 :             if (dobj->objType == DO_NAMESPACE &&
   10793         [ +  + ]:         563 :                 strcmp(dobj->name, "public") == 0)
   10794                 :         185 :                 continue;
   10795                 :             : 
   10796                 :             :             /* Else it had better be of a type we think has ACLs */
   10797         [ +  + ]:       30386 :             if (dobj->objType == DO_NAMESPACE ||
   10798         [ +  + ]:       30008 :                 dobj->objType == DO_TYPE ||
   10799         [ +  + ]:       29984 :                 dobj->objType == DO_FUNC ||
   10800         [ +  + ]:       29889 :                 dobj->objType == DO_AGG ||
   10801         [ -  + ]:       29865 :                 dobj->objType == DO_TABLE ||
   10802         [ #  # ]:           0 :                 dobj->objType == DO_PROCLANG ||
   10803         [ #  # ]:           0 :                 dobj->objType == DO_FDW ||
   10804         [ #  # ]:           0 :                 dobj->objType == DO_FOREIGN_SERVER)
   10805                 :       30386 :             {
   10806                 :       30386 :                 DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10807                 :             : 
   10808                 :       30386 :                 daobj->dacl.privtype = privtype;
   10809                 :       30386 :                 daobj->dacl.initprivs = pstrdup(initprivs);
   10810                 :             :             }
   10811                 :             :             else
   10812                 :           0 :                 pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10813                 :             :                                classoid, objoid, objsubid);
   10814                 :             :         }
   10815                 :             :     }
   10816                 :         189 :     PQclear(res);
   10817                 :             : 
   10818                 :         189 :     destroyPQExpBuffer(query);
   10819                 :         189 : }
   10820                 :             : 
   10821                 :             : /*
   10822                 :             :  * dumpCommentExtended --
   10823                 :             :  *
   10824                 :             :  * This routine is used to dump any comments associated with the
   10825                 :             :  * object handed to this routine. The routine takes the object type
   10826                 :             :  * and object name (ready to print, except for schema decoration), plus
   10827                 :             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10828                 :             :  * plus catalog ID and subid which are the lookup key for pg_description,
   10829                 :             :  * plus the dump ID for the object (for setting a dependency).
   10830                 :             :  * If a matching pg_description entry is found, it is dumped.
   10831                 :             :  *
   10832                 :             :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10833                 :             :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10834                 :             :  * but it doesn't seem worth complicating the API for all callers to make
   10835                 :             :  * it cleaner.
   10836                 :             :  *
   10837                 :             :  * Note: although this routine takes a dumpId for dependency purposes,
   10838                 :             :  * that purpose is just to mark the dependency in the emitted dump file
   10839                 :             :  * for possible future use by pg_restore.  We do NOT use it for determining
   10840                 :             :  * ordering of the comment in the dump file, because this routine is called
   10841                 :             :  * after dependency sorting occurs.  This routine should be called just after
   10842                 :             :  * calling ArchiveEntry() for the specified object.
   10843                 :             :  */
   10844                 :             : static void
   10845                 :        6643 : dumpCommentExtended(Archive *fout, const char *type,
   10846                 :             :                     const char *name, const char *namespace,
   10847                 :             :                     const char *owner, CatalogId catalogId,
   10848                 :             :                     int subid, DumpId dumpId,
   10849                 :             :                     const char *initdb_comment)
   10850                 :             : {
   10851                 :        6643 :     DumpOptions *dopt = fout->dopt;
   10852                 :             :     CommentItem *comments;
   10853                 :             :     int         ncomments;
   10854                 :             : 
   10855                 :             :     /* do nothing, if --no-comments is supplied */
   10856         [ -  + ]:        6643 :     if (dopt->no_comments)
   10857                 :           0 :         return;
   10858                 :             : 
   10859                 :             :     /* Comments are schema not data ... except LO comments are data */
   10860         [ +  + ]:        6643 :     if (strcmp(type, "LARGE OBJECT") != 0)
   10861                 :             :     {
   10862         [ -  + ]:        6583 :         if (!dopt->dumpSchema)
   10863                 :           0 :             return;
   10864                 :             :     }
   10865                 :             :     else
   10866                 :             :     {
   10867                 :             :         /* We do dump LO comments in binary-upgrade mode */
   10868   [ +  +  -  + ]:          60 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   10869                 :           0 :             return;
   10870                 :             :     }
   10871                 :             : 
   10872                 :             :     /* Search for comments associated with catalogId, using table */
   10873                 :        6643 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   10874                 :             :                              &comments);
   10875                 :             : 
   10876                 :             :     /* Is there one matching the subid? */
   10877         [ +  + ]:        6643 :     while (ncomments > 0)
   10878                 :             :     {
   10879         [ +  - ]:        6596 :         if (comments->objsubid == subid)
   10880                 :        6596 :             break;
   10881                 :           0 :         comments++;
   10882                 :           0 :         ncomments--;
   10883                 :             :     }
   10884                 :             : 
   10885         [ +  + ]:        6643 :     if (initdb_comment != NULL)
   10886                 :             :     {
   10887                 :             :         static CommentItem empty_comment = {.descr = ""};
   10888                 :             : 
   10889                 :             :         /*
   10890                 :             :          * initdb creates this object with a comment.  Skip dumping the
   10891                 :             :          * initdb-provided comment, which would complicate matters for
   10892                 :             :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   10893                 :             :          * comment, replicate that.
   10894                 :             :          */
   10895         [ +  + ]:         117 :         if (ncomments == 0)
   10896                 :             :         {
   10897                 :           4 :             comments = &empty_comment;
   10898                 :           4 :             ncomments = 1;
   10899                 :             :         }
   10900         [ +  - ]:         113 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   10901                 :         113 :             ncomments = 0;
   10902                 :             :     }
   10903                 :             : 
   10904                 :             :     /* If a comment exists, build COMMENT ON statement */
   10905         [ +  + ]:        6643 :     if (ncomments > 0)
   10906                 :             :     {
   10907                 :        6487 :         PQExpBuffer query = createPQExpBuffer();
   10908                 :        6487 :         PQExpBuffer tag = createPQExpBuffer();
   10909                 :             : 
   10910                 :        6487 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   10911   [ +  +  +  - ]:        6487 :         if (namespace && *namespace)
   10912                 :        6300 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   10913                 :        6487 :         appendPQExpBuffer(query, "%s IS ", name);
   10914                 :        6487 :         appendStringLiteralAH(query, comments->descr, fout);
   10915                 :        6487 :         appendPQExpBufferStr(query, ";\n");
   10916                 :             : 
   10917                 :        6487 :         appendPQExpBuffer(tag, "%s %s", type, name);
   10918                 :             : 
   10919                 :             :         /*
   10920                 :             :          * We mark comments as SECTION_NONE because they really belong in the
   10921                 :             :          * same section as their parent, whether that is pre-data or
   10922                 :             :          * post-data.
   10923                 :             :          */
   10924                 :        6487 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10925                 :        6487 :                      ARCHIVE_OPTS(.tag = tag->data,
   10926                 :             :                                   .namespace = namespace,
   10927                 :             :                                   .owner = owner,
   10928                 :             :                                   .description = "COMMENT",
   10929                 :             :                                   .section = SECTION_NONE,
   10930                 :             :                                   .createStmt = query->data,
   10931                 :             :                                   .deps = &dumpId,
   10932                 :             :                                   .nDeps = 1));
   10933                 :             : 
   10934                 :        6487 :         destroyPQExpBuffer(query);
   10935                 :        6487 :         destroyPQExpBuffer(tag);
   10936                 :             :     }
   10937                 :             : }
   10938                 :             : 
   10939                 :             : /*
   10940                 :             :  * dumpComment --
   10941                 :             :  *
   10942                 :             :  * Typical simplification of the above function.
   10943                 :             :  */
   10944                 :             : static inline void
   10945                 :        6483 : dumpComment(Archive *fout, const char *type,
   10946                 :             :             const char *name, const char *namespace,
   10947                 :             :             const char *owner, CatalogId catalogId,
   10948                 :             :             int subid, DumpId dumpId)
   10949                 :             : {
   10950                 :        6483 :     dumpCommentExtended(fout, type, name, namespace, owner,
   10951                 :             :                         catalogId, subid, dumpId, NULL);
   10952                 :        6483 : }
   10953                 :             : 
   10954                 :             : /*
   10955                 :             :  * appendNamedArgument --
   10956                 :             :  *
   10957                 :             :  * Convenience routine for constructing parameters of the form:
   10958                 :             :  * 'paraname', 'value'::type
   10959                 :             :  */
   10960                 :             : static void
   10961                 :        5825 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   10962                 :             :                     const char *argtype, const char *argval)
   10963                 :             : {
   10964                 :        5825 :     appendPQExpBufferStr(out, ",\n\t");
   10965                 :             : 
   10966                 :        5825 :     appendStringLiteralAH(out, argname, fout);
   10967                 :        5825 :     appendPQExpBufferStr(out, ", ");
   10968                 :             : 
   10969                 :        5825 :     appendStringLiteralAH(out, argval, fout);
   10970                 :        5825 :     appendPQExpBuffer(out, "::%s", argtype);
   10971                 :        5825 : }
   10972                 :             : 
   10973                 :             : /*
   10974                 :             :  * fetchAttributeStats --
   10975                 :             :  *
   10976                 :             :  * Fetch next batch of attribute statistics for dumpRelationStats_dumper().
   10977                 :             :  */
   10978                 :             : static PGresult *
   10979                 :        1104 : fetchAttributeStats(Archive *fout)
   10980                 :             : {
   10981                 :        1104 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   10982                 :        1104 :     PQExpBuffer relids = createPQExpBuffer();
   10983                 :        1104 :     PQExpBuffer nspnames = createPQExpBuffer();
   10984                 :        1104 :     PQExpBuffer relnames = createPQExpBuffer();
   10985                 :        1104 :     int         count = 0;
   10986                 :        1104 :     PGresult   *res = NULL;
   10987                 :             :     static TocEntry *te;
   10988                 :             :     static bool restarted;
   10989                 :        1104 :     int         max_rels = MAX_ATTR_STATS_RELS;
   10990                 :             : 
   10991                 :             :     /* If we're just starting, set our TOC pointer. */
   10992         [ +  + ]:        1104 :     if (!te)
   10993                 :          65 :         te = AH->toc->next;
   10994                 :             : 
   10995                 :             :     /*
   10996                 :             :      * We can't easily avoid a second TOC scan for the tar format because it
   10997                 :             :      * writes restore.sql separately, which means we must execute the queries
   10998                 :             :      * twice.  This feels risky, but there is no known reason it should
   10999                 :             :      * generate different output than the first pass.  Even if it does, the
   11000                 :             :      * worst-case scenario is that restore.sql might have different statistics
   11001                 :             :      * data than the archive.
   11002                 :             :      */
   11003   [ +  +  +  +  :        1104 :     if (!restarted && te == AH->toc && AH->format == archTar)
                   +  + ]
   11004                 :             :     {
   11005                 :           1 :         te = AH->toc->next;
   11006                 :           1 :         restarted = true;
   11007                 :             :     }
   11008                 :             : 
   11009                 :        1104 :     appendPQExpBufferChar(relids, '{');
   11010                 :        1104 :     appendPQExpBufferChar(nspnames, '{');
   11011                 :        1104 :     appendPQExpBufferChar(relnames, '{');
   11012                 :             : 
   11013                 :             :     /*
   11014                 :             :      * Scan the TOC for the next set of relevant stats entries.  We assume
   11015                 :             :      * that statistics are dumped in the order they are listed in the TOC.
   11016                 :             :      * This is perhaps not the sturdiest assumption, so we verify it matches
   11017                 :             :      * reality in dumpRelationStats_dumper().
   11018                 :             :      */
   11019   [ +  +  +  + ]:       17285 :     for (; te != AH->toc && count < max_rels; te = te->next)
   11020                 :             :     {
   11021         [ +  + ]:       16181 :         if ((te->reqs & REQ_STATS) == 0 ||
   11022         [ +  + ]:        3650 :             strcmp(te->desc, "STATISTICS DATA") != 0)
   11023                 :       12569 :             continue;
   11024                 :             : 
   11025         [ +  - ]:        3612 :         if (fout->remoteVersion >= 190000)
   11026                 :             :         {
   11027                 :        3612 :             const RelStatsInfo *rsinfo = (const RelStatsInfo *) te->defnDumperArg;
   11028                 :             :             char        relid[32];
   11029                 :             : 
   11030                 :        3612 :             sprintf(relid, "%u", rsinfo->relid);
   11031                 :        3612 :             appendPGArray(relids, relid);
   11032                 :             :         }
   11033                 :             :         else
   11034                 :             :         {
   11035                 :           0 :             appendPGArray(nspnames, te->namespace);
   11036                 :           0 :             appendPGArray(relnames, te->tag);
   11037                 :             :         }
   11038                 :             : 
   11039                 :        3612 :         count++;
   11040                 :             :     }
   11041                 :             : 
   11042                 :        1104 :     appendPQExpBufferChar(relids, '}');
   11043                 :        1104 :     appendPQExpBufferChar(nspnames, '}');
   11044                 :        1104 :     appendPQExpBufferChar(relnames, '}');
   11045                 :             : 
   11046                 :             :     /* Execute the query for the next batch of relations. */
   11047         [ +  + ]:        1104 :     if (count > 0)
   11048                 :             :     {
   11049                 :         112 :         PQExpBuffer query = createPQExpBuffer();
   11050                 :             : 
   11051                 :         112 :         appendPQExpBufferStr(query, "EXECUTE getAttributeStats(");
   11052                 :             : 
   11053         [ +  - ]:         112 :         if (fout->remoteVersion >= 190000)
   11054                 :             :         {
   11055                 :         112 :             appendStringLiteralAH(query, relids->data, fout);
   11056                 :         112 :             appendPQExpBufferStr(query, "::pg_catalog.oid[])");
   11057                 :             :         }
   11058                 :             :         else
   11059                 :             :         {
   11060                 :           0 :             appendStringLiteralAH(query, nspnames->data, fout);
   11061                 :           0 :             appendPQExpBufferStr(query, "::pg_catalog.name[],");
   11062                 :           0 :             appendStringLiteralAH(query, relnames->data, fout);
   11063                 :           0 :             appendPQExpBufferStr(query, "::pg_catalog.name[])");
   11064                 :             :         }
   11065                 :             : 
   11066                 :         112 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11067                 :         112 :         destroyPQExpBuffer(query);
   11068                 :             :     }
   11069                 :             : 
   11070                 :        1104 :     destroyPQExpBuffer(relids);
   11071                 :        1104 :     destroyPQExpBuffer(nspnames);
   11072                 :        1104 :     destroyPQExpBuffer(relnames);
   11073                 :        1104 :     return res;
   11074                 :             : }
   11075                 :             : 
   11076                 :             : /*
   11077                 :             :  * dumpRelationStats_dumper --
   11078                 :             :  *
   11079                 :             :  * Generate command to import stats into the relation on the new database.
   11080                 :             :  * This routine is called by the Archiver when it wants the statistics to be
   11081                 :             :  * dumped.
   11082                 :             :  */
   11083                 :             : static char *
   11084                 :        3612 : dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te)
   11085                 :             : {
   11086                 :        3612 :     const RelStatsInfo *rsinfo = userArg;
   11087                 :             :     static PGresult *res;
   11088                 :             :     static int  rownum;
   11089                 :             :     PQExpBuffer query;
   11090                 :             :     PQExpBufferData out_data;
   11091                 :        3612 :     PQExpBuffer out = &out_data;
   11092                 :             :     int         i_schemaname;
   11093                 :             :     int         i_tablename;
   11094                 :             :     int         i_attname;
   11095                 :             :     int         i_inherited;
   11096                 :             :     int         i_null_frac;
   11097                 :             :     int         i_avg_width;
   11098                 :             :     int         i_n_distinct;
   11099                 :             :     int         i_most_common_vals;
   11100                 :             :     int         i_most_common_freqs;
   11101                 :             :     int         i_histogram_bounds;
   11102                 :             :     int         i_correlation;
   11103                 :             :     int         i_most_common_elems;
   11104                 :             :     int         i_most_common_elem_freqs;
   11105                 :             :     int         i_elem_count_histogram;
   11106                 :             :     int         i_range_length_histogram;
   11107                 :             :     int         i_range_empty_frac;
   11108                 :             :     int         i_range_bounds_histogram;
   11109                 :             :     static TocEntry *expected_te;
   11110                 :             : 
   11111                 :             :     /*
   11112                 :             :      * fetchAttributeStats() assumes that the statistics are dumped in the
   11113                 :             :      * order they are listed in the TOC.  We verify that here for safety.
   11114                 :             :      */
   11115         [ +  + ]:        3612 :     if (!expected_te)
   11116                 :          65 :         expected_te = ((ArchiveHandle *) fout)->toc;
   11117                 :             : 
   11118                 :        3612 :     expected_te = expected_te->next;
   11119         [ +  + ]:       14129 :     while ((expected_te->reqs & REQ_STATS) == 0 ||
   11120         [ +  + ]:        3613 :            strcmp(expected_te->desc, "STATISTICS DATA") != 0)
   11121                 :       10517 :         expected_te = expected_te->next;
   11122                 :             : 
   11123         [ -  + ]:        3612 :     if (te != expected_te)
   11124                 :           0 :         pg_fatal("statistics dumped out of order (current: %d %s %s, expected: %d %s %s)",
   11125                 :             :                  te->dumpId, te->desc, te->tag,
   11126                 :             :                  expected_te->dumpId, expected_te->desc, expected_te->tag);
   11127                 :             : 
   11128                 :        3612 :     query = createPQExpBuffer();
   11129         [ +  + ]:        3612 :     if (!fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS])
   11130                 :             :     {
   11131         [ +  - ]:          65 :         if (fout->remoteVersion >= 190000)
   11132                 :          65 :             appendPQExpBufferStr(query,
   11133                 :             :                                  "PREPARE getAttributeStats(pg_catalog.oid[]) AS\n");
   11134                 :             :         else
   11135                 :           0 :             appendPQExpBufferStr(query,
   11136                 :             :                                  "PREPARE getAttributeStats(pg_catalog.name[], pg_catalog.name[]) AS\n");
   11137                 :             : 
   11138                 :          65 :         appendPQExpBufferStr(query,
   11139                 :             :                              "SELECT s.schemaname, s.tablename, s.attname, s.inherited, "
   11140                 :             :                              "s.null_frac, s.avg_width, s.n_distinct, "
   11141                 :             :                              "s.most_common_vals, s.most_common_freqs, "
   11142                 :             :                              "s.histogram_bounds, s.correlation, "
   11143                 :             :                              "s.most_common_elems, s.most_common_elem_freqs, "
   11144                 :             :                              "s.elem_count_histogram, ");
   11145                 :             : 
   11146         [ +  - ]:          65 :         if (fout->remoteVersion >= 170000)
   11147                 :          65 :             appendPQExpBufferStr(query,
   11148                 :             :                                  "s.range_length_histogram, "
   11149                 :             :                                  "s.range_empty_frac, "
   11150                 :             :                                  "s.range_bounds_histogram ");
   11151                 :             :         else
   11152                 :           0 :             appendPQExpBufferStr(query,
   11153                 :             :                                  "NULL AS range_length_histogram,"
   11154                 :             :                                  "NULL AS range_empty_frac,"
   11155                 :             :                                  "NULL AS range_bounds_histogram ");
   11156                 :             : 
   11157                 :             :         /*
   11158                 :             :          * The results must be in the order of the relations supplied in the
   11159                 :             :          * parameters to ensure we remain in sync as we walk through the TOC.
   11160                 :             :          *
   11161                 :             :          * For versions before 19, the redundant filter clause on s.tablename
   11162                 :             :          * = ANY(...) seems sufficient to convince the planner to use
   11163                 :             :          * pg_class_relname_nsp_index, which avoids a full scan of pg_stats.
   11164                 :             :          * In newer versions, pg_stats returns the table OIDs, eliminating the
   11165                 :             :          * need for that hack.
   11166                 :             :          */
   11167         [ +  - ]:          65 :         if (fout->remoteVersion >= 190000)
   11168                 :          65 :             appendPQExpBufferStr(query,
   11169                 :             :                                  "FROM pg_catalog.pg_stats s "
   11170                 :             :                                  "JOIN unnest($1) WITH ORDINALITY AS u (tableid, ord) "
   11171                 :             :                                  "ON s.tableid = u.tableid "
   11172                 :             :                                  "ORDER BY u.ord, s.attname, s.inherited");
   11173                 :             :         else
   11174                 :           0 :             appendPQExpBufferStr(query,
   11175                 :             :                                  "FROM pg_catalog.pg_stats s "
   11176                 :             :                                  "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) "
   11177                 :             :                                  "ON s.schemaname = u.schemaname "
   11178                 :             :                                  "AND s.tablename = u.tablename "
   11179                 :             :                                  "WHERE s.tablename = ANY($2) "
   11180                 :             :                                  "ORDER BY u.ord, s.attname, s.inherited");
   11181                 :             : 
   11182                 :          65 :         ExecuteSqlStatement(fout, query->data);
   11183                 :             : 
   11184                 :          65 :         fout->is_prepared[PREPQUERY_GETATTRIBUTESTATS] = true;
   11185                 :          65 :         resetPQExpBuffer(query);
   11186                 :             :     }
   11187                 :             : 
   11188                 :        3612 :     initPQExpBuffer(out);
   11189                 :             : 
   11190                 :             :     /* restore relation stats */
   11191                 :        3612 :     appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   11192                 :        3612 :     appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11193                 :             :                       fout->remoteVersion);
   11194                 :        3612 :     appendPQExpBufferStr(out, "\t'schemaname', ");
   11195                 :        3612 :     appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11196                 :        3612 :     appendPQExpBufferStr(out, ",\n");
   11197                 :        3612 :     appendPQExpBufferStr(out, "\t'relname', ");
   11198                 :        3612 :     appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11199                 :        3612 :     appendPQExpBufferStr(out, ",\n");
   11200                 :        3612 :     appendPQExpBuffer(out, "\t'relpages', '%d'::integer,\n", rsinfo->relpages);
   11201                 :             : 
   11202                 :             :     /*
   11203                 :             :      * Before v14, a reltuples value of 0 was ambiguous: it could either mean
   11204                 :             :      * the relation is empty, or it could mean that it hadn't yet been
   11205                 :             :      * vacuumed or analyzed.  (Newer versions use -1 for the latter case.)
   11206                 :             :      * This ambiguity allegedly can cause the planner to choose inefficient
   11207                 :             :      * plans after restoring to v18 or newer.  To deal with this, let's just
   11208                 :             :      * set reltuples to -1 in that case.
   11209                 :             :      */
   11210   [ -  +  -  - ]:        3612 :     if (fout->remoteVersion < 140000 && strcmp("0", rsinfo->reltuples) == 0)
   11211                 :           0 :         appendPQExpBufferStr(out, "\t'reltuples', '-1'::real,\n");
   11212                 :             :     else
   11213                 :        3612 :         appendPQExpBuffer(out, "\t'reltuples', '%s'::real,\n", rsinfo->reltuples);
   11214                 :             : 
   11215                 :        3612 :     appendPQExpBuffer(out, "\t'relallvisible', '%d'::integer",
   11216                 :        3612 :                       rsinfo->relallvisible);
   11217                 :             : 
   11218         [ +  - ]:        3612 :     if (fout->remoteVersion >= 180000)
   11219                 :        3612 :         appendPQExpBuffer(out, ",\n\t'relallfrozen', '%d'::integer", rsinfo->relallfrozen);
   11220                 :             : 
   11221                 :        3612 :     appendPQExpBufferStr(out, "\n);\n");
   11222                 :             : 
   11223                 :             :     /* Fetch the next batch of attribute statistics if needed. */
   11224         [ +  + ]:        3612 :     if (rownum >= PQntuples(res))
   11225                 :             :     {
   11226                 :        1104 :         PQclear(res);
   11227                 :        1104 :         res = fetchAttributeStats(fout);
   11228                 :        1104 :         rownum = 0;
   11229                 :             :     }
   11230                 :             : 
   11231                 :        3612 :     i_schemaname = PQfnumber(res, "schemaname");
   11232                 :        3612 :     i_tablename = PQfnumber(res, "tablename");
   11233                 :        3612 :     i_attname = PQfnumber(res, "attname");
   11234                 :        3612 :     i_inherited = PQfnumber(res, "inherited");
   11235                 :        3612 :     i_null_frac = PQfnumber(res, "null_frac");
   11236                 :        3612 :     i_avg_width = PQfnumber(res, "avg_width");
   11237                 :        3612 :     i_n_distinct = PQfnumber(res, "n_distinct");
   11238                 :        3612 :     i_most_common_vals = PQfnumber(res, "most_common_vals");
   11239                 :        3612 :     i_most_common_freqs = PQfnumber(res, "most_common_freqs");
   11240                 :        3612 :     i_histogram_bounds = PQfnumber(res, "histogram_bounds");
   11241                 :        3612 :     i_correlation = PQfnumber(res, "correlation");
   11242                 :        3612 :     i_most_common_elems = PQfnumber(res, "most_common_elems");
   11243                 :        3612 :     i_most_common_elem_freqs = PQfnumber(res, "most_common_elem_freqs");
   11244                 :        3612 :     i_elem_count_histogram = PQfnumber(res, "elem_count_histogram");
   11245                 :        3612 :     i_range_length_histogram = PQfnumber(res, "range_length_histogram");
   11246                 :        3612 :     i_range_empty_frac = PQfnumber(res, "range_empty_frac");
   11247                 :        3612 :     i_range_bounds_histogram = PQfnumber(res, "range_bounds_histogram");
   11248                 :             : 
   11249                 :             :     /* restore attribute stats */
   11250         [ +  + ]:        4451 :     for (; rownum < PQntuples(res); rownum++)
   11251                 :             :     {
   11252                 :             :         const char *attname;
   11253                 :             : 
   11254                 :             :         /* Stop if the next stat row in our cache isn't for this relation. */
   11255         [ +  + ]:        3347 :         if (strcmp(te->tag, PQgetvalue(res, rownum, i_tablename)) != 0 ||
   11256         [ +  - ]:         839 :             strcmp(te->namespace, PQgetvalue(res, rownum, i_schemaname)) != 0)
   11257                 :             :             break;
   11258                 :             : 
   11259                 :         839 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   11260                 :         839 :         appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   11261                 :             :                           fout->remoteVersion);
   11262                 :         839 :         appendPQExpBufferStr(out, "\t'schemaname', ");
   11263                 :         839 :         appendStringLiteralAH(out, rsinfo->dobj.namespace->dobj.name, fout);
   11264                 :         839 :         appendPQExpBufferStr(out, ",\n\t'relname', ");
   11265                 :         839 :         appendStringLiteralAH(out, rsinfo->dobj.name, fout);
   11266                 :             : 
   11267         [ -  + ]:         839 :         if (PQgetisnull(res, rownum, i_attname))
   11268                 :           0 :             pg_fatal("unexpected null attname");
   11269                 :         839 :         attname = PQgetvalue(res, rownum, i_attname);
   11270                 :             : 
   11271                 :             :         /*
   11272                 :             :          * Indexes look up attname in indAttNames to derive attnum, all others
   11273                 :             :          * use attname directly.  We must specify attnum for indexes, since
   11274                 :             :          * their attnames are not necessarily stable across dump/reload.
   11275                 :             :          */
   11276         [ +  + ]:         839 :         if (rsinfo->nindAttNames == 0)
   11277                 :             :         {
   11278                 :         801 :             appendPQExpBufferStr(out, ",\n\t'attname', ");
   11279                 :         801 :             appendStringLiteralAH(out, attname, fout);
   11280                 :             :         }
   11281                 :             :         else
   11282                 :             :         {
   11283                 :          38 :             bool        found = false;
   11284                 :             : 
   11285         [ +  - ]:          72 :             for (int i = 0; i < rsinfo->nindAttNames; i++)
   11286                 :             :             {
   11287         [ +  + ]:          72 :                 if (strcmp(attname, rsinfo->indAttNames[i]) == 0)
   11288                 :             :                 {
   11289                 :          38 :                     appendPQExpBuffer(out, ",\n\t'attnum', '%d'::smallint",
   11290                 :             :                                       i + 1);
   11291                 :          38 :                     found = true;
   11292                 :          38 :                     break;
   11293                 :             :                 }
   11294                 :             :             }
   11295                 :             : 
   11296         [ -  + ]:          38 :             if (!found)
   11297                 :           0 :                 pg_fatal("could not find index attname \"%s\"", attname);
   11298                 :             :         }
   11299                 :             : 
   11300         [ +  - ]:         839 :         if (!PQgetisnull(res, rownum, i_inherited))
   11301                 :         839 :             appendNamedArgument(out, fout, "inherited", "boolean",
   11302                 :         839 :                                 PQgetvalue(res, rownum, i_inherited));
   11303         [ +  - ]:         839 :         if (!PQgetisnull(res, rownum, i_null_frac))
   11304                 :         839 :             appendNamedArgument(out, fout, "null_frac", "real",
   11305                 :         839 :                                 PQgetvalue(res, rownum, i_null_frac));
   11306         [ +  - ]:         839 :         if (!PQgetisnull(res, rownum, i_avg_width))
   11307                 :         839 :             appendNamedArgument(out, fout, "avg_width", "integer",
   11308                 :         839 :                                 PQgetvalue(res, rownum, i_avg_width));
   11309         [ +  - ]:         839 :         if (!PQgetisnull(res, rownum, i_n_distinct))
   11310                 :         839 :             appendNamedArgument(out, fout, "n_distinct", "real",
   11311                 :         839 :                                 PQgetvalue(res, rownum, i_n_distinct));
   11312         [ +  + ]:         839 :         if (!PQgetisnull(res, rownum, i_most_common_vals))
   11313                 :         418 :             appendNamedArgument(out, fout, "most_common_vals", "text",
   11314                 :         418 :                                 PQgetvalue(res, rownum, i_most_common_vals));
   11315         [ +  + ]:         839 :         if (!PQgetisnull(res, rownum, i_most_common_freqs))
   11316                 :         418 :             appendNamedArgument(out, fout, "most_common_freqs", "real[]",
   11317                 :         418 :                                 PQgetvalue(res, rownum, i_most_common_freqs));
   11318         [ +  + ]:         839 :         if (!PQgetisnull(res, rownum, i_histogram_bounds))
   11319                 :         535 :             appendNamedArgument(out, fout, "histogram_bounds", "text",
   11320                 :         535 :                                 PQgetvalue(res, rownum, i_histogram_bounds));
   11321         [ +  + ]:         839 :         if (!PQgetisnull(res, rownum, i_correlation))
   11322                 :         806 :             appendNamedArgument(out, fout, "correlation", "real",
   11323                 :         806 :                                 PQgetvalue(res, rownum, i_correlation));
   11324         [ +  + ]:         839 :         if (!PQgetisnull(res, rownum, i_most_common_elems))
   11325                 :           8 :             appendNamedArgument(out, fout, "most_common_elems", "text",
   11326                 :           8 :                                 PQgetvalue(res, rownum, i_most_common_elems));
   11327         [ +  + ]:         839 :         if (!PQgetisnull(res, rownum, i_most_common_elem_freqs))
   11328                 :           8 :             appendNamedArgument(out, fout, "most_common_elem_freqs", "real[]",
   11329                 :           8 :                                 PQgetvalue(res, rownum, i_most_common_elem_freqs));
   11330         [ +  + ]:         839 :         if (!PQgetisnull(res, rownum, i_elem_count_histogram))
   11331                 :           7 :             appendNamedArgument(out, fout, "elem_count_histogram", "real[]",
   11332                 :           7 :                                 PQgetvalue(res, rownum, i_elem_count_histogram));
   11333         [ +  - ]:         839 :         if (fout->remoteVersion >= 170000)
   11334                 :             :         {
   11335         [ +  + ]:         839 :             if (!PQgetisnull(res, rownum, i_range_length_histogram))
   11336                 :           3 :                 appendNamedArgument(out, fout, "range_length_histogram", "text",
   11337                 :           3 :                                     PQgetvalue(res, rownum, i_range_length_histogram));
   11338         [ +  + ]:         839 :             if (!PQgetisnull(res, rownum, i_range_empty_frac))
   11339                 :           3 :                 appendNamedArgument(out, fout, "range_empty_frac", "real",
   11340                 :           3 :                                     PQgetvalue(res, rownum, i_range_empty_frac));
   11341         [ +  + ]:         839 :             if (!PQgetisnull(res, rownum, i_range_bounds_histogram))
   11342                 :           3 :                 appendNamedArgument(out, fout, "range_bounds_histogram", "text",
   11343                 :           3 :                                     PQgetvalue(res, rownum, i_range_bounds_histogram));
   11344                 :             :         }
   11345                 :         839 :         appendPQExpBufferStr(out, "\n);\n");
   11346                 :             :     }
   11347                 :             : 
   11348                 :        3612 :     destroyPQExpBuffer(query);
   11349                 :        3612 :     return out->data;
   11350                 :             : }
   11351                 :             : 
   11352                 :             : /*
   11353                 :             :  * dumpRelationStats --
   11354                 :             :  *
   11355                 :             :  * Make an ArchiveEntry for the relation statistics.  The Archiver will take
   11356                 :             :  * care of gathering the statistics and generating the restore commands when
   11357                 :             :  * they are needed.
   11358                 :             :  */
   11359                 :             : static void
   11360                 :        3684 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   11361                 :             : {
   11362                 :        3684 :     const DumpableObject *dobj = &rsinfo->dobj;
   11363                 :             : 
   11364                 :             :     /* nothing to do if we are not dumping statistics */
   11365         [ -  + ]:        3684 :     if (!fout->dopt->dumpStatistics)
   11366                 :           0 :         return;
   11367                 :             : 
   11368                 :        3684 :     ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11369                 :        3684 :                  ARCHIVE_OPTS(.tag = dobj->name,
   11370                 :             :                               .namespace = dobj->namespace->dobj.name,
   11371                 :             :                               .description = "STATISTICS DATA",
   11372                 :             :                               .section = rsinfo->section,
   11373                 :             :                               .defnFn = dumpRelationStats_dumper,
   11374                 :             :                               .defnArg = rsinfo,
   11375                 :             :                               .deps = dobj->dependencies,
   11376                 :             :                               .nDeps = dobj->nDeps));
   11377                 :             : }
   11378                 :             : 
   11379                 :             : /*
   11380                 :             :  * dumpTableComment --
   11381                 :             :  *
   11382                 :             :  * As above, but dump comments for both the specified table (or view)
   11383                 :             :  * and its columns.
   11384                 :             :  */
   11385                 :             : static void
   11386                 :          78 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   11387                 :             :                  const char *reltypename)
   11388                 :             : {
   11389                 :          78 :     DumpOptions *dopt = fout->dopt;
   11390                 :             :     CommentItem *comments;
   11391                 :             :     int         ncomments;
   11392                 :             :     PQExpBuffer query;
   11393                 :             :     PQExpBuffer tag;
   11394                 :             : 
   11395                 :             :     /* do nothing, if --no-comments is supplied */
   11396         [ -  + ]:          78 :     if (dopt->no_comments)
   11397                 :           0 :         return;
   11398                 :             : 
   11399                 :             :     /* Comments are SCHEMA not data */
   11400         [ -  + ]:          78 :     if (!dopt->dumpSchema)
   11401                 :           0 :         return;
   11402                 :             : 
   11403                 :             :     /* Search for comments associated with relation, using table */
   11404                 :          78 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   11405                 :          78 :                              tbinfo->dobj.catId.oid,
   11406                 :             :                              &comments);
   11407                 :             : 
   11408                 :             :     /* If comments exist, build COMMENT ON statements */
   11409         [ -  + ]:          78 :     if (ncomments <= 0)
   11410                 :           0 :         return;
   11411                 :             : 
   11412                 :          78 :     query = createPQExpBuffer();
   11413                 :          78 :     tag = createPQExpBuffer();
   11414                 :             : 
   11415         [ +  + ]:         224 :     while (ncomments > 0)
   11416                 :             :     {
   11417                 :         146 :         const char *descr = comments->descr;
   11418                 :         146 :         int         objsubid = comments->objsubid;
   11419                 :             : 
   11420         [ +  + ]:         146 :         if (objsubid == 0)
   11421                 :             :         {
   11422                 :          34 :             resetPQExpBuffer(tag);
   11423                 :          34 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   11424                 :          34 :                               fmtId(tbinfo->dobj.name));
   11425                 :             : 
   11426                 :          34 :             resetPQExpBuffer(query);
   11427                 :          34 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   11428                 :          34 :                               fmtQualifiedDumpable(tbinfo));
   11429                 :          34 :             appendStringLiteralAH(query, descr, fout);
   11430                 :          34 :             appendPQExpBufferStr(query, ";\n");
   11431                 :             : 
   11432                 :          34 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11433                 :          34 :                          ARCHIVE_OPTS(.tag = tag->data,
   11434                 :             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11435                 :             :                                       .owner = tbinfo->rolname,
   11436                 :             :                                       .description = "COMMENT",
   11437                 :             :                                       .section = SECTION_NONE,
   11438                 :             :                                       .createStmt = query->data,
   11439                 :             :                                       .deps = &(tbinfo->dobj.dumpId),
   11440                 :             :                                       .nDeps = 1));
   11441                 :             :         }
   11442   [ +  -  +  - ]:         112 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   11443                 :             :         {
   11444                 :         112 :             resetPQExpBuffer(tag);
   11445                 :         112 :             appendPQExpBuffer(tag, "COLUMN %s.",
   11446                 :         112 :                               fmtId(tbinfo->dobj.name));
   11447                 :         112 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   11448                 :             : 
   11449                 :         112 :             resetPQExpBuffer(query);
   11450                 :         112 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   11451                 :         112 :                               fmtQualifiedDumpable(tbinfo));
   11452                 :         112 :             appendPQExpBuffer(query, "%s IS ",
   11453                 :         112 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   11454                 :         112 :             appendStringLiteralAH(query, descr, fout);
   11455                 :         112 :             appendPQExpBufferStr(query, ";\n");
   11456                 :             : 
   11457                 :         112 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   11458                 :         112 :                          ARCHIVE_OPTS(.tag = tag->data,
   11459                 :             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   11460                 :             :                                       .owner = tbinfo->rolname,
   11461                 :             :                                       .description = "COMMENT",
   11462                 :             :                                       .section = SECTION_NONE,
   11463                 :             :                                       .createStmt = query->data,
   11464                 :             :                                       .deps = &(tbinfo->dobj.dumpId),
   11465                 :             :                                       .nDeps = 1));
   11466                 :             :         }
   11467                 :             : 
   11468                 :         146 :         comments++;
   11469                 :         146 :         ncomments--;
   11470                 :             :     }
   11471                 :             : 
   11472                 :          78 :     destroyPQExpBuffer(query);
   11473                 :          78 :     destroyPQExpBuffer(tag);
   11474                 :             : }
   11475                 :             : 
   11476                 :             : /*
   11477                 :             :  * findComments --
   11478                 :             :  *
   11479                 :             :  * Find the comment(s), if any, associated with the given object.  All the
   11480                 :             :  * objsubid values associated with the given classoid/objoid are found with
   11481                 :             :  * one search.
   11482                 :             :  */
   11483                 :             : static int
   11484                 :        6755 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   11485                 :             : {
   11486                 :        6755 :     CommentItem *middle = NULL;
   11487                 :             :     CommentItem *low;
   11488                 :             :     CommentItem *high;
   11489                 :             :     int         nmatch;
   11490                 :             : 
   11491                 :             :     /*
   11492                 :             :      * Do binary search to find some item matching the object.
   11493                 :             :      */
   11494                 :        6755 :     low = &comments[0];
   11495                 :        6755 :     high = &comments[ncomments - 1];
   11496         [ +  + ]:       67655 :     while (low <= high)
   11497                 :             :     {
   11498                 :       67608 :         middle = low + (high - low) / 2;
   11499                 :             : 
   11500         [ +  + ]:       67608 :         if (classoid < middle->classoid)
   11501                 :        7211 :             high = middle - 1;
   11502         [ +  + ]:       60397 :         else if (classoid > middle->classoid)
   11503                 :        7309 :             low = middle + 1;
   11504         [ +  + ]:       53088 :         else if (objoid < middle->objoid)
   11505                 :       22504 :             high = middle - 1;
   11506         [ +  + ]:       30584 :         else if (objoid > middle->objoid)
   11507                 :       23876 :             low = middle + 1;
   11508                 :             :         else
   11509                 :        6708 :             break;              /* found a match */
   11510                 :             :     }
   11511                 :             : 
   11512         [ +  + ]:        6755 :     if (low > high)              /* no matches */
   11513                 :             :     {
   11514                 :          47 :         *items = NULL;
   11515                 :          47 :         return 0;
   11516                 :             :     }
   11517                 :             : 
   11518                 :             :     /*
   11519                 :             :      * Now determine how many items match the object.  The search loop
   11520                 :             :      * invariant still holds: only items between low and high inclusive could
   11521                 :             :      * match.
   11522                 :             :      */
   11523                 :        6708 :     nmatch = 1;
   11524         [ +  + ]:        6764 :     while (middle > low)
   11525                 :             :     {
   11526         [ +  + ]:        3260 :         if (classoid != middle[-1].classoid ||
   11527         [ +  + ]:        3098 :             objoid != middle[-1].objoid)
   11528                 :             :             break;
   11529                 :          56 :         middle--;
   11530                 :          56 :         nmatch++;
   11531                 :             :     }
   11532                 :             : 
   11533                 :        6708 :     *items = middle;
   11534                 :             : 
   11535                 :        6708 :     middle += nmatch;
   11536         [ +  + ]:        6720 :     while (middle <= high)
   11537                 :             :     {
   11538         [ +  + ]:        3467 :         if (classoid != middle->classoid ||
   11539         [ +  + ]:        3346 :             objoid != middle->objoid)
   11540                 :             :             break;
   11541                 :          12 :         middle++;
   11542                 :          12 :         nmatch++;
   11543                 :             :     }
   11544                 :             : 
   11545                 :        6708 :     return nmatch;
   11546                 :             : }
   11547                 :             : 
   11548                 :             : /*
   11549                 :             :  * collectComments --
   11550                 :             :  *
   11551                 :             :  * Construct a table of all comments available for database objects;
   11552                 :             :  * also set the has-comment component flag for each relevant object.
   11553                 :             :  *
   11554                 :             :  * We used to do per-object queries for the comments, but it's much faster
   11555                 :             :  * to pull them all over at once, and on most databases the memory cost
   11556                 :             :  * isn't high.
   11557                 :             :  *
   11558                 :             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   11559                 :             :  */
   11560                 :             : static void
   11561                 :         191 : collectComments(Archive *fout)
   11562                 :             : {
   11563                 :             :     PGresult   *res;
   11564                 :             :     PQExpBuffer query;
   11565                 :             :     int         i_description;
   11566                 :             :     int         i_classoid;
   11567                 :             :     int         i_objoid;
   11568                 :             :     int         i_objsubid;
   11569                 :             :     int         ntups;
   11570                 :             :     int         i;
   11571                 :             :     DumpableObject *dobj;
   11572                 :             : 
   11573                 :         191 :     query = createPQExpBuffer();
   11574                 :             : 
   11575                 :         191 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   11576                 :             :                          "FROM pg_catalog.pg_description "
   11577                 :             :                          "ORDER BY classoid, objoid, objsubid");
   11578                 :             : 
   11579                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11580                 :             : 
   11581                 :             :     /* Construct lookup table containing OIDs in numeric form */
   11582                 :             : 
   11583                 :         191 :     i_description = PQfnumber(res, "description");
   11584                 :         191 :     i_classoid = PQfnumber(res, "classoid");
   11585                 :         191 :     i_objoid = PQfnumber(res, "objoid");
   11586                 :         191 :     i_objsubid = PQfnumber(res, "objsubid");
   11587                 :             : 
   11588                 :         191 :     ntups = PQntuples(res);
   11589                 :             : 
   11590                 :         191 :     comments = pg_malloc_array(CommentItem, ntups);
   11591                 :         191 :     ncomments = 0;
   11592                 :         191 :     dobj = NULL;
   11593                 :             : 
   11594         [ +  + ]:     1030024 :     for (i = 0; i < ntups; i++)
   11595                 :             :     {
   11596                 :             :         CatalogId   objId;
   11597                 :             :         int         subid;
   11598                 :             : 
   11599                 :     1029833 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   11600                 :     1029833 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   11601                 :     1029833 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   11602                 :             : 
   11603                 :             :         /* We needn't remember comments that don't match any dumpable object */
   11604         [ +  + ]:     1029833 :         if (dobj == NULL ||
   11605         [ +  + ]:      374621 :             dobj->catId.tableoid != objId.tableoid ||
   11606         [ +  + ]:      372269 :             dobj->catId.oid != objId.oid)
   11607                 :     1029737 :             dobj = findObjectByCatalogId(objId);
   11608         [ +  + ]:     1029833 :         if (dobj == NULL)
   11609                 :      655027 :             continue;
   11610                 :             : 
   11611                 :             :         /*
   11612                 :             :          * Comments on columns of composite types are linked to the type's
   11613                 :             :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   11614                 :             :          * in the type's own DumpableObject.
   11615                 :             :          */
   11616   [ +  +  +  - ]:      374806 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   11617         [ +  + ]:         206 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   11618                 :          48 :         {
   11619                 :             :             TypeInfo   *cTypeInfo;
   11620                 :             : 
   11621                 :          48 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   11622         [ +  - ]:          48 :             if (cTypeInfo)
   11623                 :          48 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   11624                 :             :         }
   11625                 :             :         else
   11626                 :      374758 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   11627                 :             : 
   11628                 :      374806 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   11629                 :      374806 :         comments[ncomments].classoid = objId.tableoid;
   11630                 :      374806 :         comments[ncomments].objoid = objId.oid;
   11631                 :      374806 :         comments[ncomments].objsubid = subid;
   11632                 :      374806 :         ncomments++;
   11633                 :             :     }
   11634                 :             : 
   11635                 :         191 :     PQclear(res);
   11636                 :         191 :     destroyPQExpBuffer(query);
   11637                 :         191 : }
   11638                 :             : 
   11639                 :             : /*
   11640                 :             :  * dumpDumpableObject
   11641                 :             :  *
   11642                 :             :  * This routine and its subsidiaries are responsible for creating
   11643                 :             :  * ArchiveEntries (TOC objects) for each object to be dumped.
   11644                 :             :  */
   11645                 :             : static void
   11646                 :      738370 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   11647                 :             : {
   11648                 :             :     /*
   11649                 :             :      * Clear any dump-request bits for components that don't exist for this
   11650                 :             :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   11651                 :             :      * request for every kind of object.)
   11652                 :             :      */
   11653                 :      738370 :     dobj->dump &= dobj->components;
   11654                 :             : 
   11655                 :             :     /* Now, short-circuit if there's nothing to be done here. */
   11656         [ +  + ]:      738370 :     if (dobj->dump == 0)
   11657                 :      655467 :         return;
   11658                 :             : 
   11659   [ +  +  +  +  :       82903 :     switch (dobj->objType)
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  - ]
   11660                 :             :     {
   11661                 :         518 :         case DO_NAMESPACE:
   11662                 :         518 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   11663                 :         518 :             break;
   11664                 :          25 :         case DO_EXTENSION:
   11665                 :          25 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   11666                 :          25 :             break;
   11667                 :         971 :         case DO_TYPE:
   11668                 :         971 :             dumpType(fout, (const TypeInfo *) dobj);
   11669                 :         971 :             break;
   11670                 :          76 :         case DO_SHELL_TYPE:
   11671                 :          76 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   11672                 :          76 :             break;
   11673                 :        1917 :         case DO_FUNC:
   11674                 :        1917 :             dumpFunc(fout, (const FuncInfo *) dobj);
   11675                 :        1917 :             break;
   11676                 :         295 :         case DO_AGG:
   11677                 :         295 :             dumpAgg(fout, (const AggInfo *) dobj);
   11678                 :         295 :             break;
   11679                 :        2525 :         case DO_OPERATOR:
   11680                 :        2525 :             dumpOpr(fout, (const OprInfo *) dobj);
   11681                 :        2525 :             break;
   11682                 :          84 :         case DO_ACCESS_METHOD:
   11683                 :          84 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   11684                 :          84 :             break;
   11685                 :         675 :         case DO_OPCLASS:
   11686                 :         675 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   11687                 :         675 :             break;
   11688                 :         561 :         case DO_OPFAMILY:
   11689                 :         561 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   11690                 :         561 :             break;
   11691                 :        2733 :         case DO_COLLATION:
   11692                 :        2733 :             dumpCollation(fout, (const CollInfo *) dobj);
   11693                 :        2733 :             break;
   11694                 :         335 :         case DO_CONVERSION:
   11695                 :         335 :             dumpConversion(fout, (const ConvInfo *) dobj);
   11696                 :         335 :             break;
   11697                 :       34203 :         case DO_TABLE:
   11698                 :       34203 :             dumpTable(fout, (const TableInfo *) dobj);
   11699                 :       34203 :             break;
   11700                 :        1452 :         case DO_TABLE_ATTACH:
   11701                 :        1452 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   11702                 :        1452 :             break;
   11703                 :        1121 :         case DO_ATTRDEF:
   11704                 :        1121 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11705                 :        1121 :             break;
   11706                 :        2837 :         case DO_INDEX:
   11707                 :        2837 :             dumpIndex(fout, (const IndxInfo *) dobj);
   11708                 :        2837 :             break;
   11709                 :         610 :         case DO_INDEX_ATTACH:
   11710                 :         610 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11711                 :         610 :             break;
   11712                 :         183 :         case DO_STATSEXT:
   11713                 :         183 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11714                 :         183 :             dumpStatisticsExtStats(fout, (const StatsExtInfo *) dobj);
   11715                 :         183 :             break;
   11716                 :         363 :         case DO_REFRESH_MATVIEW:
   11717                 :         363 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11718                 :         363 :             break;
   11719                 :        1197 :         case DO_RULE:
   11720                 :        1197 :             dumpRule(fout, (const RuleInfo *) dobj);
   11721                 :        1197 :             break;
   11722                 :         535 :         case DO_TRIGGER:
   11723                 :         535 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   11724                 :         535 :             break;
   11725                 :          44 :         case DO_EVENT_TRIGGER:
   11726                 :          44 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11727                 :          44 :             break;
   11728                 :        2563 :         case DO_CONSTRAINT:
   11729                 :        2563 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11730                 :        2563 :             break;
   11731                 :         237 :         case DO_FK_CONSTRAINT:
   11732                 :         237 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11733                 :         237 :             break;
   11734                 :          87 :         case DO_PROCLANG:
   11735                 :          87 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11736                 :          87 :             break;
   11737                 :          69 :         case DO_CAST:
   11738                 :          69 :             dumpCast(fout, (const CastInfo *) dobj);
   11739                 :          69 :             break;
   11740                 :          44 :         case DO_TRANSFORM:
   11741                 :          44 :             dumpTransform(fout, (const TransformInfo *) dobj);
   11742                 :          44 :             break;
   11743                 :         399 :         case DO_SEQUENCE_SET:
   11744                 :         399 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11745                 :         399 :             break;
   11746                 :        4605 :         case DO_TABLE_DATA:
   11747                 :        4605 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   11748                 :        4605 :             break;
   11749                 :       15383 :         case DO_DUMMY_TYPE:
   11750                 :             :             /* table rowtypes and array types are never dumped separately */
   11751                 :       15383 :             break;
   11752                 :          44 :         case DO_TSPARSER:
   11753                 :          44 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   11754                 :          44 :             break;
   11755                 :         182 :         case DO_TSDICT:
   11756                 :         182 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11757                 :         182 :             break;
   11758                 :          56 :         case DO_TSTEMPLATE:
   11759                 :          56 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11760                 :          56 :             break;
   11761                 :         157 :         case DO_TSCONFIG:
   11762                 :         157 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11763                 :         157 :             break;
   11764                 :          54 :         case DO_FDW:
   11765                 :          54 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11766                 :          54 :             break;
   11767                 :          58 :         case DO_FOREIGN_SERVER:
   11768                 :          58 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11769                 :          58 :             break;
   11770                 :         170 :         case DO_DEFAULT_ACL:
   11771                 :         170 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11772                 :         170 :             break;
   11773                 :          88 :         case DO_LARGE_OBJECT:
   11774                 :          88 :             dumpLO(fout, (const LoInfo *) dobj);
   11775                 :          88 :             break;
   11776                 :          88 :         case DO_LARGE_OBJECT_DATA:
   11777         [ +  - ]:          88 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   11778                 :             :             {
   11779                 :             :                 LoInfo     *loinfo;
   11780                 :             :                 TocEntry   *te;
   11781                 :             : 
   11782                 :          88 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11783         [ -  + ]:          88 :                 if (loinfo == NULL)
   11784                 :           0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   11785                 :             :                              dobj->name);
   11786                 :             : 
   11787                 :          88 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11788                 :          88 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   11789                 :             :                                                .owner = loinfo->rolname,
   11790                 :             :                                                .description = "BLOBS",
   11791                 :             :                                                .section = SECTION_DATA,
   11792                 :             :                                                .deps = dobj->dependencies,
   11793                 :             :                                                .nDeps = dobj->nDeps,
   11794                 :             :                                                .dumpFn = dumpLOs,
   11795                 :             :                                                .dumpArg = loinfo));
   11796                 :             : 
   11797                 :             :                 /*
   11798                 :             :                  * Set the TocEntry's dataLength in case we are doing a
   11799                 :             :                  * parallel dump and want to order dump jobs by table size.
   11800                 :             :                  * (We need some size estimate for every TocEntry with a
   11801                 :             :                  * DataDumper function.)  We don't currently have any cheap
   11802                 :             :                  * way to estimate the size of LOs, but fortunately it doesn't
   11803                 :             :                  * matter too much as long as we get large batches of LOs
   11804                 :             :                  * processed reasonably early.  Assume 8K per blob.
   11805                 :             :                  */
   11806                 :          88 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11807                 :             :             }
   11808                 :          88 :             break;
   11809                 :         357 :         case DO_POLICY:
   11810                 :         357 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   11811                 :         357 :             break;
   11812                 :         416 :         case DO_PUBLICATION:
   11813                 :         416 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   11814                 :         416 :             break;
   11815                 :         298 :         case DO_PUBLICATION_REL:
   11816                 :         298 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11817                 :         298 :             break;
   11818                 :         103 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11819                 :         103 :             dumpPublicationNamespace(fout,
   11820                 :             :                                      (const PublicationSchemaInfo *) dobj);
   11821                 :         103 :             break;
   11822                 :         116 :         case DO_SUBSCRIPTION:
   11823                 :         116 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11824                 :         116 :             break;
   11825                 :           3 :         case DO_SUBSCRIPTION_REL:
   11826                 :           3 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   11827                 :           3 :             break;
   11828                 :        3684 :         case DO_REL_STATS:
   11829                 :        3684 :             dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   11830                 :        3684 :             break;
   11831                 :         382 :         case DO_PRE_DATA_BOUNDARY:
   11832                 :             :         case DO_POST_DATA_BOUNDARY:
   11833                 :             :             /* never dumped, nothing to do */
   11834                 :         382 :             break;
   11835                 :             :     }
   11836                 :             : }
   11837                 :             : 
   11838                 :             : /*
   11839                 :             :  * dumpNamespace
   11840                 :             :  *    writes out to fout the queries to recreate a user-defined namespace
   11841                 :             :  */
   11842                 :             : static void
   11843                 :         518 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   11844                 :             : {
   11845                 :         518 :     DumpOptions *dopt = fout->dopt;
   11846                 :             :     PQExpBuffer q;
   11847                 :             :     PQExpBuffer delq;
   11848                 :             :     char       *qnspname;
   11849                 :             : 
   11850                 :             :     /* Do nothing if not dumping schema */
   11851         [ +  + ]:         518 :     if (!dopt->dumpSchema)
   11852                 :          29 :         return;
   11853                 :             : 
   11854                 :         489 :     q = createPQExpBuffer();
   11855                 :         489 :     delq = createPQExpBuffer();
   11856                 :             : 
   11857                 :         489 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   11858                 :             : 
   11859         [ +  + ]:         489 :     if (nspinfo->create)
   11860                 :             :     {
   11861                 :         334 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   11862                 :         334 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   11863                 :             :     }
   11864                 :             :     else
   11865                 :             :     {
   11866                 :             :         /* see selectDumpableNamespace() */
   11867                 :         155 :         appendPQExpBufferStr(delq,
   11868                 :             :                              "-- *not* dropping schema, since initdb creates it\n");
   11869                 :         155 :         appendPQExpBufferStr(q,
   11870                 :             :                              "-- *not* creating schema, since initdb creates it\n");
   11871                 :             :     }
   11872                 :             : 
   11873         [ +  + ]:         489 :     if (dopt->binary_upgrade)
   11874                 :         102 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   11875                 :             :                                         "SCHEMA", qnspname, NULL);
   11876                 :             : 
   11877         [ +  + ]:         489 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11878                 :         211 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   11879                 :         211 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   11880                 :             :                                   .owner = nspinfo->rolname,
   11881                 :             :                                   .description = "SCHEMA",
   11882                 :             :                                   .section = SECTION_PRE_DATA,
   11883                 :             :                                   .createStmt = q->data,
   11884                 :             :                                   .dropStmt = delq->data));
   11885                 :             : 
   11886                 :             :     /* Dump Schema Comments and Security Labels */
   11887         [ +  + ]:         489 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11888                 :             :     {
   11889                 :         160 :         const char *initdb_comment = NULL;
   11890                 :             : 
   11891   [ +  +  +  + ]:         160 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   11892                 :         117 :             initdb_comment = "standard public schema";
   11893                 :         160 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   11894                 :         160 :                             NULL, nspinfo->rolname,
   11895                 :         160 :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   11896                 :             :                             initdb_comment);
   11897                 :             :     }
   11898                 :             : 
   11899         [ -  + ]:         489 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11900                 :           0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   11901                 :           0 :                      NULL, nspinfo->rolname,
   11902                 :           0 :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   11903                 :             : 
   11904         [ +  + ]:         489 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11905                 :         385 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   11906                 :             :                 qnspname, NULL, NULL,
   11907                 :         385 :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   11908                 :             : 
   11909                 :         489 :     pg_free(qnspname);
   11910                 :             : 
   11911                 :         489 :     destroyPQExpBuffer(q);
   11912                 :         489 :     destroyPQExpBuffer(delq);
   11913                 :             : }
   11914                 :             : 
   11915                 :             : /*
   11916                 :             :  * dumpExtension
   11917                 :             :  *    writes out to fout the queries to recreate an extension
   11918                 :             :  */
   11919                 :             : static void
   11920                 :          25 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   11921                 :             : {
   11922                 :          25 :     DumpOptions *dopt = fout->dopt;
   11923                 :             :     PQExpBuffer q;
   11924                 :             :     PQExpBuffer delq;
   11925                 :             :     char       *qextname;
   11926                 :             : 
   11927                 :             :     /* Do nothing if not dumping schema */
   11928         [ +  + ]:          25 :     if (!dopt->dumpSchema)
   11929                 :           1 :         return;
   11930                 :             : 
   11931                 :          24 :     q = createPQExpBuffer();
   11932                 :          24 :     delq = createPQExpBuffer();
   11933                 :             : 
   11934                 :          24 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   11935                 :             : 
   11936                 :          24 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   11937                 :             : 
   11938         [ +  + ]:          24 :     if (!dopt->binary_upgrade)
   11939                 :             :     {
   11940                 :             :         /*
   11941                 :             :          * In a regular dump, we simply create the extension, intentionally
   11942                 :             :          * not specifying a version, so that the destination installation's
   11943                 :             :          * default version is used.
   11944                 :             :          *
   11945                 :             :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   11946                 :             :          * types; but there are various scenarios in which it's convenient to
   11947                 :             :          * manually create the desired extension before restoring, so we
   11948                 :             :          * prefer to allow it to exist already.
   11949                 :             :          */
   11950                 :          17 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   11951                 :          17 :                           qextname, fmtId(extinfo->namespace));
   11952                 :             :     }
   11953                 :             :     else
   11954                 :             :     {
   11955                 :             :         /*
   11956                 :             :          * In binary-upgrade mode, it's critical to reproduce the state of the
   11957                 :             :          * database exactly, so our procedure is to create an empty extension,
   11958                 :             :          * restore all the contained objects normally, and add them to the
   11959                 :             :          * extension one by one.  This function performs just the first of
   11960                 :             :          * those steps.  binary_upgrade_extension_member() takes care of
   11961                 :             :          * adding member objects as they're created.
   11962                 :             :          */
   11963                 :             :         int         i;
   11964                 :             :         int         n;
   11965                 :             : 
   11966                 :           7 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   11967                 :             : 
   11968                 :             :         /*
   11969                 :             :          * We unconditionally create the extension, so we must drop it if it
   11970                 :             :          * exists.  This could happen if the user deleted 'plpgsql' and then
   11971                 :             :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   11972                 :             :          */
   11973                 :           7 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   11974                 :             : 
   11975                 :           7 :         appendPQExpBufferStr(q,
   11976                 :             :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   11977                 :           7 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   11978                 :           7 :         appendPQExpBufferStr(q, ", ");
   11979                 :           7 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   11980                 :           7 :         appendPQExpBufferStr(q, ", ");
   11981         [ +  - ]:           7 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   11982                 :           7 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   11983                 :           7 :         appendPQExpBufferStr(q, ", ");
   11984                 :             : 
   11985                 :             :         /*
   11986                 :             :          * Note that we're pushing extconfig (an OID array) back into
   11987                 :             :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   11988                 :             :          * preserved in binary upgrade.
   11989                 :             :          */
   11990         [ +  + ]:           7 :         if (strlen(extinfo->extconfig) > 2)
   11991                 :           1 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   11992                 :             :         else
   11993                 :           6 :             appendPQExpBufferStr(q, "NULL");
   11994                 :           7 :         appendPQExpBufferStr(q, ", ");
   11995         [ +  + ]:           7 :         if (strlen(extinfo->extcondition) > 2)
   11996                 :           1 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   11997                 :             :         else
   11998                 :           6 :             appendPQExpBufferStr(q, "NULL");
   11999                 :           7 :         appendPQExpBufferStr(q, ", ");
   12000                 :           7 :         appendPQExpBufferStr(q, "ARRAY[");
   12001                 :           7 :         n = 0;
   12002         [ +  + ]:          14 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   12003                 :             :         {
   12004                 :             :             DumpableObject *extobj;
   12005                 :             : 
   12006                 :           7 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   12007   [ +  -  -  + ]:           7 :             if (extobj && extobj->objType == DO_EXTENSION)
   12008                 :             :             {
   12009         [ #  # ]:           0 :                 if (n++ > 0)
   12010                 :           0 :                     appendPQExpBufferChar(q, ',');
   12011                 :           0 :                 appendStringLiteralAH(q, extobj->name, fout);
   12012                 :             :             }
   12013                 :             :         }
   12014                 :           7 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   12015                 :           7 :         appendPQExpBufferStr(q, ");\n");
   12016                 :             :     }
   12017                 :             : 
   12018         [ +  - ]:          24 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12019                 :          24 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   12020                 :          24 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   12021                 :             :                                   .description = "EXTENSION",
   12022                 :             :                                   .section = SECTION_PRE_DATA,
   12023                 :             :                                   .createStmt = q->data,
   12024                 :             :                                   .dropStmt = delq->data));
   12025                 :             : 
   12026                 :             :     /* Dump Extension Comments */
   12027         [ +  - ]:          24 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12028                 :          24 :         dumpComment(fout, "EXTENSION", qextname,
   12029                 :             :                     NULL, "",
   12030                 :          24 :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   12031                 :             : 
   12032                 :          24 :     pg_free(qextname);
   12033                 :             : 
   12034                 :          24 :     destroyPQExpBuffer(q);
   12035                 :          24 :     destroyPQExpBuffer(delq);
   12036                 :             : }
   12037                 :             : 
   12038                 :             : /*
   12039                 :             :  * dumpType
   12040                 :             :  *    writes out to fout the queries to recreate a user-defined type
   12041                 :             :  */
   12042                 :             : static void
   12043                 :         971 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   12044                 :             : {
   12045                 :         971 :     DumpOptions *dopt = fout->dopt;
   12046                 :             : 
   12047                 :             :     /* Do nothing if not dumping schema */
   12048         [ +  + ]:         971 :     if (!dopt->dumpSchema)
   12049                 :          56 :         return;
   12050                 :             : 
   12051                 :             :     /* Dump out in proper style */
   12052         [ +  + ]:         915 :     if (tyinfo->typtype == TYPTYPE_BASE)
   12053                 :         285 :         dumpBaseType(fout, tyinfo);
   12054         [ +  + ]:         630 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   12055                 :         174 :         dumpDomain(fout, tyinfo);
   12056         [ +  + ]:         456 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   12057                 :         132 :         dumpCompositeType(fout, tyinfo);
   12058         [ +  + ]:         324 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   12059                 :          89 :         dumpEnumType(fout, tyinfo);
   12060         [ +  + ]:         235 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   12061                 :         121 :         dumpRangeType(fout, tyinfo);
   12062   [ +  -  +  + ]:         114 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   12063                 :          39 :         dumpUndefinedType(fout, tyinfo);
   12064                 :             :     else
   12065                 :          75 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   12066                 :             :                        tyinfo->dobj.name);
   12067                 :             : }
   12068                 :             : 
   12069                 :             : /*
   12070                 :             :  * dumpEnumType
   12071                 :             :  *    writes out to fout the queries to recreate a user-defined enum type
   12072                 :             :  */
   12073                 :             : static void
   12074                 :          89 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   12075                 :             : {
   12076                 :          89 :     DumpOptions *dopt = fout->dopt;
   12077                 :          89 :     PQExpBuffer q = createPQExpBuffer();
   12078                 :          89 :     PQExpBuffer delq = createPQExpBuffer();
   12079                 :          89 :     PQExpBuffer query = createPQExpBuffer();
   12080                 :             :     PGresult   *res;
   12081                 :             :     int         num,
   12082                 :             :                 i;
   12083                 :             :     Oid         enum_oid;
   12084                 :             :     char       *qtypname;
   12085                 :             :     char       *qualtypname;
   12086                 :             :     char       *label;
   12087                 :             :     int         i_enumlabel;
   12088                 :             :     int         i_oid;
   12089                 :             : 
   12090         [ +  + ]:          89 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   12091                 :             :     {
   12092                 :             :         /* Set up query for enum-specific details */
   12093                 :          42 :         appendPQExpBufferStr(query,
   12094                 :             :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   12095                 :             :                              "SELECT oid, enumlabel "
   12096                 :             :                              "FROM pg_catalog.pg_enum "
   12097                 :             :                              "WHERE enumtypid = $1 "
   12098                 :             :                              "ORDER BY enumsortorder");
   12099                 :             : 
   12100                 :          42 :         ExecuteSqlStatement(fout, query->data);
   12101                 :             : 
   12102                 :          42 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   12103                 :             :     }
   12104                 :             : 
   12105                 :          89 :     printfPQExpBuffer(query,
   12106                 :             :                       "EXECUTE dumpEnumType('%u')",
   12107                 :          89 :                       tyinfo->dobj.catId.oid);
   12108                 :             : 
   12109                 :          89 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12110                 :             : 
   12111                 :          89 :     num = PQntuples(res);
   12112                 :             : 
   12113                 :          89 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12114                 :          89 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12115                 :             : 
   12116                 :             :     /*
   12117                 :             :      * CASCADE shouldn't be required here as for normal types since the I/O
   12118                 :             :      * functions are generic and do not get dropped.
   12119                 :             :      */
   12120                 :          89 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12121                 :             : 
   12122         [ +  + ]:          89 :     if (dopt->binary_upgrade)
   12123                 :           6 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12124                 :           6 :                                                  tyinfo->dobj.catId.oid,
   12125                 :             :                                                  false, false);
   12126                 :             : 
   12127                 :          89 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   12128                 :             :                       qualtypname);
   12129                 :             : 
   12130         [ +  + ]:          89 :     if (!dopt->binary_upgrade)
   12131                 :             :     {
   12132                 :          83 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12133                 :             : 
   12134                 :             :         /* Labels with server-assigned oids */
   12135         [ +  + ]:         498 :         for (i = 0; i < num; i++)
   12136                 :             :         {
   12137                 :         415 :             label = PQgetvalue(res, i, i_enumlabel);
   12138         [ +  + ]:         415 :             if (i > 0)
   12139                 :         332 :                 appendPQExpBufferChar(q, ',');
   12140                 :         415 :             appendPQExpBufferStr(q, "\n    ");
   12141                 :         415 :             appendStringLiteralAH(q, label, fout);
   12142                 :             :         }
   12143                 :             :     }
   12144                 :             : 
   12145                 :          89 :     appendPQExpBufferStr(q, "\n);\n");
   12146                 :             : 
   12147         [ +  + ]:          89 :     if (dopt->binary_upgrade)
   12148                 :             :     {
   12149                 :           6 :         i_oid = PQfnumber(res, "oid");
   12150                 :           6 :         i_enumlabel = PQfnumber(res, "enumlabel");
   12151                 :             : 
   12152                 :             :         /* Labels with dump-assigned (preserved) oids */
   12153         [ +  + ]:          62 :         for (i = 0; i < num; i++)
   12154                 :             :         {
   12155                 :          56 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   12156                 :          56 :             label = PQgetvalue(res, i, i_enumlabel);
   12157                 :             : 
   12158         [ +  + ]:          56 :             if (i == 0)
   12159                 :           6 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   12160                 :          56 :             appendPQExpBuffer(q,
   12161                 :             :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   12162                 :             :                               enum_oid);
   12163                 :          56 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   12164                 :          56 :             appendStringLiteralAH(q, label, fout);
   12165                 :          56 :             appendPQExpBufferStr(q, ";\n\n");
   12166                 :             :         }
   12167                 :             :     }
   12168                 :             : 
   12169         [ +  + ]:          89 :     if (dopt->binary_upgrade)
   12170                 :           6 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12171                 :             :                                         "TYPE", qtypname,
   12172                 :           6 :                                         tyinfo->dobj.namespace->dobj.name);
   12173                 :             : 
   12174         [ +  - ]:          89 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12175                 :          89 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12176                 :          89 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12177                 :             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12178                 :             :                                   .owner = tyinfo->rolname,
   12179                 :             :                                   .description = "TYPE",
   12180                 :             :                                   .section = SECTION_PRE_DATA,
   12181                 :             :                                   .createStmt = q->data,
   12182                 :             :                                   .dropStmt = delq->data));
   12183                 :             : 
   12184                 :             :     /* Dump Type Comments and Security Labels */
   12185         [ +  + ]:          89 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12186                 :          34 :         dumpComment(fout, "TYPE", qtypname,
   12187                 :          34 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12188                 :          34 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12189                 :             : 
   12190         [ -  + ]:          89 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12191                 :           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12192                 :           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12193                 :           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12194                 :             : 
   12195         [ +  + ]:          89 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12196                 :          34 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12197                 :             :                 qtypname, NULL,
   12198                 :          34 :                 tyinfo->dobj.namespace->dobj.name,
   12199                 :          34 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12200                 :             : 
   12201                 :          89 :     PQclear(res);
   12202                 :          89 :     destroyPQExpBuffer(q);
   12203                 :          89 :     destroyPQExpBuffer(delq);
   12204                 :          89 :     destroyPQExpBuffer(query);
   12205                 :          89 :     pg_free(qtypname);
   12206                 :          89 :     pg_free(qualtypname);
   12207                 :          89 : }
   12208                 :             : 
   12209                 :             : /*
   12210                 :             :  * dumpRangeType
   12211                 :             :  *    writes out to fout the queries to recreate a user-defined range type
   12212                 :             :  */
   12213                 :             : static void
   12214                 :         121 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   12215                 :             : {
   12216                 :         121 :     DumpOptions *dopt = fout->dopt;
   12217                 :         121 :     PQExpBuffer q = createPQExpBuffer();
   12218                 :         121 :     PQExpBuffer delq = createPQExpBuffer();
   12219                 :         121 :     PQExpBuffer query = createPQExpBuffer();
   12220                 :             :     PGresult   *res;
   12221                 :             :     Oid         collationOid;
   12222                 :             :     char       *qtypname;
   12223                 :             :     char       *qualtypname;
   12224                 :             :     char       *procname;
   12225                 :             : 
   12226         [ +  + ]:         121 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   12227                 :             :     {
   12228                 :             :         /* Set up query for range-specific details */
   12229                 :          42 :         appendPQExpBufferStr(query,
   12230                 :             :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   12231                 :             : 
   12232                 :          42 :         appendPQExpBufferStr(query,
   12233                 :             :                              "SELECT ");
   12234                 :             : 
   12235         [ +  - ]:          42 :         if (fout->remoteVersion >= 140000)
   12236                 :          42 :             appendPQExpBufferStr(query,
   12237                 :             :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   12238                 :             :         else
   12239                 :           0 :             appendPQExpBufferStr(query,
   12240                 :             :                                  "NULL AS rngmultitype, ");
   12241                 :             : 
   12242                 :          42 :         appendPQExpBufferStr(query,
   12243                 :             :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   12244                 :             :                              "opc.opcname AS opcname, "
   12245                 :             :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   12246                 :             :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   12247                 :             :                              "opc.opcdefault, "
   12248                 :             :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   12249                 :             :                              "     ELSE rngcollation END AS collation, "
   12250                 :             :                              "rngcanonical, rngsubdiff "
   12251                 :             :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   12252                 :             :                              "     pg_catalog.pg_opclass opc "
   12253                 :             :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   12254                 :             :                              "rngtypid = $1");
   12255                 :             : 
   12256                 :          42 :         ExecuteSqlStatement(fout, query->data);
   12257                 :             : 
   12258                 :          42 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   12259                 :             :     }
   12260                 :             : 
   12261                 :         121 :     printfPQExpBuffer(query,
   12262                 :             :                       "EXECUTE dumpRangeType('%u')",
   12263                 :         121 :                       tyinfo->dobj.catId.oid);
   12264                 :             : 
   12265                 :         121 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12266                 :             : 
   12267                 :         121 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12268                 :         121 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12269                 :             : 
   12270                 :             :     /*
   12271                 :             :      * CASCADE shouldn't be required here as for normal types since the I/O
   12272                 :             :      * functions are generic and do not get dropped.
   12273                 :             :      */
   12274                 :         121 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12275                 :             : 
   12276         [ +  + ]:         121 :     if (dopt->binary_upgrade)
   12277                 :           9 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12278                 :           9 :                                                  tyinfo->dobj.catId.oid,
   12279                 :             :                                                  false, true);
   12280                 :             : 
   12281                 :         121 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   12282                 :             :                       qualtypname);
   12283                 :             : 
   12284                 :         121 :     appendPQExpBuffer(q, "\n    subtype = %s",
   12285                 :             :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   12286                 :             : 
   12287         [ +  - ]:         121 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   12288                 :         121 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   12289                 :             :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   12290                 :             : 
   12291                 :             :     /* print subtype_opclass only if not default for subtype */
   12292         [ +  + ]:         121 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   12293                 :             :     {
   12294                 :          34 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   12295                 :          34 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   12296                 :             : 
   12297                 :          34 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   12298                 :             :                           fmtId(nspname));
   12299                 :          34 :         appendPQExpBufferStr(q, fmtId(opcname));
   12300                 :             :     }
   12301                 :             : 
   12302                 :         121 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   12303         [ +  + ]:         121 :     if (OidIsValid(collationOid))
   12304                 :             :     {
   12305                 :          39 :         CollInfo   *coll = findCollationByOid(collationOid);
   12306                 :             : 
   12307         [ +  - ]:          39 :         if (coll)
   12308                 :          39 :             appendPQExpBuffer(q, ",\n    collation = %s",
   12309                 :          39 :                               fmtQualifiedDumpable(coll));
   12310                 :             :     }
   12311                 :             : 
   12312                 :         121 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   12313         [ +  + ]:         121 :     if (strcmp(procname, "-") != 0)
   12314                 :           9 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   12315                 :             : 
   12316                 :         121 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   12317         [ +  + ]:         121 :     if (strcmp(procname, "-") != 0)
   12318                 :          23 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   12319                 :             : 
   12320                 :         121 :     appendPQExpBufferStr(q, "\n);\n");
   12321                 :             : 
   12322         [ +  + ]:         121 :     if (dopt->binary_upgrade)
   12323                 :           9 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12324                 :             :                                         "TYPE", qtypname,
   12325                 :           9 :                                         tyinfo->dobj.namespace->dobj.name);
   12326                 :             : 
   12327         [ +  - ]:         121 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12328                 :         121 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12329                 :         121 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12330                 :             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12331                 :             :                                   .owner = tyinfo->rolname,
   12332                 :             :                                   .description = "TYPE",
   12333                 :             :                                   .section = SECTION_PRE_DATA,
   12334                 :             :                                   .createStmt = q->data,
   12335                 :             :                                   .dropStmt = delq->data));
   12336                 :             : 
   12337                 :             :     /* Dump Type Comments and Security Labels */
   12338         [ +  + ]:         121 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12339                 :          52 :         dumpComment(fout, "TYPE", qtypname,
   12340                 :          52 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12341                 :          52 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12342                 :             : 
   12343         [ -  + ]:         121 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12344                 :           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12345                 :           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12346                 :           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12347                 :             : 
   12348         [ +  + ]:         121 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12349                 :          34 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12350                 :             :                 qtypname, NULL,
   12351                 :          34 :                 tyinfo->dobj.namespace->dobj.name,
   12352                 :          34 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12353                 :             : 
   12354                 :         121 :     PQclear(res);
   12355                 :         121 :     destroyPQExpBuffer(q);
   12356                 :         121 :     destroyPQExpBuffer(delq);
   12357                 :         121 :     destroyPQExpBuffer(query);
   12358                 :         121 :     pg_free(qtypname);
   12359                 :         121 :     pg_free(qualtypname);
   12360                 :         121 : }
   12361                 :             : 
   12362                 :             : /*
   12363                 :             :  * dumpUndefinedType
   12364                 :             :  *    writes out to fout the queries to recreate a !typisdefined type
   12365                 :             :  *
   12366                 :             :  * This is a shell type, but we use different terminology to distinguish
   12367                 :             :  * this case from where we have to emit a shell type definition to break
   12368                 :             :  * circular dependencies.  An undefined type shouldn't ever have anything
   12369                 :             :  * depending on it.
   12370                 :             :  */
   12371                 :             : static void
   12372                 :          39 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   12373                 :             : {
   12374                 :          39 :     DumpOptions *dopt = fout->dopt;
   12375                 :          39 :     PQExpBuffer q = createPQExpBuffer();
   12376                 :          39 :     PQExpBuffer delq = createPQExpBuffer();
   12377                 :             :     char       *qtypname;
   12378                 :             :     char       *qualtypname;
   12379                 :             : 
   12380                 :          39 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12381                 :          39 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12382                 :             : 
   12383                 :          39 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12384                 :             : 
   12385         [ +  + ]:          39 :     if (dopt->binary_upgrade)
   12386                 :           2 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12387                 :           2 :                                                  tyinfo->dobj.catId.oid,
   12388                 :             :                                                  false, false);
   12389                 :             : 
   12390                 :          39 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12391                 :             :                       qualtypname);
   12392                 :             : 
   12393         [ +  + ]:          39 :     if (dopt->binary_upgrade)
   12394                 :           2 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12395                 :             :                                         "TYPE", qtypname,
   12396                 :           2 :                                         tyinfo->dobj.namespace->dobj.name);
   12397                 :             : 
   12398         [ +  - ]:          39 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12399                 :          39 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12400                 :          39 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12401                 :             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12402                 :             :                                   .owner = tyinfo->rolname,
   12403                 :             :                                   .description = "TYPE",
   12404                 :             :                                   .section = SECTION_PRE_DATA,
   12405                 :             :                                   .createStmt = q->data,
   12406                 :             :                                   .dropStmt = delq->data));
   12407                 :             : 
   12408                 :             :     /* Dump Type Comments and Security Labels */
   12409         [ +  + ]:          39 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12410                 :          34 :         dumpComment(fout, "TYPE", qtypname,
   12411                 :          34 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12412                 :          34 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12413                 :             : 
   12414         [ -  + ]:          39 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12415                 :           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12416                 :           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12417                 :           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12418                 :             : 
   12419         [ -  + ]:          39 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12420                 :           0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12421                 :             :                 qtypname, NULL,
   12422                 :           0 :                 tyinfo->dobj.namespace->dobj.name,
   12423                 :           0 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12424                 :             : 
   12425                 :          39 :     destroyPQExpBuffer(q);
   12426                 :          39 :     destroyPQExpBuffer(delq);
   12427                 :          39 :     pg_free(qtypname);
   12428                 :          39 :     pg_free(qualtypname);
   12429                 :          39 : }
   12430                 :             : 
   12431                 :             : /*
   12432                 :             :  * dumpBaseType
   12433                 :             :  *    writes out to fout the queries to recreate a user-defined base type
   12434                 :             :  */
   12435                 :             : static void
   12436                 :         285 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   12437                 :             : {
   12438                 :         285 :     DumpOptions *dopt = fout->dopt;
   12439                 :         285 :     PQExpBuffer q = createPQExpBuffer();
   12440                 :         285 :     PQExpBuffer delq = createPQExpBuffer();
   12441                 :         285 :     PQExpBuffer query = createPQExpBuffer();
   12442                 :             :     PGresult   *res;
   12443                 :             :     char       *qtypname;
   12444                 :             :     char       *qualtypname;
   12445                 :             :     char       *typlen;
   12446                 :             :     char       *typinput;
   12447                 :             :     char       *typoutput;
   12448                 :             :     char       *typreceive;
   12449                 :             :     char       *typsend;
   12450                 :             :     char       *typmodin;
   12451                 :             :     char       *typmodout;
   12452                 :             :     char       *typanalyze;
   12453                 :             :     char       *typsubscript;
   12454                 :             :     Oid         typreceiveoid;
   12455                 :             :     Oid         typsendoid;
   12456                 :             :     Oid         typmodinoid;
   12457                 :             :     Oid         typmodoutoid;
   12458                 :             :     Oid         typanalyzeoid;
   12459                 :             :     Oid         typsubscriptoid;
   12460                 :             :     char       *typcategory;
   12461                 :             :     char       *typispreferred;
   12462                 :             :     char       *typdelim;
   12463                 :             :     char       *typbyval;
   12464                 :             :     char       *typalign;
   12465                 :             :     char       *typstorage;
   12466                 :             :     char       *typcollatable;
   12467                 :             :     char       *typdefault;
   12468                 :         285 :     bool        typdefault_is_literal = false;
   12469                 :             : 
   12470         [ +  + ]:         285 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   12471                 :             :     {
   12472                 :             :         /* Set up query for type-specific details */
   12473                 :          42 :         appendPQExpBufferStr(query,
   12474                 :             :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   12475                 :             :                              "SELECT typlen, "
   12476                 :             :                              "typinput, typoutput, typreceive, typsend, "
   12477                 :             :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   12478                 :             :                              "typsend::pg_catalog.oid AS typsendoid, "
   12479                 :             :                              "typanalyze, "
   12480                 :             :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   12481                 :             :                              "typdelim, typbyval, typalign, typstorage, "
   12482                 :             :                              "typmodin, typmodout, "
   12483                 :             :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   12484                 :             :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   12485                 :             :                              "typcategory, typispreferred, "
   12486                 :             :                              "(typcollation <> 0) AS typcollatable, "
   12487                 :             :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   12488                 :             : 
   12489         [ +  - ]:          42 :         if (fout->remoteVersion >= 140000)
   12490                 :          42 :             appendPQExpBufferStr(query,
   12491                 :             :                                  "typsubscript, "
   12492                 :             :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   12493                 :             :         else
   12494                 :           0 :             appendPQExpBufferStr(query,
   12495                 :             :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   12496                 :             : 
   12497                 :          42 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   12498                 :             :                              "WHERE oid = $1");
   12499                 :             : 
   12500                 :          42 :         ExecuteSqlStatement(fout, query->data);
   12501                 :             : 
   12502                 :          42 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   12503                 :             :     }
   12504                 :             : 
   12505                 :         285 :     printfPQExpBuffer(query,
   12506                 :             :                       "EXECUTE dumpBaseType('%u')",
   12507                 :         285 :                       tyinfo->dobj.catId.oid);
   12508                 :             : 
   12509                 :         285 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12510                 :             : 
   12511                 :         285 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   12512                 :         285 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   12513                 :         285 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   12514                 :         285 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   12515                 :         285 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   12516                 :         285 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   12517                 :         285 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   12518                 :         285 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   12519                 :         285 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   12520                 :         285 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   12521                 :         285 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   12522                 :         285 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   12523                 :         285 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   12524                 :         285 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   12525                 :         285 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   12526                 :         285 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   12527                 :         285 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   12528                 :         285 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   12529                 :         285 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   12530                 :         285 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   12531                 :         285 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   12532                 :         285 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   12533         [ -  + ]:         285 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12534                 :           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12535         [ +  + ]:         285 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12536                 :             :     {
   12537                 :          44 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12538                 :          44 :         typdefault_is_literal = true;   /* it needs quotes */
   12539                 :             :     }
   12540                 :             :     else
   12541                 :         241 :         typdefault = NULL;
   12542                 :             : 
   12543                 :         285 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12544                 :         285 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12545                 :             : 
   12546                 :             :     /*
   12547                 :             :      * The reason we include CASCADE is that the circular dependency between
   12548                 :             :      * the type and its I/O functions makes it impossible to drop the type any
   12549                 :             :      * other way.
   12550                 :             :      */
   12551                 :         285 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   12552                 :             : 
   12553                 :             :     /*
   12554                 :             :      * We might already have a shell type, but setting pg_type_oid is
   12555                 :             :      * harmless, and in any case we'd better set the array type OID.
   12556                 :             :      */
   12557         [ +  + ]:         285 :     if (dopt->binary_upgrade)
   12558                 :           8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12559                 :           8 :                                                  tyinfo->dobj.catId.oid,
   12560                 :             :                                                  false, false);
   12561                 :             : 
   12562                 :         285 :     appendPQExpBuffer(q,
   12563                 :             :                       "CREATE TYPE %s (\n"
   12564                 :             :                       "    INTERNALLENGTH = %s",
   12565                 :             :                       qualtypname,
   12566         [ +  + ]:         285 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   12567                 :             : 
   12568                 :             :     /* regproc result is sufficiently quoted already */
   12569                 :         285 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   12570                 :         285 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   12571         [ +  + ]:         285 :     if (OidIsValid(typreceiveoid))
   12572                 :         210 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   12573         [ +  + ]:         285 :     if (OidIsValid(typsendoid))
   12574                 :         210 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   12575         [ +  + ]:         285 :     if (OidIsValid(typmodinoid))
   12576                 :          35 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   12577         [ +  + ]:         285 :     if (OidIsValid(typmodoutoid))
   12578                 :          35 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   12579         [ +  + ]:         285 :     if (OidIsValid(typanalyzeoid))
   12580                 :           3 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   12581                 :             : 
   12582         [ +  + ]:         285 :     if (strcmp(typcollatable, "t") == 0)
   12583                 :          30 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   12584                 :             : 
   12585         [ +  + ]:         285 :     if (typdefault != NULL)
   12586                 :             :     {
   12587                 :          44 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   12588         [ +  - ]:          44 :         if (typdefault_is_literal)
   12589                 :          44 :             appendStringLiteralAH(q, typdefault, fout);
   12590                 :             :         else
   12591                 :           0 :             appendPQExpBufferStr(q, typdefault);
   12592                 :             :     }
   12593                 :             : 
   12594         [ +  + ]:         285 :     if (OidIsValid(typsubscriptoid))
   12595                 :          29 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   12596                 :             : 
   12597         [ +  + ]:         285 :     if (OidIsValid(tyinfo->typelem))
   12598                 :          26 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   12599                 :          26 :                           getFormattedTypeName(fout, tyinfo->typelem,
   12600                 :             :                                                zeroIsError));
   12601                 :             : 
   12602         [ +  + ]:         285 :     if (strcmp(typcategory, "U") != 0)
   12603                 :             :     {
   12604                 :         161 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   12605                 :         161 :         appendStringLiteralAH(q, typcategory, fout);
   12606                 :             :     }
   12607                 :             : 
   12608         [ +  + ]:         285 :     if (strcmp(typispreferred, "t") == 0)
   12609                 :          29 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   12610                 :             : 
   12611   [ +  -  +  + ]:         285 :     if (typdelim && strcmp(typdelim, ",") != 0)
   12612                 :             :     {
   12613                 :           3 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   12614                 :           3 :         appendStringLiteralAH(q, typdelim, fout);
   12615                 :             :     }
   12616                 :             : 
   12617         [ +  + ]:         285 :     if (*typalign == TYPALIGN_CHAR)
   12618                 :          12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   12619         [ +  + ]:         273 :     else if (*typalign == TYPALIGN_SHORT)
   12620                 :           6 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   12621         [ +  + ]:         267 :     else if (*typalign == TYPALIGN_INT)
   12622                 :         189 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   12623         [ +  - ]:          78 :     else if (*typalign == TYPALIGN_DOUBLE)
   12624                 :          78 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   12625                 :             : 
   12626         [ +  + ]:         285 :     if (*typstorage == TYPSTORAGE_PLAIN)
   12627                 :         210 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   12628         [ -  + ]:          75 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   12629                 :           0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   12630         [ +  + ]:          75 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   12631                 :          66 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   12632         [ +  - ]:           9 :     else if (*typstorage == TYPSTORAGE_MAIN)
   12633                 :           9 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   12634                 :             : 
   12635         [ +  + ]:         285 :     if (strcmp(typbyval, "t") == 0)
   12636                 :         139 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   12637                 :             : 
   12638                 :         285 :     appendPQExpBufferStr(q, "\n);\n");
   12639                 :             : 
   12640         [ +  + ]:         285 :     if (dopt->binary_upgrade)
   12641                 :           8 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12642                 :             :                                         "TYPE", qtypname,
   12643                 :           8 :                                         tyinfo->dobj.namespace->dobj.name);
   12644                 :             : 
   12645         [ +  - ]:         285 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12646                 :         285 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12647                 :         285 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12648                 :             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12649                 :             :                                   .owner = tyinfo->rolname,
   12650                 :             :                                   .description = "TYPE",
   12651                 :             :                                   .section = SECTION_PRE_DATA,
   12652                 :             :                                   .createStmt = q->data,
   12653                 :             :                                   .dropStmt = delq->data));
   12654                 :             : 
   12655                 :             :     /* Dump Type Comments and Security Labels */
   12656         [ +  + ]:         285 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12657                 :         250 :         dumpComment(fout, "TYPE", qtypname,
   12658                 :         250 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12659                 :         250 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12660                 :             : 
   12661         [ -  + ]:         285 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12662                 :           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12663                 :           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12664                 :           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12665                 :             : 
   12666         [ +  + ]:         285 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12667                 :          34 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12668                 :             :                 qtypname, NULL,
   12669                 :          34 :                 tyinfo->dobj.namespace->dobj.name,
   12670                 :          34 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12671                 :             : 
   12672                 :         285 :     PQclear(res);
   12673                 :         285 :     destroyPQExpBuffer(q);
   12674                 :         285 :     destroyPQExpBuffer(delq);
   12675                 :         285 :     destroyPQExpBuffer(query);
   12676                 :         285 :     pg_free(qtypname);
   12677                 :         285 :     pg_free(qualtypname);
   12678                 :         285 : }
   12679                 :             : 
   12680                 :             : /*
   12681                 :             :  * dumpDomain
   12682                 :             :  *    writes out to fout the queries to recreate a user-defined domain
   12683                 :             :  */
   12684                 :             : static void
   12685                 :         174 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   12686                 :             : {
   12687                 :         174 :     DumpOptions *dopt = fout->dopt;
   12688                 :         174 :     PQExpBuffer q = createPQExpBuffer();
   12689                 :         174 :     PQExpBuffer delq = createPQExpBuffer();
   12690                 :         174 :     PQExpBuffer query = createPQExpBuffer();
   12691                 :             :     PGresult   *res;
   12692                 :             :     int         i;
   12693                 :             :     char       *qtypname;
   12694                 :             :     char       *qualtypname;
   12695                 :             :     char       *typnotnull;
   12696                 :             :     char       *typdefn;
   12697                 :             :     char       *typdefault;
   12698                 :             :     Oid         typcollation;
   12699                 :         174 :     bool        typdefault_is_literal = false;
   12700                 :             : 
   12701         [ +  + ]:         174 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12702                 :             :     {
   12703                 :             :         /* Set up query for domain-specific details */
   12704                 :          39 :         appendPQExpBufferStr(query,
   12705                 :             :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12706                 :             : 
   12707                 :          39 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   12708                 :             :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   12709                 :             :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   12710                 :             :                              "t.typdefault, "
   12711                 :             :                              "CASE WHEN t.typcollation <> u.typcollation "
   12712                 :             :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   12713                 :             :                              "FROM pg_catalog.pg_type t "
   12714                 :             :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   12715                 :             :                              "WHERE t.oid = $1");
   12716                 :             : 
   12717                 :          39 :         ExecuteSqlStatement(fout, query->data);
   12718                 :             : 
   12719                 :          39 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12720                 :             :     }
   12721                 :             : 
   12722                 :         174 :     printfPQExpBuffer(query,
   12723                 :             :                       "EXECUTE dumpDomain('%u')",
   12724                 :         174 :                       tyinfo->dobj.catId.oid);
   12725                 :             : 
   12726                 :         174 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12727                 :             : 
   12728                 :         174 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12729                 :         174 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12730         [ +  + ]:         174 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12731                 :          39 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12732         [ -  + ]:         135 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12733                 :             :     {
   12734                 :           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12735                 :           0 :         typdefault_is_literal = true;   /* it needs quotes */
   12736                 :             :     }
   12737                 :             :     else
   12738                 :         135 :         typdefault = NULL;
   12739                 :         174 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12740                 :             : 
   12741         [ +  + ]:         174 :     if (dopt->binary_upgrade)
   12742                 :          29 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12743                 :          29 :                                                  tyinfo->dobj.catId.oid,
   12744                 :             :                                                  true,  /* force array type */
   12745                 :             :                                                  false);    /* force multirange type */
   12746                 :             : 
   12747                 :         174 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12748                 :         174 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12749                 :             : 
   12750                 :         174 :     appendPQExpBuffer(q,
   12751                 :             :                       "CREATE DOMAIN %s AS %s",
   12752                 :             :                       qualtypname,
   12753                 :             :                       typdefn);
   12754                 :             : 
   12755                 :             :     /* Print collation only if different from base type's collation */
   12756         [ +  + ]:         174 :     if (OidIsValid(typcollation))
   12757                 :             :     {
   12758                 :             :         CollInfo   *coll;
   12759                 :             : 
   12760                 :          34 :         coll = findCollationByOid(typcollation);
   12761         [ +  - ]:          34 :         if (coll)
   12762                 :          34 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   12763                 :             :     }
   12764                 :             : 
   12765                 :             :     /*
   12766                 :             :      * Print a not-null constraint if there's one.  In servers older than 17
   12767                 :             :      * these don't have names, so just print it unadorned; in newer ones they
   12768                 :             :      * do, but most of the time it's going to be the standard generated one,
   12769                 :             :      * so omit the name in that case also.
   12770                 :             :      */
   12771         [ +  + ]:         174 :     if (typnotnull[0] == 't')
   12772                 :             :     {
   12773   [ +  -  -  + ]:          49 :         if (fout->remoteVersion < 170000 || tyinfo->notnull == NULL)
   12774                 :           0 :             appendPQExpBufferStr(q, " NOT NULL");
   12775                 :             :         else
   12776                 :             :         {
   12777                 :          49 :             ConstraintInfo *notnull = tyinfo->notnull;
   12778                 :             : 
   12779         [ +  - ]:          49 :             if (!notnull->separate)
   12780                 :             :             {
   12781                 :             :                 char       *default_name;
   12782                 :             : 
   12783                 :             :                 /* XXX should match ChooseConstraintName better */
   12784                 :          49 :                 default_name = psprintf("%s_not_null", tyinfo->dobj.name);
   12785                 :             : 
   12786         [ +  + ]:          49 :                 if (strcmp(default_name, notnull->dobj.name) == 0)
   12787                 :          15 :                     appendPQExpBufferStr(q, " NOT NULL");
   12788                 :             :                 else
   12789                 :          34 :                     appendPQExpBuffer(q, " CONSTRAINT %s %s",
   12790                 :          34 :                                       fmtId(notnull->dobj.name), notnull->condef);
   12791                 :          49 :                 pfree(default_name);
   12792                 :             :             }
   12793                 :             :         }
   12794                 :             :     }
   12795                 :             : 
   12796         [ +  + ]:         174 :     if (typdefault != NULL)
   12797                 :             :     {
   12798                 :          39 :         appendPQExpBufferStr(q, " DEFAULT ");
   12799         [ -  + ]:          39 :         if (typdefault_is_literal)
   12800                 :           0 :             appendStringLiteralAH(q, typdefault, fout);
   12801                 :             :         else
   12802                 :          39 :             appendPQExpBufferStr(q, typdefault);
   12803                 :             :     }
   12804                 :             : 
   12805                 :         174 :     PQclear(res);
   12806                 :             : 
   12807                 :             :     /*
   12808                 :             :      * Add any CHECK constraints for the domain
   12809                 :             :      */
   12810         [ +  + ]:         303 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12811                 :             :     {
   12812                 :         129 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12813                 :             : 
   12814   [ +  +  +  - ]:         129 :         if (!domcheck->separate && domcheck->contype == 'c')
   12815                 :         124 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12816                 :         124 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   12817                 :             :     }
   12818                 :             : 
   12819                 :         174 :     appendPQExpBufferStr(q, ";\n");
   12820                 :             : 
   12821                 :         174 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12822                 :             : 
   12823         [ +  + ]:         174 :     if (dopt->binary_upgrade)
   12824                 :          29 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12825                 :             :                                         "DOMAIN", qtypname,
   12826                 :          29 :                                         tyinfo->dobj.namespace->dobj.name);
   12827                 :             : 
   12828         [ +  - ]:         174 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12829                 :         174 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12830                 :         174 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12831                 :             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12832                 :             :                                   .owner = tyinfo->rolname,
   12833                 :             :                                   .description = "DOMAIN",
   12834                 :             :                                   .section = SECTION_PRE_DATA,
   12835                 :             :                                   .createStmt = q->data,
   12836                 :             :                                   .dropStmt = delq->data));
   12837                 :             : 
   12838                 :             :     /* Dump Domain Comments and Security Labels */
   12839         [ -  + ]:         174 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12840                 :           0 :         dumpComment(fout, "DOMAIN", qtypname,
   12841                 :           0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12842                 :           0 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12843                 :             : 
   12844         [ -  + ]:         174 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12845                 :           0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   12846                 :           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12847                 :           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12848                 :             : 
   12849         [ +  + ]:         174 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12850                 :          34 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12851                 :             :                 qtypname, NULL,
   12852                 :          34 :                 tyinfo->dobj.namespace->dobj.name,
   12853                 :          34 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12854                 :             : 
   12855                 :             :     /* Dump any per-constraint comments */
   12856         [ +  + ]:         303 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12857                 :             :     {
   12858                 :         129 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12859                 :             :         PQExpBuffer conprefix;
   12860                 :             : 
   12861                 :             :         /* but only if the constraint itself was dumped here */
   12862         [ +  + ]:         129 :         if (domcheck->separate)
   12863                 :           5 :             continue;
   12864                 :             : 
   12865                 :         124 :         conprefix = createPQExpBuffer();
   12866                 :         124 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12867                 :         124 :                           fmtId(domcheck->dobj.name));
   12868                 :             : 
   12869         [ +  + ]:         124 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   12870                 :          34 :             dumpComment(fout, conprefix->data, qtypname,
   12871                 :          34 :                         tyinfo->dobj.namespace->dobj.name,
   12872                 :          34 :                         tyinfo->rolname,
   12873                 :          34 :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   12874                 :             : 
   12875                 :         124 :         destroyPQExpBuffer(conprefix);
   12876                 :             :     }
   12877                 :             : 
   12878                 :             :     /*
   12879                 :             :      * And a comment on the not-null constraint, if there's one -- but only if
   12880                 :             :      * the constraint itself was dumped here
   12881                 :             :      */
   12882   [ +  +  +  - ]:         174 :     if (tyinfo->notnull != NULL && !tyinfo->notnull->separate)
   12883                 :             :     {
   12884                 :          49 :         PQExpBuffer conprefix = createPQExpBuffer();
   12885                 :             : 
   12886                 :          49 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12887                 :          49 :                           fmtId(tyinfo->notnull->dobj.name));
   12888                 :             : 
   12889         [ +  + ]:          49 :         if (tyinfo->notnull->dobj.dump & DUMP_COMPONENT_COMMENT)
   12890                 :          34 :             dumpComment(fout, conprefix->data, qtypname,
   12891                 :          34 :                         tyinfo->dobj.namespace->dobj.name,
   12892                 :          34 :                         tyinfo->rolname,
   12893                 :          34 :                         tyinfo->notnull->dobj.catId, 0, tyinfo->dobj.dumpId);
   12894                 :          49 :         destroyPQExpBuffer(conprefix);
   12895                 :             :     }
   12896                 :             : 
   12897                 :         174 :     destroyPQExpBuffer(q);
   12898                 :         174 :     destroyPQExpBuffer(delq);
   12899                 :         174 :     destroyPQExpBuffer(query);
   12900                 :         174 :     pg_free(qtypname);
   12901                 :         174 :     pg_free(qualtypname);
   12902                 :         174 : }
   12903                 :             : 
   12904                 :             : /*
   12905                 :             :  * dumpCompositeType
   12906                 :             :  *    writes out to fout the queries to recreate a user-defined stand-alone
   12907                 :             :  *    composite type
   12908                 :             :  */
   12909                 :             : static void
   12910                 :         132 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   12911                 :             : {
   12912                 :         132 :     DumpOptions *dopt = fout->dopt;
   12913                 :         132 :     PQExpBuffer q = createPQExpBuffer();
   12914                 :         132 :     PQExpBuffer dropped = createPQExpBuffer();
   12915                 :         132 :     PQExpBuffer delq = createPQExpBuffer();
   12916                 :         132 :     PQExpBuffer query = createPQExpBuffer();
   12917                 :             :     PGresult   *res;
   12918                 :             :     char       *qtypname;
   12919                 :             :     char       *qualtypname;
   12920                 :             :     int         ntups;
   12921                 :             :     int         i_attname;
   12922                 :             :     int         i_atttypdefn;
   12923                 :             :     int         i_attlen;
   12924                 :             :     int         i_attalign;
   12925                 :             :     int         i_attisdropped;
   12926                 :             :     int         i_attcollation;
   12927                 :             :     int         i;
   12928                 :             :     int         actual_atts;
   12929                 :             : 
   12930         [ +  + ]:         132 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   12931                 :             :     {
   12932                 :             :         /*
   12933                 :             :          * Set up query for type-specific details.
   12934                 :             :          *
   12935                 :             :          * Since we only want to dump COLLATE clauses for attributes whose
   12936                 :             :          * collation is different from their type's default, we use a CASE
   12937                 :             :          * here to suppress uninteresting attcollations cheaply.  atttypid
   12938                 :             :          * will be 0 for dropped columns; collation does not matter for those.
   12939                 :             :          */
   12940                 :          57 :         appendPQExpBufferStr(query,
   12941                 :             :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   12942                 :             :                              "SELECT a.attname, a.attnum, "
   12943                 :             :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   12944                 :             :                              "a.attlen, a.attalign, a.attisdropped, "
   12945                 :             :                              "CASE WHEN a.attcollation <> at.typcollation "
   12946                 :             :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   12947                 :             :                              "FROM pg_catalog.pg_type ct "
   12948                 :             :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   12949                 :             :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   12950                 :             :                              "WHERE ct.oid = $1 "
   12951                 :             :                              "ORDER BY a.attnum");
   12952                 :             : 
   12953                 :          57 :         ExecuteSqlStatement(fout, query->data);
   12954                 :             : 
   12955                 :          57 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   12956                 :             :     }
   12957                 :             : 
   12958                 :         132 :     printfPQExpBuffer(query,
   12959                 :             :                       "EXECUTE dumpCompositeType('%u')",
   12960                 :         132 :                       tyinfo->dobj.catId.oid);
   12961                 :             : 
   12962                 :         132 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12963                 :             : 
   12964                 :         132 :     ntups = PQntuples(res);
   12965                 :             : 
   12966                 :         132 :     i_attname = PQfnumber(res, "attname");
   12967                 :         132 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   12968                 :         132 :     i_attlen = PQfnumber(res, "attlen");
   12969                 :         132 :     i_attalign = PQfnumber(res, "attalign");
   12970                 :         132 :     i_attisdropped = PQfnumber(res, "attisdropped");
   12971                 :         132 :     i_attcollation = PQfnumber(res, "attcollation");
   12972                 :             : 
   12973         [ +  + ]:         132 :     if (dopt->binary_upgrade)
   12974                 :             :     {
   12975                 :          18 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12976                 :          18 :                                                  tyinfo->dobj.catId.oid,
   12977                 :             :                                                  false, false);
   12978                 :          18 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   12979                 :             :     }
   12980                 :             : 
   12981                 :         132 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12982                 :         132 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12983                 :             : 
   12984                 :         132 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   12985                 :             :                       qualtypname);
   12986                 :             : 
   12987                 :         132 :     actual_atts = 0;
   12988         [ +  + ]:         418 :     for (i = 0; i < ntups; i++)
   12989                 :             :     {
   12990                 :             :         char       *attname;
   12991                 :             :         char       *atttypdefn;
   12992                 :             :         char       *attlen;
   12993                 :             :         char       *attalign;
   12994                 :             :         bool        attisdropped;
   12995                 :             :         Oid         attcollation;
   12996                 :             : 
   12997                 :         286 :         attname = PQgetvalue(res, i, i_attname);
   12998                 :         286 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   12999                 :         286 :         attlen = PQgetvalue(res, i, i_attlen);
   13000                 :         286 :         attalign = PQgetvalue(res, i, i_attalign);
   13001                 :         286 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   13002                 :         286 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   13003                 :             : 
   13004   [ +  +  +  + ]:         286 :         if (attisdropped && !dopt->binary_upgrade)
   13005                 :           8 :             continue;
   13006                 :             : 
   13007                 :             :         /* Format properly if not first attr */
   13008         [ +  + ]:         278 :         if (actual_atts++ > 0)
   13009                 :         146 :             appendPQExpBufferChar(q, ',');
   13010                 :         278 :         appendPQExpBufferStr(q, "\n\t");
   13011                 :             : 
   13012         [ +  + ]:         278 :         if (!attisdropped)
   13013                 :             :         {
   13014                 :         276 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   13015                 :             : 
   13016                 :             :             /* Add collation if not default for the column type */
   13017         [ -  + ]:         276 :             if (OidIsValid(attcollation))
   13018                 :             :             {
   13019                 :             :                 CollInfo   *coll;
   13020                 :             : 
   13021                 :           0 :                 coll = findCollationByOid(attcollation);
   13022         [ #  # ]:           0 :                 if (coll)
   13023                 :           0 :                     appendPQExpBuffer(q, " COLLATE %s",
   13024                 :           0 :                                       fmtQualifiedDumpable(coll));
   13025                 :             :             }
   13026                 :             :         }
   13027                 :             :         else
   13028                 :             :         {
   13029                 :             :             /*
   13030                 :             :              * This is a dropped attribute and we're in binary_upgrade mode.
   13031                 :             :              * Insert a placeholder for it in the CREATE TYPE command, and set
   13032                 :             :              * length and alignment with direct UPDATE to the catalogs
   13033                 :             :              * afterwards. See similar code in dumpTableSchema().
   13034                 :             :              */
   13035                 :           2 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   13036                 :             : 
   13037                 :             :             /* stash separately for insertion after the CREATE TYPE */
   13038                 :           2 :             appendPQExpBufferStr(dropped,
   13039                 :             :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   13040                 :           2 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   13041                 :             :                               "SET attlen = %s, "
   13042                 :             :                               "attalign = '%s', attbyval = false\n"
   13043                 :             :                               "WHERE attname = ", attlen, attalign);
   13044                 :           2 :             appendStringLiteralAH(dropped, attname, fout);
   13045                 :           2 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   13046                 :           2 :             appendStringLiteralAH(dropped, qualtypname, fout);
   13047                 :           2 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   13048                 :             : 
   13049                 :           2 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   13050                 :             :                               qualtypname);
   13051                 :           2 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   13052                 :             :                               fmtId(attname));
   13053                 :             :         }
   13054                 :             :     }
   13055                 :         132 :     appendPQExpBufferStr(q, "\n);\n");
   13056                 :         132 :     appendPQExpBufferStr(q, dropped->data);
   13057                 :             : 
   13058                 :         132 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   13059                 :             : 
   13060         [ +  + ]:         132 :     if (dopt->binary_upgrade)
   13061                 :          18 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   13062                 :             :                                         "TYPE", qtypname,
   13063                 :          18 :                                         tyinfo->dobj.namespace->dobj.name);
   13064                 :             : 
   13065         [ +  + ]:         132 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13066                 :         115 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   13067                 :         115 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   13068                 :             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   13069                 :             :                                   .owner = tyinfo->rolname,
   13070                 :             :                                   .description = "TYPE",
   13071                 :             :                                   .section = SECTION_PRE_DATA,
   13072                 :             :                                   .createStmt = q->data,
   13073                 :             :                                   .dropStmt = delq->data));
   13074                 :             : 
   13075                 :             : 
   13076                 :             :     /* Dump Type Comments and Security Labels */
   13077         [ +  + ]:         132 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13078                 :          34 :         dumpComment(fout, "TYPE", qtypname,
   13079                 :          34 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13080                 :          34 :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13081                 :             : 
   13082         [ -  + ]:         132 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13083                 :           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   13084                 :           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   13085                 :           0 :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   13086                 :             : 
   13087         [ +  + ]:         132 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   13088                 :          18 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   13089                 :             :                 qtypname, NULL,
   13090                 :          18 :                 tyinfo->dobj.namespace->dobj.name,
   13091                 :          18 :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   13092                 :             : 
   13093                 :             :     /* Dump any per-column comments */
   13094         [ +  + ]:         132 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13095                 :          34 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   13096                 :             : 
   13097                 :         132 :     PQclear(res);
   13098                 :         132 :     destroyPQExpBuffer(q);
   13099                 :         132 :     destroyPQExpBuffer(dropped);
   13100                 :         132 :     destroyPQExpBuffer(delq);
   13101                 :         132 :     destroyPQExpBuffer(query);
   13102                 :         132 :     pg_free(qtypname);
   13103                 :         132 :     pg_free(qualtypname);
   13104                 :         132 : }
   13105                 :             : 
   13106                 :             : /*
   13107                 :             :  * dumpCompositeTypeColComments
   13108                 :             :  *    writes out to fout the queries to recreate comments on the columns of
   13109                 :             :  *    a user-defined stand-alone composite type.
   13110                 :             :  *
   13111                 :             :  * The caller has already made a query to collect the names and attnums
   13112                 :             :  * of the type's columns, so we just pass that result into here rather
   13113                 :             :  * than reading them again.
   13114                 :             :  */
   13115                 :             : static void
   13116                 :          34 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   13117                 :             :                              PGresult *res)
   13118                 :             : {
   13119                 :             :     CommentItem *comments;
   13120                 :             :     int         ncomments;
   13121                 :             :     PQExpBuffer query;
   13122                 :             :     PQExpBuffer target;
   13123                 :             :     int         i;
   13124                 :             :     int         ntups;
   13125                 :             :     int         i_attname;
   13126                 :             :     int         i_attnum;
   13127                 :             :     int         i_attisdropped;
   13128                 :             : 
   13129                 :             :     /* do nothing, if --no-comments is supplied */
   13130         [ -  + ]:          34 :     if (fout->dopt->no_comments)
   13131                 :           0 :         return;
   13132                 :             : 
   13133                 :             :     /* Search for comments associated with type's pg_class OID */
   13134                 :          34 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   13135                 :             :                              &comments);
   13136                 :             : 
   13137                 :             :     /* If no comments exist, we're done */
   13138         [ -  + ]:          34 :     if (ncomments <= 0)
   13139                 :           0 :         return;
   13140                 :             : 
   13141                 :             :     /* Build COMMENT ON statements */
   13142                 :          34 :     query = createPQExpBuffer();
   13143                 :          34 :     target = createPQExpBuffer();
   13144                 :             : 
   13145                 :          34 :     ntups = PQntuples(res);
   13146                 :          34 :     i_attnum = PQfnumber(res, "attnum");
   13147                 :          34 :     i_attname = PQfnumber(res, "attname");
   13148                 :          34 :     i_attisdropped = PQfnumber(res, "attisdropped");
   13149         [ +  + ]:          68 :     while (ncomments > 0)
   13150                 :             :     {
   13151                 :             :         const char *attname;
   13152                 :             : 
   13153                 :          34 :         attname = NULL;
   13154         [ +  - ]:          34 :         for (i = 0; i < ntups; i++)
   13155                 :             :         {
   13156         [ +  - ]:          34 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   13157         [ +  - ]:          34 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   13158                 :             :             {
   13159                 :          34 :                 attname = PQgetvalue(res, i, i_attname);
   13160                 :          34 :                 break;
   13161                 :             :             }
   13162                 :             :         }
   13163         [ +  - ]:          34 :         if (attname)            /* just in case we don't find it */
   13164                 :             :         {
   13165                 :          34 :             const char *descr = comments->descr;
   13166                 :             : 
   13167                 :          34 :             resetPQExpBuffer(target);
   13168                 :          34 :             appendPQExpBuffer(target, "COLUMN %s.",
   13169                 :          34 :                               fmtId(tyinfo->dobj.name));
   13170                 :          34 :             appendPQExpBufferStr(target, fmtId(attname));
   13171                 :             : 
   13172                 :          34 :             resetPQExpBuffer(query);
   13173                 :          34 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   13174                 :          34 :                               fmtQualifiedDumpable(tyinfo));
   13175                 :          34 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   13176                 :          34 :             appendStringLiteralAH(query, descr, fout);
   13177                 :          34 :             appendPQExpBufferStr(query, ";\n");
   13178                 :             : 
   13179                 :          34 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   13180                 :          34 :                          ARCHIVE_OPTS(.tag = target->data,
   13181                 :             :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   13182                 :             :                                       .owner = tyinfo->rolname,
   13183                 :             :                                       .description = "COMMENT",
   13184                 :             :                                       .section = SECTION_NONE,
   13185                 :             :                                       .createStmt = query->data,
   13186                 :             :                                       .deps = &(tyinfo->dobj.dumpId),
   13187                 :             :                                       .nDeps = 1));
   13188                 :             :         }
   13189                 :             : 
   13190                 :          34 :         comments++;
   13191                 :          34 :         ncomments--;
   13192                 :             :     }
   13193                 :             : 
   13194                 :          34 :     destroyPQExpBuffer(query);
   13195                 :          34 :     destroyPQExpBuffer(target);
   13196                 :             : }
   13197                 :             : 
   13198                 :             : /*
   13199                 :             :  * dumpShellType
   13200                 :             :  *    writes out to fout the queries to create a shell type
   13201                 :             :  *
   13202                 :             :  * We dump a shell definition in advance of the I/O functions for the type.
   13203                 :             :  */
   13204                 :             : static void
   13205                 :          76 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   13206                 :             : {
   13207                 :          76 :     DumpOptions *dopt = fout->dopt;
   13208                 :             :     PQExpBuffer q;
   13209                 :             : 
   13210                 :             :     /* Do nothing if not dumping schema */
   13211         [ +  + ]:          76 :     if (!dopt->dumpSchema)
   13212                 :           7 :         return;
   13213                 :             : 
   13214                 :          69 :     q = createPQExpBuffer();
   13215                 :             : 
   13216                 :             :     /*
   13217                 :             :      * Note the lack of a DROP command for the shell type; any required DROP
   13218                 :             :      * is driven off the base type entry, instead.  This interacts with
   13219                 :             :      * _printTocEntry()'s use of the presence of a DROP command to decide
   13220                 :             :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   13221                 :             :      * the shell type's owner immediately on creation; that should happen only
   13222                 :             :      * after it's filled in, otherwise the backend complains.
   13223                 :             :      */
   13224                 :             : 
   13225         [ +  + ]:          69 :     if (dopt->binary_upgrade)
   13226                 :           8 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   13227                 :           8 :                                                  stinfo->baseType->dobj.catId.oid,
   13228                 :             :                                                  false, false);
   13229                 :             : 
   13230                 :          69 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   13231                 :          69 :                       fmtQualifiedDumpable(stinfo));
   13232                 :             : 
   13233         [ +  - ]:          69 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13234                 :          69 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   13235                 :          69 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   13236                 :             :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   13237                 :             :                                   .owner = stinfo->baseType->rolname,
   13238                 :             :                                   .description = "SHELL TYPE",
   13239                 :             :                                   .section = SECTION_PRE_DATA,
   13240                 :             :                                   .createStmt = q->data));
   13241                 :             : 
   13242                 :          69 :     destroyPQExpBuffer(q);
   13243                 :             : }
   13244                 :             : 
   13245                 :             : /*
   13246                 :             :  * dumpProcLang
   13247                 :             :  *        writes out to fout the queries to recreate a user-defined
   13248                 :             :  *        procedural language
   13249                 :             :  */
   13250                 :             : static void
   13251                 :          87 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   13252                 :             : {
   13253                 :          87 :     DumpOptions *dopt = fout->dopt;
   13254                 :             :     PQExpBuffer defqry;
   13255                 :             :     PQExpBuffer delqry;
   13256                 :             :     bool        useParams;
   13257                 :             :     char       *qlanname;
   13258                 :             :     FuncInfo   *funcInfo;
   13259                 :          87 :     FuncInfo   *inlineInfo = NULL;
   13260                 :          87 :     FuncInfo   *validatorInfo = NULL;
   13261                 :             : 
   13262                 :             :     /* Do nothing if not dumping schema */
   13263         [ +  + ]:          87 :     if (!dopt->dumpSchema)
   13264                 :          14 :         return;
   13265                 :             : 
   13266                 :             :     /*
   13267                 :             :      * Try to find the support function(s).  It is not an error if we don't
   13268                 :             :      * find them --- if the functions are in the pg_catalog schema, as is
   13269                 :             :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   13270                 :             :      * we will emit a parameterless CREATE LANGUAGE command, which will
   13271                 :             :      * require PL template knowledge in the backend to reload.)
   13272                 :             :      */
   13273                 :             : 
   13274                 :          73 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   13275   [ +  +  +  + ]:          73 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   13276                 :           2 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   13277                 :             : 
   13278         [ +  + ]:          73 :     if (OidIsValid(plang->laninline))
   13279                 :             :     {
   13280                 :          40 :         inlineInfo = findFuncByOid(plang->laninline);
   13281   [ +  +  +  - ]:          40 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   13282                 :           1 :             inlineInfo = NULL;
   13283                 :             :     }
   13284                 :             : 
   13285         [ +  + ]:          73 :     if (OidIsValid(plang->lanvalidator))
   13286                 :             :     {
   13287                 :          40 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   13288   [ +  +  +  - ]:          40 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   13289                 :           1 :             validatorInfo = NULL;
   13290                 :             :     }
   13291                 :             : 
   13292                 :             :     /*
   13293                 :             :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   13294                 :             :      * parameters.  Otherwise, we'll write a parameterless command, which will
   13295                 :             :      * be interpreted as CREATE EXTENSION.
   13296                 :             :      */
   13297         [ +  - ]:          32 :     useParams = (funcInfo != NULL &&
   13298   [ +  +  +  -  :         137 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
                   +  - ]
   13299         [ +  - ]:          32 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   13300                 :             : 
   13301                 :          73 :     defqry = createPQExpBuffer();
   13302                 :          73 :     delqry = createPQExpBuffer();
   13303                 :             : 
   13304                 :          73 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   13305                 :             : 
   13306                 :          73 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   13307                 :             :                       qlanname);
   13308                 :             : 
   13309         [ +  + ]:          73 :     if (useParams)
   13310                 :             :     {
   13311                 :          32 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   13312         [ -  + ]:          32 :                           plang->lanpltrusted ? "TRUSTED " : "",
   13313                 :             :                           qlanname);
   13314                 :          32 :         appendPQExpBuffer(defqry, " HANDLER %s",
   13315                 :          32 :                           fmtQualifiedDumpable(funcInfo));
   13316         [ -  + ]:          32 :         if (OidIsValid(plang->laninline))
   13317                 :           0 :             appendPQExpBuffer(defqry, " INLINE %s",
   13318                 :           0 :                               fmtQualifiedDumpable(inlineInfo));
   13319         [ -  + ]:          32 :         if (OidIsValid(plang->lanvalidator))
   13320                 :           0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   13321                 :           0 :                               fmtQualifiedDumpable(validatorInfo));
   13322                 :             :     }
   13323                 :             :     else
   13324                 :             :     {
   13325                 :             :         /*
   13326                 :             :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   13327                 :             :          * command will not fail if the language is preinstalled in the target
   13328                 :             :          * database.
   13329                 :             :          *
   13330                 :             :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   13331                 :             :          * EXISTS; perhaps we should emit that instead?  But it might just add
   13332                 :             :          * confusion.
   13333                 :             :          */
   13334                 :          41 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   13335                 :             :                           qlanname);
   13336                 :             :     }
   13337                 :          73 :     appendPQExpBufferStr(defqry, ";\n");
   13338                 :             : 
   13339         [ +  + ]:          73 :     if (dopt->binary_upgrade)
   13340                 :           2 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   13341                 :             :                                         "LANGUAGE", qlanname, NULL);
   13342                 :             : 
   13343         [ +  + ]:          73 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13344                 :          33 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   13345                 :          33 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   13346                 :             :                                   .owner = plang->lanowner,
   13347                 :             :                                   .description = "PROCEDURAL LANGUAGE",
   13348                 :             :                                   .section = SECTION_PRE_DATA,
   13349                 :             :                                   .createStmt = defqry->data,
   13350                 :             :                                   .dropStmt = delqry->data,
   13351                 :             :                                   ));
   13352                 :             : 
   13353                 :             :     /* Dump Proc Lang Comments and Security Labels */
   13354         [ -  + ]:          73 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   13355                 :           0 :         dumpComment(fout, "LANGUAGE", qlanname,
   13356                 :           0 :                     NULL, plang->lanowner,
   13357                 :           0 :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   13358                 :             : 
   13359         [ -  + ]:          73 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13360                 :           0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   13361                 :           0 :                      NULL, plang->lanowner,
   13362                 :           0 :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   13363                 :             : 
   13364   [ +  +  +  - ]:          73 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   13365                 :          40 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   13366                 :             :                 qlanname, NULL, NULL,
   13367                 :          40 :                 NULL, plang->lanowner, &plang->dacl);
   13368                 :             : 
   13369                 :          73 :     pg_free(qlanname);
   13370                 :             : 
   13371                 :          73 :     destroyPQExpBuffer(defqry);
   13372                 :          73 :     destroyPQExpBuffer(delqry);
   13373                 :             : }
   13374                 :             : 
   13375                 :             : /*
   13376                 :             :  * format_function_arguments: generate function name and argument list
   13377                 :             :  *
   13378                 :             :  * This is used when we can rely on pg_get_function_arguments to format
   13379                 :             :  * the argument list.  Note, however, that pg_get_function_arguments
   13380                 :             :  * does not special-case zero-argument aggregates.
   13381                 :             :  */
   13382                 :             : static char *
   13383                 :        4268 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   13384                 :             : {
   13385                 :             :     PQExpBufferData fn;
   13386                 :             : 
   13387                 :        4268 :     initPQExpBuffer(&fn);
   13388                 :        4268 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   13389   [ +  +  +  + ]:        4268 :     if (is_agg && finfo->nargs == 0)
   13390                 :          80 :         appendPQExpBufferStr(&fn, "(*)");
   13391                 :             :     else
   13392                 :        4188 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   13393                 :        4268 :     return fn.data;
   13394                 :             : }
   13395                 :             : 
   13396                 :             : /*
   13397                 :             :  * format_function_signature: generate function name and argument list
   13398                 :             :  *
   13399                 :             :  * Only a minimal list of input argument types is generated; this is
   13400                 :             :  * sufficient to reference the function, but not to define it.
   13401                 :             :  *
   13402                 :             :  * If honor_quotes is false then the function name is never quoted.
   13403                 :             :  * This is appropriate for use in TOC tags, but not in SQL commands.
   13404                 :             :  */
   13405                 :             : static char *
   13406                 :        2248 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   13407                 :             : {
   13408                 :             :     PQExpBufferData fn;
   13409                 :             :     int         j;
   13410                 :             : 
   13411                 :        2248 :     initPQExpBuffer(&fn);
   13412         [ +  + ]:        2248 :     if (honor_quotes)
   13413                 :         401 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   13414                 :             :     else
   13415                 :        1847 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   13416         [ +  + ]:        4135 :     for (j = 0; j < finfo->nargs; j++)
   13417                 :             :     {
   13418         [ +  + ]:        1887 :         if (j > 0)
   13419                 :         452 :             appendPQExpBufferStr(&fn, ", ");
   13420                 :             : 
   13421                 :        1887 :         appendPQExpBufferStr(&fn,
   13422                 :        1887 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   13423                 :             :                                                   zeroIsError));
   13424                 :             :     }
   13425                 :        2248 :     appendPQExpBufferChar(&fn, ')');
   13426                 :        2248 :     return fn.data;
   13427                 :             : }
   13428                 :             : 
   13429                 :             : 
   13430                 :             : /*
   13431                 :             :  * dumpFunc:
   13432                 :             :  *    dump out one function
   13433                 :             :  */
   13434                 :             : static void
   13435                 :        1917 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   13436                 :             : {
   13437                 :        1917 :     DumpOptions *dopt = fout->dopt;
   13438                 :             :     PQExpBuffer query;
   13439                 :             :     PQExpBuffer q;
   13440                 :             :     PQExpBuffer delqry;
   13441                 :             :     PQExpBuffer asPart;
   13442                 :             :     PGresult   *res;
   13443                 :             :     char       *funcsig;        /* identity signature */
   13444                 :        1917 :     char       *funcfullsig = NULL; /* full signature */
   13445                 :             :     char       *funcsig_tag;
   13446                 :             :     char       *qual_funcsig;
   13447                 :             :     char       *proretset;
   13448                 :             :     char       *prosrc;
   13449                 :             :     char       *probin;
   13450                 :             :     char       *prosqlbody;
   13451                 :             :     char       *funcargs;
   13452                 :             :     char       *funciargs;
   13453                 :             :     char       *funcresult;
   13454                 :             :     char       *protrftypes;
   13455                 :             :     char       *prokind;
   13456                 :             :     char       *provolatile;
   13457                 :             :     char       *proisstrict;
   13458                 :             :     char       *prosecdef;
   13459                 :             :     char       *proleakproof;
   13460                 :             :     char       *proconfig;
   13461                 :             :     char       *procost;
   13462                 :             :     char       *prorows;
   13463                 :             :     char       *prosupport;
   13464                 :             :     char       *proparallel;
   13465                 :             :     char       *lanname;
   13466                 :        1917 :     char      **configitems = NULL;
   13467                 :        1917 :     int         nconfigitems = 0;
   13468                 :             :     const char *keyword;
   13469                 :             : 
   13470                 :             :     /* Do nothing if not dumping schema */
   13471         [ +  + ]:        1917 :     if (!dopt->dumpSchema)
   13472                 :          70 :         return;
   13473                 :             : 
   13474                 :        1847 :     query = createPQExpBuffer();
   13475                 :        1847 :     q = createPQExpBuffer();
   13476                 :        1847 :     delqry = createPQExpBuffer();
   13477                 :        1847 :     asPart = createPQExpBuffer();
   13478                 :             : 
   13479         [ +  + ]:        1847 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   13480                 :             :     {
   13481                 :             :         /* Set up query for function-specific details */
   13482                 :          69 :         appendPQExpBufferStr(query,
   13483                 :             :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   13484                 :             : 
   13485                 :          69 :         appendPQExpBufferStr(query,
   13486                 :             :                              "SELECT\n"
   13487                 :             :                              "proretset,\n"
   13488                 :             :                              "prosrc,\n"
   13489                 :             :                              "probin,\n"
   13490                 :             :                              "provolatile,\n"
   13491                 :             :                              "proisstrict,\n"
   13492                 :             :                              "prosecdef,\n"
   13493                 :             :                              "lanname,\n"
   13494                 :             :                              "proconfig,\n"
   13495                 :             :                              "procost,\n"
   13496                 :             :                              "prorows,\n"
   13497                 :             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   13498                 :             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   13499                 :             :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   13500                 :             :                              "proleakproof,\n");
   13501                 :             : 
   13502                 :          69 :         appendPQExpBufferStr(query,
   13503                 :             :                              "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   13504                 :             : 
   13505                 :          69 :         appendPQExpBufferStr(query,
   13506                 :             :                              "proparallel,\n");
   13507                 :             : 
   13508         [ +  - ]:          69 :         if (fout->remoteVersion >= 110000)
   13509                 :          69 :             appendPQExpBufferStr(query,
   13510                 :             :                                  "prokind,\n");
   13511                 :             :         else
   13512                 :           0 :             appendPQExpBufferStr(query,
   13513                 :             :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   13514                 :             : 
   13515         [ +  - ]:          69 :         if (fout->remoteVersion >= 120000)
   13516                 :          69 :             appendPQExpBufferStr(query,
   13517                 :             :                                  "prosupport,\n");
   13518                 :             :         else
   13519                 :           0 :             appendPQExpBufferStr(query,
   13520                 :             :                                  "'-' AS prosupport,\n");
   13521                 :             : 
   13522         [ +  - ]:          69 :         if (fout->remoteVersion >= 140000)
   13523                 :          69 :             appendPQExpBufferStr(query,
   13524                 :             :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   13525                 :             :         else
   13526                 :           0 :             appendPQExpBufferStr(query,
   13527                 :             :                                  "NULL AS prosqlbody\n");
   13528                 :             : 
   13529                 :          69 :         appendPQExpBufferStr(query,
   13530                 :             :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   13531                 :             :                              "WHERE p.oid = $1 "
   13532                 :             :                              "AND l.oid = p.prolang");
   13533                 :             : 
   13534                 :          69 :         ExecuteSqlStatement(fout, query->data);
   13535                 :             : 
   13536                 :          69 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   13537                 :             :     }
   13538                 :             : 
   13539                 :        1847 :     printfPQExpBuffer(query,
   13540                 :             :                       "EXECUTE dumpFunc('%u')",
   13541                 :        1847 :                       finfo->dobj.catId.oid);
   13542                 :             : 
   13543                 :        1847 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13544                 :             : 
   13545                 :        1847 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   13546         [ +  + ]:        1847 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   13547                 :             :     {
   13548                 :        1797 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   13549                 :        1797 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   13550                 :        1797 :         prosqlbody = NULL;
   13551                 :             :     }
   13552                 :             :     else
   13553                 :             :     {
   13554                 :          50 :         prosrc = NULL;
   13555                 :          50 :         probin = NULL;
   13556                 :          50 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   13557                 :             :     }
   13558                 :        1847 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   13559                 :        1847 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   13560                 :        1847 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   13561                 :        1847 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   13562                 :        1847 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   13563                 :        1847 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   13564                 :        1847 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   13565                 :        1847 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   13566                 :        1847 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   13567                 :        1847 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   13568                 :        1847 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   13569                 :        1847 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   13570                 :        1847 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   13571                 :        1847 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   13572                 :        1847 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   13573                 :             : 
   13574                 :             :     /*
   13575                 :             :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   13576                 :             :      * is used.
   13577                 :             :      */
   13578         [ +  + ]:        1847 :     if (prosqlbody)
   13579                 :             :     {
   13580                 :          50 :         appendPQExpBufferStr(asPart, prosqlbody);
   13581                 :             :     }
   13582         [ +  + ]:        1797 :     else if (probin[0] != '\0')
   13583                 :             :     {
   13584                 :         160 :         appendPQExpBufferStr(asPart, "AS ");
   13585                 :         160 :         appendStringLiteralAH(asPart, probin, fout);
   13586         [ +  - ]:         160 :         if (prosrc[0] != '\0')
   13587                 :             :         {
   13588                 :         160 :             appendPQExpBufferStr(asPart, ", ");
   13589                 :             : 
   13590                 :             :             /*
   13591                 :             :              * where we have bin, use dollar quoting if allowed and src
   13592                 :             :              * contains quote or backslash; else use regular quoting.
   13593                 :             :              */
   13594         [ +  - ]:         160 :             if (dopt->disable_dollar_quoting ||
   13595   [ +  -  +  - ]:         160 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   13596                 :         160 :                 appendStringLiteralAH(asPart, prosrc, fout);
   13597                 :             :             else
   13598                 :           0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   13599                 :             :         }
   13600                 :             :     }
   13601                 :             :     else
   13602                 :             :     {
   13603                 :        1637 :         appendPQExpBufferStr(asPart, "AS ");
   13604                 :             :         /* with no bin, dollar quote src unconditionally if allowed */
   13605         [ -  + ]:        1637 :         if (dopt->disable_dollar_quoting)
   13606                 :           0 :             appendStringLiteralAH(asPart, prosrc, fout);
   13607                 :             :         else
   13608                 :        1637 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   13609                 :             :     }
   13610                 :             : 
   13611         [ +  + ]:        1847 :     if (*proconfig)
   13612                 :             :     {
   13613         [ -  + ]:          15 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   13614                 :           0 :             pg_fatal("could not parse %s array", "proconfig");
   13615                 :             :     }
   13616                 :             :     else
   13617                 :             :     {
   13618                 :        1832 :         configitems = NULL;
   13619                 :        1832 :         nconfigitems = 0;
   13620                 :             :     }
   13621                 :             : 
   13622                 :        1847 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   13623                 :        1847 :     funcsig = format_function_arguments(finfo, funciargs, false);
   13624                 :             : 
   13625                 :        1847 :     funcsig_tag = format_function_signature(fout, finfo, false);
   13626                 :             : 
   13627                 :        1847 :     qual_funcsig = psprintf("%s.%s",
   13628                 :        1847 :                             fmtId(finfo->dobj.namespace->dobj.name),
   13629                 :             :                             funcsig);
   13630                 :             : 
   13631         [ +  + ]:        1847 :     if (prokind[0] == PROKIND_PROCEDURE)
   13632                 :          94 :         keyword = "PROCEDURE";
   13633                 :             :     else
   13634                 :        1753 :         keyword = "FUNCTION"; /* works for window functions too */
   13635                 :             : 
   13636                 :        1847 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   13637                 :             :                       keyword, qual_funcsig);
   13638                 :             : 
   13639         [ +  - ]:        3694 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   13640                 :             :                       keyword,
   13641                 :        1847 :                       fmtId(finfo->dobj.namespace->dobj.name),
   13642                 :             :                       funcfullsig ? funcfullsig :
   13643                 :             :                       funcsig);
   13644                 :             : 
   13645         [ +  + ]:        1847 :     if (prokind[0] == PROKIND_PROCEDURE)
   13646                 :             :          /* no result type to output */ ;
   13647         [ +  - ]:        1753 :     else if (funcresult)
   13648                 :        1753 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   13649                 :             :     else
   13650                 :           0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   13651         [ #  # ]:           0 :                           (proretset[0] == 't') ? "SETOF " : "",
   13652                 :           0 :                           getFormattedTypeName(fout, finfo->prorettype,
   13653                 :             :                                                zeroIsError));
   13654                 :             : 
   13655                 :        1847 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   13656                 :             : 
   13657         [ -  + ]:        1847 :     if (*protrftypes)
   13658                 :             :     {
   13659                 :           0 :         Oid        *typeids = pg_malloc_array(Oid, FUNC_MAX_ARGS);
   13660                 :             :         int         i;
   13661                 :             : 
   13662                 :           0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   13663                 :           0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   13664         [ #  # ]:           0 :         for (i = 0; typeids[i]; i++)
   13665                 :             :         {
   13666         [ #  # ]:           0 :             if (i != 0)
   13667                 :           0 :                 appendPQExpBufferStr(q, ", ");
   13668                 :           0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   13669                 :           0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   13670                 :             :         }
   13671                 :             : 
   13672                 :           0 :         pg_free(typeids);
   13673                 :             :     }
   13674                 :             : 
   13675         [ +  + ]:        1847 :     if (prokind[0] == PROKIND_WINDOW)
   13676                 :           5 :         appendPQExpBufferStr(q, " WINDOW");
   13677                 :             : 
   13678         [ +  + ]:        1847 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   13679                 :             :     {
   13680         [ +  + ]:         355 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   13681                 :         334 :             appendPQExpBufferStr(q, " IMMUTABLE");
   13682         [ +  - ]:          21 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   13683                 :          21 :             appendPQExpBufferStr(q, " STABLE");
   13684         [ #  # ]:           0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   13685                 :           0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   13686                 :             :                      finfo->dobj.name);
   13687                 :             :     }
   13688                 :             : 
   13689         [ +  + ]:        1847 :     if (proisstrict[0] == 't')
   13690                 :         364 :         appendPQExpBufferStr(q, " STRICT");
   13691                 :             : 
   13692         [ -  + ]:        1847 :     if (prosecdef[0] == 't')
   13693                 :           0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   13694                 :             : 
   13695         [ +  + ]:        1847 :     if (proleakproof[0] == 't')
   13696                 :          10 :         appendPQExpBufferStr(q, " LEAKPROOF");
   13697                 :             : 
   13698                 :             :     /*
   13699                 :             :      * COST and ROWS are emitted only if present and not default, so as not to
   13700                 :             :      * break backwards-compatibility of the dump without need.  Keep this code
   13701                 :             :      * in sync with the defaults in functioncmds.c.
   13702                 :             :      */
   13703         [ +  - ]:        1847 :     if (strcmp(procost, "0") != 0)
   13704                 :             :     {
   13705   [ +  +  +  + ]:        1847 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   13706                 :             :         {
   13707                 :             :             /* default cost is 1 */
   13708         [ -  + ]:         397 :             if (strcmp(procost, "1") != 0)
   13709                 :           0 :                 appendPQExpBuffer(q, " COST %s", procost);
   13710                 :             :         }
   13711                 :             :         else
   13712                 :             :         {
   13713                 :             :             /* default cost is 100 */
   13714         [ +  + ]:        1450 :             if (strcmp(procost, "100") != 0)
   13715                 :          11 :                 appendPQExpBuffer(q, " COST %s", procost);
   13716                 :             :         }
   13717                 :             :     }
   13718         [ +  + ]:        1847 :     if (proretset[0] == 't' &&
   13719   [ +  -  -  + ]:         194 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   13720                 :           0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   13721                 :             : 
   13722         [ +  + ]:        1847 :     if (strcmp(prosupport, "-") != 0)
   13723                 :             :     {
   13724                 :             :         /* We rely on regprocout to provide quoting and qualification */
   13725                 :          44 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   13726                 :             :     }
   13727                 :             : 
   13728         [ +  + ]:        1847 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   13729                 :             :     {
   13730         [ +  + ]:         120 :         if (proparallel[0] == PROPARALLEL_SAFE)
   13731                 :         115 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   13732         [ +  - ]:           5 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   13733                 :           5 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   13734         [ #  # ]:           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   13735                 :           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   13736                 :             :                      finfo->dobj.name);
   13737                 :             :     }
   13738                 :             : 
   13739         [ +  + ]:        1887 :     for (int i = 0; i < nconfigitems; i++)
   13740                 :             :     {
   13741                 :             :         /* we feel free to scribble on configitems[] here */
   13742                 :          40 :         char       *configitem = configitems[i];
   13743                 :             :         char       *pos;
   13744                 :             : 
   13745                 :          40 :         pos = strchr(configitem, '=');
   13746         [ -  + ]:          40 :         if (pos == NULL)
   13747                 :           0 :             continue;
   13748                 :          40 :         *pos++ = '\0';
   13749                 :          40 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   13750                 :             : 
   13751                 :             :         /*
   13752                 :             :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   13753                 :             :          * by flatten_set_variable_args() before they were put into the
   13754                 :             :          * proconfig array.  However, because the quoting rules used there
   13755                 :             :          * aren't exactly like SQL's, we have to break the list value apart
   13756                 :             :          * and then quote the elements as string literals.  (The elements may
   13757                 :             :          * be double-quoted as-is, but we can't just feed them to the SQL
   13758                 :             :          * parser; it would do the wrong thing with elements that are
   13759                 :             :          * zero-length or longer than NAMEDATALEN.)  Also, we need a special
   13760                 :             :          * case for empty lists.
   13761                 :             :          *
   13762                 :             :          * Variables that are not so marked should just be emitted as simple
   13763                 :             :          * string literals.  If the variable is not known to
   13764                 :             :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   13765                 :             :          * to use GUC_LIST_QUOTE for extension variables.
   13766                 :             :          */
   13767         [ +  + ]:          40 :         if (variable_is_guc_list_quote(configitem))
   13768                 :             :         {
   13769                 :             :             char      **namelist;
   13770                 :             :             char      **nameptr;
   13771                 :             : 
   13772                 :             :             /* Parse string into list of identifiers */
   13773                 :             :             /* this shouldn't fail really */
   13774         [ +  - ]:          15 :             if (SplitGUCList(pos, ',', &namelist))
   13775                 :             :             {
   13776                 :             :                 /* Special case: represent an empty list as NULL */
   13777         [ +  + ]:          15 :                 if (*namelist == NULL)
   13778                 :           5 :                     appendPQExpBufferStr(q, "NULL");
   13779         [ +  + ]:          40 :                 for (nameptr = namelist; *nameptr; nameptr++)
   13780                 :             :                 {
   13781         [ +  + ]:          25 :                     if (nameptr != namelist)
   13782                 :          15 :                         appendPQExpBufferStr(q, ", ");
   13783                 :          25 :                     appendStringLiteralAH(q, *nameptr, fout);
   13784                 :             :                 }
   13785                 :             :             }
   13786                 :          15 :             pg_free(namelist);
   13787                 :             :         }
   13788                 :             :         else
   13789                 :          25 :             appendStringLiteralAH(q, pos, fout);
   13790                 :             :     }
   13791                 :             : 
   13792                 :        1847 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13793                 :             : 
   13794                 :        1847 :     append_depends_on_extension(fout, q, &finfo->dobj,
   13795                 :             :                                 "pg_catalog.pg_proc", keyword,
   13796                 :             :                                 qual_funcsig);
   13797                 :             : 
   13798         [ +  + ]:        1847 :     if (dopt->binary_upgrade)
   13799                 :         308 :         binary_upgrade_extension_member(q, &finfo->dobj,
   13800                 :             :                                         keyword, funcsig,
   13801                 :         308 :                                         finfo->dobj.namespace->dobj.name);
   13802                 :             : 
   13803         [ +  + ]:        1847 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13804                 :        1747 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13805         [ +  + ]:        1747 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   13806                 :             :                                   .namespace = finfo->dobj.namespace->dobj.name,
   13807                 :             :                                   .owner = finfo->rolname,
   13808                 :             :                                   .description = keyword,
   13809                 :             :                                   .section = finfo->postponed_def ?
   13810                 :             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   13811                 :             :                                   .createStmt = q->data,
   13812                 :             :                                   .dropStmt = delqry->data));
   13813                 :             : 
   13814                 :             :     /* Dump Function Comments and Security Labels */
   13815         [ +  + ]:        1847 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13816                 :           9 :         dumpComment(fout, keyword, funcsig,
   13817                 :           9 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   13818                 :           9 :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13819                 :             : 
   13820         [ -  + ]:        1847 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13821                 :           0 :         dumpSecLabel(fout, keyword, funcsig,
   13822                 :           0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   13823                 :           0 :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13824                 :             : 
   13825         [ +  + ]:        1847 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   13826                 :         104 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   13827                 :             :                 funcsig, NULL,
   13828                 :         104 :                 finfo->dobj.namespace->dobj.name,
   13829                 :         104 :                 NULL, finfo->rolname, &finfo->dacl);
   13830                 :             : 
   13831                 :        1847 :     PQclear(res);
   13832                 :             : 
   13833                 :        1847 :     destroyPQExpBuffer(query);
   13834                 :        1847 :     destroyPQExpBuffer(q);
   13835                 :        1847 :     destroyPQExpBuffer(delqry);
   13836                 :        1847 :     destroyPQExpBuffer(asPart);
   13837                 :        1847 :     free(funcsig);
   13838                 :        1847 :     free(funcfullsig);
   13839                 :        1847 :     free(funcsig_tag);
   13840                 :        1847 :     pfree(qual_funcsig);
   13841                 :        1847 :     free(configitems);
   13842                 :             : }
   13843                 :             : 
   13844                 :             : 
   13845                 :             : /*
   13846                 :             :  * Dump a user-defined cast
   13847                 :             :  */
   13848                 :             : static void
   13849                 :          69 : dumpCast(Archive *fout, const CastInfo *cast)
   13850                 :             : {
   13851                 :          69 :     DumpOptions *dopt = fout->dopt;
   13852                 :             :     PQExpBuffer defqry;
   13853                 :             :     PQExpBuffer delqry;
   13854                 :             :     PQExpBuffer labelq;
   13855                 :             :     PQExpBuffer castargs;
   13856                 :          69 :     FuncInfo   *funcInfo = NULL;
   13857                 :             :     const char *sourceType;
   13858                 :             :     const char *targetType;
   13859                 :             : 
   13860                 :             :     /* Do nothing if not dumping schema */
   13861         [ +  + ]:          69 :     if (!dopt->dumpSchema)
   13862                 :           6 :         return;
   13863                 :             : 
   13864                 :             :     /* Cannot dump if we don't have the cast function's info */
   13865         [ +  + ]:          63 :     if (OidIsValid(cast->castfunc))
   13866                 :             :     {
   13867                 :          38 :         funcInfo = findFuncByOid(cast->castfunc);
   13868         [ -  + ]:          38 :         if (funcInfo == NULL)
   13869                 :           0 :             pg_fatal("could not find function definition for function with OID %u",
   13870                 :             :                      cast->castfunc);
   13871                 :             :     }
   13872                 :             : 
   13873                 :          63 :     defqry = createPQExpBuffer();
   13874                 :          63 :     delqry = createPQExpBuffer();
   13875                 :          63 :     labelq = createPQExpBuffer();
   13876                 :          63 :     castargs = createPQExpBuffer();
   13877                 :             : 
   13878                 :          63 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   13879                 :          63 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   13880                 :          63 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   13881                 :             :                       sourceType, targetType);
   13882                 :             : 
   13883                 :          63 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   13884                 :             :                       sourceType, targetType);
   13885                 :             : 
   13886   [ +  -  +  - ]:          63 :     switch (cast->castmethod)
   13887                 :             :     {
   13888                 :          25 :         case COERCION_METHOD_BINARY:
   13889                 :          25 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   13890                 :          25 :             break;
   13891                 :           0 :         case COERCION_METHOD_INOUT:
   13892                 :           0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   13893                 :           0 :             break;
   13894                 :          38 :         case COERCION_METHOD_FUNCTION:
   13895         [ +  - ]:          38 :             if (funcInfo)
   13896                 :             :             {
   13897                 :          38 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   13898                 :             : 
   13899                 :             :                 /*
   13900                 :             :                  * Always qualify the function name (format_function_signature
   13901                 :             :                  * won't qualify it).
   13902                 :             :                  */
   13903                 :          38 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   13904                 :          38 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   13905                 :          38 :                 free(fsig);
   13906                 :             :             }
   13907                 :             :             else
   13908                 :           0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   13909                 :          38 :             break;
   13910                 :           0 :         default:
   13911                 :           0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   13912                 :             :     }
   13913                 :             : 
   13914         [ +  + ]:          63 :     if (cast->castcontext == 'a')
   13915                 :          33 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   13916         [ +  + ]:          30 :     else if (cast->castcontext == 'i')
   13917                 :          10 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   13918                 :          63 :     appendPQExpBufferStr(defqry, ";\n");
   13919                 :             : 
   13920                 :          63 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   13921                 :             :                       sourceType, targetType);
   13922                 :             : 
   13923                 :          63 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   13924                 :             :                       sourceType, targetType);
   13925                 :             : 
   13926         [ +  + ]:          63 :     if (dopt->binary_upgrade)
   13927                 :           7 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   13928                 :           7 :                                         "CAST", castargs->data, NULL);
   13929                 :             : 
   13930         [ +  - ]:          63 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13931                 :          63 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   13932                 :          63 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13933                 :             :                                   .description = "CAST",
   13934                 :             :                                   .section = SECTION_PRE_DATA,
   13935                 :             :                                   .createStmt = defqry->data,
   13936                 :             :                                   .dropStmt = delqry->data));
   13937                 :             : 
   13938                 :             :     /* Dump Cast Comments */
   13939         [ -  + ]:          63 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   13940                 :           0 :         dumpComment(fout, "CAST", castargs->data,
   13941                 :             :                     NULL, "",
   13942                 :           0 :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   13943                 :             : 
   13944                 :          63 :     destroyPQExpBuffer(defqry);
   13945                 :          63 :     destroyPQExpBuffer(delqry);
   13946                 :          63 :     destroyPQExpBuffer(labelq);
   13947                 :          63 :     destroyPQExpBuffer(castargs);
   13948                 :             : }
   13949                 :             : 
   13950                 :             : /*
   13951                 :             :  * Dump a transform
   13952                 :             :  */
   13953                 :             : static void
   13954                 :          44 : dumpTransform(Archive *fout, const TransformInfo *transform)
   13955                 :             : {
   13956                 :          44 :     DumpOptions *dopt = fout->dopt;
   13957                 :             :     PQExpBuffer defqry;
   13958                 :             :     PQExpBuffer delqry;
   13959                 :             :     PQExpBuffer labelq;
   13960                 :             :     PQExpBuffer transformargs;
   13961                 :          44 :     FuncInfo   *fromsqlFuncInfo = NULL;
   13962                 :          44 :     FuncInfo   *tosqlFuncInfo = NULL;
   13963                 :             :     char       *lanname;
   13964                 :             :     const char *transformType;
   13965                 :             : 
   13966                 :             :     /* Do nothing if not dumping schema */
   13967         [ +  + ]:          44 :     if (!dopt->dumpSchema)
   13968                 :           6 :         return;
   13969                 :             : 
   13970                 :             :     /* Cannot dump if we don't have the transform functions' info */
   13971         [ +  - ]:          38 :     if (OidIsValid(transform->trffromsql))
   13972                 :             :     {
   13973                 :          38 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   13974         [ -  + ]:          38 :         if (fromsqlFuncInfo == NULL)
   13975                 :           0 :             pg_fatal("could not find function definition for function with OID %u",
   13976                 :             :                      transform->trffromsql);
   13977                 :             :     }
   13978         [ +  - ]:          38 :     if (OidIsValid(transform->trftosql))
   13979                 :             :     {
   13980                 :          38 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   13981         [ -  + ]:          38 :         if (tosqlFuncInfo == NULL)
   13982                 :           0 :             pg_fatal("could not find function definition for function with OID %u",
   13983                 :             :                      transform->trftosql);
   13984                 :             :     }
   13985                 :             : 
   13986                 :          38 :     defqry = createPQExpBuffer();
   13987                 :          38 :     delqry = createPQExpBuffer();
   13988                 :          38 :     labelq = createPQExpBuffer();
   13989                 :          38 :     transformargs = createPQExpBuffer();
   13990                 :             : 
   13991                 :          38 :     lanname = get_language_name(fout, transform->trflang);
   13992                 :          38 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   13993                 :             : 
   13994                 :          38 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   13995                 :             :                       transformType, lanname);
   13996                 :             : 
   13997                 :          38 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   13998                 :             :                       transformType, lanname);
   13999                 :             : 
   14000   [ -  +  -  - ]:          38 :     if (!transform->trffromsql && !transform->trftosql)
   14001                 :           0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   14002                 :             : 
   14003         [ +  - ]:          38 :     if (transform->trffromsql)
   14004                 :             :     {
   14005         [ +  - ]:          38 :         if (fromsqlFuncInfo)
   14006                 :             :         {
   14007                 :          38 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   14008                 :             : 
   14009                 :             :             /*
   14010                 :             :              * Always qualify the function name (format_function_signature
   14011                 :             :              * won't qualify it).
   14012                 :             :              */
   14013                 :          38 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   14014                 :          38 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14015                 :          38 :             free(fsig);
   14016                 :             :         }
   14017                 :             :         else
   14018                 :           0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   14019                 :             :     }
   14020                 :             : 
   14021         [ +  - ]:          38 :     if (transform->trftosql)
   14022                 :             :     {
   14023         [ +  - ]:          38 :         if (transform->trffromsql)
   14024                 :          38 :             appendPQExpBufferStr(defqry, ", ");
   14025                 :             : 
   14026         [ +  - ]:          38 :         if (tosqlFuncInfo)
   14027                 :             :         {
   14028                 :          38 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   14029                 :             : 
   14030                 :             :             /*
   14031                 :             :              * Always qualify the function name (format_function_signature
   14032                 :             :              * won't qualify it).
   14033                 :             :              */
   14034                 :          38 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   14035                 :          38 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   14036                 :          38 :             free(fsig);
   14037                 :             :         }
   14038                 :             :         else
   14039                 :           0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   14040                 :             :     }
   14041                 :             : 
   14042                 :          38 :     appendPQExpBufferStr(defqry, ");\n");
   14043                 :             : 
   14044                 :          38 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   14045                 :             :                       transformType, lanname);
   14046                 :             : 
   14047                 :          38 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   14048                 :             :                       transformType, lanname);
   14049                 :             : 
   14050         [ +  + ]:          38 :     if (dopt->binary_upgrade)
   14051                 :           2 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   14052                 :           2 :                                         "TRANSFORM", transformargs->data, NULL);
   14053                 :             : 
   14054         [ +  - ]:          38 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14055                 :          38 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   14056                 :          38 :                      ARCHIVE_OPTS(.tag = labelq->data,
   14057                 :             :                                   .description = "TRANSFORM",
   14058                 :             :                                   .section = SECTION_PRE_DATA,
   14059                 :             :                                   .createStmt = defqry->data,
   14060                 :             :                                   .dropStmt = delqry->data,
   14061                 :             :                                   .deps = transform->dobj.dependencies,
   14062                 :             :                                   .nDeps = transform->dobj.nDeps));
   14063                 :             : 
   14064                 :             :     /* Dump Transform Comments */
   14065         [ -  + ]:          38 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   14066                 :           0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   14067                 :             :                     NULL, "",
   14068                 :           0 :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   14069                 :             : 
   14070                 :          38 :     free(lanname);
   14071                 :          38 :     destroyPQExpBuffer(defqry);
   14072                 :          38 :     destroyPQExpBuffer(delqry);
   14073                 :          38 :     destroyPQExpBuffer(labelq);
   14074                 :          38 :     destroyPQExpBuffer(transformargs);
   14075                 :             : }
   14076                 :             : 
   14077                 :             : 
   14078                 :             : /*
   14079                 :             :  * dumpOpr
   14080                 :             :  *    write out a single operator definition
   14081                 :             :  */
   14082                 :             : static void
   14083                 :        2525 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   14084                 :             : {
   14085                 :        2525 :     DumpOptions *dopt = fout->dopt;
   14086                 :             :     PQExpBuffer query;
   14087                 :             :     PQExpBuffer q;
   14088                 :             :     PQExpBuffer delq;
   14089                 :             :     PQExpBuffer oprid;
   14090                 :             :     PQExpBuffer details;
   14091                 :             :     PGresult   *res;
   14092                 :             :     int         i_oprkind;
   14093                 :             :     int         i_oprcode;
   14094                 :             :     int         i_oprleft;
   14095                 :             :     int         i_oprright;
   14096                 :             :     int         i_oprcom;
   14097                 :             :     int         i_oprnegate;
   14098                 :             :     int         i_oprrest;
   14099                 :             :     int         i_oprjoin;
   14100                 :             :     int         i_oprcanmerge;
   14101                 :             :     int         i_oprcanhash;
   14102                 :             :     char       *oprkind;
   14103                 :             :     char       *oprcode;
   14104                 :             :     char       *oprleft;
   14105                 :             :     char       *oprright;
   14106                 :             :     char       *oprcom;
   14107                 :             :     char       *oprnegate;
   14108                 :             :     char       *oprrest;
   14109                 :             :     char       *oprjoin;
   14110                 :             :     char       *oprcanmerge;
   14111                 :             :     char       *oprcanhash;
   14112                 :             :     char       *oprregproc;
   14113                 :             :     char       *oprref;
   14114                 :             : 
   14115                 :             :     /* Do nothing if not dumping schema */
   14116         [ +  + ]:        2525 :     if (!dopt->dumpSchema)
   14117                 :           7 :         return;
   14118                 :             : 
   14119                 :             :     /*
   14120                 :             :      * some operators are invalid because they were the result of user
   14121                 :             :      * defining operators before commutators exist
   14122                 :             :      */
   14123         [ +  + ]:        2518 :     if (!OidIsValid(oprinfo->oprcode))
   14124                 :          14 :         return;
   14125                 :             : 
   14126                 :        2504 :     query = createPQExpBuffer();
   14127                 :        2504 :     q = createPQExpBuffer();
   14128                 :        2504 :     delq = createPQExpBuffer();
   14129                 :        2504 :     oprid = createPQExpBuffer();
   14130                 :        2504 :     details = createPQExpBuffer();
   14131                 :             : 
   14132         [ +  + ]:        2504 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   14133                 :             :     {
   14134                 :             :         /* Set up query for operator-specific details */
   14135                 :          42 :         appendPQExpBufferStr(query,
   14136                 :             :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   14137                 :             :                              "SELECT oprkind, "
   14138                 :             :                              "oprcode::pg_catalog.regprocedure, "
   14139                 :             :                              "oprleft::pg_catalog.regtype, "
   14140                 :             :                              "oprright::pg_catalog.regtype, "
   14141                 :             :                              "oprcom, "
   14142                 :             :                              "oprnegate, "
   14143                 :             :                              "oprrest::pg_catalog.regprocedure, "
   14144                 :             :                              "oprjoin::pg_catalog.regprocedure, "
   14145                 :             :                              "oprcanmerge, oprcanhash "
   14146                 :             :                              "FROM pg_catalog.pg_operator "
   14147                 :             :                              "WHERE oid = $1");
   14148                 :             : 
   14149                 :          42 :         ExecuteSqlStatement(fout, query->data);
   14150                 :             : 
   14151                 :          42 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   14152                 :             :     }
   14153                 :             : 
   14154                 :        2504 :     printfPQExpBuffer(query,
   14155                 :             :                       "EXECUTE dumpOpr('%u')",
   14156                 :        2504 :                       oprinfo->dobj.catId.oid);
   14157                 :             : 
   14158                 :        2504 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14159                 :             : 
   14160                 :        2504 :     i_oprkind = PQfnumber(res, "oprkind");
   14161                 :        2504 :     i_oprcode = PQfnumber(res, "oprcode");
   14162                 :        2504 :     i_oprleft = PQfnumber(res, "oprleft");
   14163                 :        2504 :     i_oprright = PQfnumber(res, "oprright");
   14164                 :        2504 :     i_oprcom = PQfnumber(res, "oprcom");
   14165                 :        2504 :     i_oprnegate = PQfnumber(res, "oprnegate");
   14166                 :        2504 :     i_oprrest = PQfnumber(res, "oprrest");
   14167                 :        2504 :     i_oprjoin = PQfnumber(res, "oprjoin");
   14168                 :        2504 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   14169                 :        2504 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   14170                 :             : 
   14171                 :        2504 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   14172                 :        2504 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   14173                 :        2504 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   14174                 :        2504 :     oprright = PQgetvalue(res, 0, i_oprright);
   14175                 :        2504 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   14176                 :        2504 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   14177                 :        2504 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   14178                 :        2504 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   14179                 :        2504 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   14180                 :        2504 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   14181                 :             : 
   14182                 :             :     /* In PG14 upwards postfix operator support does not exist anymore. */
   14183         [ -  + ]:        2504 :     if (strcmp(oprkind, "r") == 0)
   14184                 :           0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   14185                 :             :                        oprcode);
   14186                 :             : 
   14187                 :        2504 :     oprregproc = convertRegProcReference(oprcode);
   14188         [ +  - ]:        2504 :     if (oprregproc)
   14189                 :             :     {
   14190                 :        2504 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   14191                 :        2504 :         free(oprregproc);
   14192                 :             :     }
   14193                 :             : 
   14194                 :        2504 :     appendPQExpBuffer(oprid, "%s (",
   14195                 :        2504 :                       oprinfo->dobj.name);
   14196                 :             : 
   14197                 :             :     /*
   14198                 :             :      * right unary means there's a left arg and left unary means there's a
   14199                 :             :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   14200                 :             :      * continue to support it in case we're dumping from an old server.)
   14201                 :             :      */
   14202         [ +  - ]:        2504 :     if (strcmp(oprkind, "r") == 0 ||
   14203         [ +  + ]:        2504 :         strcmp(oprkind, "b") == 0)
   14204                 :             :     {
   14205                 :        2361 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   14206                 :        2361 :         appendPQExpBufferStr(oprid, oprleft);
   14207                 :             :     }
   14208                 :             :     else
   14209                 :         143 :         appendPQExpBufferStr(oprid, "NONE");
   14210                 :             : 
   14211         [ +  + ]:        2504 :     if (strcmp(oprkind, "l") == 0 ||
   14212         [ +  - ]:        2361 :         strcmp(oprkind, "b") == 0)
   14213                 :             :     {
   14214                 :        2504 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   14215                 :        2504 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   14216                 :             :     }
   14217                 :             :     else
   14218                 :           0 :         appendPQExpBufferStr(oprid, ", NONE)");
   14219                 :             : 
   14220                 :        2504 :     oprref = getFormattedOperatorName(oprcom);
   14221         [ +  + ]:        2504 :     if (oprref)
   14222                 :             :     {
   14223                 :        1679 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   14224                 :        1679 :         free(oprref);
   14225                 :             :     }
   14226                 :             : 
   14227                 :        2504 :     oprref = getFormattedOperatorName(oprnegate);
   14228         [ +  + ]:        2504 :     if (oprref)
   14229                 :             :     {
   14230                 :        1181 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   14231                 :        1181 :         free(oprref);
   14232                 :             :     }
   14233                 :             : 
   14234         [ +  + ]:        2504 :     if (strcmp(oprcanmerge, "t") == 0)
   14235                 :         188 :         appendPQExpBufferStr(details, ",\n    MERGES");
   14236                 :             : 
   14237         [ +  + ]:        2504 :     if (strcmp(oprcanhash, "t") == 0)
   14238                 :         141 :         appendPQExpBufferStr(details, ",\n    HASHES");
   14239                 :             : 
   14240                 :        2504 :     oprregproc = convertRegProcReference(oprrest);
   14241         [ +  + ]:        2504 :     if (oprregproc)
   14242                 :             :     {
   14243                 :        1532 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   14244                 :        1532 :         free(oprregproc);
   14245                 :             :     }
   14246                 :             : 
   14247                 :        2504 :     oprregproc = convertRegProcReference(oprjoin);
   14248         [ +  + ]:        2504 :     if (oprregproc)
   14249                 :             :     {
   14250                 :        1532 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   14251                 :        1532 :         free(oprregproc);
   14252                 :             :     }
   14253                 :             : 
   14254                 :        2504 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   14255                 :        2504 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14256                 :             :                       oprid->data);
   14257                 :             : 
   14258                 :        2504 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   14259                 :        2504 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   14260                 :        2504 :                       oprinfo->dobj.name, details->data);
   14261                 :             : 
   14262         [ +  + ]:        2504 :     if (dopt->binary_upgrade)
   14263                 :          12 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   14264                 :          12 :                                         "OPERATOR", oprid->data,
   14265                 :          12 :                                         oprinfo->dobj.namespace->dobj.name);
   14266                 :             : 
   14267         [ +  - ]:        2504 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14268                 :        2504 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   14269                 :        2504 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   14270                 :             :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   14271                 :             :                                   .owner = oprinfo->rolname,
   14272                 :             :                                   .description = "OPERATOR",
   14273                 :             :                                   .section = SECTION_PRE_DATA,
   14274                 :             :                                   .createStmt = q->data,
   14275                 :             :                                   .dropStmt = delq->data));
   14276                 :             : 
   14277                 :             :     /* Dump Operator Comments */
   14278         [ +  + ]:        2504 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14279                 :        2415 :         dumpComment(fout, "OPERATOR", oprid->data,
   14280                 :        2415 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   14281                 :        2415 :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   14282                 :             : 
   14283                 :        2504 :     PQclear(res);
   14284                 :             : 
   14285                 :        2504 :     destroyPQExpBuffer(query);
   14286                 :        2504 :     destroyPQExpBuffer(q);
   14287                 :        2504 :     destroyPQExpBuffer(delq);
   14288                 :        2504 :     destroyPQExpBuffer(oprid);
   14289                 :        2504 :     destroyPQExpBuffer(details);
   14290                 :             : }
   14291                 :             : 
   14292                 :             : /*
   14293                 :             :  * Convert a function reference obtained from pg_operator
   14294                 :             :  *
   14295                 :             :  * Returns allocated string of what to print, or NULL if function references
   14296                 :             :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   14297                 :             :  *
   14298                 :             :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   14299                 :             :  * part.
   14300                 :             :  */
   14301                 :             : static char *
   14302                 :        7512 : convertRegProcReference(const char *proc)
   14303                 :             : {
   14304                 :             :     char       *name;
   14305                 :             :     char       *paren;
   14306                 :             :     bool        inquote;
   14307                 :             : 
   14308                 :             :     /* In all cases "-" means a null reference */
   14309         [ +  + ]:        7512 :     if (strcmp(proc, "-") == 0)
   14310                 :        1944 :         return NULL;
   14311                 :             : 
   14312                 :        5568 :     name = pg_strdup(proc);
   14313                 :             :     /* find non-double-quoted left paren */
   14314                 :        5568 :     inquote = false;
   14315         [ +  - ]:       67010 :     for (paren = name; *paren; paren++)
   14316                 :             :     {
   14317   [ +  +  +  - ]:       67010 :         if (*paren == '(' && !inquote)
   14318                 :             :         {
   14319                 :        5568 :             *paren = '\0';
   14320                 :        5568 :             break;
   14321                 :             :         }
   14322         [ +  + ]:       61442 :         if (*paren == '"')
   14323                 :          50 :             inquote = !inquote;
   14324                 :             :     }
   14325                 :        5568 :     return name;
   14326                 :             : }
   14327                 :             : 
   14328                 :             : /*
   14329                 :             :  * getFormattedOperatorName - retrieve the operator name for the
   14330                 :             :  * given operator OID (presented in string form).
   14331                 :             :  *
   14332                 :             :  * Returns an allocated string, or NULL if the given OID is invalid.
   14333                 :             :  * Caller is responsible for free'ing result string.
   14334                 :             :  *
   14335                 :             :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   14336                 :             :  * useful in commands where the operator's argument types can be inferred from
   14337                 :             :  * context.  We always schema-qualify the name, though.  The predecessor to
   14338                 :             :  * this code tried to skip the schema qualification if possible, but that led
   14339                 :             :  * to wrong results in corner cases, such as if an operator and its negator
   14340                 :             :  * are in different schemas.
   14341                 :             :  */
   14342                 :             : static char *
   14343                 :        5295 : getFormattedOperatorName(const char *oproid)
   14344                 :             : {
   14345                 :             :     OprInfo    *oprInfo;
   14346                 :             : 
   14347                 :             :     /* In all cases "0" means a null reference */
   14348         [ +  + ]:        5295 :     if (strcmp(oproid, "0") == 0)
   14349                 :        2435 :         return NULL;
   14350                 :             : 
   14351                 :        2860 :     oprInfo = findOprByOid(atooid(oproid));
   14352         [ -  + ]:        2860 :     if (oprInfo == NULL)
   14353                 :             :     {
   14354                 :           0 :         pg_log_warning("could not find operator with OID %s",
   14355                 :             :                        oproid);
   14356                 :           0 :         return NULL;
   14357                 :             :     }
   14358                 :             : 
   14359                 :        2860 :     return psprintf("OPERATOR(%s.%s)",
   14360                 :        2860 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   14361                 :             :                     oprInfo->dobj.name);
   14362                 :             : }
   14363                 :             : 
   14364                 :             : /*
   14365                 :             :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   14366                 :             :  *
   14367                 :             :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   14368                 :             :  * argument lists of these functions are predetermined.  Note that the
   14369                 :             :  * caller should ensure we are in the proper schema, because the results
   14370                 :             :  * are search path dependent!
   14371                 :             :  */
   14372                 :             : static char *
   14373                 :         215 : convertTSFunction(Archive *fout, Oid funcOid)
   14374                 :             : {
   14375                 :             :     char       *result;
   14376                 :             :     char        query[128];
   14377                 :             :     PGresult   *res;
   14378                 :             : 
   14379                 :         215 :     snprintf(query, sizeof(query),
   14380                 :             :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   14381                 :         215 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   14382                 :             : 
   14383                 :         215 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   14384                 :             : 
   14385                 :         215 :     PQclear(res);
   14386                 :             : 
   14387                 :         215 :     return result;
   14388                 :             : }
   14389                 :             : 
   14390                 :             : /*
   14391                 :             :  * dumpAccessMethod
   14392                 :             :  *    write out a single access method definition
   14393                 :             :  */
   14394                 :             : static void
   14395                 :          84 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   14396                 :             : {
   14397                 :          84 :     DumpOptions *dopt = fout->dopt;
   14398                 :             :     PQExpBuffer q;
   14399                 :             :     PQExpBuffer delq;
   14400                 :             :     char       *qamname;
   14401                 :             : 
   14402                 :             :     /* Do nothing if not dumping schema */
   14403         [ +  + ]:          84 :     if (!dopt->dumpSchema)
   14404                 :          12 :         return;
   14405                 :             : 
   14406                 :          72 :     q = createPQExpBuffer();
   14407                 :          72 :     delq = createPQExpBuffer();
   14408                 :             : 
   14409                 :          72 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   14410                 :             : 
   14411                 :          72 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   14412                 :             : 
   14413      [ +  +  - ]:          72 :     switch (aminfo->amtype)
   14414                 :             :     {
   14415                 :          34 :         case AMTYPE_INDEX:
   14416                 :          34 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   14417                 :          34 :             break;
   14418                 :          38 :         case AMTYPE_TABLE:
   14419                 :          38 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   14420                 :          38 :             break;
   14421                 :           0 :         default:
   14422                 :           0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   14423                 :             :                            aminfo->amtype, qamname);
   14424                 :           0 :             destroyPQExpBuffer(q);
   14425                 :           0 :             destroyPQExpBuffer(delq);
   14426                 :           0 :             pg_free(qamname);
   14427                 :           0 :             return;
   14428                 :             :     }
   14429                 :             : 
   14430                 :          72 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   14431                 :             : 
   14432                 :          72 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   14433                 :             :                       qamname);
   14434                 :             : 
   14435         [ +  + ]:          72 :     if (dopt->binary_upgrade)
   14436                 :           4 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   14437                 :             :                                         "ACCESS METHOD", qamname, NULL);
   14438                 :             : 
   14439         [ +  - ]:          72 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14440                 :          72 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   14441                 :          72 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   14442                 :             :                                   .description = "ACCESS METHOD",
   14443                 :             :                                   .section = SECTION_PRE_DATA,
   14444                 :             :                                   .createStmt = q->data,
   14445                 :             :                                   .dropStmt = delq->data));
   14446                 :             : 
   14447                 :             :     /* Dump Access Method Comments */
   14448         [ -  + ]:          72 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14449                 :           0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   14450                 :             :                     NULL, "",
   14451                 :           0 :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   14452                 :             : 
   14453                 :          72 :     destroyPQExpBuffer(q);
   14454                 :          72 :     destroyPQExpBuffer(delq);
   14455                 :          72 :     pg_free(qamname);
   14456                 :             : }
   14457                 :             : 
   14458                 :             : /*
   14459                 :             :  * dumpOpclass
   14460                 :             :  *    write out a single operator class definition
   14461                 :             :  */
   14462                 :             : static void
   14463                 :         675 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   14464                 :             : {
   14465                 :         675 :     DumpOptions *dopt = fout->dopt;
   14466                 :             :     PQExpBuffer query;
   14467                 :             :     PQExpBuffer q;
   14468                 :             :     PQExpBuffer delq;
   14469                 :             :     PQExpBuffer nameusing;
   14470                 :             :     PGresult   *res;
   14471                 :             :     int         ntups;
   14472                 :             :     int         i_opcintype;
   14473                 :             :     int         i_opckeytype;
   14474                 :             :     int         i_opcdefault;
   14475                 :             :     int         i_opcfamily;
   14476                 :             :     int         i_opcfamilyname;
   14477                 :             :     int         i_opcfamilynsp;
   14478                 :             :     int         i_amname;
   14479                 :             :     int         i_amopstrategy;
   14480                 :             :     int         i_amopopr;
   14481                 :             :     int         i_sortfamily;
   14482                 :             :     int         i_sortfamilynsp;
   14483                 :             :     int         i_amprocnum;
   14484                 :             :     int         i_amproc;
   14485                 :             :     int         i_amproclefttype;
   14486                 :             :     int         i_amprocrighttype;
   14487                 :             :     char       *opcintype;
   14488                 :             :     char       *opckeytype;
   14489                 :             :     char       *opcdefault;
   14490                 :             :     char       *opcfamily;
   14491                 :             :     char       *opcfamilyname;
   14492                 :             :     char       *opcfamilynsp;
   14493                 :             :     char       *amname;
   14494                 :             :     char       *amopstrategy;
   14495                 :             :     char       *amopopr;
   14496                 :             :     char       *sortfamily;
   14497                 :             :     char       *sortfamilynsp;
   14498                 :             :     char       *amprocnum;
   14499                 :             :     char       *amproc;
   14500                 :             :     char       *amproclefttype;
   14501                 :             :     char       *amprocrighttype;
   14502                 :             :     bool        needComma;
   14503                 :             :     int         i;
   14504                 :             : 
   14505                 :             :     /* Do nothing if not dumping schema */
   14506         [ +  + ]:         675 :     if (!dopt->dumpSchema)
   14507                 :          21 :         return;
   14508                 :             : 
   14509                 :         654 :     query = createPQExpBuffer();
   14510                 :         654 :     q = createPQExpBuffer();
   14511                 :         654 :     delq = createPQExpBuffer();
   14512                 :         654 :     nameusing = createPQExpBuffer();
   14513                 :             : 
   14514                 :             :     /* Get additional fields from the pg_opclass row */
   14515                 :         654 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   14516                 :             :                       "opckeytype::pg_catalog.regtype, "
   14517                 :             :                       "opcdefault, opcfamily, "
   14518                 :             :                       "opfname AS opcfamilyname, "
   14519                 :             :                       "nspname AS opcfamilynsp, "
   14520                 :             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   14521                 :             :                       "FROM pg_catalog.pg_opclass c "
   14522                 :             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   14523                 :             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14524                 :             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14525                 :         654 :                       opcinfo->dobj.catId.oid);
   14526                 :             : 
   14527                 :         654 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14528                 :             : 
   14529                 :         654 :     i_opcintype = PQfnumber(res, "opcintype");
   14530                 :         654 :     i_opckeytype = PQfnumber(res, "opckeytype");
   14531                 :         654 :     i_opcdefault = PQfnumber(res, "opcdefault");
   14532                 :         654 :     i_opcfamily = PQfnumber(res, "opcfamily");
   14533                 :         654 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   14534                 :         654 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   14535                 :         654 :     i_amname = PQfnumber(res, "amname");
   14536                 :             : 
   14537                 :             :     /* opcintype may still be needed after we PQclear res */
   14538                 :         654 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   14539                 :         654 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   14540                 :         654 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   14541                 :             :     /* opcfamily will still be needed after we PQclear res */
   14542                 :         654 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   14543                 :         654 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   14544                 :         654 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   14545                 :             :     /* amname will still be needed after we PQclear res */
   14546                 :         654 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14547                 :             : 
   14548                 :         654 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   14549                 :         654 :                       fmtQualifiedDumpable(opcinfo));
   14550                 :         654 :     appendPQExpBuffer(delq, " USING %s;\n",
   14551                 :             :                       fmtId(amname));
   14552                 :             : 
   14553                 :             :     /* Build the fixed portion of the CREATE command */
   14554                 :         654 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   14555                 :         654 :                       fmtQualifiedDumpable(opcinfo));
   14556         [ +  + ]:         654 :     if (strcmp(opcdefault, "t") == 0)
   14557                 :         366 :         appendPQExpBufferStr(q, "DEFAULT ");
   14558                 :         654 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   14559                 :             :                       opcintype,
   14560                 :             :                       fmtId(amname));
   14561         [ +  - ]:         654 :     if (strlen(opcfamilyname) > 0)
   14562                 :             :     {
   14563                 :         654 :         appendPQExpBufferStr(q, " FAMILY ");
   14564                 :         654 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   14565                 :         654 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   14566                 :             :     }
   14567                 :         654 :     appendPQExpBufferStr(q, " AS\n    ");
   14568                 :             : 
   14569                 :         654 :     needComma = false;
   14570                 :             : 
   14571         [ +  + ]:         654 :     if (strcmp(opckeytype, "-") != 0)
   14572                 :             :     {
   14573                 :         252 :         appendPQExpBuffer(q, "STORAGE %s",
   14574                 :             :                           opckeytype);
   14575                 :         252 :         needComma = true;
   14576                 :             :     }
   14577                 :             : 
   14578                 :         654 :     PQclear(res);
   14579                 :             : 
   14580                 :             :     /*
   14581                 :             :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   14582                 :             :      *
   14583                 :             :      * Print only those opfamily members that are tied to the opclass by
   14584                 :             :      * pg_depend entries.
   14585                 :             :      */
   14586                 :         654 :     resetPQExpBuffer(query);
   14587                 :         654 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14588                 :             :                       "amopopr::pg_catalog.regoperator, "
   14589                 :             :                       "opfname AS sortfamily, "
   14590                 :             :                       "nspname AS sortfamilynsp "
   14591                 :             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14592                 :             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14593                 :             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14594                 :             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14595                 :             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14596                 :             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14597                 :             :                       "AND amopfamily = '%s'::pg_catalog.oid "
   14598                 :             :                       "ORDER BY amopstrategy",
   14599                 :         654 :                       opcinfo->dobj.catId.oid,
   14600                 :             :                       opcfamily);
   14601                 :             : 
   14602                 :         654 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14603                 :             : 
   14604                 :         654 :     ntups = PQntuples(res);
   14605                 :             : 
   14606                 :         654 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   14607                 :         654 :     i_amopopr = PQfnumber(res, "amopopr");
   14608                 :         654 :     i_sortfamily = PQfnumber(res, "sortfamily");
   14609                 :         654 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   14610                 :             : 
   14611         [ +  + ]:         868 :     for (i = 0; i < ntups; i++)
   14612                 :             :     {
   14613                 :         214 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   14614                 :         214 :         amopopr = PQgetvalue(res, i, i_amopopr);
   14615                 :         214 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   14616                 :         214 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   14617                 :             : 
   14618         [ +  + ]:         214 :         if (needComma)
   14619                 :         136 :             appendPQExpBufferStr(q, " ,\n    ");
   14620                 :             : 
   14621                 :         214 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   14622                 :             :                           amopstrategy, amopopr);
   14623                 :             : 
   14624         [ -  + ]:         214 :         if (strlen(sortfamily) > 0)
   14625                 :             :         {
   14626                 :           0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   14627                 :           0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14628                 :           0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   14629                 :             :         }
   14630                 :             : 
   14631                 :         214 :         needComma = true;
   14632                 :             :     }
   14633                 :             : 
   14634                 :         654 :     PQclear(res);
   14635                 :             : 
   14636                 :             :     /*
   14637                 :             :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14638                 :             :      *
   14639                 :             :      * Print only those opfamily members that are tied to the opclass by
   14640                 :             :      * pg_depend entries.
   14641                 :             :      *
   14642                 :             :      * We print the amproclefttype/amprocrighttype even though in most cases
   14643                 :             :      * the backend could deduce the right values, because of the corner case
   14644                 :             :      * of a btree sort support function for a cross-type comparison.
   14645                 :             :      */
   14646                 :         654 :     resetPQExpBuffer(query);
   14647                 :             : 
   14648                 :         654 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14649                 :             :                       "amproc::pg_catalog.regprocedure, "
   14650                 :             :                       "amproclefttype::pg_catalog.regtype, "
   14651                 :             :                       "amprocrighttype::pg_catalog.regtype "
   14652                 :             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14653                 :             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   14654                 :             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14655                 :             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14656                 :             :                       "AND objid = ap.oid "
   14657                 :             :                       "ORDER BY amprocnum",
   14658                 :         654 :                       opcinfo->dobj.catId.oid);
   14659                 :             : 
   14660                 :         654 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14661                 :             : 
   14662                 :         654 :     ntups = PQntuples(res);
   14663                 :             : 
   14664                 :         654 :     i_amprocnum = PQfnumber(res, "amprocnum");
   14665                 :         654 :     i_amproc = PQfnumber(res, "amproc");
   14666                 :         654 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   14667                 :         654 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   14668                 :             : 
   14669         [ +  + ]:         688 :     for (i = 0; i < ntups; i++)
   14670                 :             :     {
   14671                 :          34 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   14672                 :          34 :         amproc = PQgetvalue(res, i, i_amproc);
   14673                 :          34 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   14674                 :          34 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   14675                 :             : 
   14676         [ +  - ]:          34 :         if (needComma)
   14677                 :          34 :             appendPQExpBufferStr(q, " ,\n    ");
   14678                 :             : 
   14679                 :          34 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   14680                 :             : 
   14681   [ +  -  +  - ]:          34 :         if (*amproclefttype && *amprocrighttype)
   14682                 :          34 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   14683                 :             : 
   14684                 :          34 :         appendPQExpBuffer(q, " %s", amproc);
   14685                 :             : 
   14686                 :          34 :         needComma = true;
   14687                 :             :     }
   14688                 :             : 
   14689                 :         654 :     PQclear(res);
   14690                 :             : 
   14691                 :             :     /*
   14692                 :             :      * If needComma is still false it means we haven't added anything after
   14693                 :             :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   14694                 :             :      * clause with the same datatype.  This isn't sanctioned by the
   14695                 :             :      * documentation, but actually DefineOpClass will treat it as a no-op.
   14696                 :             :      */
   14697         [ +  + ]:         654 :     if (!needComma)
   14698                 :         324 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   14699                 :             : 
   14700                 :         654 :     appendPQExpBufferStr(q, ";\n");
   14701                 :             : 
   14702                 :         654 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   14703                 :         654 :     appendPQExpBuffer(nameusing, " USING %s",
   14704                 :             :                       fmtId(amname));
   14705                 :             : 
   14706         [ +  + ]:         654 :     if (dopt->binary_upgrade)
   14707                 :           6 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   14708                 :           6 :                                         "OPERATOR CLASS", nameusing->data,
   14709                 :           6 :                                         opcinfo->dobj.namespace->dobj.name);
   14710                 :             : 
   14711         [ +  - ]:         654 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14712                 :         654 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   14713                 :         654 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   14714                 :             :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   14715                 :             :                                   .owner = opcinfo->rolname,
   14716                 :             :                                   .description = "OPERATOR CLASS",
   14717                 :             :                                   .section = SECTION_PRE_DATA,
   14718                 :             :                                   .createStmt = q->data,
   14719                 :             :                                   .dropStmt = delq->data));
   14720                 :             : 
   14721                 :             :     /* Dump Operator Class Comments */
   14722         [ -  + ]:         654 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14723                 :           0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   14724                 :           0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   14725                 :           0 :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   14726                 :             : 
   14727                 :         654 :     pg_free(opcintype);
   14728                 :         654 :     pg_free(opcfamily);
   14729                 :         654 :     pg_free(amname);
   14730                 :         654 :     destroyPQExpBuffer(query);
   14731                 :         654 :     destroyPQExpBuffer(q);
   14732                 :         654 :     destroyPQExpBuffer(delq);
   14733                 :         654 :     destroyPQExpBuffer(nameusing);
   14734                 :             : }
   14735                 :             : 
   14736                 :             : /*
   14737                 :             :  * dumpOpfamily
   14738                 :             :  *    write out a single operator family definition
   14739                 :             :  *
   14740                 :             :  * Note: this also dumps any "loose" operator members that aren't bound to a
   14741                 :             :  * specific opclass within the opfamily.
   14742                 :             :  */
   14743                 :             : static void
   14744                 :         561 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   14745                 :             : {
   14746                 :         561 :     DumpOptions *dopt = fout->dopt;
   14747                 :             :     PQExpBuffer query;
   14748                 :             :     PQExpBuffer q;
   14749                 :             :     PQExpBuffer delq;
   14750                 :             :     PQExpBuffer nameusing;
   14751                 :             :     PGresult   *res;
   14752                 :             :     PGresult   *res_ops;
   14753                 :             :     PGresult   *res_procs;
   14754                 :             :     int         ntups;
   14755                 :             :     int         i_amname;
   14756                 :             :     int         i_amopstrategy;
   14757                 :             :     int         i_amopopr;
   14758                 :             :     int         i_sortfamily;
   14759                 :             :     int         i_sortfamilynsp;
   14760                 :             :     int         i_amprocnum;
   14761                 :             :     int         i_amproc;
   14762                 :             :     int         i_amproclefttype;
   14763                 :             :     int         i_amprocrighttype;
   14764                 :             :     char       *amname;
   14765                 :             :     char       *amopstrategy;
   14766                 :             :     char       *amopopr;
   14767                 :             :     char       *sortfamily;
   14768                 :             :     char       *sortfamilynsp;
   14769                 :             :     char       *amprocnum;
   14770                 :             :     char       *amproc;
   14771                 :             :     char       *amproclefttype;
   14772                 :             :     char       *amprocrighttype;
   14773                 :             :     bool        needComma;
   14774                 :             :     int         i;
   14775                 :             : 
   14776                 :             :     /* Do nothing if not dumping schema */
   14777         [ +  + ]:         561 :     if (!dopt->dumpSchema)
   14778                 :          14 :         return;
   14779                 :             : 
   14780                 :         547 :     query = createPQExpBuffer();
   14781                 :         547 :     q = createPQExpBuffer();
   14782                 :         547 :     delq = createPQExpBuffer();
   14783                 :         547 :     nameusing = createPQExpBuffer();
   14784                 :             : 
   14785                 :             :     /*
   14786                 :             :      * Fetch only those opfamily members that are tied directly to the
   14787                 :             :      * opfamily by pg_depend entries.
   14788                 :             :      */
   14789                 :         547 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14790                 :             :                       "amopopr::pg_catalog.regoperator, "
   14791                 :             :                       "opfname AS sortfamily, "
   14792                 :             :                       "nspname AS sortfamilynsp "
   14793                 :             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14794                 :             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14795                 :             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14796                 :             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14797                 :             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14798                 :             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14799                 :             :                       "AND amopfamily = '%u'::pg_catalog.oid "
   14800                 :             :                       "ORDER BY amopstrategy",
   14801                 :         547 :                       opfinfo->dobj.catId.oid,
   14802                 :         547 :                       opfinfo->dobj.catId.oid);
   14803                 :             : 
   14804                 :         547 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14805                 :             : 
   14806                 :         547 :     resetPQExpBuffer(query);
   14807                 :             : 
   14808                 :         547 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14809                 :             :                       "amproc::pg_catalog.regprocedure, "
   14810                 :             :                       "amproclefttype::pg_catalog.regtype, "
   14811                 :             :                       "amprocrighttype::pg_catalog.regtype "
   14812                 :             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14813                 :             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14814                 :             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14815                 :             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14816                 :             :                       "AND objid = ap.oid "
   14817                 :             :                       "ORDER BY amprocnum",
   14818                 :         547 :                       opfinfo->dobj.catId.oid);
   14819                 :             : 
   14820                 :         547 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14821                 :             : 
   14822                 :             :     /* Get additional fields from the pg_opfamily row */
   14823                 :         547 :     resetPQExpBuffer(query);
   14824                 :             : 
   14825                 :         547 :     appendPQExpBuffer(query, "SELECT "
   14826                 :             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   14827                 :             :                       "FROM pg_catalog.pg_opfamily "
   14828                 :             :                       "WHERE oid = '%u'::pg_catalog.oid",
   14829                 :         547 :                       opfinfo->dobj.catId.oid);
   14830                 :             : 
   14831                 :         547 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14832                 :             : 
   14833                 :         547 :     i_amname = PQfnumber(res, "amname");
   14834                 :             : 
   14835                 :             :     /* amname will still be needed after we PQclear res */
   14836                 :         547 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14837                 :             : 
   14838                 :         547 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   14839                 :         547 :                       fmtQualifiedDumpable(opfinfo));
   14840                 :         547 :     appendPQExpBuffer(delq, " USING %s;\n",
   14841                 :             :                       fmtId(amname));
   14842                 :             : 
   14843                 :             :     /* Build the fixed portion of the CREATE command */
   14844                 :         547 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   14845                 :         547 :                       fmtQualifiedDumpable(opfinfo));
   14846                 :         547 :     appendPQExpBuffer(q, " USING %s;\n",
   14847                 :             :                       fmtId(amname));
   14848                 :             : 
   14849                 :         547 :     PQclear(res);
   14850                 :             : 
   14851                 :             :     /* Do we need an ALTER to add loose members? */
   14852   [ +  +  +  + ]:         547 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   14853                 :             :     {
   14854                 :          49 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   14855                 :          49 :                           fmtQualifiedDumpable(opfinfo));
   14856                 :          49 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   14857                 :             :                           fmtId(amname));
   14858                 :             : 
   14859                 :          49 :         needComma = false;
   14860                 :             : 
   14861                 :             :         /*
   14862                 :             :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   14863                 :             :          */
   14864                 :          49 :         ntups = PQntuples(res_ops);
   14865                 :             : 
   14866                 :          49 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   14867                 :          49 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   14868                 :          49 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   14869                 :          49 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   14870                 :             : 
   14871         [ +  + ]:         219 :         for (i = 0; i < ntups; i++)
   14872                 :             :         {
   14873                 :         170 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   14874                 :         170 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   14875                 :         170 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   14876                 :         170 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   14877                 :             : 
   14878         [ +  + ]:         170 :             if (needComma)
   14879                 :         136 :                 appendPQExpBufferStr(q, " ,\n    ");
   14880                 :             : 
   14881                 :         170 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   14882                 :             :                               amopstrategy, amopopr);
   14883                 :             : 
   14884         [ -  + ]:         170 :             if (strlen(sortfamily) > 0)
   14885                 :             :             {
   14886                 :           0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   14887                 :           0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14888                 :           0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   14889                 :             :             }
   14890                 :             : 
   14891                 :         170 :             needComma = true;
   14892                 :             :         }
   14893                 :             : 
   14894                 :             :         /*
   14895                 :             :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14896                 :             :          */
   14897                 :          49 :         ntups = PQntuples(res_procs);
   14898                 :             : 
   14899                 :          49 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   14900                 :          49 :         i_amproc = PQfnumber(res_procs, "amproc");
   14901                 :          49 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   14902                 :          49 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   14903                 :             : 
   14904         [ +  + ]:         234 :         for (i = 0; i < ntups; i++)
   14905                 :             :         {
   14906                 :         185 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   14907                 :         185 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   14908                 :         185 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   14909                 :         185 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   14910                 :             : 
   14911         [ +  + ]:         185 :             if (needComma)
   14912                 :         170 :                 appendPQExpBufferStr(q, " ,\n    ");
   14913                 :             : 
   14914                 :         185 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   14915                 :             :                               amprocnum, amproclefttype, amprocrighttype,
   14916                 :             :                               amproc);
   14917                 :             : 
   14918                 :         185 :             needComma = true;
   14919                 :             :         }
   14920                 :             : 
   14921                 :          49 :         appendPQExpBufferStr(q, ";\n");
   14922                 :             :     }
   14923                 :             : 
   14924                 :         547 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   14925                 :         547 :     appendPQExpBuffer(nameusing, " USING %s",
   14926                 :             :                       fmtId(amname));
   14927                 :             : 
   14928         [ +  + ]:         547 :     if (dopt->binary_upgrade)
   14929                 :           9 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   14930                 :           9 :                                         "OPERATOR FAMILY", nameusing->data,
   14931                 :           9 :                                         opfinfo->dobj.namespace->dobj.name);
   14932                 :             : 
   14933         [ +  - ]:         547 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14934                 :         547 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   14935                 :         547 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   14936                 :             :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   14937                 :             :                                   .owner = opfinfo->rolname,
   14938                 :             :                                   .description = "OPERATOR FAMILY",
   14939                 :             :                                   .section = SECTION_PRE_DATA,
   14940                 :             :                                   .createStmt = q->data,
   14941                 :             :                                   .dropStmt = delq->data));
   14942                 :             : 
   14943                 :             :     /* Dump Operator Family Comments */
   14944         [ -  + ]:         547 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14945                 :           0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   14946                 :           0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   14947                 :           0 :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   14948                 :             : 
   14949                 :         547 :     pg_free(amname);
   14950                 :         547 :     PQclear(res_ops);
   14951                 :         547 :     PQclear(res_procs);
   14952                 :         547 :     destroyPQExpBuffer(query);
   14953                 :         547 :     destroyPQExpBuffer(q);
   14954                 :         547 :     destroyPQExpBuffer(delq);
   14955                 :         547 :     destroyPQExpBuffer(nameusing);
   14956                 :             : }
   14957                 :             : 
   14958                 :             : /*
   14959                 :             :  * dumpCollation
   14960                 :             :  *    write out a single collation definition
   14961                 :             :  */
   14962                 :             : static void
   14963                 :        2733 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   14964                 :             : {
   14965                 :        2733 :     DumpOptions *dopt = fout->dopt;
   14966                 :             :     PQExpBuffer query;
   14967                 :             :     PQExpBuffer q;
   14968                 :             :     PQExpBuffer delq;
   14969                 :             :     char       *qcollname;
   14970                 :             :     PGresult   *res;
   14971                 :             :     int         i_collprovider;
   14972                 :             :     int         i_collisdeterministic;
   14973                 :             :     int         i_collcollate;
   14974                 :             :     int         i_collctype;
   14975                 :             :     int         i_colllocale;
   14976                 :             :     int         i_collicurules;
   14977                 :             :     const char *collprovider;
   14978                 :             :     const char *collcollate;
   14979                 :             :     const char *collctype;
   14980                 :             :     const char *colllocale;
   14981                 :             :     const char *collicurules;
   14982                 :             : 
   14983                 :             :     /* Do nothing if not dumping schema */
   14984         [ +  + ]:        2733 :     if (!dopt->dumpSchema)
   14985                 :          12 :         return;
   14986                 :             : 
   14987                 :        2721 :     query = createPQExpBuffer();
   14988                 :        2721 :     q = createPQExpBuffer();
   14989                 :        2721 :     delq = createPQExpBuffer();
   14990                 :             : 
   14991                 :        2721 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   14992                 :             : 
   14993                 :             :     /* Get collation-specific details */
   14994                 :        2721 :     appendPQExpBufferStr(query, "SELECT ");
   14995                 :             : 
   14996                 :        2721 :     appendPQExpBufferStr(query,
   14997                 :             :                          "collprovider, "
   14998                 :             :                          "collversion, ");
   14999                 :             : 
   15000         [ +  - ]:        2721 :     if (fout->remoteVersion >= 120000)
   15001                 :        2721 :         appendPQExpBufferStr(query,
   15002                 :             :                              "collisdeterministic, ");
   15003                 :             :     else
   15004                 :           0 :         appendPQExpBufferStr(query,
   15005                 :             :                              "true AS collisdeterministic, ");
   15006                 :             : 
   15007         [ +  - ]:        2721 :     if (fout->remoteVersion >= 170000)
   15008                 :        2721 :         appendPQExpBufferStr(query,
   15009                 :             :                              "colllocale, ");
   15010         [ #  # ]:           0 :     else if (fout->remoteVersion >= 150000)
   15011                 :           0 :         appendPQExpBufferStr(query,
   15012                 :             :                              "colliculocale AS colllocale, ");
   15013                 :             :     else
   15014                 :           0 :         appendPQExpBufferStr(query,
   15015                 :             :                              "NULL AS colllocale, ");
   15016                 :             : 
   15017         [ +  - ]:        2721 :     if (fout->remoteVersion >= 160000)
   15018                 :        2721 :         appendPQExpBufferStr(query,
   15019                 :             :                              "collicurules, ");
   15020                 :             :     else
   15021                 :           0 :         appendPQExpBufferStr(query,
   15022                 :             :                              "NULL AS collicurules, ");
   15023                 :             : 
   15024                 :        2721 :     appendPQExpBuffer(query,
   15025                 :             :                       "collcollate, "
   15026                 :             :                       "collctype "
   15027                 :             :                       "FROM pg_catalog.pg_collation c "
   15028                 :             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15029                 :        2721 :                       collinfo->dobj.catId.oid);
   15030                 :             : 
   15031                 :        2721 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15032                 :             : 
   15033                 :        2721 :     i_collprovider = PQfnumber(res, "collprovider");
   15034                 :        2721 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   15035                 :        2721 :     i_collcollate = PQfnumber(res, "collcollate");
   15036                 :        2721 :     i_collctype = PQfnumber(res, "collctype");
   15037                 :        2721 :     i_colllocale = PQfnumber(res, "colllocale");
   15038                 :        2721 :     i_collicurules = PQfnumber(res, "collicurules");
   15039                 :             : 
   15040                 :        2721 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   15041                 :             : 
   15042         [ +  + ]:        2721 :     if (!PQgetisnull(res, 0, i_collcollate))
   15043                 :          48 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   15044                 :             :     else
   15045                 :        2673 :         collcollate = NULL;
   15046                 :             : 
   15047         [ +  + ]:        2721 :     if (!PQgetisnull(res, 0, i_collctype))
   15048                 :          48 :         collctype = PQgetvalue(res, 0, i_collctype);
   15049                 :             :     else
   15050                 :        2673 :         collctype = NULL;
   15051                 :             : 
   15052                 :             :     /*
   15053                 :             :      * Before version 15, collcollate and collctype were of type NAME and
   15054                 :             :      * non-nullable. Treat empty strings as NULL for consistency.
   15055                 :             :      */
   15056         [ -  + ]:        2721 :     if (fout->remoteVersion < 150000)
   15057                 :             :     {
   15058         [ #  # ]:           0 :         if (collcollate[0] == '\0')
   15059                 :           0 :             collcollate = NULL;
   15060         [ #  # ]:           0 :         if (collctype[0] == '\0')
   15061                 :           0 :             collctype = NULL;
   15062                 :             :     }
   15063                 :             : 
   15064         [ +  + ]:        2721 :     if (!PQgetisnull(res, 0, i_colllocale))
   15065                 :        2670 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   15066                 :             :     else
   15067                 :          51 :         colllocale = NULL;
   15068                 :             : 
   15069         [ -  + ]:        2721 :     if (!PQgetisnull(res, 0, i_collicurules))
   15070                 :           0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   15071                 :             :     else
   15072                 :        2721 :         collicurules = NULL;
   15073                 :             : 
   15074                 :        2721 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   15075                 :        2721 :                       fmtQualifiedDumpable(collinfo));
   15076                 :             : 
   15077                 :        2721 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   15078                 :        2721 :                       fmtQualifiedDumpable(collinfo));
   15079                 :             : 
   15080                 :        2721 :     appendPQExpBufferStr(q, "provider = ");
   15081         [ +  + ]:        2721 :     if (collprovider[0] == 'b')
   15082                 :          19 :         appendPQExpBufferStr(q, "builtin");
   15083         [ +  + ]:        2702 :     else if (collprovider[0] == 'c')
   15084                 :          48 :         appendPQExpBufferStr(q, "libc");
   15085         [ +  + ]:        2654 :     else if (collprovider[0] == 'i')
   15086                 :        2651 :         appendPQExpBufferStr(q, "icu");
   15087         [ +  - ]:           3 :     else if (collprovider[0] == 'd')
   15088                 :             :         /* to allow dumping pg_catalog; not accepted on input */
   15089                 :           3 :         appendPQExpBufferStr(q, "default");
   15090                 :             :     else
   15091                 :           0 :         pg_fatal("unrecognized collation provider: %s",
   15092                 :             :                  collprovider);
   15093                 :             : 
   15094         [ -  + ]:        2721 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   15095                 :           0 :         appendPQExpBufferStr(q, ", deterministic = false");
   15096                 :             : 
   15097         [ +  + ]:        2721 :     if (collprovider[0] == 'd')
   15098                 :             :     {
   15099   [ +  -  +  -  :           3 :         if (collcollate || collctype || colllocale || collicurules)
             +  -  -  + ]
   15100                 :           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15101                 :             : 
   15102                 :             :         /* no locale -- the default collation cannot be reloaded anyway */
   15103                 :             :     }
   15104         [ +  + ]:        2718 :     else if (collprovider[0] == 'b')
   15105                 :             :     {
   15106   [ +  -  +  -  :          19 :         if (collcollate || collctype || !colllocale || collicurules)
             +  -  -  + ]
   15107                 :           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15108                 :             : 
   15109                 :          19 :         appendPQExpBufferStr(q, ", locale = ");
   15110         [ +  - ]:          19 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   15111                 :             :                               fout);
   15112                 :             :     }
   15113         [ +  + ]:        2699 :     else if (collprovider[0] == 'i')
   15114                 :             :     {
   15115         [ +  - ]:        2651 :         if (fout->remoteVersion >= 150000)
   15116                 :             :         {
   15117   [ +  -  +  -  :        2651 :             if (collcollate || collctype || !colllocale)
                   -  + ]
   15118                 :           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15119                 :             : 
   15120                 :        2651 :             appendPQExpBufferStr(q, ", locale = ");
   15121         [ +  - ]:        2651 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   15122                 :             :                                   fout);
   15123                 :             :         }
   15124                 :             :         else
   15125                 :             :         {
   15126   [ #  #  #  #  :           0 :             if (!collcollate || !collctype || colllocale ||
                   #  # ]
   15127         [ #  # ]:           0 :                 strcmp(collcollate, collctype) != 0)
   15128                 :           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   15129                 :             : 
   15130                 :           0 :             appendPQExpBufferStr(q, ", locale = ");
   15131         [ #  # ]:           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15132                 :             :         }
   15133                 :             : 
   15134         [ -  + ]:        2651 :         if (collicurules)
   15135                 :             :         {
   15136                 :           0 :             appendPQExpBufferStr(q, ", rules = ");
   15137         [ #  # ]:           0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   15138                 :             :         }
   15139                 :             :     }
   15140         [ +  - ]:          48 :     else if (collprovider[0] == 'c')
   15141                 :             :     {
   15142   [ +  -  +  -  :          48 :         if (colllocale || collicurules || !collcollate || !collctype)
             +  -  -  + ]
   15143                 :           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   15144                 :             : 
   15145   [ +  -  +  -  :          48 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
                   +  - ]
   15146                 :             :         {
   15147                 :          48 :             appendPQExpBufferStr(q, ", locale = ");
   15148         [ +  - ]:          48 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15149                 :             :         }
   15150                 :             :         else
   15151                 :             :         {
   15152                 :           0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   15153         [ #  # ]:           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   15154                 :           0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   15155         [ #  # ]:           0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   15156                 :             :         }
   15157                 :             :     }
   15158                 :             :     else
   15159                 :           0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   15160                 :             : 
   15161                 :             :     /*
   15162                 :             :      * For binary upgrade, carry over the collation version.  For normal
   15163                 :             :      * dump/restore, omit the version, so that it is computed upon restore.
   15164                 :             :      */
   15165         [ +  + ]:        2721 :     if (dopt->binary_upgrade)
   15166                 :             :     {
   15167                 :             :         int         i_collversion;
   15168                 :             : 
   15169                 :           5 :         i_collversion = PQfnumber(res, "collversion");
   15170         [ +  + ]:           5 :         if (!PQgetisnull(res, 0, i_collversion))
   15171                 :             :         {
   15172                 :           4 :             appendPQExpBufferStr(q, ", version = ");
   15173                 :           4 :             appendStringLiteralAH(q,
   15174                 :             :                                   PQgetvalue(res, 0, i_collversion),
   15175                 :             :                                   fout);
   15176                 :             :         }
   15177                 :             :     }
   15178                 :             : 
   15179                 :        2721 :     appendPQExpBufferStr(q, ");\n");
   15180                 :             : 
   15181         [ +  + ]:        2721 :     if (dopt->binary_upgrade)
   15182                 :           5 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   15183                 :             :                                         "COLLATION", qcollname,
   15184                 :           5 :                                         collinfo->dobj.namespace->dobj.name);
   15185                 :             : 
   15186         [ +  - ]:        2721 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15187                 :        2721 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   15188                 :        2721 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   15189                 :             :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   15190                 :             :                                   .owner = collinfo->rolname,
   15191                 :             :                                   .description = "COLLATION",
   15192                 :             :                                   .section = SECTION_PRE_DATA,
   15193                 :             :                                   .createStmt = q->data,
   15194                 :             :                                   .dropStmt = delq->data));
   15195                 :             : 
   15196                 :             :     /* Dump Collation Comments */
   15197         [ +  + ]:        2721 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15198                 :        2613 :         dumpComment(fout, "COLLATION", qcollname,
   15199                 :        2613 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   15200                 :        2613 :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   15201                 :             : 
   15202                 :        2721 :     PQclear(res);
   15203                 :             : 
   15204                 :        2721 :     destroyPQExpBuffer(query);
   15205                 :        2721 :     destroyPQExpBuffer(q);
   15206                 :        2721 :     destroyPQExpBuffer(delq);
   15207                 :        2721 :     pg_free(qcollname);
   15208                 :             : }
   15209                 :             : 
   15210                 :             : /*
   15211                 :             :  * dumpConversion
   15212                 :             :  *    write out a single conversion definition
   15213                 :             :  */
   15214                 :             : static void
   15215                 :         335 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   15216                 :             : {
   15217                 :         335 :     DumpOptions *dopt = fout->dopt;
   15218                 :             :     PQExpBuffer query;
   15219                 :             :     PQExpBuffer q;
   15220                 :             :     PQExpBuffer delq;
   15221                 :             :     char       *qconvname;
   15222                 :             :     PGresult   *res;
   15223                 :             :     int         i_conforencoding;
   15224                 :             :     int         i_contoencoding;
   15225                 :             :     int         i_conproc;
   15226                 :             :     int         i_condefault;
   15227                 :             :     const char *conforencoding;
   15228                 :             :     const char *contoencoding;
   15229                 :             :     const char *conproc;
   15230                 :             :     bool        condefault;
   15231                 :             : 
   15232                 :             :     /* Do nothing if not dumping schema */
   15233         [ +  + ]:         335 :     if (!dopt->dumpSchema)
   15234                 :           7 :         return;
   15235                 :             : 
   15236                 :         328 :     query = createPQExpBuffer();
   15237                 :         328 :     q = createPQExpBuffer();
   15238                 :         328 :     delq = createPQExpBuffer();
   15239                 :             : 
   15240                 :         328 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   15241                 :             : 
   15242                 :             :     /* Get conversion-specific details */
   15243                 :         328 :     appendPQExpBuffer(query, "SELECT "
   15244                 :             :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   15245                 :             :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   15246                 :             :                       "conproc, condefault "
   15247                 :             :                       "FROM pg_catalog.pg_conversion c "
   15248                 :             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   15249                 :         328 :                       convinfo->dobj.catId.oid);
   15250                 :             : 
   15251                 :         328 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15252                 :             : 
   15253                 :         328 :     i_conforencoding = PQfnumber(res, "conforencoding");
   15254                 :         328 :     i_contoencoding = PQfnumber(res, "contoencoding");
   15255                 :         328 :     i_conproc = PQfnumber(res, "conproc");
   15256                 :         328 :     i_condefault = PQfnumber(res, "condefault");
   15257                 :             : 
   15258                 :         328 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   15259                 :         328 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   15260                 :         328 :     conproc = PQgetvalue(res, 0, i_conproc);
   15261                 :         328 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   15262                 :             : 
   15263                 :         328 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   15264                 :         328 :                       fmtQualifiedDumpable(convinfo));
   15265                 :             : 
   15266         [ +  - ]:         328 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   15267                 :             :                       (condefault) ? "DEFAULT " : "",
   15268                 :         328 :                       fmtQualifiedDumpable(convinfo));
   15269                 :         328 :     appendStringLiteralAH(q, conforencoding, fout);
   15270                 :         328 :     appendPQExpBufferStr(q, " TO ");
   15271                 :         328 :     appendStringLiteralAH(q, contoencoding, fout);
   15272                 :             :     /* regproc output is already sufficiently quoted */
   15273                 :         328 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   15274                 :             : 
   15275         [ +  + ]:         328 :     if (dopt->binary_upgrade)
   15276                 :           1 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   15277                 :             :                                         "CONVERSION", qconvname,
   15278                 :           1 :                                         convinfo->dobj.namespace->dobj.name);
   15279                 :             : 
   15280         [ +  - ]:         328 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15281                 :         328 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   15282                 :         328 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   15283                 :             :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   15284                 :             :                                   .owner = convinfo->rolname,
   15285                 :             :                                   .description = "CONVERSION",
   15286                 :             :                                   .section = SECTION_PRE_DATA,
   15287                 :             :                                   .createStmt = q->data,
   15288                 :             :                                   .dropStmt = delq->data));
   15289                 :             : 
   15290                 :             :     /* Dump Conversion Comments */
   15291         [ +  - ]:         328 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15292                 :         328 :         dumpComment(fout, "CONVERSION", qconvname,
   15293                 :         328 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   15294                 :         328 :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   15295                 :             : 
   15296                 :         328 :     PQclear(res);
   15297                 :             : 
   15298                 :         328 :     destroyPQExpBuffer(query);
   15299                 :         328 :     destroyPQExpBuffer(q);
   15300                 :         328 :     destroyPQExpBuffer(delq);
   15301                 :         328 :     pg_free(qconvname);
   15302                 :             : }
   15303                 :             : 
   15304                 :             : /*
   15305                 :             :  * format_aggregate_signature: generate aggregate name and argument list
   15306                 :             :  *
   15307                 :             :  * The argument type names are qualified if needed.  The aggregate name
   15308                 :             :  * is never qualified.
   15309                 :             :  */
   15310                 :             : static char *
   15311                 :         287 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   15312                 :             : {
   15313                 :             :     PQExpBufferData buf;
   15314                 :             :     int         j;
   15315                 :             : 
   15316                 :         287 :     initPQExpBuffer(&buf);
   15317         [ -  + ]:         287 :     if (honor_quotes)
   15318                 :           0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   15319                 :             :     else
   15320                 :         287 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   15321                 :             : 
   15322         [ +  + ]:         287 :     if (agginfo->aggfn.nargs == 0)
   15323                 :          40 :         appendPQExpBufferStr(&buf, "(*)");
   15324                 :             :     else
   15325                 :             :     {
   15326                 :         247 :         appendPQExpBufferChar(&buf, '(');
   15327         [ +  + ]:         539 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   15328         [ +  + ]:         292 :             appendPQExpBuffer(&buf, "%s%s",
   15329                 :             :                               (j > 0) ? ", " : "",
   15330                 :             :                               getFormattedTypeName(fout,
   15331                 :         292 :                                                    agginfo->aggfn.argtypes[j],
   15332                 :             :                                                    zeroIsError));
   15333                 :         247 :         appendPQExpBufferChar(&buf, ')');
   15334                 :             :     }
   15335                 :         287 :     return buf.data;
   15336                 :             : }
   15337                 :             : 
   15338                 :             : /*
   15339                 :             :  * dumpAgg
   15340                 :             :  *    write out a single aggregate definition
   15341                 :             :  */
   15342                 :             : static void
   15343                 :         295 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   15344                 :             : {
   15345                 :         295 :     DumpOptions *dopt = fout->dopt;
   15346                 :             :     PQExpBuffer query;
   15347                 :             :     PQExpBuffer q;
   15348                 :             :     PQExpBuffer delq;
   15349                 :             :     PQExpBuffer details;
   15350                 :             :     char       *aggsig;         /* identity signature */
   15351                 :         295 :     char       *aggfullsig = NULL;  /* full signature */
   15352                 :             :     char       *aggsig_tag;
   15353                 :             :     PGresult   *res;
   15354                 :             :     int         i_agginitval;
   15355                 :             :     int         i_aggminitval;
   15356                 :             :     const char *aggtransfn;
   15357                 :             :     const char *aggfinalfn;
   15358                 :             :     const char *aggcombinefn;
   15359                 :             :     const char *aggserialfn;
   15360                 :             :     const char *aggdeserialfn;
   15361                 :             :     const char *aggmtransfn;
   15362                 :             :     const char *aggminvtransfn;
   15363                 :             :     const char *aggmfinalfn;
   15364                 :             :     bool        aggfinalextra;
   15365                 :             :     bool        aggmfinalextra;
   15366                 :             :     char        aggfinalmodify;
   15367                 :             :     char        aggmfinalmodify;
   15368                 :             :     const char *aggsortop;
   15369                 :             :     char       *aggsortconvop;
   15370                 :             :     char        aggkind;
   15371                 :             :     const char *aggtranstype;
   15372                 :             :     const char *aggtransspace;
   15373                 :             :     const char *aggmtranstype;
   15374                 :             :     const char *aggmtransspace;
   15375                 :             :     const char *agginitval;
   15376                 :             :     const char *aggminitval;
   15377                 :             :     const char *proparallel;
   15378                 :             :     char        defaultfinalmodify;
   15379                 :             : 
   15380                 :             :     /* Do nothing if not dumping schema */
   15381         [ +  + ]:         295 :     if (!dopt->dumpSchema)
   15382                 :           8 :         return;
   15383                 :             : 
   15384                 :         287 :     query = createPQExpBuffer();
   15385                 :         287 :     q = createPQExpBuffer();
   15386                 :         287 :     delq = createPQExpBuffer();
   15387                 :         287 :     details = createPQExpBuffer();
   15388                 :             : 
   15389         [ +  + ]:         287 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   15390                 :             :     {
   15391                 :             :         /* Set up query for aggregate-specific details */
   15392                 :          57 :         appendPQExpBufferStr(query,
   15393                 :             :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   15394                 :             : 
   15395                 :          57 :         appendPQExpBufferStr(query,
   15396                 :             :                              "SELECT "
   15397                 :             :                              "aggtransfn,\n"
   15398                 :             :                              "aggfinalfn,\n"
   15399                 :             :                              "aggtranstype::pg_catalog.regtype,\n"
   15400                 :             :                              "agginitval,\n"
   15401                 :             :                              "aggsortop,\n"
   15402                 :             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   15403                 :             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   15404                 :             : 
   15405                 :          57 :         appendPQExpBufferStr(query,
   15406                 :             :                              "aggkind,\n"
   15407                 :             :                              "aggmtransfn,\n"
   15408                 :             :                              "aggminvtransfn,\n"
   15409                 :             :                              "aggmfinalfn,\n"
   15410                 :             :                              "aggmtranstype::pg_catalog.regtype,\n"
   15411                 :             :                              "aggfinalextra,\n"
   15412                 :             :                              "aggmfinalextra,\n"
   15413                 :             :                              "aggtransspace,\n"
   15414                 :             :                              "aggmtransspace,\n"
   15415                 :             :                              "aggminitval,\n");
   15416                 :             : 
   15417                 :          57 :         appendPQExpBufferStr(query,
   15418                 :             :                              "aggcombinefn,\n"
   15419                 :             :                              "aggserialfn,\n"
   15420                 :             :                              "aggdeserialfn,\n"
   15421                 :             :                              "proparallel,\n");
   15422                 :             : 
   15423         [ +  - ]:          57 :         if (fout->remoteVersion >= 110000)
   15424                 :          57 :             appendPQExpBufferStr(query,
   15425                 :             :                                  "aggfinalmodify,\n"
   15426                 :             :                                  "aggmfinalmodify\n");
   15427                 :             :         else
   15428                 :           0 :             appendPQExpBufferStr(query,
   15429                 :             :                                  "'0' AS aggfinalmodify,\n"
   15430                 :             :                                  "'0' AS aggmfinalmodify\n");
   15431                 :             : 
   15432                 :          57 :         appendPQExpBufferStr(query,
   15433                 :             :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   15434                 :             :                              "WHERE a.aggfnoid = p.oid "
   15435                 :             :                              "AND p.oid = $1");
   15436                 :             : 
   15437                 :          57 :         ExecuteSqlStatement(fout, query->data);
   15438                 :             : 
   15439                 :          57 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   15440                 :             :     }
   15441                 :             : 
   15442                 :         287 :     printfPQExpBuffer(query,
   15443                 :             :                       "EXECUTE dumpAgg('%u')",
   15444                 :         287 :                       agginfo->aggfn.dobj.catId.oid);
   15445                 :             : 
   15446                 :         287 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15447                 :             : 
   15448                 :         287 :     i_agginitval = PQfnumber(res, "agginitval");
   15449                 :         287 :     i_aggminitval = PQfnumber(res, "aggminitval");
   15450                 :             : 
   15451                 :         287 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   15452                 :         287 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   15453                 :         287 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   15454                 :         287 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   15455                 :         287 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   15456                 :         287 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   15457                 :         287 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   15458                 :         287 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   15459                 :         287 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   15460                 :         287 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   15461                 :         287 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   15462                 :         287 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   15463                 :         287 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   15464                 :         287 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   15465                 :         287 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   15466                 :         287 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   15467                 :         287 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   15468                 :         287 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   15469                 :         287 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   15470                 :         287 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   15471                 :         287 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   15472                 :             : 
   15473                 :             :     {
   15474                 :             :         char       *funcargs;
   15475                 :             :         char       *funciargs;
   15476                 :             : 
   15477                 :         287 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   15478                 :         287 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   15479                 :         287 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   15480                 :         287 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   15481                 :             :     }
   15482                 :             : 
   15483                 :         287 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   15484                 :             : 
   15485                 :             :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   15486         [ +  + ]:         287 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   15487                 :             :     /* replace omitted flags for old versions */
   15488         [ -  + ]:         287 :     if (aggfinalmodify == '0')
   15489                 :           0 :         aggfinalmodify = defaultfinalmodify;
   15490         [ -  + ]:         287 :     if (aggmfinalmodify == '0')
   15491                 :           0 :         aggmfinalmodify = defaultfinalmodify;
   15492                 :             : 
   15493                 :             :     /* regproc and regtype output is already sufficiently quoted */
   15494                 :         287 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   15495                 :             :                       aggtransfn, aggtranstype);
   15496                 :             : 
   15497         [ +  + ]:         287 :     if (strcmp(aggtransspace, "0") != 0)
   15498                 :             :     {
   15499                 :           5 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   15500                 :             :                           aggtransspace);
   15501                 :             :     }
   15502                 :             : 
   15503         [ +  + ]:         287 :     if (!PQgetisnull(res, 0, i_agginitval))
   15504                 :             :     {
   15505                 :         209 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   15506                 :         209 :         appendStringLiteralAH(details, agginitval, fout);
   15507                 :             :     }
   15508                 :             : 
   15509         [ +  + ]:         287 :     if (strcmp(aggfinalfn, "-") != 0)
   15510                 :             :     {
   15511                 :         134 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   15512                 :             :                           aggfinalfn);
   15513         [ +  + ]:         134 :         if (aggfinalextra)
   15514                 :          10 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   15515         [ +  + ]:         134 :         if (aggfinalmodify != defaultfinalmodify)
   15516                 :             :         {
   15517   [ -  +  -  - ]:          34 :             switch (aggfinalmodify)
   15518                 :             :             {
   15519                 :           0 :                 case AGGMODIFY_READ_ONLY:
   15520                 :           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   15521                 :           0 :                     break;
   15522                 :          34 :                 case AGGMODIFY_SHAREABLE:
   15523                 :          34 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   15524                 :          34 :                     break;
   15525                 :           0 :                 case AGGMODIFY_READ_WRITE:
   15526                 :           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   15527                 :           0 :                     break;
   15528                 :           0 :                 default:
   15529                 :           0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   15530                 :             :                              agginfo->aggfn.dobj.name);
   15531                 :             :                     break;
   15532                 :             :             }
   15533                 :             :         }
   15534                 :             :     }
   15535                 :             : 
   15536         [ -  + ]:         287 :     if (strcmp(aggcombinefn, "-") != 0)
   15537                 :           0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   15538                 :             : 
   15539         [ -  + ]:         287 :     if (strcmp(aggserialfn, "-") != 0)
   15540                 :           0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   15541                 :             : 
   15542         [ -  + ]:         287 :     if (strcmp(aggdeserialfn, "-") != 0)
   15543                 :           0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   15544                 :             : 
   15545         [ +  + ]:         287 :     if (strcmp(aggmtransfn, "-") != 0)
   15546                 :             :     {
   15547                 :          30 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   15548                 :             :                           aggmtransfn,
   15549                 :             :                           aggminvtransfn,
   15550                 :             :                           aggmtranstype);
   15551                 :             :     }
   15552                 :             : 
   15553         [ -  + ]:         287 :     if (strcmp(aggmtransspace, "0") != 0)
   15554                 :             :     {
   15555                 :           0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   15556                 :             :                           aggmtransspace);
   15557                 :             :     }
   15558                 :             : 
   15559         [ +  + ]:         287 :     if (!PQgetisnull(res, 0, i_aggminitval))
   15560                 :             :     {
   15561                 :          10 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   15562                 :          10 :         appendStringLiteralAH(details, aggminitval, fout);
   15563                 :             :     }
   15564                 :             : 
   15565         [ -  + ]:         287 :     if (strcmp(aggmfinalfn, "-") != 0)
   15566                 :             :     {
   15567                 :           0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   15568                 :             :                           aggmfinalfn);
   15569         [ #  # ]:           0 :         if (aggmfinalextra)
   15570                 :           0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   15571         [ #  # ]:           0 :         if (aggmfinalmodify != defaultfinalmodify)
   15572                 :             :         {
   15573   [ #  #  #  # ]:           0 :             switch (aggmfinalmodify)
   15574                 :             :             {
   15575                 :           0 :                 case AGGMODIFY_READ_ONLY:
   15576                 :           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   15577                 :           0 :                     break;
   15578                 :           0 :                 case AGGMODIFY_SHAREABLE:
   15579                 :           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   15580                 :           0 :                     break;
   15581                 :           0 :                 case AGGMODIFY_READ_WRITE:
   15582                 :           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   15583                 :           0 :                     break;
   15584                 :           0 :                 default:
   15585                 :           0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   15586                 :             :                              agginfo->aggfn.dobj.name);
   15587                 :             :                     break;
   15588                 :             :             }
   15589                 :             :         }
   15590                 :             :     }
   15591                 :             : 
   15592                 :         287 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   15593         [ -  + ]:         287 :     if (aggsortconvop)
   15594                 :             :     {
   15595                 :           0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   15596                 :             :                           aggsortconvop);
   15597                 :           0 :         free(aggsortconvop);
   15598                 :             :     }
   15599                 :             : 
   15600         [ +  + ]:         287 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   15601                 :           5 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   15602                 :             : 
   15603         [ +  + ]:         287 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   15604                 :             :     {
   15605         [ +  - ]:           5 :         if (proparallel[0] == PROPARALLEL_SAFE)
   15606                 :           5 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   15607         [ #  # ]:           0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   15608                 :           0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   15609         [ #  # ]:           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   15610                 :           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   15611                 :             :                      agginfo->aggfn.dobj.name);
   15612                 :             :     }
   15613                 :             : 
   15614                 :         287 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   15615                 :         287 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15616                 :             :                       aggsig);
   15617                 :             : 
   15618         [ +  - ]:         574 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   15619                 :         287 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   15620                 :             :                       aggfullsig ? aggfullsig : aggsig, details->data);
   15621                 :             : 
   15622         [ +  + ]:         287 :     if (dopt->binary_upgrade)
   15623                 :          49 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   15624                 :             :                                         "AGGREGATE", aggsig,
   15625                 :          49 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   15626                 :             : 
   15627         [ +  + ]:         287 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   15628                 :         270 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   15629                 :         270 :                      agginfo->aggfn.dobj.dumpId,
   15630                 :         270 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   15631                 :             :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   15632                 :             :                                   .owner = agginfo->aggfn.rolname,
   15633                 :             :                                   .description = "AGGREGATE",
   15634                 :             :                                   .section = SECTION_PRE_DATA,
   15635                 :             :                                   .createStmt = q->data,
   15636                 :             :                                   .dropStmt = delq->data));
   15637                 :             : 
   15638                 :             :     /* Dump Aggregate Comments */
   15639         [ +  + ]:         287 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   15640                 :          10 :         dumpComment(fout, "AGGREGATE", aggsig,
   15641                 :          10 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   15642                 :          10 :                     agginfo->aggfn.rolname,
   15643                 :          10 :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15644                 :             : 
   15645         [ -  + ]:         287 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   15646                 :           0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   15647                 :           0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   15648                 :           0 :                      agginfo->aggfn.rolname,
   15649                 :           0 :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   15650                 :             : 
   15651                 :             :     /*
   15652                 :             :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   15653                 :             :      * command look like a function's GRANT; in particular this affects the
   15654                 :             :      * syntax for zero-argument aggregates and ordered-set aggregates.
   15655                 :             :      */
   15656                 :         287 :     free(aggsig);
   15657                 :             : 
   15658                 :         287 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   15659                 :             : 
   15660         [ +  + ]:         287 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   15661                 :          18 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   15662                 :             :                 "FUNCTION", aggsig, NULL,
   15663                 :          18 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   15664                 :          18 :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   15665                 :             : 
   15666                 :         287 :     free(aggsig);
   15667                 :         287 :     free(aggfullsig);
   15668                 :         287 :     free(aggsig_tag);
   15669                 :             : 
   15670                 :         287 :     PQclear(res);
   15671                 :             : 
   15672                 :         287 :     destroyPQExpBuffer(query);
   15673                 :         287 :     destroyPQExpBuffer(q);
   15674                 :         287 :     destroyPQExpBuffer(delq);
   15675                 :         287 :     destroyPQExpBuffer(details);
   15676                 :             : }
   15677                 :             : 
   15678                 :             : /*
   15679                 :             :  * dumpTSParser
   15680                 :             :  *    write out a single text search parser
   15681                 :             :  */
   15682                 :             : static void
   15683                 :          44 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   15684                 :             : {
   15685                 :          44 :     DumpOptions *dopt = fout->dopt;
   15686                 :             :     PQExpBuffer q;
   15687                 :             :     PQExpBuffer delq;
   15688                 :             :     char       *qprsname;
   15689                 :             : 
   15690                 :             :     /* Do nothing if not dumping schema */
   15691         [ +  + ]:          44 :     if (!dopt->dumpSchema)
   15692                 :           7 :         return;
   15693                 :             : 
   15694                 :          37 :     q = createPQExpBuffer();
   15695                 :          37 :     delq = createPQExpBuffer();
   15696                 :             : 
   15697                 :          37 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   15698                 :             : 
   15699                 :          37 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   15700                 :          37 :                       fmtQualifiedDumpable(prsinfo));
   15701                 :             : 
   15702                 :          37 :     appendPQExpBuffer(q, "    START = %s,\n",
   15703                 :          37 :                       convertTSFunction(fout, prsinfo->prsstart));
   15704                 :          37 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   15705                 :          37 :                       convertTSFunction(fout, prsinfo->prstoken));
   15706                 :          37 :     appendPQExpBuffer(q, "    END = %s,\n",
   15707                 :          37 :                       convertTSFunction(fout, prsinfo->prsend));
   15708         [ +  + ]:          37 :     if (prsinfo->prsheadline != InvalidOid)
   15709                 :           3 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   15710                 :           3 :                           convertTSFunction(fout, prsinfo->prsheadline));
   15711                 :          37 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   15712                 :          37 :                       convertTSFunction(fout, prsinfo->prslextype));
   15713                 :             : 
   15714                 :          37 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   15715                 :          37 :                       fmtQualifiedDumpable(prsinfo));
   15716                 :             : 
   15717         [ +  + ]:          37 :     if (dopt->binary_upgrade)
   15718                 :           1 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   15719                 :             :                                         "TEXT SEARCH PARSER", qprsname,
   15720                 :           1 :                                         prsinfo->dobj.namespace->dobj.name);
   15721                 :             : 
   15722         [ +  - ]:          37 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15723                 :          37 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15724                 :          37 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   15725                 :             :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   15726                 :             :                                   .description = "TEXT SEARCH PARSER",
   15727                 :             :                                   .section = SECTION_PRE_DATA,
   15728                 :             :                                   .createStmt = q->data,
   15729                 :             :                                   .dropStmt = delq->data));
   15730                 :             : 
   15731                 :             :     /* Dump Parser Comments */
   15732         [ +  - ]:          37 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15733                 :          37 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15734                 :          37 :                     prsinfo->dobj.namespace->dobj.name, "",
   15735                 :          37 :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15736                 :             : 
   15737                 :          37 :     destroyPQExpBuffer(q);
   15738                 :          37 :     destroyPQExpBuffer(delq);
   15739                 :          37 :     pg_free(qprsname);
   15740                 :             : }
   15741                 :             : 
   15742                 :             : /*
   15743                 :             :  * dumpTSDictionary
   15744                 :             :  *    write out a single text search dictionary
   15745                 :             :  */
   15746                 :             : static void
   15747                 :         182 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15748                 :             : {
   15749                 :         182 :     DumpOptions *dopt = fout->dopt;
   15750                 :             :     PQExpBuffer q;
   15751                 :             :     PQExpBuffer delq;
   15752                 :             :     PQExpBuffer query;
   15753                 :             :     char       *qdictname;
   15754                 :             :     PGresult   *res;
   15755                 :             :     char       *nspname;
   15756                 :             :     char       *tmplname;
   15757                 :             : 
   15758                 :             :     /* Do nothing if not dumping schema */
   15759         [ +  + ]:         182 :     if (!dopt->dumpSchema)
   15760                 :           7 :         return;
   15761                 :             : 
   15762                 :         175 :     q = createPQExpBuffer();
   15763                 :         175 :     delq = createPQExpBuffer();
   15764                 :         175 :     query = createPQExpBuffer();
   15765                 :             : 
   15766                 :         175 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15767                 :             : 
   15768                 :             :     /* Fetch name and namespace of the dictionary's template */
   15769                 :         175 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15770                 :             :                       "FROM pg_ts_template p, pg_namespace n "
   15771                 :             :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15772                 :         175 :                       dictinfo->dicttemplate);
   15773                 :         175 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15774                 :         175 :     nspname = PQgetvalue(res, 0, 0);
   15775                 :         175 :     tmplname = PQgetvalue(res, 0, 1);
   15776                 :             : 
   15777                 :         175 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15778                 :         175 :                       fmtQualifiedDumpable(dictinfo));
   15779                 :             : 
   15780                 :         175 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   15781                 :         175 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15782                 :         175 :     appendPQExpBufferStr(q, fmtId(tmplname));
   15783                 :             : 
   15784                 :         175 :     PQclear(res);
   15785                 :             : 
   15786                 :             :     /* the dictinitoption can be dumped straight into the command */
   15787         [ +  + ]:         175 :     if (dictinfo->dictinitoption)
   15788                 :         138 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15789                 :             : 
   15790                 :         175 :     appendPQExpBufferStr(q, " );\n");
   15791                 :             : 
   15792                 :         175 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   15793                 :         175 :                       fmtQualifiedDumpable(dictinfo));
   15794                 :             : 
   15795         [ +  + ]:         175 :     if (dopt->binary_upgrade)
   15796                 :          10 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   15797                 :             :                                         "TEXT SEARCH DICTIONARY", qdictname,
   15798                 :          10 :                                         dictinfo->dobj.namespace->dobj.name);
   15799                 :             : 
   15800         [ +  - ]:         175 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15801                 :         175 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   15802                 :         175 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   15803                 :             :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   15804                 :             :                                   .owner = dictinfo->rolname,
   15805                 :             :                                   .description = "TEXT SEARCH DICTIONARY",
   15806                 :             :                                   .section = SECTION_PRE_DATA,
   15807                 :             :                                   .createStmt = q->data,
   15808                 :             :                                   .dropStmt = delq->data));
   15809                 :             : 
   15810                 :             :     /* Dump Dictionary Comments */
   15811         [ +  + ]:         175 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15812                 :         130 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   15813                 :         130 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   15814                 :         130 :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   15815                 :             : 
   15816                 :         175 :     destroyPQExpBuffer(q);
   15817                 :         175 :     destroyPQExpBuffer(delq);
   15818                 :         175 :     destroyPQExpBuffer(query);
   15819                 :         175 :     pg_free(qdictname);
   15820                 :             : }
   15821                 :             : 
   15822                 :             : /*
   15823                 :             :  * dumpTSTemplate
   15824                 :             :  *    write out a single text search template
   15825                 :             :  */
   15826                 :             : static void
   15827                 :          56 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   15828                 :             : {
   15829                 :          56 :     DumpOptions *dopt = fout->dopt;
   15830                 :             :     PQExpBuffer q;
   15831                 :             :     PQExpBuffer delq;
   15832                 :             :     char       *qtmplname;
   15833                 :             : 
   15834                 :             :     /* Do nothing if not dumping schema */
   15835         [ +  + ]:          56 :     if (!dopt->dumpSchema)
   15836                 :           7 :         return;
   15837                 :             : 
   15838                 :          49 :     q = createPQExpBuffer();
   15839                 :          49 :     delq = createPQExpBuffer();
   15840                 :             : 
   15841                 :          49 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   15842                 :             : 
   15843                 :          49 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   15844                 :          49 :                       fmtQualifiedDumpable(tmplinfo));
   15845                 :             : 
   15846         [ +  + ]:          49 :     if (tmplinfo->tmplinit != InvalidOid)
   15847                 :          15 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   15848                 :          15 :                           convertTSFunction(fout, tmplinfo->tmplinit));
   15849                 :          49 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   15850                 :          49 :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   15851                 :             : 
   15852                 :          49 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   15853                 :          49 :                       fmtQualifiedDumpable(tmplinfo));
   15854                 :             : 
   15855         [ +  + ]:          49 :     if (dopt->binary_upgrade)
   15856                 :           1 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   15857                 :             :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   15858                 :           1 :                                         tmplinfo->dobj.namespace->dobj.name);
   15859                 :             : 
   15860         [ +  - ]:          49 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15861                 :          49 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   15862                 :          49 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   15863                 :             :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   15864                 :             :                                   .description = "TEXT SEARCH TEMPLATE",
   15865                 :             :                                   .section = SECTION_PRE_DATA,
   15866                 :             :                                   .createStmt = q->data,
   15867                 :             :                                   .dropStmt = delq->data));
   15868                 :             : 
   15869                 :             :     /* Dump Template Comments */
   15870         [ +  - ]:          49 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15871                 :          49 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   15872                 :          49 :                     tmplinfo->dobj.namespace->dobj.name, "",
   15873                 :          49 :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   15874                 :             : 
   15875                 :          49 :     destroyPQExpBuffer(q);
   15876                 :          49 :     destroyPQExpBuffer(delq);
   15877                 :          49 :     pg_free(qtmplname);
   15878                 :             : }
   15879                 :             : 
   15880                 :             : /*
   15881                 :             :  * dumpTSConfig
   15882                 :             :  *    write out a single text search configuration
   15883                 :             :  */
   15884                 :             : static void
   15885                 :         157 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   15886                 :             : {
   15887                 :         157 :     DumpOptions *dopt = fout->dopt;
   15888                 :             :     PQExpBuffer q;
   15889                 :             :     PQExpBuffer delq;
   15890                 :             :     PQExpBuffer query;
   15891                 :             :     char       *qcfgname;
   15892                 :             :     PGresult   *res;
   15893                 :             :     char       *nspname;
   15894                 :             :     char       *prsname;
   15895                 :             :     int         ntups,
   15896                 :             :                 i;
   15897                 :             :     int         i_tokenname;
   15898                 :             :     int         i_dictname;
   15899                 :             : 
   15900                 :             :     /* Do nothing if not dumping schema */
   15901         [ +  + ]:         157 :     if (!dopt->dumpSchema)
   15902                 :           7 :         return;
   15903                 :             : 
   15904                 :         150 :     q = createPQExpBuffer();
   15905                 :         150 :     delq = createPQExpBuffer();
   15906                 :         150 :     query = createPQExpBuffer();
   15907                 :             : 
   15908                 :         150 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   15909                 :             : 
   15910                 :             :     /* Fetch name and namespace of the config's parser */
   15911                 :         150 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   15912                 :             :                       "FROM pg_ts_parser p, pg_namespace n "
   15913                 :             :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   15914                 :         150 :                       cfginfo->cfgparser);
   15915                 :         150 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15916                 :         150 :     nspname = PQgetvalue(res, 0, 0);
   15917                 :         150 :     prsname = PQgetvalue(res, 0, 1);
   15918                 :             : 
   15919                 :         150 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   15920                 :         150 :                       fmtQualifiedDumpable(cfginfo));
   15921                 :             : 
   15922                 :         150 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   15923                 :         150 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   15924                 :             : 
   15925                 :         150 :     PQclear(res);
   15926                 :             : 
   15927                 :         150 :     resetPQExpBuffer(query);
   15928                 :         150 :     appendPQExpBuffer(query,
   15929                 :             :                       "SELECT\n"
   15930                 :             :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   15931                 :             :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   15932                 :             :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   15933                 :             :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   15934                 :             :                       "WHERE m.mapcfg = '%u'\n"
   15935                 :             :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   15936                 :         150 :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   15937                 :             : 
   15938                 :         150 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15939                 :         150 :     ntups = PQntuples(res);
   15940                 :             : 
   15941                 :         150 :     i_tokenname = PQfnumber(res, "tokenname");
   15942                 :         150 :     i_dictname = PQfnumber(res, "dictname");
   15943                 :             : 
   15944         [ +  + ]:        3135 :     for (i = 0; i < ntups; i++)
   15945                 :             :     {
   15946                 :        2985 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   15947                 :        2985 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   15948                 :             : 
   15949         [ +  + ]:        2985 :         if (i == 0 ||
   15950         [ +  + ]:        2835 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   15951                 :             :         {
   15952                 :             :             /* starting a new token type, so start a new command */
   15953         [ +  + ]:        2850 :             if (i > 0)
   15954                 :        2700 :                 appendPQExpBufferStr(q, ";\n");
   15955                 :        2850 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   15956                 :        2850 :                               fmtQualifiedDumpable(cfginfo));
   15957                 :             :             /* tokenname needs quoting, dictname does NOT */
   15958                 :        2850 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   15959                 :             :                               fmtId(tokenname), dictname);
   15960                 :             :         }
   15961                 :             :         else
   15962                 :         135 :             appendPQExpBuffer(q, ", %s", dictname);
   15963                 :             :     }
   15964                 :             : 
   15965         [ +  - ]:         150 :     if (ntups > 0)
   15966                 :         150 :         appendPQExpBufferStr(q, ";\n");
   15967                 :             : 
   15968                 :         150 :     PQclear(res);
   15969                 :             : 
   15970                 :         150 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   15971                 :         150 :                       fmtQualifiedDumpable(cfginfo));
   15972                 :             : 
   15973         [ +  + ]:         150 :     if (dopt->binary_upgrade)
   15974                 :           5 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   15975                 :             :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   15976                 :           5 :                                         cfginfo->dobj.namespace->dobj.name);
   15977                 :             : 
   15978         [ +  - ]:         150 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15979                 :         150 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   15980                 :         150 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   15981                 :             :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   15982                 :             :                                   .owner = cfginfo->rolname,
   15983                 :             :                                   .description = "TEXT SEARCH CONFIGURATION",
   15984                 :             :                                   .section = SECTION_PRE_DATA,
   15985                 :             :                                   .createStmt = q->data,
   15986                 :             :                                   .dropStmt = delq->data));
   15987                 :             : 
   15988                 :             :     /* Dump Configuration Comments */
   15989         [ +  + ]:         150 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15990                 :         130 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   15991                 :         130 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   15992                 :         130 :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   15993                 :             : 
   15994                 :         150 :     destroyPQExpBuffer(q);
   15995                 :         150 :     destroyPQExpBuffer(delq);
   15996                 :         150 :     destroyPQExpBuffer(query);
   15997                 :         150 :     pg_free(qcfgname);
   15998                 :             : }
   15999                 :             : 
   16000                 :             : /*
   16001                 :             :  * dumpForeignDataWrapper
   16002                 :             :  *    write out a single foreign-data wrapper definition
   16003                 :             :  */
   16004                 :             : static void
   16005                 :          54 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   16006                 :             : {
   16007                 :          54 :     DumpOptions *dopt = fout->dopt;
   16008                 :             :     PQExpBuffer q;
   16009                 :             :     PQExpBuffer delq;
   16010                 :             :     char       *qfdwname;
   16011                 :             : 
   16012                 :             :     /* Do nothing if not dumping schema */
   16013         [ +  + ]:          54 :     if (!dopt->dumpSchema)
   16014                 :           7 :         return;
   16015                 :             : 
   16016                 :          47 :     q = createPQExpBuffer();
   16017                 :          47 :     delq = createPQExpBuffer();
   16018                 :             : 
   16019                 :          47 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   16020                 :             : 
   16021                 :          47 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   16022                 :             :                       qfdwname);
   16023                 :             : 
   16024         [ -  + ]:          47 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   16025                 :           0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   16026                 :             : 
   16027         [ -  + ]:          47 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   16028                 :           0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   16029                 :             : 
   16030         [ -  + ]:          47 :     if (strcmp(fdwinfo->fdwconnection, "-") != 0)
   16031                 :           0 :         appendPQExpBuffer(q, " CONNECTION %s", fdwinfo->fdwconnection);
   16032                 :             : 
   16033         [ -  + ]:          47 :     if (strlen(fdwinfo->fdwoptions) > 0)
   16034                 :           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   16035                 :             : 
   16036                 :          47 :     appendPQExpBufferStr(q, ";\n");
   16037                 :             : 
   16038                 :          47 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   16039                 :             :                       qfdwname);
   16040                 :             : 
   16041         [ +  + ]:          47 :     if (dopt->binary_upgrade)
   16042                 :           2 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   16043                 :             :                                         "FOREIGN DATA WRAPPER", qfdwname,
   16044                 :             :                                         NULL);
   16045                 :             : 
   16046         [ +  - ]:          47 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16047                 :          47 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   16048                 :          47 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   16049                 :             :                                   .owner = fdwinfo->rolname,
   16050                 :             :                                   .description = "FOREIGN DATA WRAPPER",
   16051                 :             :                                   .section = SECTION_PRE_DATA,
   16052                 :             :                                   .createStmt = q->data,
   16053                 :             :                                   .dropStmt = delq->data));
   16054                 :             : 
   16055                 :             :     /* Dump Foreign Data Wrapper Comments */
   16056         [ -  + ]:          47 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16057                 :           0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   16058                 :           0 :                     NULL, fdwinfo->rolname,
   16059                 :           0 :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   16060                 :             : 
   16061                 :             :     /* Handle the ACL */
   16062         [ +  + ]:          47 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16063                 :          33 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   16064                 :             :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   16065                 :          33 :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   16066                 :             : 
   16067                 :          47 :     pg_free(qfdwname);
   16068                 :             : 
   16069                 :          47 :     destroyPQExpBuffer(q);
   16070                 :          47 :     destroyPQExpBuffer(delq);
   16071                 :             : }
   16072                 :             : 
   16073                 :             : /*
   16074                 :             :  * dumpForeignServer
   16075                 :             :  *    write out a foreign server definition
   16076                 :             :  */
   16077                 :             : static void
   16078                 :          58 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   16079                 :             : {
   16080                 :          58 :     DumpOptions *dopt = fout->dopt;
   16081                 :             :     PQExpBuffer q;
   16082                 :             :     PQExpBuffer delq;
   16083                 :             :     PQExpBuffer query;
   16084                 :             :     PGresult   *res;
   16085                 :             :     char       *qsrvname;
   16086                 :             :     char       *fdwname;
   16087                 :             : 
   16088                 :             :     /* Do nothing if not dumping schema */
   16089         [ +  + ]:          58 :     if (!dopt->dumpSchema)
   16090                 :           9 :         return;
   16091                 :             : 
   16092                 :          49 :     q = createPQExpBuffer();
   16093                 :          49 :     delq = createPQExpBuffer();
   16094                 :          49 :     query = createPQExpBuffer();
   16095                 :             : 
   16096                 :          49 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   16097                 :             : 
   16098                 :             :     /* look up the foreign-data wrapper */
   16099                 :          49 :     appendPQExpBuffer(query, "SELECT fdwname "
   16100                 :             :                       "FROM pg_foreign_data_wrapper w "
   16101                 :             :                       "WHERE w.oid = '%u'",
   16102                 :          49 :                       srvinfo->srvfdw);
   16103                 :          49 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16104                 :          49 :     fdwname = PQgetvalue(res, 0, 0);
   16105                 :             : 
   16106                 :          49 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   16107   [ +  -  -  + ]:          49 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   16108                 :             :     {
   16109                 :           0 :         appendPQExpBufferStr(q, " TYPE ");
   16110                 :           0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   16111                 :             :     }
   16112   [ +  -  -  + ]:          49 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   16113                 :             :     {
   16114                 :           0 :         appendPQExpBufferStr(q, " VERSION ");
   16115                 :           0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   16116                 :             :     }
   16117                 :             : 
   16118                 :          49 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   16119                 :          49 :     appendPQExpBufferStr(q, fmtId(fdwname));
   16120                 :             : 
   16121   [ +  -  -  + ]:          49 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   16122                 :           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   16123                 :             : 
   16124                 :          49 :     appendPQExpBufferStr(q, ";\n");
   16125                 :             : 
   16126                 :          49 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   16127                 :             :                       qsrvname);
   16128                 :             : 
   16129         [ +  + ]:          49 :     if (dopt->binary_upgrade)
   16130                 :           2 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   16131                 :             :                                         "SERVER", qsrvname, NULL);
   16132                 :             : 
   16133         [ +  - ]:          49 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16134                 :          49 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   16135                 :          49 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   16136                 :             :                                   .owner = srvinfo->rolname,
   16137                 :             :                                   .description = "SERVER",
   16138                 :             :                                   .section = SECTION_PRE_DATA,
   16139                 :             :                                   .createStmt = q->data,
   16140                 :             :                                   .dropStmt = delq->data));
   16141                 :             : 
   16142                 :             :     /* Dump Foreign Server Comments */
   16143         [ -  + ]:          49 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16144                 :           0 :         dumpComment(fout, "SERVER", qsrvname,
   16145                 :           0 :                     NULL, srvinfo->rolname,
   16146                 :           0 :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   16147                 :             : 
   16148                 :             :     /* Handle the ACL */
   16149         [ +  + ]:          49 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16150                 :          33 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   16151                 :             :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   16152                 :          33 :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   16153                 :             : 
   16154                 :             :     /* Dump user mappings */
   16155         [ +  - ]:          49 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   16156                 :          49 :         dumpUserMappings(fout,
   16157                 :          49 :                          srvinfo->dobj.name, NULL,
   16158                 :          49 :                          srvinfo->rolname,
   16159                 :          49 :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   16160                 :             : 
   16161                 :          49 :     PQclear(res);
   16162                 :             : 
   16163                 :          49 :     pg_free(qsrvname);
   16164                 :             : 
   16165                 :          49 :     destroyPQExpBuffer(q);
   16166                 :          49 :     destroyPQExpBuffer(delq);
   16167                 :          49 :     destroyPQExpBuffer(query);
   16168                 :             : }
   16169                 :             : 
   16170                 :             : /*
   16171                 :             :  * dumpUserMappings
   16172                 :             :  *
   16173                 :             :  * This routine is used to dump any user mappings associated with the
   16174                 :             :  * server handed to this routine. Should be called after ArchiveEntry()
   16175                 :             :  * for the server.
   16176                 :             :  */
   16177                 :             : static void
   16178                 :          49 : dumpUserMappings(Archive *fout,
   16179                 :             :                  const char *servername, const char *namespace,
   16180                 :             :                  const char *owner,
   16181                 :             :                  CatalogId catalogId, DumpId dumpId)
   16182                 :             : {
   16183                 :             :     PQExpBuffer q;
   16184                 :             :     PQExpBuffer delq;
   16185                 :             :     PQExpBuffer query;
   16186                 :             :     PQExpBuffer tag;
   16187                 :             :     PGresult   *res;
   16188                 :             :     int         ntups;
   16189                 :             :     int         i_usename;
   16190                 :             :     int         i_umoptions;
   16191                 :             :     int         i;
   16192                 :             : 
   16193                 :          49 :     q = createPQExpBuffer();
   16194                 :          49 :     tag = createPQExpBuffer();
   16195                 :          49 :     delq = createPQExpBuffer();
   16196                 :          49 :     query = createPQExpBuffer();
   16197                 :             : 
   16198                 :             :     /*
   16199                 :             :      * We read from the publicly accessible view pg_user_mappings, so as not
   16200                 :             :      * to fail if run by a non-superuser.  Note that the view will show
   16201                 :             :      * umoptions as null if the user hasn't got privileges for the associated
   16202                 :             :      * server; this means that pg_dump will dump such a mapping, but with no
   16203                 :             :      * OPTIONS clause.  A possible alternative is to skip such mappings
   16204                 :             :      * altogether, but it's not clear that that's an improvement.
   16205                 :             :      */
   16206                 :          49 :     appendPQExpBuffer(query,
   16207                 :             :                       "SELECT usename, "
   16208                 :             :                       "array_to_string(ARRAY("
   16209                 :             :                       "SELECT quote_ident(option_name) || ' ' || "
   16210                 :             :                       "quote_literal(option_value) "
   16211                 :             :                       "FROM pg_options_to_table(umoptions) "
   16212                 :             :                       "ORDER BY option_name"
   16213                 :             :                       "), E',\n    ') AS umoptions "
   16214                 :             :                       "FROM pg_user_mappings "
   16215                 :             :                       "WHERE srvid = '%u' "
   16216                 :             :                       "ORDER BY usename",
   16217                 :             :                       catalogId.oid);
   16218                 :             : 
   16219                 :          49 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16220                 :             : 
   16221                 :          49 :     ntups = PQntuples(res);
   16222                 :          49 :     i_usename = PQfnumber(res, "usename");
   16223                 :          49 :     i_umoptions = PQfnumber(res, "umoptions");
   16224                 :             : 
   16225         [ +  + ]:          82 :     for (i = 0; i < ntups; i++)
   16226                 :             :     {
   16227                 :             :         char       *usename;
   16228                 :             :         char       *umoptions;
   16229                 :             : 
   16230                 :          33 :         usename = PQgetvalue(res, i, i_usename);
   16231                 :          33 :         umoptions = PQgetvalue(res, i, i_umoptions);
   16232                 :             : 
   16233                 :          33 :         resetPQExpBuffer(q);
   16234                 :          33 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   16235                 :          33 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   16236                 :             : 
   16237   [ +  -  -  + ]:          33 :         if (umoptions && strlen(umoptions) > 0)
   16238                 :           0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   16239                 :             : 
   16240                 :          33 :         appendPQExpBufferStr(q, ";\n");
   16241                 :             : 
   16242                 :          33 :         resetPQExpBuffer(delq);
   16243                 :          33 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   16244                 :          33 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   16245                 :             : 
   16246                 :          33 :         resetPQExpBuffer(tag);
   16247                 :          33 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   16248                 :             :                           usename, servername);
   16249                 :             : 
   16250                 :          33 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16251                 :          33 :                      ARCHIVE_OPTS(.tag = tag->data,
   16252                 :             :                                   .namespace = namespace,
   16253                 :             :                                   .owner = owner,
   16254                 :             :                                   .description = "USER MAPPING",
   16255                 :             :                                   .section = SECTION_PRE_DATA,
   16256                 :             :                                   .createStmt = q->data,
   16257                 :             :                                   .dropStmt = delq->data));
   16258                 :             :     }
   16259                 :             : 
   16260                 :          49 :     PQclear(res);
   16261                 :             : 
   16262                 :          49 :     destroyPQExpBuffer(query);
   16263                 :          49 :     destroyPQExpBuffer(delq);
   16264                 :          49 :     destroyPQExpBuffer(tag);
   16265                 :          49 :     destroyPQExpBuffer(q);
   16266                 :          49 : }
   16267                 :             : 
   16268                 :             : /*
   16269                 :             :  * Write out default privileges information
   16270                 :             :  */
   16271                 :             : static void
   16272                 :         170 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   16273                 :             : {
   16274                 :         170 :     DumpOptions *dopt = fout->dopt;
   16275                 :             :     PQExpBuffer q;
   16276                 :             :     PQExpBuffer tag;
   16277                 :             :     const char *type;
   16278                 :             : 
   16279                 :             :     /* Do nothing if not dumping schema, or if we're skipping ACLs */
   16280   [ +  +  +  + ]:         170 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   16281                 :          30 :         return;
   16282                 :             : 
   16283                 :         140 :     q = createPQExpBuffer();
   16284                 :         140 :     tag = createPQExpBuffer();
   16285                 :             : 
   16286   [ +  -  +  +  :         140 :     switch (daclinfo->defaclobjtype)
                -  -  - ]
   16287                 :             :     {
   16288                 :          65 :         case DEFACLOBJ_RELATION:
   16289                 :          65 :             type = "TABLES";
   16290                 :          65 :             break;
   16291                 :           0 :         case DEFACLOBJ_SEQUENCE:
   16292                 :           0 :             type = "SEQUENCES";
   16293                 :           0 :             break;
   16294                 :          65 :         case DEFACLOBJ_FUNCTION:
   16295                 :          65 :             type = "FUNCTIONS";
   16296                 :          65 :             break;
   16297                 :          10 :         case DEFACLOBJ_TYPE:
   16298                 :          10 :             type = "TYPES";
   16299                 :          10 :             break;
   16300                 :           0 :         case DEFACLOBJ_NAMESPACE:
   16301                 :           0 :             type = "SCHEMAS";
   16302                 :           0 :             break;
   16303                 :           0 :         case DEFACLOBJ_LARGEOBJECT:
   16304                 :           0 :             type = "LARGE OBJECTS";
   16305                 :           0 :             break;
   16306                 :           0 :         default:
   16307                 :             :             /* shouldn't get here */
   16308                 :           0 :             pg_fatal("unrecognized object type in default privileges: %d",
   16309                 :             :                      (int) daclinfo->defaclobjtype);
   16310                 :             :             type = "";            /* keep compiler quiet */
   16311                 :             :     }
   16312                 :             : 
   16313                 :         140 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   16314                 :             : 
   16315                 :             :     /* build the actual command(s) for this tuple */
   16316         [ -  + ]:         140 :     if (!buildDefaultACLCommands(type,
   16317                 :         140 :                                  daclinfo->dobj.namespace != NULL ?
   16318                 :          66 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   16319                 :         140 :                                  daclinfo->dacl.acl,
   16320                 :         140 :                                  daclinfo->dacl.acldefault,
   16321         [ +  + ]:         140 :                                  daclinfo->defaclrole,
   16322                 :             :                                  fout->remoteVersion,
   16323                 :             :                                  q))
   16324                 :           0 :         pg_fatal("could not parse default ACL list (%s)",
   16325                 :             :                  daclinfo->dacl.acl);
   16326                 :             : 
   16327         [ +  - ]:         140 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16328                 :         140 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   16329         [ +  + ]:         140 :                      ARCHIVE_OPTS(.tag = tag->data,
   16330                 :             :                                   .namespace = daclinfo->dobj.namespace ?
   16331                 :             :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   16332                 :             :                                   .owner = daclinfo->defaclrole,
   16333                 :             :                                   .description = "DEFAULT ACL",
   16334                 :             :                                   .section = SECTION_POST_DATA,
   16335                 :             :                                   .createStmt = q->data));
   16336                 :             : 
   16337                 :         140 :     destroyPQExpBuffer(tag);
   16338                 :         140 :     destroyPQExpBuffer(q);
   16339                 :             : }
   16340                 :             : 
   16341                 :             : /*----------
   16342                 :             :  * Write out grant/revoke information
   16343                 :             :  *
   16344                 :             :  * 'objDumpId' is the dump ID of the underlying object.
   16345                 :             :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   16346                 :             :  *      or InvalidDumpId if there is no need for a second dependency.
   16347                 :             :  * 'type' must be one of
   16348                 :             :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   16349                 :             :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   16350                 :             :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   16351                 :             :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   16352                 :             :  *      (Currently we assume that subname is only provided for table columns.)
   16353                 :             :  * 'nspname' is the namespace the object is in (NULL if none).
   16354                 :             :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   16355                 :             :  *      to use the default for the object type.
   16356                 :             :  * 'owner' is the owner, NULL if there is no owner (for languages).
   16357                 :             :  * 'dacl' is the DumpableAcl struct for the object.
   16358                 :             :  *
   16359                 :             :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   16360                 :             :  * no ACL entry was created.
   16361                 :             :  *----------
   16362                 :             :  */
   16363                 :             : static DumpId
   16364                 :       31974 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   16365                 :             :         const char *type, const char *name, const char *subname,
   16366                 :             :         const char *nspname, const char *tag, const char *owner,
   16367                 :             :         const DumpableAcl *dacl)
   16368                 :             : {
   16369                 :       31974 :     DumpId      aclDumpId = InvalidDumpId;
   16370                 :       31974 :     DumpOptions *dopt = fout->dopt;
   16371                 :       31974 :     const char *acls = dacl->acl;
   16372                 :       31974 :     const char *acldefault = dacl->acldefault;
   16373                 :       31974 :     char        privtype = dacl->privtype;
   16374                 :       31974 :     const char *initprivs = dacl->initprivs;
   16375                 :             :     const char *baseacls;
   16376                 :             :     PQExpBuffer sql;
   16377                 :             : 
   16378                 :             :     /* Do nothing if ACL dump is not enabled */
   16379         [ +  + ]:       31974 :     if (dopt->aclsSkip)
   16380                 :         349 :         return InvalidDumpId;
   16381                 :             : 
   16382                 :             :     /* --data-only skips ACLs *except* large object ACLs */
   16383   [ +  +  +  + ]:       31625 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   16384                 :           1 :         return InvalidDumpId;
   16385                 :             : 
   16386                 :       31624 :     sql = createPQExpBuffer();
   16387                 :             : 
   16388                 :             :     /*
   16389                 :             :      * In binary upgrade mode, we don't run an extension's script but instead
   16390                 :             :      * dump out the objects independently and then recreate them.  To preserve
   16391                 :             :      * any initial privileges which were set on extension objects, we need to
   16392                 :             :      * compute the set of GRANT and REVOKE commands necessary to get from the
   16393                 :             :      * default privileges of an object to its initial privileges as recorded
   16394                 :             :      * in pg_init_privs.
   16395                 :             :      *
   16396                 :             :      * At restore time, we apply these commands after having called
   16397                 :             :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   16398                 :             :      * copy the results into pg_init_privs.  This is how we preserve the
   16399                 :             :      * contents of that catalog across binary upgrades.
   16400                 :             :      */
   16401   [ +  +  +  +  :       31624 :     if (dopt->binary_upgrade && privtype == 'e' &&
                   +  - ]
   16402         [ +  - ]:          13 :         initprivs && *initprivs != '\0')
   16403                 :             :     {
   16404                 :          13 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   16405         [ -  + ]:          13 :         if (!buildACLCommands(name, subname, nspname, type,
   16406                 :             :                               initprivs, acldefault, owner,
   16407                 :             :                               "", fout->remoteVersion, sql))
   16408                 :           0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16409                 :             :                      initprivs, acldefault, name, type);
   16410                 :          13 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   16411                 :             :     }
   16412                 :             : 
   16413                 :             :     /*
   16414                 :             :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   16415                 :             :      * actual current ACL, starting from the initprivs if given, else from the
   16416                 :             :      * object-type-specific default.  Also, while buildACLCommands will assume
   16417                 :             :      * that a NULL/empty acls string means it needn't do anything, what that
   16418                 :             :      * actually represents is the object-type-specific default; so we need to
   16419                 :             :      * substitute the acldefault string to get the right results in that case.
   16420                 :             :      */
   16421   [ +  +  +  + ]:       31624 :     if (initprivs && *initprivs != '\0')
   16422                 :             :     {
   16423                 :       29711 :         baseacls = initprivs;
   16424   [ +  -  +  + ]:       29711 :         if (acls == NULL || *acls == '\0')
   16425                 :          17 :             acls = acldefault;
   16426                 :             :     }
   16427                 :             :     else
   16428                 :        1913 :         baseacls = acldefault;
   16429                 :             : 
   16430         [ -  + ]:       31624 :     if (!buildACLCommands(name, subname, nspname, type,
   16431                 :             :                           acls, baseacls, owner,
   16432                 :             :                           "", fout->remoteVersion, sql))
   16433                 :           0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   16434                 :             :                  acls, baseacls, name, type);
   16435                 :             : 
   16436         [ +  + ]:       31624 :     if (sql->len > 0)
   16437                 :             :     {
   16438                 :        1971 :         PQExpBuffer tagbuf = createPQExpBuffer();
   16439                 :             :         DumpId      aclDeps[2];
   16440                 :        1971 :         int         nDeps = 0;
   16441                 :             : 
   16442         [ -  + ]:        1971 :         if (tag)
   16443                 :           0 :             appendPQExpBufferStr(tagbuf, tag);
   16444         [ +  + ]:        1971 :         else if (subname)
   16445                 :        1111 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   16446                 :             :         else
   16447                 :         860 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   16448                 :             : 
   16449                 :        1971 :         aclDeps[nDeps++] = objDumpId;
   16450         [ +  + ]:        1971 :         if (altDumpId != InvalidDumpId)
   16451                 :        1025 :             aclDeps[nDeps++] = altDumpId;
   16452                 :             : 
   16453                 :        1971 :         aclDumpId = createDumpId();
   16454                 :             : 
   16455                 :        1971 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   16456                 :        1971 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   16457                 :             :                                   .namespace = nspname,
   16458                 :             :                                   .owner = owner,
   16459                 :             :                                   .description = "ACL",
   16460                 :             :                                   .section = SECTION_NONE,
   16461                 :             :                                   .createStmt = sql->data,
   16462                 :             :                                   .deps = aclDeps,
   16463                 :             :                                   .nDeps = nDeps));
   16464                 :             : 
   16465                 :        1971 :         destroyPQExpBuffer(tagbuf);
   16466                 :             :     }
   16467                 :             : 
   16468                 :       31624 :     destroyPQExpBuffer(sql);
   16469                 :             : 
   16470                 :       31624 :     return aclDumpId;
   16471                 :             : }
   16472                 :             : 
   16473                 :             : /*
   16474                 :             :  * dumpSecLabel
   16475                 :             :  *
   16476                 :             :  * This routine is used to dump any security labels associated with the
   16477                 :             :  * object handed to this routine. The routine takes the object type
   16478                 :             :  * and object name (ready to print, except for schema decoration), plus
   16479                 :             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   16480                 :             :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   16481                 :             :  * plus the dump ID for the object (for setting a dependency).
   16482                 :             :  * If a matching pg_seclabel entry is found, it is dumped.
   16483                 :             :  *
   16484                 :             :  * Note: although this routine takes a dumpId for dependency purposes,
   16485                 :             :  * that purpose is just to mark the dependency in the emitted dump file
   16486                 :             :  * for possible future use by pg_restore.  We do NOT use it for determining
   16487                 :             :  * ordering of the label in the dump file, because this routine is called
   16488                 :             :  * after dependency sorting occurs.  This routine should be called just after
   16489                 :             :  * calling ArchiveEntry() for the specified object.
   16490                 :             :  */
   16491                 :             : static void
   16492                 :          10 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   16493                 :             :              const char *namespace, const char *owner,
   16494                 :             :              CatalogId catalogId, int subid, DumpId dumpId)
   16495                 :             : {
   16496                 :          10 :     DumpOptions *dopt = fout->dopt;
   16497                 :             :     SecLabelItem *labels;
   16498                 :             :     int         nlabels;
   16499                 :             :     int         i;
   16500                 :             :     PQExpBuffer query;
   16501                 :             : 
   16502                 :             :     /* do nothing, if --no-security-labels is supplied */
   16503         [ -  + ]:          10 :     if (dopt->no_security_labels)
   16504                 :           0 :         return;
   16505                 :             : 
   16506                 :             :     /*
   16507                 :             :      * Security labels are schema not data ... except large object labels are
   16508                 :             :      * data
   16509                 :             :      */
   16510         [ -  + ]:          10 :     if (strcmp(type, "LARGE OBJECT") != 0)
   16511                 :             :     {
   16512         [ #  # ]:           0 :         if (!dopt->dumpSchema)
   16513                 :           0 :             return;
   16514                 :             :     }
   16515                 :             :     else
   16516                 :             :     {
   16517                 :             :         /* We do dump large object security labels in binary-upgrade mode */
   16518   [ +  -  -  + ]:          10 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   16519                 :           0 :             return;
   16520                 :             :     }
   16521                 :             : 
   16522                 :             :     /* Search for security labels associated with catalogId, using table */
   16523                 :          10 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   16524                 :             : 
   16525                 :          10 :     query = createPQExpBuffer();
   16526                 :             : 
   16527         [ +  + ]:          15 :     for (i = 0; i < nlabels; i++)
   16528                 :             :     {
   16529                 :             :         /*
   16530                 :             :          * Ignore label entries for which the subid doesn't match.
   16531                 :             :          */
   16532         [ -  + ]:           5 :         if (labels[i].objsubid != subid)
   16533                 :           0 :             continue;
   16534                 :             : 
   16535                 :           5 :         appendPQExpBuffer(query,
   16536                 :             :                           "SECURITY LABEL FOR %s ON %s ",
   16537                 :           5 :                           fmtId(labels[i].provider), type);
   16538   [ -  +  -  - ]:           5 :         if (namespace && *namespace)
   16539                 :           0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   16540                 :           5 :         appendPQExpBuffer(query, "%s IS ", name);
   16541                 :           5 :         appendStringLiteralAH(query, labels[i].label, fout);
   16542                 :           5 :         appendPQExpBufferStr(query, ";\n");
   16543                 :             :     }
   16544                 :             : 
   16545         [ +  + ]:          10 :     if (query->len > 0)
   16546                 :             :     {
   16547                 :           5 :         PQExpBuffer tag = createPQExpBuffer();
   16548                 :             : 
   16549                 :           5 :         appendPQExpBuffer(tag, "%s %s", type, name);
   16550                 :           5 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16551                 :           5 :                      ARCHIVE_OPTS(.tag = tag->data,
   16552                 :             :                                   .namespace = namespace,
   16553                 :             :                                   .owner = owner,
   16554                 :             :                                   .description = "SECURITY LABEL",
   16555                 :             :                                   .section = SECTION_NONE,
   16556                 :             :                                   .createStmt = query->data,
   16557                 :             :                                   .deps = &dumpId,
   16558                 :             :                                   .nDeps = 1));
   16559                 :           5 :         destroyPQExpBuffer(tag);
   16560                 :             :     }
   16561                 :             : 
   16562                 :          10 :     destroyPQExpBuffer(query);
   16563                 :             : }
   16564                 :             : 
   16565                 :             : /*
   16566                 :             :  * dumpTableSecLabel
   16567                 :             :  *
   16568                 :             :  * As above, but dump security label for both the specified table (or view)
   16569                 :             :  * and its columns.
   16570                 :             :  */
   16571                 :             : static void
   16572                 :           0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   16573                 :             : {
   16574                 :           0 :     DumpOptions *dopt = fout->dopt;
   16575                 :             :     SecLabelItem *labels;
   16576                 :             :     int         nlabels;
   16577                 :             :     int         i;
   16578                 :             :     PQExpBuffer query;
   16579                 :             :     PQExpBuffer target;
   16580                 :             : 
   16581                 :             :     /* do nothing, if --no-security-labels is supplied */
   16582         [ #  # ]:           0 :     if (dopt->no_security_labels)
   16583                 :           0 :         return;
   16584                 :             : 
   16585                 :             :     /* SecLabel are SCHEMA not data */
   16586         [ #  # ]:           0 :     if (!dopt->dumpSchema)
   16587                 :           0 :         return;
   16588                 :             : 
   16589                 :             :     /* Search for comments associated with relation, using table */
   16590                 :           0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   16591                 :           0 :                             tbinfo->dobj.catId.oid,
   16592                 :             :                             &labels);
   16593                 :             : 
   16594                 :             :     /* If security labels exist, build SECURITY LABEL statements */
   16595         [ #  # ]:           0 :     if (nlabels <= 0)
   16596                 :           0 :         return;
   16597                 :             : 
   16598                 :           0 :     query = createPQExpBuffer();
   16599                 :           0 :     target = createPQExpBuffer();
   16600                 :             : 
   16601         [ #  # ]:           0 :     for (i = 0; i < nlabels; i++)
   16602                 :             :     {
   16603                 :             :         const char *colname;
   16604                 :           0 :         const char *provider = labels[i].provider;
   16605                 :           0 :         const char *label = labels[i].label;
   16606                 :           0 :         int         objsubid = labels[i].objsubid;
   16607                 :             : 
   16608                 :           0 :         resetPQExpBuffer(target);
   16609         [ #  # ]:           0 :         if (objsubid == 0)
   16610                 :             :         {
   16611                 :           0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   16612                 :           0 :                               fmtQualifiedDumpable(tbinfo));
   16613                 :             :         }
   16614                 :             :         else
   16615                 :             :         {
   16616                 :           0 :             colname = getAttrName(objsubid, tbinfo);
   16617                 :             :             /* first fmtXXX result must be consumed before calling again */
   16618                 :           0 :             appendPQExpBuffer(target, "COLUMN %s",
   16619                 :           0 :                               fmtQualifiedDumpable(tbinfo));
   16620                 :           0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   16621                 :             :         }
   16622                 :           0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   16623                 :             :                           fmtId(provider), target->data);
   16624                 :           0 :         appendStringLiteralAH(query, label, fout);
   16625                 :           0 :         appendPQExpBufferStr(query, ";\n");
   16626                 :             :     }
   16627         [ #  # ]:           0 :     if (query->len > 0)
   16628                 :             :     {
   16629                 :           0 :         resetPQExpBuffer(target);
   16630                 :           0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   16631                 :           0 :                           fmtId(tbinfo->dobj.name));
   16632                 :           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   16633                 :           0 :                      ARCHIVE_OPTS(.tag = target->data,
   16634                 :             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16635                 :             :                                   .owner = tbinfo->rolname,
   16636                 :             :                                   .description = "SECURITY LABEL",
   16637                 :             :                                   .section = SECTION_NONE,
   16638                 :             :                                   .createStmt = query->data,
   16639                 :             :                                   .deps = &(tbinfo->dobj.dumpId),
   16640                 :             :                                   .nDeps = 1));
   16641                 :             :     }
   16642                 :           0 :     destroyPQExpBuffer(query);
   16643                 :           0 :     destroyPQExpBuffer(target);
   16644                 :             : }
   16645                 :             : 
   16646                 :             : /*
   16647                 :             :  * findSecLabels
   16648                 :             :  *
   16649                 :             :  * Find the security label(s), if any, associated with the given object.
   16650                 :             :  * All the objsubid values associated with the given classoid/objoid are
   16651                 :             :  * found with one search.
   16652                 :             :  */
   16653                 :             : static int
   16654                 :          10 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   16655                 :             : {
   16656                 :          10 :     SecLabelItem *middle = NULL;
   16657                 :             :     SecLabelItem *low;
   16658                 :             :     SecLabelItem *high;
   16659                 :             :     int         nmatch;
   16660                 :             : 
   16661         [ -  + ]:          10 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   16662                 :             :     {
   16663                 :           0 :         *items = NULL;
   16664                 :           0 :         return 0;
   16665                 :             :     }
   16666                 :             : 
   16667                 :             :     /*
   16668                 :             :      * Do binary search to find some item matching the object.
   16669                 :             :      */
   16670                 :          10 :     low = &seclabels[0];
   16671                 :          10 :     high = &seclabels[nseclabels - 1];
   16672         [ +  + ]:          15 :     while (low <= high)
   16673                 :             :     {
   16674                 :          10 :         middle = low + (high - low) / 2;
   16675                 :             : 
   16676         [ -  + ]:          10 :         if (classoid < middle->classoid)
   16677                 :           0 :             high = middle - 1;
   16678         [ -  + ]:          10 :         else if (classoid > middle->classoid)
   16679                 :           0 :             low = middle + 1;
   16680         [ +  + ]:          10 :         else if (objoid < middle->objoid)
   16681                 :           5 :             high = middle - 1;
   16682         [ -  + ]:           5 :         else if (objoid > middle->objoid)
   16683                 :           0 :             low = middle + 1;
   16684                 :             :         else
   16685                 :           5 :             break;              /* found a match */
   16686                 :             :     }
   16687                 :             : 
   16688         [ +  + ]:          10 :     if (low > high)              /* no matches */
   16689                 :             :     {
   16690                 :           5 :         *items = NULL;
   16691                 :           5 :         return 0;
   16692                 :             :     }
   16693                 :             : 
   16694                 :             :     /*
   16695                 :             :      * Now determine how many items match the object.  The search loop
   16696                 :             :      * invariant still holds: only items between low and high inclusive could
   16697                 :             :      * match.
   16698                 :             :      */
   16699                 :           5 :     nmatch = 1;
   16700         [ -  + ]:           5 :     while (middle > low)
   16701                 :             :     {
   16702         [ #  # ]:           0 :         if (classoid != middle[-1].classoid ||
   16703         [ #  # ]:           0 :             objoid != middle[-1].objoid)
   16704                 :             :             break;
   16705                 :           0 :         middle--;
   16706                 :           0 :         nmatch++;
   16707                 :             :     }
   16708                 :             : 
   16709                 :           5 :     *items = middle;
   16710                 :             : 
   16711                 :           5 :     middle += nmatch;
   16712         [ -  + ]:           5 :     while (middle <= high)
   16713                 :             :     {
   16714         [ #  # ]:           0 :         if (classoid != middle->classoid ||
   16715         [ #  # ]:           0 :             objoid != middle->objoid)
   16716                 :             :             break;
   16717                 :           0 :         middle++;
   16718                 :           0 :         nmatch++;
   16719                 :             :     }
   16720                 :             : 
   16721                 :           5 :     return nmatch;
   16722                 :             : }
   16723                 :             : 
   16724                 :             : /*
   16725                 :             :  * collectSecLabels
   16726                 :             :  *
   16727                 :             :  * Construct a table of all security labels available for database objects;
   16728                 :             :  * also set the has-seclabel component flag for each relevant object.
   16729                 :             :  *
   16730                 :             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   16731                 :             :  */
   16732                 :             : static void
   16733                 :         191 : collectSecLabels(Archive *fout)
   16734                 :             : {
   16735                 :             :     PGresult   *res;
   16736                 :             :     PQExpBuffer query;
   16737                 :             :     int         i_label;
   16738                 :             :     int         i_provider;
   16739                 :             :     int         i_classoid;
   16740                 :             :     int         i_objoid;
   16741                 :             :     int         i_objsubid;
   16742                 :             :     int         ntups;
   16743                 :             :     int         i;
   16744                 :             :     DumpableObject *dobj;
   16745                 :             : 
   16746                 :         191 :     query = createPQExpBuffer();
   16747                 :             : 
   16748                 :         191 :     appendPQExpBufferStr(query,
   16749                 :             :                          "SELECT label, provider, classoid, objoid, objsubid "
   16750                 :             :                          "FROM pg_catalog.pg_seclabels "
   16751                 :             :                          "ORDER BY classoid, objoid, objsubid");
   16752                 :             : 
   16753                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16754                 :             : 
   16755                 :             :     /* Construct lookup table containing OIDs in numeric form */
   16756                 :         191 :     i_label = PQfnumber(res, "label");
   16757                 :         191 :     i_provider = PQfnumber(res, "provider");
   16758                 :         191 :     i_classoid = PQfnumber(res, "classoid");
   16759                 :         191 :     i_objoid = PQfnumber(res, "objoid");
   16760                 :         191 :     i_objsubid = PQfnumber(res, "objsubid");
   16761                 :             : 
   16762                 :         191 :     ntups = PQntuples(res);
   16763                 :             : 
   16764                 :         191 :     seclabels = pg_malloc_array(SecLabelItem, ntups);
   16765                 :         191 :     nseclabels = 0;
   16766                 :         191 :     dobj = NULL;
   16767                 :             : 
   16768         [ +  + ]:         196 :     for (i = 0; i < ntups; i++)
   16769                 :             :     {
   16770                 :             :         CatalogId   objId;
   16771                 :             :         int         subid;
   16772                 :             : 
   16773                 :           5 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   16774                 :           5 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   16775                 :           5 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   16776                 :             : 
   16777                 :             :         /* We needn't remember labels that don't match any dumpable object */
   16778         [ -  + ]:           5 :         if (dobj == NULL ||
   16779         [ #  # ]:           0 :             dobj->catId.tableoid != objId.tableoid ||
   16780         [ #  # ]:           0 :             dobj->catId.oid != objId.oid)
   16781                 :           5 :             dobj = findObjectByCatalogId(objId);
   16782         [ -  + ]:           5 :         if (dobj == NULL)
   16783                 :           0 :             continue;
   16784                 :             : 
   16785                 :             :         /*
   16786                 :             :          * Labels on columns of composite types are linked to the type's
   16787                 :             :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   16788                 :             :          * in the type's own DumpableObject.
   16789                 :             :          */
   16790   [ -  +  -  - ]:           5 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   16791         [ #  # ]:           0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   16792                 :           0 :         {
   16793                 :             :             TypeInfo   *cTypeInfo;
   16794                 :             : 
   16795                 :           0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   16796         [ #  # ]:           0 :             if (cTypeInfo)
   16797                 :           0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   16798                 :             :         }
   16799                 :             :         else
   16800                 :           5 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   16801                 :             : 
   16802                 :           5 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   16803                 :           5 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   16804                 :           5 :         seclabels[nseclabels].classoid = objId.tableoid;
   16805                 :           5 :         seclabels[nseclabels].objoid = objId.oid;
   16806                 :           5 :         seclabels[nseclabels].objsubid = subid;
   16807                 :           5 :         nseclabels++;
   16808                 :             :     }
   16809                 :             : 
   16810                 :         191 :     PQclear(res);
   16811                 :         191 :     destroyPQExpBuffer(query);
   16812                 :         191 : }
   16813                 :             : 
   16814                 :             : /*
   16815                 :             :  * dumpTable
   16816                 :             :  *    write out to fout the declarations (not data) of a user-defined table
   16817                 :             :  */
   16818                 :             : static void
   16819                 :       34203 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   16820                 :             : {
   16821                 :       34203 :     DumpOptions *dopt = fout->dopt;
   16822                 :       34203 :     DumpId      tableAclDumpId = InvalidDumpId;
   16823                 :             :     char       *namecopy;
   16824                 :             : 
   16825                 :             :     /* Do nothing if not dumping schema */
   16826         [ +  + ]:       34203 :     if (!dopt->dumpSchema)
   16827                 :        1671 :         return;
   16828                 :             : 
   16829         [ +  + ]:       32532 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16830                 :             :     {
   16831         [ +  + ]:        7259 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   16832                 :         381 :             dumpSequence(fout, tbinfo);
   16833                 :             :         else
   16834                 :        6878 :             dumpTableSchema(fout, tbinfo);
   16835                 :             :     }
   16836                 :             : 
   16837                 :             :     /* Handle the ACL here */
   16838                 :       32532 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   16839         [ +  + ]:       32532 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16840                 :             :     {
   16841                 :             :         const char *objtype;
   16842                 :             : 
   16843      [ +  +  + ]:       26105 :         switch (tbinfo->relkind)
   16844                 :             :         {
   16845                 :          90 :             case RELKIND_SEQUENCE:
   16846                 :          90 :                 objtype = "SEQUENCE";
   16847                 :          90 :                 break;
   16848                 :          39 :             case RELKIND_PROPGRAPH:
   16849                 :          39 :                 objtype = "PROPERTY GRAPH";
   16850                 :          39 :                 break;
   16851                 :       25976 :             default:
   16852                 :       25976 :                 objtype = "TABLE";
   16853                 :       25976 :                 break;
   16854                 :             :         }
   16855                 :             : 
   16856                 :             :         tableAclDumpId =
   16857                 :       26105 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   16858                 :             :                     objtype, namecopy, NULL,
   16859                 :       26105 :                     tbinfo->dobj.namespace->dobj.name,
   16860                 :       26105 :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   16861                 :             :     }
   16862                 :             : 
   16863                 :             :     /*
   16864                 :             :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   16865                 :             :      * rather than trying to fetch them during getTableAttrs, so that we won't
   16866                 :             :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   16867                 :             :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   16868                 :             :      */
   16869   [ +  +  +  + ]:       32532 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   16870                 :             :     {
   16871                 :         291 :         PQExpBuffer query = createPQExpBuffer();
   16872                 :             :         PGresult   *res;
   16873                 :             :         int         i;
   16874                 :             : 
   16875         [ +  + ]:         291 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   16876                 :             :         {
   16877                 :             :             /* Set up query for column ACLs */
   16878                 :         164 :             appendPQExpBufferStr(query,
   16879                 :             :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   16880                 :             : 
   16881                 :             :             /*
   16882                 :             :              * In principle we should call acldefault('c', relowner) to get
   16883                 :             :              * the default ACL for a column.  However, we don't currently
   16884                 :             :              * store the numeric OID of the relowner in TableInfo.  We could
   16885                 :             :              * convert the owner name using regrole, but that creates a risk
   16886                 :             :              * of failure due to concurrent role renames.  Given that the
   16887                 :             :              * default ACL for columns is empty and is likely to stay that
   16888                 :             :              * way, it's not worth extra cycles and risk to avoid hard-wiring
   16889                 :             :              * that knowledge here.
   16890                 :             :              */
   16891                 :         164 :             appendPQExpBufferStr(query,
   16892                 :             :                                  "SELECT at.attname, "
   16893                 :             :                                  "at.attacl, "
   16894                 :             :                                  "'{}' AS acldefault, "
   16895                 :             :                                  "pip.privtype, pip.initprivs "
   16896                 :             :                                  "FROM pg_catalog.pg_attribute at "
   16897                 :             :                                  "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   16898                 :             :                                  "(at.attrelid = pip.objoid "
   16899                 :             :                                  "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   16900                 :             :                                  "AND at.attnum = pip.objsubid) "
   16901                 :             :                                  "WHERE at.attrelid = $1 AND "
   16902                 :             :                                  "NOT at.attisdropped "
   16903                 :             :                                  "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   16904                 :             :                                  "ORDER BY at.attnum");
   16905                 :             : 
   16906                 :         164 :             ExecuteSqlStatement(fout, query->data);
   16907                 :             : 
   16908                 :         164 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   16909                 :             :         }
   16910                 :             : 
   16911                 :         291 :         printfPQExpBuffer(query,
   16912                 :             :                           "EXECUTE getColumnACLs('%u')",
   16913                 :         291 :                           tbinfo->dobj.catId.oid);
   16914                 :             : 
   16915                 :         291 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16916                 :             : 
   16917         [ +  + ]:        5266 :         for (i = 0; i < PQntuples(res); i++)
   16918                 :             :         {
   16919                 :        4975 :             char       *attname = PQgetvalue(res, i, 0);
   16920                 :        4975 :             char       *attacl = PQgetvalue(res, i, 1);
   16921                 :        4975 :             char       *acldefault = PQgetvalue(res, i, 2);
   16922                 :        4975 :             char        privtype = *(PQgetvalue(res, i, 3));
   16923                 :        4975 :             char       *initprivs = PQgetvalue(res, i, 4);
   16924                 :             :             DumpableAcl coldacl;
   16925                 :             :             char       *attnamecopy;
   16926                 :             : 
   16927                 :        4975 :             coldacl.acl = attacl;
   16928                 :        4975 :             coldacl.acldefault = acldefault;
   16929                 :        4975 :             coldacl.privtype = privtype;
   16930                 :        4975 :             coldacl.initprivs = initprivs;
   16931                 :        4975 :             attnamecopy = pg_strdup(fmtId(attname));
   16932                 :             : 
   16933                 :             :             /*
   16934                 :             :              * Column's GRANT type is always TABLE.  Each column ACL depends
   16935                 :             :              * on the table-level ACL, since we can restore column ACLs in
   16936                 :             :              * parallel but the table-level ACL has to be done first.
   16937                 :             :              */
   16938                 :        4975 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   16939                 :             :                     "TABLE", namecopy, attnamecopy,
   16940                 :        4975 :                     tbinfo->dobj.namespace->dobj.name,
   16941                 :        4975 :                     NULL, tbinfo->rolname, &coldacl);
   16942                 :        4975 :             pg_free(attnamecopy);
   16943                 :             :         }
   16944                 :         291 :         PQclear(res);
   16945                 :         291 :         destroyPQExpBuffer(query);
   16946                 :             :     }
   16947                 :             : 
   16948                 :       32532 :     pg_free(namecopy);
   16949                 :             : }
   16950                 :             : 
   16951                 :             : /*
   16952                 :             :  * Create the AS clause for a view or materialized view. The semicolon is
   16953                 :             :  * stripped because a materialized view must add a WITH NO DATA clause.
   16954                 :             :  *
   16955                 :             :  * This returns a new buffer which must be freed by the caller.
   16956                 :             :  */
   16957                 :             : static PQExpBuffer
   16958                 :         926 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   16959                 :             : {
   16960                 :         926 :     PQExpBuffer query = createPQExpBuffer();
   16961                 :         926 :     PQExpBuffer result = createPQExpBuffer();
   16962                 :             :     PGresult   *res;
   16963                 :             :     int         len;
   16964                 :             : 
   16965                 :             :     /* Fetch the view definition */
   16966                 :         926 :     appendPQExpBuffer(query,
   16967                 :             :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   16968                 :         926 :                       tbinfo->dobj.catId.oid);
   16969                 :             : 
   16970                 :         926 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16971                 :             : 
   16972         [ -  + ]:         926 :     if (PQntuples(res) != 1)
   16973                 :             :     {
   16974         [ #  # ]:           0 :         if (PQntuples(res) < 1)
   16975                 :           0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   16976                 :             :                      tbinfo->dobj.name);
   16977                 :             :         else
   16978                 :           0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   16979                 :             :                      tbinfo->dobj.name);
   16980                 :             :     }
   16981                 :             : 
   16982                 :         926 :     len = PQgetlength(res, 0, 0);
   16983                 :             : 
   16984         [ -  + ]:         926 :     if (len == 0)
   16985                 :           0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   16986                 :             :                  tbinfo->dobj.name);
   16987                 :             : 
   16988                 :             :     /* Strip off the trailing semicolon so that other things may follow. */
   16989                 :             :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   16990                 :         926 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   16991                 :             : 
   16992                 :         926 :     PQclear(res);
   16993                 :         926 :     destroyPQExpBuffer(query);
   16994                 :             : 
   16995                 :         926 :     return result;
   16996                 :             : }
   16997                 :             : 
   16998                 :             : /*
   16999                 :             :  * Create a dummy AS clause for a view.  This is used when the real view
   17000                 :             :  * definition has to be postponed because of circular dependencies.
   17001                 :             :  * We must duplicate the view's external properties -- column names and types
   17002                 :             :  * (including collation) -- so that it works for subsequent references.
   17003                 :             :  *
   17004                 :             :  * This returns a new buffer which must be freed by the caller.
   17005                 :             :  */
   17006                 :             : static PQExpBuffer
   17007                 :          20 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   17008                 :             : {
   17009                 :          20 :     PQExpBuffer result = createPQExpBuffer();
   17010                 :             :     int         j;
   17011                 :             : 
   17012                 :          20 :     appendPQExpBufferStr(result, "SELECT");
   17013                 :             : 
   17014         [ +  + ]:          40 :     for (j = 0; j < tbinfo->numatts; j++)
   17015                 :             :     {
   17016         [ +  + ]:          20 :         if (j > 0)
   17017                 :          10 :             appendPQExpBufferChar(result, ',');
   17018                 :          20 :         appendPQExpBufferStr(result, "\n    ");
   17019                 :             : 
   17020                 :          20 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   17021                 :             : 
   17022                 :             :         /*
   17023                 :             :          * Must add collation if not default for the type, because CREATE OR
   17024                 :             :          * REPLACE VIEW won't change it
   17025                 :             :          */
   17026         [ -  + ]:          20 :         if (OidIsValid(tbinfo->attcollation[j]))
   17027                 :             :         {
   17028                 :             :             CollInfo   *coll;
   17029                 :             : 
   17030                 :           0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   17031         [ #  # ]:           0 :             if (coll)
   17032                 :           0 :                 appendPQExpBuffer(result, " COLLATE %s",
   17033                 :           0 :                                   fmtQualifiedDumpable(coll));
   17034                 :             :         }
   17035                 :             : 
   17036                 :          20 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   17037                 :             :     }
   17038                 :             : 
   17039                 :          20 :     return result;
   17040                 :             : }
   17041                 :             : 
   17042                 :             : /*
   17043                 :             :  * dumpTableSchema
   17044                 :             :  *    write the declaration (not data) of one user-defined table or view
   17045                 :             :  */
   17046                 :             : static void
   17047                 :        6878 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   17048                 :             : {
   17049                 :        6878 :     DumpOptions *dopt = fout->dopt;
   17050                 :        6878 :     PQExpBuffer q = createPQExpBuffer();
   17051                 :        6878 :     PQExpBuffer delq = createPQExpBuffer();
   17052                 :        6878 :     PQExpBuffer extra = createPQExpBuffer();
   17053                 :             :     char       *qrelname;
   17054                 :             :     char       *qualrelname;
   17055                 :             :     int         numParents;
   17056                 :             :     TableInfo **parents;
   17057                 :             :     int         actual_atts;    /* number of attrs in this CREATE statement */
   17058                 :             :     const char *reltypename;
   17059                 :             :     char       *storage;
   17060                 :             :     int         j,
   17061                 :             :                 k;
   17062                 :             : 
   17063                 :             :     /* We had better have loaded per-column details about this table */
   17064                 :             :     Assert(tbinfo->interesting);
   17065                 :             : 
   17066                 :        6878 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   17067                 :        6878 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   17068                 :             : 
   17069         [ -  + ]:        6878 :     if (tbinfo->hasoids)
   17070                 :           0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   17071                 :             :                        qrelname);
   17072                 :             : 
   17073         [ +  + ]:        6878 :     if (dopt->binary_upgrade)
   17074                 :         952 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   17075                 :             : 
   17076                 :             :     /* Is it a table or a view? */
   17077         [ +  + ]:        6878 :     if (tbinfo->relkind == RELKIND_VIEW)
   17078                 :             :     {
   17079                 :             :         PQExpBuffer result;
   17080                 :             : 
   17081                 :             :         /*
   17082                 :             :          * Note: keep this code in sync with the is_view case in dumpRule()
   17083                 :             :          */
   17084                 :             : 
   17085                 :         573 :         reltypename = "VIEW";
   17086                 :             : 
   17087         [ +  + ]:         573 :         if (dopt->binary_upgrade)
   17088                 :          56 :             binary_upgrade_set_pg_class_oids(fout, q,
   17089                 :          56 :                                              tbinfo->dobj.catId.oid);
   17090                 :             : 
   17091                 :         573 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   17092                 :             : 
   17093         [ +  + ]:         573 :         if (tbinfo->dummy_view)
   17094                 :          10 :             result = createDummyViewAsClause(fout, tbinfo);
   17095                 :             :         else
   17096                 :             :         {
   17097         [ +  + ]:         563 :             if (nonemptyReloptions(tbinfo->reloptions))
   17098                 :             :             {
   17099                 :          63 :                 appendPQExpBufferStr(q, " WITH (");
   17100                 :          63 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17101                 :          63 :                 appendPQExpBufferChar(q, ')');
   17102                 :             :             }
   17103                 :         563 :             result = createViewAsClause(fout, tbinfo);
   17104                 :             :         }
   17105                 :         573 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   17106                 :         573 :         destroyPQExpBuffer(result);
   17107                 :             : 
   17108   [ +  +  +  - ]:         573 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   17109                 :          34 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   17110                 :         573 :         appendPQExpBufferStr(q, ";\n");
   17111                 :             :     }
   17112         [ +  + ]:        6305 :     else if (tbinfo->relkind == RELKIND_PROPGRAPH)
   17113                 :             :     {
   17114                 :         104 :         PQExpBuffer query = createPQExpBuffer();
   17115                 :             :         PGresult   *res;
   17116                 :             :         int         len;
   17117                 :             : 
   17118                 :         104 :         reltypename = "PROPERTY GRAPH";
   17119                 :             : 
   17120         [ +  + ]:         104 :         if (dopt->binary_upgrade)
   17121                 :          15 :             binary_upgrade_set_pg_class_oids(fout, q,
   17122                 :          15 :                                              tbinfo->dobj.catId.oid);
   17123                 :             : 
   17124                 :         104 :         appendPQExpBuffer(query,
   17125                 :             :                           "SELECT pg_catalog.pg_get_propgraphdef('%u'::pg_catalog.oid) AS pgdef",
   17126                 :         104 :                           tbinfo->dobj.catId.oid);
   17127                 :             : 
   17128                 :         104 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17129                 :             : 
   17130         [ -  + ]:         104 :         if (PQntuples(res) != 1)
   17131                 :             :         {
   17132         [ #  # ]:           0 :             if (PQntuples(res) < 1)
   17133                 :           0 :                 pg_fatal("query to obtain definition of property graph \"%s\" returned no data",
   17134                 :             :                          tbinfo->dobj.name);
   17135                 :             :             else
   17136                 :           0 :                 pg_fatal("query to obtain definition of property graph \"%s\" returned more than one definition",
   17137                 :             :                          tbinfo->dobj.name);
   17138                 :             :         }
   17139                 :             : 
   17140                 :         104 :         len = PQgetlength(res, 0, 0);
   17141                 :             : 
   17142         [ -  + ]:         104 :         if (len == 0)
   17143                 :           0 :             pg_fatal("definition of property graph \"%s\" appears to be empty (length zero)",
   17144                 :             :                      tbinfo->dobj.name);
   17145                 :             : 
   17146                 :         104 :         appendPQExpBufferStr(q, PQgetvalue(res, 0, 0));
   17147                 :             : 
   17148                 :         104 :         PQclear(res);
   17149                 :         104 :         destroyPQExpBuffer(query);
   17150                 :             : 
   17151                 :         104 :         appendPQExpBufferStr(q, ";\n");
   17152                 :             :     }
   17153                 :             :     else
   17154                 :             :     {
   17155                 :        6201 :         char       *partkeydef = NULL;
   17156                 :        6201 :         char       *ftoptions = NULL;
   17157                 :        6201 :         char       *srvname = NULL;
   17158                 :        6201 :         const char *foreign = "";
   17159                 :             : 
   17160                 :             :         /*
   17161                 :             :          * Set reltypename, and collect any relkind-specific data that we
   17162                 :             :          * didn't fetch during getTables().
   17163                 :             :          */
   17164   [ +  +  +  + ]:        6201 :         switch (tbinfo->relkind)
   17165                 :             :         {
   17166                 :         604 :             case RELKIND_PARTITIONED_TABLE:
   17167                 :             :                 {
   17168                 :         604 :                     PQExpBuffer query = createPQExpBuffer();
   17169                 :             :                     PGresult   *res;
   17170                 :             : 
   17171                 :         604 :                     reltypename = "TABLE";
   17172                 :             : 
   17173                 :             :                     /* retrieve partition key definition */
   17174                 :         604 :                     appendPQExpBuffer(query,
   17175                 :             :                                       "SELECT pg_get_partkeydef('%u')",
   17176                 :         604 :                                       tbinfo->dobj.catId.oid);
   17177                 :         604 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17178                 :         604 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   17179                 :         604 :                     PQclear(res);
   17180                 :         604 :                     destroyPQExpBuffer(query);
   17181                 :         604 :                     break;
   17182                 :             :                 }
   17183                 :          36 :             case RELKIND_FOREIGN_TABLE:
   17184                 :             :                 {
   17185                 :          36 :                     PQExpBuffer query = createPQExpBuffer();
   17186                 :             :                     PGresult   *res;
   17187                 :             :                     int         i_srvname;
   17188                 :             :                     int         i_ftoptions;
   17189                 :             : 
   17190                 :          36 :                     reltypename = "FOREIGN TABLE";
   17191                 :             : 
   17192                 :             :                     /* retrieve name of foreign server and generic options */
   17193                 :          36 :                     appendPQExpBuffer(query,
   17194                 :             :                                       "SELECT fs.srvname, "
   17195                 :             :                                       "pg_catalog.array_to_string(ARRAY("
   17196                 :             :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   17197                 :             :                                       "' ' || pg_catalog.quote_literal(option_value) "
   17198                 :             :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   17199                 :             :                                       "ORDER BY option_name"
   17200                 :             :                                       "), E',\n    ') AS ftoptions "
   17201                 :             :                                       "FROM pg_catalog.pg_foreign_table ft "
   17202                 :             :                                       "JOIN pg_catalog.pg_foreign_server fs "
   17203                 :             :                                       "ON (fs.oid = ft.ftserver) "
   17204                 :             :                                       "WHERE ft.ftrelid = '%u'",
   17205                 :          36 :                                       tbinfo->dobj.catId.oid);
   17206                 :          36 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17207                 :          36 :                     i_srvname = PQfnumber(res, "srvname");
   17208                 :          36 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   17209                 :          36 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   17210                 :          36 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   17211                 :          36 :                     PQclear(res);
   17212                 :          36 :                     destroyPQExpBuffer(query);
   17213                 :             : 
   17214                 :          36 :                     foreign = "FOREIGN ";
   17215                 :          36 :                     break;
   17216                 :             :                 }
   17217                 :         353 :             case RELKIND_MATVIEW:
   17218                 :         353 :                 reltypename = "MATERIALIZED VIEW";
   17219                 :         353 :                 break;
   17220                 :        5208 :             default:
   17221                 :        5208 :                 reltypename = "TABLE";
   17222                 :        5208 :                 break;
   17223                 :             :         }
   17224                 :             : 
   17225                 :        6201 :         numParents = tbinfo->numParents;
   17226                 :        6201 :         parents = tbinfo->parents;
   17227                 :             : 
   17228         [ +  + ]:        6201 :         if (dopt->binary_upgrade)
   17229                 :         881 :             binary_upgrade_set_pg_class_oids(fout, q,
   17230                 :         881 :                                              tbinfo->dobj.catId.oid);
   17231                 :             : 
   17232                 :             :         /*
   17233                 :             :          * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   17234                 :             :          * ignore it when dumping if it was set in this case.
   17235                 :             :          */
   17236                 :        6201 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   17237         [ +  + ]:        6201 :                           (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   17238         [ +  - ]:          20 :                            tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   17239                 :             :                           "UNLOGGED " : "",
   17240                 :             :                           reltypename,
   17241                 :             :                           qualrelname);
   17242                 :             : 
   17243                 :             :         /*
   17244                 :             :          * Attach to type, if reloftype; except in case of a binary upgrade,
   17245                 :             :          * we dump the table normally and attach it to the type afterward.
   17246                 :             :          */
   17247   [ +  +  +  + ]:        6201 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   17248                 :          24 :             appendPQExpBuffer(q, " OF %s",
   17249                 :          24 :                               getFormattedTypeName(fout, tbinfo->reloftype,
   17250                 :             :                                                    zeroIsError));
   17251                 :             : 
   17252         [ +  + ]:        6201 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   17253                 :             :         {
   17254                 :             :             /* Dump the attributes */
   17255                 :        5848 :             actual_atts = 0;
   17256         [ +  + ]:       27092 :             for (j = 0; j < tbinfo->numatts; j++)
   17257                 :             :             {
   17258                 :             :                 /*
   17259                 :             :                  * Normally, dump if it's locally defined in this table, and
   17260                 :             :                  * not dropped.  But for binary upgrade, we'll dump all the
   17261                 :             :                  * columns, and then fix up the dropped and nonlocal cases
   17262                 :             :                  * below.
   17263                 :             :                  */
   17264         [ +  + ]:       21244 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   17265                 :             :                 {
   17266                 :             :                     bool        print_default;
   17267                 :             :                     bool        print_notnull;
   17268                 :             : 
   17269                 :             :                     /*
   17270                 :             :                      * Default value --- suppress if to be printed separately
   17271                 :             :                      * or not at all.
   17272                 :             :                      */
   17273                 :       41370 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   17274   [ +  +  +  + ]:       21202 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   17275         [ +  + ]:        1083 :                                      !tbinfo->attrdefs[j]->separate);
   17276                 :             : 
   17277                 :             :                     /*
   17278                 :             :                      * Not Null constraint --- print it if it is locally
   17279                 :             :                      * defined, or if binary upgrade.  (In the latter case, we
   17280                 :             :                      * reset conislocal below.)
   17281                 :             :                      */
   17282         [ +  + ]:       22624 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   17283         [ +  + ]:        2505 :                                      (tbinfo->notnull_islocal[j] ||
   17284         [ +  + ]:         675 :                                       dopt->binary_upgrade ||
   17285         [ +  + ]:         581 :                                       tbinfo->ispartition));
   17286                 :             : 
   17287                 :             :                     /*
   17288                 :             :                      * Skip column if fully defined by reloftype, except in
   17289                 :             :                      * binary upgrade
   17290                 :             :                      */
   17291         [ +  + ]:       20119 :                     if (OidIsValid(tbinfo->reloftype) &&
   17292   [ +  +  +  + ]:          50 :                         !print_default && !print_notnull &&
   17293         [ +  + ]:          30 :                         !dopt->binary_upgrade)
   17294                 :          24 :                         continue;
   17295                 :             : 
   17296                 :             :                     /* Format properly if not first attr */
   17297         [ +  + ]:       20095 :                     if (actual_atts == 0)
   17298                 :        5461 :                         appendPQExpBufferStr(q, " (");
   17299                 :             :                     else
   17300                 :       14634 :                         appendPQExpBufferChar(q, ',');
   17301                 :       20095 :                     appendPQExpBufferStr(q, "\n    ");
   17302                 :       20095 :                     actual_atts++;
   17303                 :             : 
   17304                 :             :                     /* Attribute name */
   17305                 :       20095 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   17306                 :             : 
   17307         [ +  + ]:       20095 :                     if (tbinfo->attisdropped[j])
   17308                 :             :                     {
   17309                 :             :                         /*
   17310                 :             :                          * ALTER TABLE DROP COLUMN clears
   17311                 :             :                          * pg_attribute.atttypid, so we will not have gotten a
   17312                 :             :                          * valid type name; insert INTEGER as a stopgap. We'll
   17313                 :             :                          * clean things up later.
   17314                 :             :                          */
   17315                 :          85 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   17316                 :             :                         /* and skip to the next column */
   17317                 :          85 :                         continue;
   17318                 :             :                     }
   17319                 :             : 
   17320                 :             :                     /*
   17321                 :             :                      * Attribute type; print it except when creating a typed
   17322                 :             :                      * table ('OF type_name'), but in binary-upgrade mode,
   17323                 :             :                      * print it in that case too.
   17324                 :             :                      */
   17325   [ +  +  +  + ]:       20010 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   17326                 :             :                     {
   17327                 :       19994 :                         appendPQExpBuffer(q, " %s",
   17328                 :       19994 :                                           tbinfo->atttypnames[j]);
   17329                 :             :                     }
   17330                 :             : 
   17331         [ +  + ]:       20010 :                     if (print_default)
   17332                 :             :                     {
   17333         [ +  + ]:         949 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   17334                 :         328 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   17335                 :         328 :                                               tbinfo->attrdefs[j]->adef_expr);
   17336         [ +  + ]:         621 :                         else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   17337                 :         230 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   17338                 :         230 :                                               tbinfo->attrdefs[j]->adef_expr);
   17339                 :             :                         else
   17340                 :         391 :                             appendPQExpBuffer(q, " DEFAULT %s",
   17341                 :         391 :                                               tbinfo->attrdefs[j]->adef_expr);
   17342                 :             :                     }
   17343                 :             : 
   17344         [ +  + ]:       20010 :                     if (print_notnull)
   17345                 :             :                     {
   17346         [ +  + ]:        2472 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   17347                 :        1769 :                             appendPQExpBufferStr(q, " NOT NULL");
   17348                 :             :                         else
   17349                 :         703 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   17350                 :         703 :                                               fmtId(tbinfo->notnull_constrs[j]));
   17351                 :             : 
   17352         [ +  + ]:        2472 :                         if (tbinfo->notnull_noinh[j])
   17353                 :          35 :                             appendPQExpBufferStr(q, " NO INHERIT");
   17354                 :             :                     }
   17355                 :             : 
   17356                 :             :                     /* Add collation if not default for the type */
   17357         [ +  + ]:       20010 :                     if (OidIsValid(tbinfo->attcollation[j]))
   17358                 :             :                     {
   17359                 :             :                         CollInfo   *coll;
   17360                 :             : 
   17361                 :         216 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   17362         [ +  - ]:         216 :                         if (coll)
   17363                 :         216 :                             appendPQExpBuffer(q, " COLLATE %s",
   17364                 :         216 :                                               fmtQualifiedDumpable(coll));
   17365                 :             :                     }
   17366                 :             :                 }
   17367                 :             : 
   17368                 :             :                 /*
   17369                 :             :                  * On the other hand, if we choose not to print a column
   17370                 :             :                  * (likely because it is created by inheritance), but the
   17371                 :             :                  * column has a locally-defined not-null constraint, we need
   17372                 :             :                  * to dump the constraint as a standalone object.
   17373                 :             :                  *
   17374                 :             :                  * This syntax isn't SQL-conforming, but if you wanted
   17375                 :             :                  * standard output you wouldn't be creating non-standard
   17376                 :             :                  * objects to begin with.
   17377                 :             :                  */
   17378         [ +  + ]:       21135 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   17379         [ +  + ]:        1125 :                     !tbinfo->attisdropped[j] &&
   17380         [ +  + ]:         756 :                     tbinfo->notnull_constrs[j] != NULL &&
   17381         [ +  + ]:         216 :                     tbinfo->notnull_islocal[j])
   17382                 :             :                 {
   17383                 :             :                     /* Format properly if not first attr */
   17384         [ +  + ]:          94 :                     if (actual_atts == 0)
   17385                 :          90 :                         appendPQExpBufferStr(q, " (");
   17386                 :             :                     else
   17387                 :           4 :                         appendPQExpBufferChar(q, ',');
   17388                 :          94 :                     appendPQExpBufferStr(q, "\n    ");
   17389                 :          94 :                     actual_atts++;
   17390                 :             : 
   17391         [ +  + ]:          94 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   17392                 :           8 :                         appendPQExpBuffer(q, "NOT NULL %s",
   17393                 :           8 :                                           fmtId(tbinfo->attnames[j]));
   17394                 :             :                     else
   17395                 :         172 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   17396                 :          86 :                                           tbinfo->notnull_constrs[j],
   17397                 :          86 :                                           fmtId(tbinfo->attnames[j]));
   17398                 :             : 
   17399         [ +  + ]:          94 :                     if (tbinfo->notnull_noinh[j])
   17400                 :          33 :                         appendPQExpBufferStr(q, " NO INHERIT");
   17401                 :             :                 }
   17402                 :             :             }
   17403                 :             : 
   17404                 :             :             /*
   17405                 :             :              * Add non-inherited CHECK constraints, if any.
   17406                 :             :              *
   17407                 :             :              * For partitions, we need to include check constraints even if
   17408                 :             :              * they're not defined locally, because the ALTER TABLE ATTACH
   17409                 :             :              * PARTITION that we'll emit later expects the constraint to be
   17410                 :             :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   17411                 :             :              */
   17412         [ +  + ]:        6441 :             for (j = 0; j < tbinfo->ncheck; j++)
   17413                 :             :             {
   17414                 :         593 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17415                 :             : 
   17416         [ +  + ]:         593 :                 if (constr->separate ||
   17417   [ +  +  +  + ]:         523 :                     (!constr->conislocal && !tbinfo->ispartition))
   17418                 :         109 :                     continue;
   17419                 :             : 
   17420         [ +  + ]:         484 :                 if (actual_atts == 0)
   17421                 :          16 :                     appendPQExpBufferStr(q, " (\n    ");
   17422                 :             :                 else
   17423                 :         468 :                     appendPQExpBufferStr(q, ",\n    ");
   17424                 :             : 
   17425                 :         484 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   17426                 :         484 :                                   fmtId(constr->dobj.name));
   17427                 :         484 :                 appendPQExpBufferStr(q, constr->condef);
   17428                 :             : 
   17429                 :         484 :                 actual_atts++;
   17430                 :             :             }
   17431                 :             : 
   17432         [ +  + ]:        5848 :             if (actual_atts)
   17433                 :        5567 :                 appendPQExpBufferStr(q, "\n)");
   17434   [ +  +  -  + ]:         281 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   17435                 :             :             {
   17436                 :             :                 /*
   17437                 :             :                  * No attributes? we must have a parenthesized attribute list,
   17438                 :             :                  * even though empty, when not using the OF TYPE syntax.
   17439                 :             :                  */
   17440                 :         269 :                 appendPQExpBufferStr(q, " (\n)");
   17441                 :             :             }
   17442                 :             : 
   17443                 :             :             /*
   17444                 :             :              * Emit the INHERITS clause (not for partitions), except in
   17445                 :             :              * binary-upgrade mode.
   17446                 :             :              */
   17447   [ +  +  +  + ]:        5848 :             if (numParents > 0 && !tbinfo->ispartition &&
   17448         [ +  + ]:         555 :                 !dopt->binary_upgrade)
   17449                 :             :             {
   17450                 :         486 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   17451         [ +  + ]:        1045 :                 for (k = 0; k < numParents; k++)
   17452                 :             :                 {
   17453                 :         559 :                     TableInfo  *parentRel = parents[k];
   17454                 :             : 
   17455         [ +  + ]:         559 :                     if (k > 0)
   17456                 :          73 :                         appendPQExpBufferStr(q, ", ");
   17457                 :         559 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   17458                 :             :                 }
   17459                 :         486 :                 appendPQExpBufferChar(q, ')');
   17460                 :             :             }
   17461                 :             : 
   17462         [ +  + ]:        5848 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17463                 :         604 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   17464                 :             : 
   17465         [ +  + ]:        5848 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   17466                 :          36 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   17467                 :             :         }
   17468                 :             : 
   17469   [ +  +  -  + ]:       12247 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   17470                 :        6046 :             nonemptyReloptions(tbinfo->toast_reloptions))
   17471                 :             :         {
   17472                 :         155 :             bool        addcomma = false;
   17473                 :             : 
   17474                 :         155 :             appendPQExpBufferStr(q, "\nWITH (");
   17475         [ +  - ]:         155 :             if (nonemptyReloptions(tbinfo->reloptions))
   17476                 :             :             {
   17477                 :         155 :                 addcomma = true;
   17478                 :         155 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   17479                 :             :             }
   17480         [ +  + ]:         155 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   17481                 :             :             {
   17482         [ +  - ]:           5 :                 if (addcomma)
   17483                 :           5 :                     appendPQExpBufferStr(q, ", ");
   17484                 :           5 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   17485                 :             :                                         fout);
   17486                 :             :             }
   17487                 :         155 :             appendPQExpBufferChar(q, ')');
   17488                 :             :         }
   17489                 :             : 
   17490                 :             :         /* Dump generic options if any */
   17491   [ +  +  +  + ]:        6201 :         if (ftoptions && ftoptions[0])
   17492                 :          34 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   17493                 :             : 
   17494                 :             :         /*
   17495                 :             :          * For materialized views, create the AS clause just like a view. At
   17496                 :             :          * this point, we always mark the view as not populated.
   17497                 :             :          */
   17498         [ +  + ]:        6201 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17499                 :             :         {
   17500                 :             :             PQExpBuffer result;
   17501                 :             : 
   17502                 :         353 :             result = createViewAsClause(fout, tbinfo);
   17503                 :         353 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   17504                 :             :                               result->data);
   17505                 :         353 :             destroyPQExpBuffer(result);
   17506                 :             :         }
   17507                 :             :         else
   17508                 :        5848 :             appendPQExpBufferStr(q, ";\n");
   17509                 :             : 
   17510                 :             :         /* Materialized views can depend on extensions */
   17511         [ +  + ]:        6201 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   17512                 :         353 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   17513                 :             :                                         "pg_catalog.pg_class",
   17514                 :             :                                         "MATERIALIZED VIEW",
   17515                 :             :                                         qualrelname);
   17516                 :             : 
   17517                 :             :         /*
   17518                 :             :          * in binary upgrade mode, update the catalog with any missing values
   17519                 :             :          * that might be present.
   17520                 :             :          */
   17521         [ +  + ]:        6201 :         if (dopt->binary_upgrade)
   17522                 :             :         {
   17523         [ +  + ]:        4221 :             for (j = 0; j < tbinfo->numatts; j++)
   17524                 :             :             {
   17525         [ +  + ]:        3340 :                 if (tbinfo->attmissingval[j][0] != '\0')
   17526                 :             :                 {
   17527                 :           4 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   17528                 :           4 :                     appendPQExpBufferStr(q,
   17529                 :             :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   17530                 :           4 :                     appendStringLiteralAH(q, qualrelname, fout);
   17531                 :           4 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   17532                 :           4 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17533                 :           4 :                     appendPQExpBufferChar(q, ',');
   17534                 :           4 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   17535                 :           4 :                     appendPQExpBufferStr(q, ");\n\n");
   17536                 :             :                 }
   17537                 :             :             }
   17538                 :             :         }
   17539                 :             : 
   17540                 :             :         /*
   17541                 :             :          * To create binary-compatible heap files, we have to ensure the same
   17542                 :             :          * physical column order, including dropped columns, as in the
   17543                 :             :          * original.  Therefore, we create dropped columns above and drop them
   17544                 :             :          * here, also updating their attlen/attalign values so that the
   17545                 :             :          * dropped column can be skipped properly.  (We do not bother with
   17546                 :             :          * restoring the original attbyval setting.)  Also, inheritance
   17547                 :             :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   17548                 :             :          * using an INHERITS clause --- the latter would possibly mess up the
   17549                 :             :          * column order.  That also means we have to take care about setting
   17550                 :             :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   17551                 :             :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   17552                 :             :          *
   17553                 :             :          * We process foreign and partitioned tables here, even though they
   17554                 :             :          * lack heap storage, because they can participate in inheritance
   17555                 :             :          * relationships and we want this stuff to be consistent across the
   17556                 :             :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   17557                 :             :          * and matviews, even though they have storage, because we don't
   17558                 :             :          * support altering or dropping columns in them, nor can they be part
   17559                 :             :          * of inheritance trees.
   17560                 :             :          */
   17561         [ +  + ]:        6201 :         if (dopt->binary_upgrade &&
   17562         [ +  + ]:         881 :             (tbinfo->relkind == RELKIND_RELATION ||
   17563         [ +  + ]:         115 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   17564         [ +  + ]:         114 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   17565                 :             :         {
   17566                 :             :             bool        firstitem;
   17567                 :             :             bool        firstitem_extra;
   17568                 :             : 
   17569                 :             :             /*
   17570                 :             :              * Drop any dropped columns.  Merge the pg_attribute manipulations
   17571                 :             :              * into a single SQL command, so that we don't cause repeated
   17572                 :             :              * relcache flushes on the target table.  Otherwise we risk O(N^2)
   17573                 :             :              * relcache bloat while dropping N columns.
   17574                 :             :              */
   17575                 :         864 :             resetPQExpBuffer(extra);
   17576                 :         864 :             firstitem = true;
   17577         [ +  + ]:        4183 :             for (j = 0; j < tbinfo->numatts; j++)
   17578                 :             :             {
   17579         [ +  + ]:        3319 :                 if (tbinfo->attisdropped[j])
   17580                 :             :                 {
   17581         [ +  + ]:          85 :                     if (firstitem)
   17582                 :             :                     {
   17583                 :          39 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   17584                 :             :                                              "UPDATE pg_catalog.pg_attribute\n"
   17585                 :             :                                              "SET attlen = v.dlen, "
   17586                 :             :                                              "attalign = v.dalign, "
   17587                 :             :                                              "attbyval = false\n"
   17588                 :             :                                              "FROM (VALUES ");
   17589                 :          39 :                         firstitem = false;
   17590                 :             :                     }
   17591                 :             :                     else
   17592                 :          46 :                         appendPQExpBufferStr(q, ",\n             ");
   17593                 :          85 :                     appendPQExpBufferChar(q, '(');
   17594                 :          85 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17595                 :          85 :                     appendPQExpBuffer(q, ", %d, '%c')",
   17596                 :          85 :                                       tbinfo->attlen[j],
   17597                 :          85 :                                       tbinfo->attalign[j]);
   17598                 :             :                     /* The ALTER ... DROP COLUMN commands must come after */
   17599                 :          85 :                     appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   17600                 :             :                                       foreign, qualrelname);
   17601                 :          85 :                     appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   17602                 :          85 :                                       fmtId(tbinfo->attnames[j]));
   17603                 :             :                 }
   17604                 :             :             }
   17605         [ +  + ]:         864 :             if (!firstitem)
   17606                 :             :             {
   17607                 :          39 :                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   17608                 :             :                                      "WHERE attrelid = ");
   17609                 :          39 :                 appendStringLiteralAH(q, qualrelname, fout);
   17610                 :          39 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17611                 :             :                                      "  AND attname = v.dname;\n");
   17612                 :             :                 /* Now we can issue the actual DROP COLUMN commands */
   17613                 :          39 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17614                 :             :             }
   17615                 :             : 
   17616                 :             :             /*
   17617                 :             :              * Fix up inherited columns.  As above, do the pg_attribute
   17618                 :             :              * manipulations in a single SQL command.
   17619                 :             :              */
   17620                 :         864 :             firstitem = true;
   17621         [ +  + ]:        4183 :             for (j = 0; j < tbinfo->numatts; j++)
   17622                 :             :             {
   17623         [ +  + ]:        3319 :                 if (!tbinfo->attisdropped[j] &&
   17624         [ +  + ]:        3234 :                     !tbinfo->attislocal[j])
   17625                 :             :                 {
   17626         [ +  + ]:         650 :                     if (firstitem)
   17627                 :             :                     {
   17628                 :         282 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   17629                 :         282 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   17630                 :             :                                              "SET attislocal = false\n"
   17631                 :             :                                              "WHERE attrelid = ");
   17632                 :         282 :                         appendStringLiteralAH(q, qualrelname, fout);
   17633                 :         282 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   17634                 :             :                                              "  AND attname IN (");
   17635                 :         282 :                         firstitem = false;
   17636                 :             :                     }
   17637                 :             :                     else
   17638                 :         368 :                         appendPQExpBufferStr(q, ", ");
   17639                 :         650 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   17640                 :             :                 }
   17641                 :             :             }
   17642         [ +  + ]:         864 :             if (!firstitem)
   17643                 :         282 :                 appendPQExpBufferStr(q, ");\n");
   17644                 :             : 
   17645                 :             :             /*
   17646                 :             :              * Fix up not-null constraints that come from inheritance.  As
   17647                 :             :              * above, do the pg_constraint manipulations in a single SQL
   17648                 :             :              * command.  (Actually, two in special cases, if we're doing an
   17649                 :             :              * upgrade from < 18).
   17650                 :             :              */
   17651                 :         864 :             firstitem = true;
   17652                 :         864 :             firstitem_extra = true;
   17653                 :         864 :             resetPQExpBuffer(extra);
   17654         [ +  + ]:        4183 :             for (j = 0; j < tbinfo->numatts; j++)
   17655                 :             :             {
   17656                 :             :                 /*
   17657                 :             :                  * If a not-null constraint comes from inheritance, reset
   17658                 :             :                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   17659                 :             :                  * below.  Special hack: in versions < 18, columns with no
   17660                 :             :                  * local definition need their constraint to be matched by
   17661                 :             :                  * column number in conkeys instead of by constraint name,
   17662                 :             :                  * because the latter is not available.  (We distinguish the
   17663                 :             :                  * case because the constraint name is the empty string.)
   17664                 :             :                  */
   17665         [ +  + ]:        3319 :                 if (tbinfo->notnull_constrs[j] != NULL &&
   17666         [ +  + ]:         333 :                     !tbinfo->notnull_islocal[j])
   17667                 :             :                 {
   17668         [ +  + ]:          94 :                     if (tbinfo->notnull_constrs[j][0] != '\0')
   17669                 :             :                     {
   17670         [ +  + ]:          81 :                         if (firstitem)
   17671                 :             :                         {
   17672                 :          69 :                             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   17673                 :             :                                                  "SET conislocal = false\n"
   17674                 :             :                                                  "WHERE contype = 'n' AND conrelid = ");
   17675                 :          69 :                             appendStringLiteralAH(q, qualrelname, fout);
   17676                 :          69 :                             appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   17677                 :             :                                                  "conname IN (");
   17678                 :          69 :                             firstitem = false;
   17679                 :             :                         }
   17680                 :             :                         else
   17681                 :          12 :                             appendPQExpBufferStr(q, ", ");
   17682                 :          81 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   17683                 :             :                     }
   17684                 :             :                     else
   17685                 :             :                     {
   17686         [ +  - ]:          13 :                         if (firstitem_extra)
   17687                 :             :                         {
   17688                 :          13 :                             appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17689                 :             :                                                  "SET conislocal = false\n"
   17690                 :             :                                                  "WHERE contype = 'n' AND conrelid = ");
   17691                 :          13 :                             appendStringLiteralAH(extra, qualrelname, fout);
   17692                 :          13 :                             appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   17693                 :             :                                                  "conkey IN (");
   17694                 :          13 :                             firstitem_extra = false;
   17695                 :             :                         }
   17696                 :             :                         else
   17697                 :           0 :                             appendPQExpBufferStr(extra, ", ");
   17698                 :          13 :                         appendPQExpBuffer(extra, "'{%d}'", j + 1);
   17699                 :             :                     }
   17700                 :             :                 }
   17701                 :             :             }
   17702         [ +  + ]:         864 :             if (!firstitem)
   17703                 :          69 :                 appendPQExpBufferStr(q, ");\n");
   17704         [ +  + ]:         864 :             if (!firstitem_extra)
   17705                 :          13 :                 appendPQExpBufferStr(extra, ");\n");
   17706                 :             : 
   17707         [ +  + ]:         864 :             if (extra->len > 0)
   17708                 :          13 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17709                 :             : 
   17710                 :             :             /*
   17711                 :             :              * Add inherited CHECK constraints, if any.
   17712                 :             :              *
   17713                 :             :              * For partitions, they were already dumped, and conislocal
   17714                 :             :              * doesn't need fixing.
   17715                 :             :              *
   17716                 :             :              * As above, issue only one direct manipulation of pg_constraint.
   17717                 :             :              * Although it is tempting to merge the ALTER ADD CONSTRAINT
   17718                 :             :              * commands into one as well, refrain for now due to concern about
   17719                 :             :              * possible backend memory bloat if there are many such
   17720                 :             :              * constraints.
   17721                 :             :              */
   17722                 :         864 :             resetPQExpBuffer(extra);
   17723                 :         864 :             firstitem = true;
   17724         [ +  + ]:         926 :             for (k = 0; k < tbinfo->ncheck; k++)
   17725                 :             :             {
   17726                 :          62 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   17727                 :             : 
   17728   [ +  +  +  +  :          62 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
                   +  + ]
   17729                 :          60 :                     continue;
   17730                 :             : 
   17731         [ +  - ]:           2 :                 if (firstitem)
   17732                 :           2 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   17733                 :           2 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   17734                 :             :                                   foreign, qualrelname,
   17735                 :           2 :                                   fmtId(constr->dobj.name),
   17736                 :             :                                   constr->condef);
   17737                 :             :                 /* Update pg_constraint after all the ALTER TABLEs */
   17738         [ +  - ]:           2 :                 if (firstitem)
   17739                 :             :                 {
   17740                 :           2 :                     appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   17741                 :             :                                          "SET conislocal = false\n"
   17742                 :             :                                          "WHERE contype = 'c' AND conrelid = ");
   17743                 :           2 :                     appendStringLiteralAH(extra, qualrelname, fout);
   17744                 :           2 :                     appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   17745                 :           2 :                     appendPQExpBufferStr(extra, "  AND conname IN (");
   17746                 :           2 :                     firstitem = false;
   17747                 :             :                 }
   17748                 :             :                 else
   17749                 :           0 :                     appendPQExpBufferStr(extra, ", ");
   17750                 :           2 :                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   17751                 :             :             }
   17752         [ +  + ]:         864 :             if (!firstitem)
   17753                 :             :             {
   17754                 :           2 :                 appendPQExpBufferStr(extra, ");\n");
   17755                 :           2 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   17756                 :             :             }
   17757                 :             : 
   17758   [ +  +  +  + ]:         864 :             if (numParents > 0 && !tbinfo->ispartition)
   17759                 :             :             {
   17760                 :          69 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   17761         [ +  + ]:         149 :                 for (k = 0; k < numParents; k++)
   17762                 :             :                 {
   17763                 :          80 :                     TableInfo  *parentRel = parents[k];
   17764                 :             : 
   17765                 :          80 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   17766                 :             :                                       qualrelname,
   17767                 :          80 :                                       fmtQualifiedDumpable(parentRel));
   17768                 :             :                 }
   17769                 :             :             }
   17770                 :             : 
   17771         [ +  + ]:         864 :             if (OidIsValid(tbinfo->reloftype))
   17772                 :             :             {
   17773                 :           6 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   17774                 :           6 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   17775                 :             :                                   qualrelname,
   17776                 :           6 :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   17777                 :             :                                                        zeroIsError));
   17778                 :             :             }
   17779                 :             :         }
   17780                 :             : 
   17781                 :             :         /*
   17782                 :             :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   17783                 :             :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   17784                 :             :          * TOAST tables semi-independently, here we see them only as children
   17785                 :             :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   17786                 :             :          * child toast table is handled below.)
   17787                 :             :          */
   17788         [ +  + ]:        6201 :         if (dopt->binary_upgrade &&
   17789         [ +  + ]:         881 :             (tbinfo->relkind == RELKIND_RELATION ||
   17790         [ +  + ]:         115 :              tbinfo->relkind == RELKIND_MATVIEW))
   17791                 :             :         {
   17792                 :         783 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   17793                 :         783 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17794                 :             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17795                 :             :                               "WHERE oid = ",
   17796                 :         783 :                               tbinfo->frozenxid, tbinfo->minmxid);
   17797                 :         783 :             appendStringLiteralAH(q, qualrelname, fout);
   17798                 :         783 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17799                 :             : 
   17800         [ +  + ]:         783 :             if (tbinfo->toast_oid)
   17801                 :             :             {
   17802                 :             :                 /*
   17803                 :             :                  * The toast table will have the same OID at restore, so we
   17804                 :             :                  * can safely target it by OID.
   17805                 :             :                  */
   17806                 :         296 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   17807                 :         296 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17808                 :             :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17809                 :             :                                   "WHERE oid = '%u';\n",
   17810                 :         296 :                                   tbinfo->toast_frozenxid,
   17811                 :         296 :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   17812                 :             :             }
   17813                 :             :         }
   17814                 :             : 
   17815                 :             :         /*
   17816                 :             :          * In binary_upgrade mode, restore matviews' populated status by
   17817                 :             :          * poking pg_class directly.  This is pretty ugly, but we can't use
   17818                 :             :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   17819                 :             :          * matview is not populated even though this matview is; in any case,
   17820                 :             :          * we want to transfer the matview's heap storage, not run REFRESH.
   17821                 :             :          */
   17822   [ +  +  +  + ]:        6201 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   17823         [ +  + ]:          17 :             tbinfo->relispopulated)
   17824                 :             :         {
   17825                 :          15 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   17826                 :          15 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   17827                 :             :                                  "SET relispopulated = 't'\n"
   17828                 :             :                                  "WHERE oid = ");
   17829                 :          15 :             appendStringLiteralAH(q, qualrelname, fout);
   17830                 :          15 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17831                 :             :         }
   17832                 :             : 
   17833                 :             :         /*
   17834                 :             :          * Dump additional per-column properties that we can't handle in the
   17835                 :             :          * main CREATE TABLE command.
   17836                 :             :          */
   17837         [ +  + ]:       27876 :         for (j = 0; j < tbinfo->numatts; j++)
   17838                 :             :         {
   17839                 :             :             /* None of this applies to dropped columns */
   17840         [ +  + ]:       21675 :             if (tbinfo->attisdropped[j])
   17841                 :         454 :                 continue;
   17842                 :             : 
   17843                 :             :             /*
   17844                 :             :              * Dump per-column statistics information. We only issue an ALTER
   17845                 :             :              * TABLE statement if the attstattarget entry for this column is
   17846                 :             :              * not the default value.
   17847                 :             :              */
   17848         [ +  + ]:       21221 :             if (tbinfo->attstattarget[j] >= 0)
   17849                 :          34 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   17850                 :             :                                   foreign, qualrelname,
   17851                 :          34 :                                   fmtId(tbinfo->attnames[j]),
   17852                 :          34 :                                   tbinfo->attstattarget[j]);
   17853                 :             : 
   17854                 :             :             /*
   17855                 :             :              * Dump per-column storage information.  The statement is only
   17856                 :             :              * dumped if the storage has been changed from the type's default.
   17857                 :             :              */
   17858         [ +  + ]:       21221 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   17859                 :             :             {
   17860   [ +  +  -  +  :          83 :                 switch (tbinfo->attstorage[j])
                      - ]
   17861                 :             :                 {
   17862                 :          10 :                     case TYPSTORAGE_PLAIN:
   17863                 :          10 :                         storage = "PLAIN";
   17864                 :          10 :                         break;
   17865                 :          39 :                     case TYPSTORAGE_EXTERNAL:
   17866                 :          39 :                         storage = "EXTERNAL";
   17867                 :          39 :                         break;
   17868                 :           0 :                     case TYPSTORAGE_EXTENDED:
   17869                 :           0 :                         storage = "EXTENDED";
   17870                 :           0 :                         break;
   17871                 :          34 :                     case TYPSTORAGE_MAIN:
   17872                 :          34 :                         storage = "MAIN";
   17873                 :          34 :                         break;
   17874                 :           0 :                     default:
   17875                 :           0 :                         storage = NULL;
   17876                 :             :                 }
   17877                 :             : 
   17878                 :             :                 /*
   17879                 :             :                  * Only dump the statement if it's a storage type we recognize
   17880                 :             :                  */
   17881         [ +  - ]:          83 :                 if (storage != NULL)
   17882                 :          83 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   17883                 :             :                                       foreign, qualrelname,
   17884                 :          83 :                                       fmtId(tbinfo->attnames[j]),
   17885                 :             :                                       storage);
   17886                 :             :             }
   17887                 :             : 
   17888                 :             :             /*
   17889                 :             :              * Dump per-column compression, if it's been set.
   17890                 :             :              */
   17891         [ +  + ]:       21221 :             if (!dopt->no_toast_compression)
   17892                 :             :             {
   17893                 :             :                 const char *cmname;
   17894                 :             : 
   17895      [ +  +  + ]:       21121 :                 switch (tbinfo->attcompression[j])
   17896                 :             :                 {
   17897                 :          73 :                     case 'p':
   17898                 :          73 :                         cmname = "pglz";
   17899                 :          73 :                         break;
   17900                 :          39 :                     case 'l':
   17901                 :          39 :                         cmname = "lz4";
   17902                 :          39 :                         break;
   17903                 :       21009 :                     default:
   17904                 :       21009 :                         cmname = NULL;
   17905                 :       21009 :                         break;
   17906                 :             :                 }
   17907                 :             : 
   17908         [ +  + ]:       21121 :                 if (cmname != NULL)
   17909                 :         112 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   17910                 :             :                                       foreign, qualrelname,
   17911                 :         112 :                                       fmtId(tbinfo->attnames[j]),
   17912                 :             :                                       cmname);
   17913                 :             :             }
   17914                 :             : 
   17915                 :             :             /*
   17916                 :             :              * Dump per-column attributes.
   17917                 :             :              */
   17918         [ +  + ]:       21221 :             if (tbinfo->attoptions[j][0] != '\0')
   17919                 :          34 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   17920                 :             :                                   foreign, qualrelname,
   17921                 :          34 :                                   fmtId(tbinfo->attnames[j]),
   17922                 :          34 :                                   tbinfo->attoptions[j]);
   17923                 :             : 
   17924                 :             :             /*
   17925                 :             :              * Dump per-column fdw options.
   17926                 :             :              */
   17927         [ +  + ]:       21221 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   17928         [ +  + ]:          36 :                 tbinfo->attfdwoptions[j][0] != '\0')
   17929                 :          34 :                 appendPQExpBuffer(q,
   17930                 :             :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   17931                 :             :                                   "    %s\n"
   17932                 :             :                                   ");\n",
   17933                 :             :                                   qualrelname,
   17934                 :          34 :                                   fmtId(tbinfo->attnames[j]),
   17935                 :          34 :                                   tbinfo->attfdwoptions[j]);
   17936                 :             :         }                       /* end loop over columns */
   17937                 :             : 
   17938                 :        6201 :         pg_free(partkeydef);
   17939                 :        6201 :         pg_free(ftoptions);
   17940                 :        6201 :         pg_free(srvname);
   17941                 :             :     }
   17942                 :             : 
   17943                 :             :     /*
   17944                 :             :      * dump properties we only have ALTER TABLE syntax for
   17945                 :             :      */
   17946         [ +  + ]:        6878 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   17947         [ +  + ]:        1670 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   17948         [ +  + ]:        1066 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   17949         [ +  + ]:        6165 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   17950                 :             :     {
   17951         [ +  - ]:         207 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   17952                 :             :         {
   17953                 :             :             /* nothing to do, will be set when the index is dumped */
   17954                 :             :         }
   17955         [ +  - ]:         207 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   17956                 :             :         {
   17957                 :         207 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   17958                 :             :                               qualrelname);
   17959                 :             :         }
   17960         [ #  # ]:           0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   17961                 :             :         {
   17962                 :           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   17963                 :             :                               qualrelname);
   17964                 :             :         }
   17965                 :             :     }
   17966                 :             : 
   17967         [ +  + ]:        6878 :     if (tbinfo->forcerowsec)
   17968                 :          10 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   17969                 :             :                           qualrelname);
   17970                 :             : 
   17971                 :        6878 :     appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   17972                 :             : 
   17973         [ +  + ]:        6878 :     if (dopt->binary_upgrade)
   17974                 :         952 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   17975                 :             :                                         reltypename, qrelname,
   17976                 :         952 :                                         tbinfo->dobj.namespace->dobj.name);
   17977                 :             : 
   17978         [ +  - ]:        6878 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17979                 :             :     {
   17980                 :        6878 :         char       *tablespace = NULL;
   17981                 :        6878 :         char       *tableam = NULL;
   17982                 :             : 
   17983                 :             :         /*
   17984                 :             :          * _selectTablespace() relies on tablespace-enabled objects in the
   17985                 :             :          * default tablespace to have a tablespace of "" (empty string) versus
   17986                 :             :          * non-tablespace-enabled objects to have a tablespace of NULL.
   17987                 :             :          * getTables() sets tbinfo->reltablespace to "" for the default
   17988                 :             :          * tablespace (not NULL).
   17989                 :             :          */
   17990   [ +  +  +  -  :        6878 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
          +  -  +  -  +  
          +  +  +  -  +  
                   +  - ]
   17991                 :        6165 :             tablespace = tbinfo->reltablespace;
   17992                 :             : 
   17993   [ +  +  +  -  :        6878 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
                   +  + ]
   17994         [ +  + ]:        1317 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17995                 :        6165 :             tableam = tbinfo->amname;
   17996                 :             : 
   17997                 :        6878 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   17998         [ +  + ]:        6878 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17999                 :             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18000                 :             :                                   .tablespace = tablespace,
   18001                 :             :                                   .tableam = tableam,
   18002                 :             :                                   .relkind = tbinfo->relkind,
   18003                 :             :                                   .owner = tbinfo->rolname,
   18004                 :             :                                   .description = reltypename,
   18005                 :             :                                   .section = tbinfo->postponed_def ?
   18006                 :             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   18007                 :             :                                   .createStmt = q->data,
   18008                 :             :                                   .dropStmt = delq->data));
   18009                 :             :     }
   18010                 :             : 
   18011                 :             :     /* Dump Table Comments */
   18012         [ +  + ]:        6878 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18013                 :          78 :         dumpTableComment(fout, tbinfo, reltypename);
   18014                 :             : 
   18015                 :             :     /* Dump Table Security Labels */
   18016         [ -  + ]:        6878 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   18017                 :           0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   18018                 :             : 
   18019                 :             :     /*
   18020                 :             :      * Dump comments for not-null constraints that aren't to be dumped
   18021                 :             :      * separately (those are processed by collectComments/dumpComment).
   18022                 :             :      */
   18023   [ +  -  +  - ]:        6878 :     if (!fout->dopt->no_comments && dopt->dumpSchema &&
   18024         [ +  - ]:        6878 :         fout->remoteVersion >= 180000)
   18025                 :             :     {
   18026                 :        6878 :         PQExpBuffer comment = NULL;
   18027                 :        6878 :         PQExpBuffer tag = NULL;
   18028                 :             : 
   18029         [ +  + ]:       32259 :         for (j = 0; j < tbinfo->numatts; j++)
   18030                 :             :         {
   18031         [ +  + ]:       25381 :             if (tbinfo->notnull_constrs[j] != NULL &&
   18032         [ +  + ]:        2721 :                 tbinfo->notnull_comment[j] != NULL)
   18033                 :             :             {
   18034         [ +  - ]:          44 :                 if (comment == NULL)
   18035                 :             :                 {
   18036                 :          44 :                     comment = createPQExpBuffer();
   18037                 :          44 :                     tag = createPQExpBuffer();
   18038                 :             :                 }
   18039                 :             :                 else
   18040                 :             :                 {
   18041                 :           0 :                     resetPQExpBuffer(comment);
   18042                 :           0 :                     resetPQExpBuffer(tag);
   18043                 :             :                 }
   18044                 :             : 
   18045                 :          44 :                 appendPQExpBuffer(comment, "COMMENT ON CONSTRAINT %s ON %s IS ",
   18046                 :          44 :                                   fmtId(tbinfo->notnull_constrs[j]), qualrelname);
   18047                 :          44 :                 appendStringLiteralAH(comment, tbinfo->notnull_comment[j], fout);
   18048                 :          44 :                 appendPQExpBufferStr(comment, ";\n");
   18049                 :             : 
   18050                 :          44 :                 appendPQExpBuffer(tag, "CONSTRAINT %s ON %s",
   18051                 :          44 :                                   fmtId(tbinfo->notnull_constrs[j]), qrelname);
   18052                 :             : 
   18053                 :          44 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18054                 :          44 :                              ARCHIVE_OPTS(.tag = tag->data,
   18055                 :             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18056                 :             :                                           .owner = tbinfo->rolname,
   18057                 :             :                                           .description = "COMMENT",
   18058                 :             :                                           .section = SECTION_NONE,
   18059                 :             :                                           .createStmt = comment->data,
   18060                 :             :                                           .deps = &(tbinfo->dobj.dumpId),
   18061                 :             :                                           .nDeps = 1));
   18062                 :             :             }
   18063                 :             :         }
   18064                 :             : 
   18065                 :        6878 :         destroyPQExpBuffer(comment);
   18066                 :        6878 :         destroyPQExpBuffer(tag);
   18067                 :             :     }
   18068                 :             : 
   18069                 :             :     /* Dump comments on inlined table constraints */
   18070         [ +  + ]:        7471 :     for (j = 0; j < tbinfo->ncheck; j++)
   18071                 :             :     {
   18072                 :         593 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   18073                 :             : 
   18074   [ +  +  +  + ]:         593 :         if (constr->separate || !constr->conislocal)
   18075                 :         254 :             continue;
   18076                 :             : 
   18077         [ +  + ]:         339 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   18078                 :          39 :             dumpTableConstraintComment(fout, constr);
   18079                 :             :     }
   18080                 :             : 
   18081                 :        6878 :     destroyPQExpBuffer(q);
   18082                 :        6878 :     destroyPQExpBuffer(delq);
   18083                 :        6878 :     destroyPQExpBuffer(extra);
   18084                 :        6878 :     pg_free(qrelname);
   18085                 :        6878 :     pg_free(qualrelname);
   18086                 :        6878 : }
   18087                 :             : 
   18088                 :             : /*
   18089                 :             :  * dumpTableAttach
   18090                 :             :  *    write to fout the commands to attach a child partition
   18091                 :             :  *
   18092                 :             :  * Child partitions are always made by creating them separately
   18093                 :             :  * and then using ATTACH PARTITION, rather than using
   18094                 :             :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   18095                 :             :  * any possible discrepancy in column layout, to allow assigning the
   18096                 :             :  * correct tablespace if different, and so that it's possible to restore
   18097                 :             :  * a partition without restoring its parent.  (You'll get an error from
   18098                 :             :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   18099                 :             :  * using "pg_restore -L" if you prefer.)  The last point motivates
   18100                 :             :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   18101                 :             :  * rather than emitting it within the child partition's ArchiveEntry.
   18102                 :             :  */
   18103                 :             : static void
   18104                 :        1452 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   18105                 :             : {
   18106                 :        1452 :     DumpOptions *dopt = fout->dopt;
   18107                 :             :     PQExpBuffer q;
   18108                 :             :     PGresult   *res;
   18109                 :             :     char       *partbound;
   18110                 :             : 
   18111                 :             :     /* Do nothing if not dumping schema */
   18112         [ +  + ]:        1452 :     if (!dopt->dumpSchema)
   18113                 :          57 :         return;
   18114                 :             : 
   18115                 :        1395 :     q = createPQExpBuffer();
   18116                 :             : 
   18117         [ +  + ]:        1395 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   18118                 :             :     {
   18119                 :             :         /* Set up query for partbound details */
   18120                 :          45 :         appendPQExpBufferStr(q,
   18121                 :             :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   18122                 :             : 
   18123                 :          45 :         appendPQExpBufferStr(q,
   18124                 :             :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   18125                 :             :                              "FROM pg_class c "
   18126                 :             :                              "WHERE c.oid = $1");
   18127                 :             : 
   18128                 :          45 :         ExecuteSqlStatement(fout, q->data);
   18129                 :             : 
   18130                 :          45 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   18131                 :             :     }
   18132                 :             : 
   18133                 :        1395 :     printfPQExpBuffer(q,
   18134                 :             :                       "EXECUTE dumpTableAttach('%u')",
   18135                 :        1395 :                       attachinfo->partitionTbl->dobj.catId.oid);
   18136                 :             : 
   18137                 :        1395 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   18138                 :        1395 :     partbound = PQgetvalue(res, 0, 0);
   18139                 :             : 
   18140                 :             :     /* Perform ALTER TABLE on the parent */
   18141                 :        1395 :     printfPQExpBuffer(q,
   18142                 :             :                       "ALTER TABLE ONLY %s ",
   18143                 :        1395 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   18144                 :        1395 :     appendPQExpBuffer(q,
   18145                 :             :                       "ATTACH PARTITION %s %s;\n",
   18146                 :        1395 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   18147                 :             :                       partbound);
   18148                 :             : 
   18149                 :             :     /*
   18150                 :             :      * There is no point in creating a drop query as the drop is done by table
   18151                 :             :      * drop.  (If you think to change this, see also _printTocEntry().)
   18152                 :             :      * Although this object doesn't really have ownership as such, set the
   18153                 :             :      * owner field anyway to ensure that the command is run by the correct
   18154                 :             :      * role at restore time.
   18155                 :             :      */
   18156                 :        1395 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18157                 :        1395 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18158                 :             :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   18159                 :             :                               .owner = attachinfo->partitionTbl->rolname,
   18160                 :             :                               .description = "TABLE ATTACH",
   18161                 :             :                               .section = SECTION_PRE_DATA,
   18162                 :             :                               .createStmt = q->data));
   18163                 :             : 
   18164                 :        1395 :     PQclear(res);
   18165                 :        1395 :     destroyPQExpBuffer(q);
   18166                 :             : }
   18167                 :             : 
   18168                 :             : /*
   18169                 :             :  * dumpAttrDef --- dump an attribute's default-value declaration
   18170                 :             :  */
   18171                 :             : static void
   18172                 :        1121 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   18173                 :             : {
   18174                 :        1121 :     DumpOptions *dopt = fout->dopt;
   18175                 :        1121 :     TableInfo  *tbinfo = adinfo->adtable;
   18176                 :        1121 :     int         adnum = adinfo->adnum;
   18177                 :             :     PQExpBuffer q;
   18178                 :             :     PQExpBuffer delq;
   18179                 :             :     char       *qualrelname;
   18180                 :             :     char       *tag;
   18181                 :             :     char       *foreign;
   18182                 :             : 
   18183                 :             :     /* Do nothing if not dumping schema */
   18184         [ -  + ]:        1121 :     if (!dopt->dumpSchema)
   18185                 :           0 :         return;
   18186                 :             : 
   18187                 :             :     /* Skip if not "separate"; it was dumped in the table's definition */
   18188         [ +  + ]:        1121 :     if (!adinfo->separate)
   18189                 :         949 :         return;
   18190                 :             : 
   18191                 :         172 :     q = createPQExpBuffer();
   18192                 :         172 :     delq = createPQExpBuffer();
   18193                 :             : 
   18194                 :         172 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   18195                 :             : 
   18196         [ -  + ]:         172 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18197                 :             : 
   18198                 :         172 :     appendPQExpBuffer(q,
   18199                 :             :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   18200                 :         172 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   18201                 :         172 :                       adinfo->adef_expr);
   18202                 :             : 
   18203                 :         172 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   18204                 :             :                       foreign, qualrelname,
   18205                 :         172 :                       fmtId(tbinfo->attnames[adnum - 1]));
   18206                 :             : 
   18207                 :         172 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   18208                 :             : 
   18209         [ +  - ]:         172 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18210                 :         172 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   18211                 :         172 :                      ARCHIVE_OPTS(.tag = tag,
   18212                 :             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18213                 :             :                                   .owner = tbinfo->rolname,
   18214                 :             :                                   .description = "DEFAULT",
   18215                 :             :                                   .section = SECTION_PRE_DATA,
   18216                 :             :                                   .createStmt = q->data,
   18217                 :             :                                   .dropStmt = delq->data));
   18218                 :             : 
   18219                 :         172 :     pfree(tag);
   18220                 :         172 :     destroyPQExpBuffer(q);
   18221                 :         172 :     destroyPQExpBuffer(delq);
   18222                 :         172 :     pg_free(qualrelname);
   18223                 :             : }
   18224                 :             : 
   18225                 :             : /*
   18226                 :             :  * getAttrName: extract the correct name for an attribute
   18227                 :             :  *
   18228                 :             :  * The array tblInfo->attnames[] only provides names of user attributes;
   18229                 :             :  * if a system attribute number is supplied, we have to fake it.
   18230                 :             :  * We also do a little bit of bounds checking for safety's sake.
   18231                 :             :  */
   18232                 :             : static const char *
   18233                 :        2288 : getAttrName(int attrnum, const TableInfo *tblInfo)
   18234                 :             : {
   18235   [ +  -  +  - ]:        2288 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   18236                 :        2288 :         return tblInfo->attnames[attrnum - 1];
   18237   [ #  #  #  #  :           0 :     switch (attrnum)
                #  #  # ]
   18238                 :             :     {
   18239                 :           0 :         case SelfItemPointerAttributeNumber:
   18240                 :           0 :             return "ctid";
   18241                 :           0 :         case MinTransactionIdAttributeNumber:
   18242                 :           0 :             return "xmin";
   18243                 :           0 :         case MinCommandIdAttributeNumber:
   18244                 :           0 :             return "cmin";
   18245                 :           0 :         case MaxTransactionIdAttributeNumber:
   18246                 :           0 :             return "xmax";
   18247                 :           0 :         case MaxCommandIdAttributeNumber:
   18248                 :           0 :             return "cmax";
   18249                 :           0 :         case TableOidAttributeNumber:
   18250                 :           0 :             return "tableoid";
   18251                 :             :     }
   18252                 :           0 :     pg_fatal("invalid column number %d for table \"%s\"",
   18253                 :             :              attrnum, tblInfo->dobj.name);
   18254                 :             :     return NULL;                /* keep compiler quiet */
   18255                 :             : }
   18256                 :             : 
   18257                 :             : /*
   18258                 :             :  * dumpIndex
   18259                 :             :  *    write out to fout a user-defined index
   18260                 :             :  */
   18261                 :             : static void
   18262                 :        2837 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   18263                 :             : {
   18264                 :        2837 :     DumpOptions *dopt = fout->dopt;
   18265                 :        2837 :     TableInfo  *tbinfo = indxinfo->indextable;
   18266                 :        2837 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   18267                 :             :     PQExpBuffer q;
   18268                 :             :     PQExpBuffer delq;
   18269                 :             :     char       *qindxname;
   18270                 :             :     char       *qqindxname;
   18271                 :             : 
   18272                 :             :     /* Do nothing if not dumping schema */
   18273         [ +  + ]:        2837 :     if (!dopt->dumpSchema)
   18274                 :         128 :         return;
   18275                 :             : 
   18276                 :        2709 :     q = createPQExpBuffer();
   18277                 :        2709 :     delq = createPQExpBuffer();
   18278                 :             : 
   18279                 :        2709 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   18280                 :        2709 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   18281                 :             : 
   18282                 :             :     /*
   18283                 :             :      * If there's an associated constraint, don't dump the index per se, but
   18284                 :             :      * do dump any comment for it.  (This is safe because dependency ordering
   18285                 :             :      * will have ensured the constraint is emitted first.)  Note that the
   18286                 :             :      * emitted comment has to be shown as depending on the constraint, not the
   18287                 :             :      * index, in such cases.
   18288                 :             :      */
   18289         [ +  + ]:        2709 :     if (!is_constraint)
   18290                 :             :     {
   18291                 :        1082 :         char       *indstatcols = indxinfo->indstatcols;
   18292                 :        1082 :         char       *indstatvals = indxinfo->indstatvals;
   18293                 :        1082 :         char      **indstatcolsarray = NULL;
   18294                 :        1082 :         char      **indstatvalsarray = NULL;
   18295                 :        1082 :         int         nstatcols = 0;
   18296                 :        1082 :         int         nstatvals = 0;
   18297                 :             : 
   18298         [ +  + ]:        1082 :         if (dopt->binary_upgrade)
   18299                 :         162 :             binary_upgrade_set_pg_class_oids(fout, q,
   18300                 :         162 :                                              indxinfo->dobj.catId.oid);
   18301                 :             : 
   18302                 :             :         /* Plain secondary index */
   18303                 :        1082 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   18304                 :             : 
   18305                 :             :         /*
   18306                 :             :          * Append ALTER TABLE commands as needed to set properties that we
   18307                 :             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18308                 :             :          * similar code in dumpConstraint!
   18309                 :             :          */
   18310                 :             : 
   18311                 :             :         /* If the index is clustered, we need to record that. */
   18312         [ +  + ]:        1082 :         if (indxinfo->indisclustered)
   18313                 :             :         {
   18314                 :           5 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18315                 :           5 :                               fmtQualifiedDumpable(tbinfo));
   18316                 :             :             /* index name is not qualified in this syntax */
   18317                 :           5 :             appendPQExpBuffer(q, " ON %s;\n",
   18318                 :             :                               qindxname);
   18319                 :             :         }
   18320                 :             : 
   18321                 :             :         /*
   18322                 :             :          * If the index has any statistics on some of its columns, generate
   18323                 :             :          * the associated ALTER INDEX queries.
   18324                 :             :          */
   18325   [ +  +  -  + ]:        1082 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   18326                 :             :         {
   18327                 :             :             int         j;
   18328                 :             : 
   18329         [ -  + ]:          34 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   18330                 :           0 :                 pg_fatal("could not parse index statistic columns");
   18331         [ -  + ]:          34 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   18332                 :           0 :                 pg_fatal("could not parse index statistic values");
   18333         [ -  + ]:          34 :             if (nstatcols != nstatvals)
   18334                 :           0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   18335                 :             : 
   18336         [ +  + ]:         102 :             for (j = 0; j < nstatcols; j++)
   18337                 :             :             {
   18338                 :          68 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   18339                 :             : 
   18340                 :             :                 /*
   18341                 :             :                  * Note that this is a column number, so no quotes should be
   18342                 :             :                  * used.
   18343                 :             :                  */
   18344                 :          68 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   18345                 :          68 :                                   indstatcolsarray[j]);
   18346                 :          68 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   18347                 :          68 :                                   indstatvalsarray[j]);
   18348                 :             :             }
   18349                 :             :         }
   18350                 :             : 
   18351                 :             :         /* Indexes can depend on extensions */
   18352                 :        1082 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18353                 :             :                                     "pg_catalog.pg_class",
   18354                 :             :                                     "INDEX", qqindxname);
   18355                 :             : 
   18356                 :             :         /* If the index defines identity, we need to record that. */
   18357         [ -  + ]:        1082 :         if (indxinfo->indisreplident)
   18358                 :             :         {
   18359                 :           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18360                 :           0 :                               fmtQualifiedDumpable(tbinfo));
   18361                 :             :             /* index name is not qualified in this syntax */
   18362                 :           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18363                 :             :                               qindxname);
   18364                 :             :         }
   18365                 :             : 
   18366                 :             :         /*
   18367                 :             :          * If this index is a member of a partitioned index, the backend will
   18368                 :             :          * not allow us to drop it separately, so don't try.  It will go away
   18369                 :             :          * automatically when we drop either the index's table or the
   18370                 :             :          * partitioned index.  (If, in a selective restore with --clean, we
   18371                 :             :          * drop neither of those, then this index will not be dropped either.
   18372                 :             :          * But that's fine, and even if you think it's not, the backend won't
   18373                 :             :          * let us do differently.)
   18374                 :             :          */
   18375         [ +  + ]:        1082 :         if (indxinfo->parentidx == 0)
   18376                 :         892 :             appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   18377                 :             : 
   18378         [ +  - ]:        1082 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18379                 :        1082 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   18380                 :        1082 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   18381                 :             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18382                 :             :                                       .tablespace = indxinfo->tablespace,
   18383                 :             :                                       .owner = tbinfo->rolname,
   18384                 :             :                                       .description = "INDEX",
   18385                 :             :                                       .section = SECTION_POST_DATA,
   18386                 :             :                                       .createStmt = q->data,
   18387                 :             :                                       .dropStmt = delq->data));
   18388                 :             : 
   18389                 :        1082 :         free(indstatcolsarray);
   18390                 :        1082 :         free(indstatvalsarray);
   18391                 :             :     }
   18392                 :             : 
   18393                 :             :     /* Dump Index Comments */
   18394         [ +  + ]:        2709 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18395         [ +  + ]:          15 :         dumpComment(fout, "INDEX", qindxname,
   18396                 :          15 :                     tbinfo->dobj.namespace->dobj.name,
   18397                 :             :                     tbinfo->rolname,
   18398                 :             :                     indxinfo->dobj.catId, 0,
   18399                 :             :                     is_constraint ? indxinfo->indexconstraint :
   18400                 :             :                     indxinfo->dobj.dumpId);
   18401                 :             : 
   18402                 :        2709 :     destroyPQExpBuffer(q);
   18403                 :        2709 :     destroyPQExpBuffer(delq);
   18404                 :        2709 :     pg_free(qindxname);
   18405                 :        2709 :     pg_free(qqindxname);
   18406                 :             : }
   18407                 :             : 
   18408                 :             : /*
   18409                 :             :  * dumpIndexAttach
   18410                 :             :  *    write out to fout a partitioned-index attachment clause
   18411                 :             :  */
   18412                 :             : static void
   18413                 :         610 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   18414                 :             : {
   18415                 :             :     /* Do nothing if not dumping schema */
   18416         [ +  + ]:         610 :     if (!fout->dopt->dumpSchema)
   18417                 :          48 :         return;
   18418                 :             : 
   18419         [ +  - ]:         562 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18420                 :             :     {
   18421                 :         562 :         PQExpBuffer q = createPQExpBuffer();
   18422                 :             : 
   18423                 :         562 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   18424                 :         562 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   18425                 :         562 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   18426                 :         562 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   18427                 :             : 
   18428                 :             :         /*
   18429                 :             :          * There is no need for a dropStmt since the drop is done implicitly
   18430                 :             :          * when we drop either the index's table or the partitioned index.
   18431                 :             :          * Moreover, since there's no ALTER INDEX DETACH PARTITION command,
   18432                 :             :          * there's no way to do it anyway.  (If you think to change this,
   18433                 :             :          * consider also what to do with --if-exists.)
   18434                 :             :          *
   18435                 :             :          * Although this object doesn't really have ownership as such, set the
   18436                 :             :          * owner field anyway to ensure that the command is run by the correct
   18437                 :             :          * role at restore time.
   18438                 :             :          */
   18439                 :         562 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   18440                 :         562 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   18441                 :             :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   18442                 :             :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   18443                 :             :                                   .description = "INDEX ATTACH",
   18444                 :             :                                   .section = SECTION_POST_DATA,
   18445                 :             :                                   .createStmt = q->data));
   18446                 :             : 
   18447                 :         562 :         destroyPQExpBuffer(q);
   18448                 :             :     }
   18449                 :             : }
   18450                 :             : 
   18451                 :             : /*
   18452                 :             :  * dumpStatisticsExt
   18453                 :             :  *    write out to fout an extended statistics object
   18454                 :             :  */
   18455                 :             : static void
   18456                 :         183 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   18457                 :             : {
   18458                 :         183 :     DumpOptions *dopt = fout->dopt;
   18459                 :             :     PQExpBuffer q;
   18460                 :             :     PQExpBuffer delq;
   18461                 :             :     PQExpBuffer query;
   18462                 :             :     char       *qstatsextname;
   18463                 :             :     PGresult   *res;
   18464                 :             :     char       *stxdef;
   18465                 :             : 
   18466                 :             :     /* Do nothing if not dumping schema */
   18467         [ +  + ]:         183 :     if (!dopt->dumpSchema)
   18468                 :          28 :         return;
   18469                 :             : 
   18470                 :         155 :     q = createPQExpBuffer();
   18471                 :         155 :     delq = createPQExpBuffer();
   18472                 :         155 :     query = createPQExpBuffer();
   18473                 :             : 
   18474                 :         155 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   18475                 :             : 
   18476                 :         155 :     appendPQExpBuffer(query, "SELECT "
   18477                 :             :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   18478                 :         155 :                       statsextinfo->dobj.catId.oid);
   18479                 :             : 
   18480                 :         155 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   18481                 :             : 
   18482                 :         155 :     stxdef = PQgetvalue(res, 0, 0);
   18483                 :             : 
   18484                 :             :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   18485                 :         155 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   18486                 :             : 
   18487                 :             :     /*
   18488                 :             :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   18489                 :             :      * for this statistics object is not the default value.
   18490                 :             :      */
   18491         [ +  + ]:         155 :     if (statsextinfo->stattarget >= 0)
   18492                 :             :     {
   18493                 :          34 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   18494                 :          34 :                           fmtQualifiedDumpable(statsextinfo));
   18495                 :          34 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   18496                 :          34 :                           statsextinfo->stattarget);
   18497                 :             :     }
   18498                 :             : 
   18499                 :         155 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   18500                 :         155 :                       fmtQualifiedDumpable(statsextinfo));
   18501                 :             : 
   18502         [ +  - ]:         155 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18503                 :         155 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   18504                 :         155 :                      statsextinfo->dobj.dumpId,
   18505                 :         155 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   18506                 :             :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   18507                 :             :                                   .owner = statsextinfo->rolname,
   18508                 :             :                                   .description = "STATISTICS",
   18509                 :             :                                   .section = SECTION_POST_DATA,
   18510                 :             :                                   .createStmt = q->data,
   18511                 :             :                                   .dropStmt = delq->data));
   18512                 :             : 
   18513                 :             :     /* Dump Statistics Comments */
   18514         [ -  + ]:         155 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18515                 :           0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   18516                 :           0 :                     statsextinfo->dobj.namespace->dobj.name,
   18517                 :           0 :                     statsextinfo->rolname,
   18518                 :             :                     statsextinfo->dobj.catId, 0,
   18519                 :           0 :                     statsextinfo->dobj.dumpId);
   18520                 :             : 
   18521                 :         155 :     PQclear(res);
   18522                 :         155 :     destroyPQExpBuffer(q);
   18523                 :         155 :     destroyPQExpBuffer(delq);
   18524                 :         155 :     destroyPQExpBuffer(query);
   18525                 :         155 :     pg_free(qstatsextname);
   18526                 :             : }
   18527                 :             : 
   18528                 :             : /*
   18529                 :             :  * dumpStatisticsExtStats
   18530                 :             :  *    write out to fout the stats for an extended statistics object
   18531                 :             :  */
   18532                 :             : static void
   18533                 :         183 : dumpStatisticsExtStats(Archive *fout, const StatsExtInfo *statsextinfo)
   18534                 :             : {
   18535                 :         183 :     DumpOptions *dopt = fout->dopt;
   18536                 :             :     PQExpBuffer query;
   18537                 :             :     PGresult   *res;
   18538                 :             :     int         nstats;
   18539                 :             : 
   18540                 :             :     /* Do nothing if not dumping statistics */
   18541         [ +  + ]:         183 :     if (!dopt->dumpStatistics)
   18542                 :          40 :         return;
   18543                 :             : 
   18544         [ +  + ]:         143 :     if (!fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS])
   18545                 :             :     {
   18546                 :          36 :         PQExpBuffer pq = createPQExpBuffer();
   18547                 :             : 
   18548                 :             :         /*---------
   18549                 :             :          * Set up query for details about extended statistics objects.
   18550                 :             :          *
   18551                 :             :          * The query depends on the backend version:
   18552                 :             :          * - In v19 and newer versions, query directly the pg_stats_ext*
   18553                 :             :          *   catalogs.
   18554                 :             :          * - In v18 and older versions, ndistinct and dependencies have a
   18555                 :             :          *   different format that needs translation.
   18556                 :             :          * - In v14 and older versions, inherited does not exist.
   18557                 :             :          * - In v11 and older versions, there is no pg_stats_ext, hence
   18558                 :             :          *   the logic joins pg_statistic_ext and pg_namespace.
   18559                 :             :          *---------
   18560                 :             :          */
   18561                 :             : 
   18562                 :          36 :         appendPQExpBufferStr(pq,
   18563                 :             :                              "PREPARE getExtStatsStats(pg_catalog.name, pg_catalog.name) AS\n"
   18564                 :             :                              "SELECT ");
   18565                 :             : 
   18566                 :             :         /*
   18567                 :             :          * Versions 15 and newer have inherited stats.
   18568                 :             :          *
   18569                 :             :          * Create this column in all versions because we need to order by it
   18570                 :             :          * later.
   18571                 :             :          */
   18572         [ +  - ]:          36 :         if (fout->remoteVersion >= 150000)
   18573                 :          36 :             appendPQExpBufferStr(pq, "e.inherited, ");
   18574                 :             :         else
   18575                 :           0 :             appendPQExpBufferStr(pq, "false AS inherited, ");
   18576                 :             : 
   18577                 :             :         /*--------
   18578                 :             :          * The ndistinct and dependencies formats changed in v19, so
   18579                 :             :          * everything before that needs to be translated.
   18580                 :             :          *
   18581                 :             :          * The ndistinct translation converts this kind of data:
   18582                 :             :          * {"3, 4": 11, "3, 6": 11, "4, 6": 11, "3, 4, 6": 11}
   18583                 :             :          *
   18584                 :             :          * to this:
   18585                 :             :          * [ {"attributes": [3,4], "ndistinct": 11},
   18586                 :             :          *   {"attributes": [3,6], "ndistinct": 11},
   18587                 :             :          *   {"attributes": [4,6], "ndistinct": 11},
   18588                 :             :          *   {"attributes": [3,4,6], "ndistinct": 11} ]
   18589                 :             :          *
   18590                 :             :          * The dependencies translation converts this kind of data:
   18591                 :             :          * {"3 => 4": 1.000000, "3 => 6": 1.000000,
   18592                 :             :          *  "4 => 6": 1.000000, "3, 4 => 6": 1.000000,
   18593                 :             :          *  "3, 6 => 4": 1.000000}
   18594                 :             :          *
   18595                 :             :          * to this:
   18596                 :             :          * [ {"attributes": [3], "dependency": 4, "degree": 1.000000},
   18597                 :             :          *   {"attributes": [3], "dependency": 6, "degree": 1.000000},
   18598                 :             :          *   {"attributes": [4], "dependency": 6, "degree": 1.000000},
   18599                 :             :          *   {"attributes": [3,4], "dependency": 6, "degree": 1.000000},
   18600                 :             :          *   {"attributes": [3,6], "dependency": 4, "degree": 1.000000} ]
   18601                 :             :          *--------
   18602                 :             :          */
   18603         [ +  - ]:          36 :         if (fout->remoteVersion >= 190000)
   18604                 :          36 :             appendPQExpBufferStr(pq, "e.n_distinct, e.dependencies, ");
   18605                 :             :         else
   18606                 :           0 :             appendPQExpBufferStr(pq,
   18607                 :             :                                  "( "
   18608                 :             :                                  "SELECT json_agg( "
   18609                 :             :                                  "  json_build_object( "
   18610                 :             :                                  "    '" PG_NDISTINCT_KEY_ATTRIBUTES "', "
   18611                 :             :                                  "    string_to_array(kv.key, ', ')::integer[], "
   18612                 :             :                                  "    '" PG_NDISTINCT_KEY_NDISTINCT "', "
   18613                 :             :                                  "    kv.value::bigint )) "
   18614                 :             :                                  "FROM json_each_text(e.n_distinct::text::json) AS kv"
   18615                 :             :                                  ") AS n_distinct, "
   18616                 :             :                                  "( "
   18617                 :             :                                  "SELECT json_agg( "
   18618                 :             :                                  "  json_build_object( "
   18619                 :             :                                  "    '" PG_DEPENDENCIES_KEY_ATTRIBUTES "', "
   18620                 :             :                                  "    string_to_array( "
   18621                 :             :                                  "      split_part(kv.key, ' => ', 1), "
   18622                 :             :                                  "      ', ')::integer[], "
   18623                 :             :                                  "    '" PG_DEPENDENCIES_KEY_DEPENDENCY "', "
   18624                 :             :                                  "    split_part(kv.key, ' => ', 2)::integer, "
   18625                 :             :                                  "    '" PG_DEPENDENCIES_KEY_DEGREE "', "
   18626                 :             :                                  "    kv.value::double precision )) "
   18627                 :             :                                  "FROM json_each_text(e.dependencies::text::json) AS kv "
   18628                 :             :                                  ") AS dependencies, ");
   18629                 :             : 
   18630                 :             :         /* MCV was introduced v13 */
   18631         [ +  - ]:          36 :         if (fout->remoteVersion >= 130000)
   18632                 :          36 :             appendPQExpBufferStr(pq,
   18633                 :             :                                  "e.most_common_vals, e.most_common_freqs, "
   18634                 :             :                                  "e.most_common_base_freqs, ");
   18635                 :             :         else
   18636                 :           0 :             appendPQExpBufferStr(pq,
   18637                 :             :                                  "NULL AS most_common_vals, NULL AS most_common_freqs, "
   18638                 :             :                                  "NULL AS most_common_base_freqs, ");
   18639                 :             : 
   18640                 :             :         /* Expressions were introduced in v14 */
   18641         [ +  - ]:          36 :         if (fout->remoteVersion >= 140000)
   18642                 :             :         {
   18643                 :             :             /*
   18644                 :             :              * There is no ordering column in pg_stats_ext_exprs.  However, we
   18645                 :             :              * can rely on the unnesting of pg_statistic_ext_data.stxdexpr to
   18646                 :             :              * maintain the desired order of expression elements.
   18647                 :             :              */
   18648                 :          36 :             appendPQExpBufferStr(pq,
   18649                 :             :                                  "( "
   18650                 :             :                                  "SELECT jsonb_pretty(jsonb_agg("
   18651                 :             :                                  "nullif(j.obj, '{}'::jsonb))) "
   18652                 :             :                                  "FROM pg_stats_ext_exprs AS ee "
   18653                 :             :                                  "CROSS JOIN LATERAL jsonb_strip_nulls("
   18654                 :             :                                  "    jsonb_build_object( "
   18655                 :             :                                  "       'null_frac', ee.null_frac::text, "
   18656                 :             :                                  "       'avg_width', ee.avg_width::text, "
   18657                 :             :                                  "       'n_distinct', ee.n_distinct::text, "
   18658                 :             :                                  "       'most_common_vals', ee.most_common_vals::text, "
   18659                 :             :                                  "       'most_common_freqs', ee.most_common_freqs::text, "
   18660                 :             :                                  "       'histogram_bounds', ee.histogram_bounds::text, "
   18661                 :             :                                  "       'correlation', ee.correlation::text, "
   18662                 :             :                                  "       'most_common_elems', ee.most_common_elems::text, "
   18663                 :             :                                  "       'most_common_elem_freqs', ee.most_common_elem_freqs::text, "
   18664                 :             :                                  "       'elem_count_histogram', ee.elem_count_histogram::text");
   18665                 :             : 
   18666                 :             :             /* These three have been added to pg_stats_ext_exprs in v19. */
   18667         [ +  - ]:          36 :             if (fout->remoteVersion >= 190000)
   18668                 :          36 :                 appendPQExpBufferStr(pq,
   18669                 :             :                                      ", "
   18670                 :             :                                      "       'range_length_histogram', ee.range_length_histogram::text, "
   18671                 :             :                                      "       'range_empty_frac', ee.range_empty_frac::text, "
   18672                 :             :                                      "       'range_bounds_histogram', ee.range_bounds_histogram::text");
   18673                 :             : 
   18674                 :          36 :             appendPQExpBufferStr(pq,
   18675                 :             :                                  "    )) AS j(obj)"
   18676                 :             :                                  "WHERE ee.statistics_schemaname = $1 "
   18677                 :             :                                  "AND ee.statistics_name = $2 ");
   18678                 :             :             /* Inherited expressions introduced in v15 */
   18679         [ +  - ]:          36 :             if (fout->remoteVersion >= 150000)
   18680                 :          36 :                 appendPQExpBufferStr(pq, "AND ee.inherited = e.inherited");
   18681                 :             : 
   18682                 :          36 :             appendPQExpBufferStr(pq, ") AS exprs ");
   18683                 :             :         }
   18684                 :             :         else
   18685                 :           0 :             appendPQExpBufferStr(pq, "NULL AS exprs ");
   18686                 :             : 
   18687                 :             :         /* pg_stats_ext introduced in v12 */
   18688         [ +  - ]:          36 :         if (fout->remoteVersion >= 120000)
   18689                 :          36 :             appendPQExpBufferStr(pq,
   18690                 :             :                                  "FROM pg_catalog.pg_stats_ext AS e "
   18691                 :             :                                  "WHERE e.statistics_schemaname = $1 "
   18692                 :             :                                  "AND e.statistics_name = $2 ");
   18693                 :             :         else
   18694                 :           0 :             appendPQExpBufferStr(pq,
   18695                 :             :                                  "FROM ( "
   18696                 :             :                                  "SELECT s.stxndistinct AS n_distinct, "
   18697                 :             :                                  "    s.stxdependencies AS dependencies "
   18698                 :             :                                  "FROM pg_catalog.pg_statistic_ext AS s "
   18699                 :             :                                  "JOIN pg_catalog.pg_namespace AS n "
   18700                 :             :                                  "ON n.oid = s.stxnamespace "
   18701                 :             :                                  "WHERE n.nspname = $1 "
   18702                 :             :                                  "AND s.stxname = $2 "
   18703                 :             :                                  ") AS e ");
   18704                 :             : 
   18705                 :             :         /* we always have an inherited column, but it may be a constant */
   18706                 :          36 :         appendPQExpBufferStr(pq, "ORDER BY inherited");
   18707                 :             : 
   18708                 :          36 :         ExecuteSqlStatement(fout, pq->data);
   18709                 :             : 
   18710                 :          36 :         fout->is_prepared[PREPQUERY_DUMPEXTSTATSOBJSTATS] = true;
   18711                 :             : 
   18712                 :          36 :         destroyPQExpBuffer(pq);
   18713                 :             :     }
   18714                 :             : 
   18715                 :         143 :     query = createPQExpBuffer();
   18716                 :             : 
   18717                 :         143 :     appendPQExpBufferStr(query, "EXECUTE getExtStatsStats(");
   18718                 :         143 :     appendStringLiteralAH(query, statsextinfo->dobj.namespace->dobj.name, fout);
   18719                 :         143 :     appendPQExpBufferStr(query, "::pg_catalog.name, ");
   18720                 :         143 :     appendStringLiteralAH(query, statsextinfo->dobj.name, fout);
   18721                 :         143 :     appendPQExpBufferStr(query, "::pg_catalog.name)");
   18722                 :             : 
   18723                 :         143 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18724                 :             : 
   18725                 :         143 :     destroyPQExpBuffer(query);
   18726                 :             : 
   18727                 :         143 :     nstats = PQntuples(res);
   18728                 :             : 
   18729         [ +  + ]:         143 :     if (nstats > 0)
   18730                 :             :     {
   18731                 :          39 :         PQExpBuffer out = createPQExpBuffer();
   18732                 :             : 
   18733                 :          39 :         int         i_inherited = PQfnumber(res, "inherited");
   18734                 :          39 :         int         i_ndistinct = PQfnumber(res, "n_distinct");
   18735                 :          39 :         int         i_dependencies = PQfnumber(res, "dependencies");
   18736                 :          39 :         int         i_mcv = PQfnumber(res, "most_common_vals");
   18737                 :          39 :         int         i_mcf = PQfnumber(res, "most_common_freqs");
   18738                 :          39 :         int         i_mcbf = PQfnumber(res, "most_common_base_freqs");
   18739                 :          39 :         int         i_exprs = PQfnumber(res, "exprs");
   18740                 :             : 
   18741         [ +  + ]:          78 :         for (int i = 0; i < nstats; i++)
   18742                 :             :         {
   18743                 :          39 :             TableInfo  *tbinfo = statsextinfo->stattable;
   18744                 :             : 
   18745         [ -  + ]:          39 :             if (PQgetisnull(res, i, i_inherited))
   18746                 :           0 :                 pg_fatal("inherited cannot be NULL");
   18747                 :             : 
   18748                 :          39 :             appendPQExpBufferStr(out,
   18749                 :             :                                  "SELECT * FROM pg_catalog.pg_restore_extended_stats(\n");
   18750                 :          39 :             appendPQExpBuffer(out, "\t'version', '%d'::integer,\n",
   18751                 :             :                               fout->remoteVersion);
   18752                 :             : 
   18753                 :             :             /* Relation information */
   18754                 :          39 :             appendPQExpBufferStr(out, "\t'schemaname', ");
   18755                 :          39 :             appendStringLiteralAH(out, tbinfo->dobj.namespace->dobj.name, fout);
   18756                 :          39 :             appendPQExpBufferStr(out, ",\n\t'relname', ");
   18757                 :          39 :             appendStringLiteralAH(out, tbinfo->dobj.name, fout);
   18758                 :             : 
   18759                 :             :             /* Extended statistics information */
   18760                 :          39 :             appendPQExpBufferStr(out, ",\n\t'statistics_schemaname', ");
   18761                 :          39 :             appendStringLiteralAH(out, statsextinfo->dobj.namespace->dobj.name, fout);
   18762                 :          39 :             appendPQExpBufferStr(out, ",\n\t'statistics_name', ");
   18763                 :          39 :             appendStringLiteralAH(out, statsextinfo->dobj.name, fout);
   18764                 :          39 :             appendNamedArgument(out, fout, "inherited", "boolean",
   18765                 :          39 :                                 PQgetvalue(res, i, i_inherited));
   18766                 :             : 
   18767         [ +  + ]:          39 :             if (!PQgetisnull(res, i, i_ndistinct))
   18768                 :          35 :                 appendNamedArgument(out, fout, "n_distinct", "pg_ndistinct",
   18769                 :          35 :                                     PQgetvalue(res, i, i_ndistinct));
   18770                 :             : 
   18771         [ +  + ]:          39 :             if (!PQgetisnull(res, i, i_dependencies))
   18772                 :          36 :                 appendNamedArgument(out, fout, "dependencies", "pg_dependencies",
   18773                 :          36 :                                     PQgetvalue(res, i, i_dependencies));
   18774                 :             : 
   18775         [ +  + ]:          39 :             if (!PQgetisnull(res, i, i_mcv))
   18776                 :          38 :                 appendNamedArgument(out, fout, "most_common_vals", "text[]",
   18777                 :          38 :                                     PQgetvalue(res, i, i_mcv));
   18778                 :             : 
   18779         [ +  + ]:          39 :             if (!PQgetisnull(res, i, i_mcf))
   18780                 :          38 :                 appendNamedArgument(out, fout, "most_common_freqs", "double precision[]",
   18781                 :          38 :                                     PQgetvalue(res, i, i_mcf));
   18782                 :             : 
   18783         [ +  + ]:          39 :             if (!PQgetisnull(res, i, i_mcbf))
   18784                 :          38 :                 appendNamedArgument(out, fout, "most_common_base_freqs", "double precision[]",
   18785                 :          38 :                                     PQgetvalue(res, i, i_mcbf));
   18786                 :             : 
   18787         [ +  + ]:          39 :             if (!PQgetisnull(res, i, i_exprs))
   18788                 :          36 :                 appendNamedArgument(out, fout, "exprs", "jsonb",
   18789                 :          36 :                                     PQgetvalue(res, i, i_exprs));
   18790                 :             : 
   18791                 :          39 :             appendPQExpBufferStr(out, "\n);\n");
   18792                 :             :         }
   18793                 :             : 
   18794                 :          39 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18795                 :          39 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   18796                 :             :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   18797                 :             :                                   .owner = statsextinfo->rolname,
   18798                 :             :                                   .description = "EXTENDED STATISTICS DATA",
   18799                 :             :                                   .section = SECTION_POST_DATA,
   18800                 :             :                                   .createStmt = out->data,
   18801                 :             :                                   .deps = &statsextinfo->dobj.dumpId,
   18802                 :             :                                   .nDeps = 1));
   18803                 :          39 :         destroyPQExpBuffer(out);
   18804                 :             :     }
   18805                 :         143 :     PQclear(res);
   18806                 :             : }
   18807                 :             : 
   18808                 :             : /*
   18809                 :             :  * dumpConstraint
   18810                 :             :  *    write out to fout a user-defined constraint
   18811                 :             :  */
   18812                 :             : static void
   18813                 :        2800 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   18814                 :             : {
   18815                 :        2800 :     DumpOptions *dopt = fout->dopt;
   18816                 :        2800 :     TableInfo  *tbinfo = coninfo->contable;
   18817                 :             :     PQExpBuffer q;
   18818                 :             :     PQExpBuffer delq;
   18819                 :        2800 :     char       *tag = NULL;
   18820                 :             :     char       *foreign;
   18821                 :             : 
   18822                 :             :     /* Do nothing if not dumping schema */
   18823         [ +  + ]:        2800 :     if (!dopt->dumpSchema)
   18824                 :         110 :         return;
   18825                 :             : 
   18826                 :        2690 :     q = createPQExpBuffer();
   18827                 :        2690 :     delq = createPQExpBuffer();
   18828                 :             : 
   18829                 :        5202 :     foreign = tbinfo &&
   18830   [ +  +  -  + ]:        2690 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   18831                 :             : 
   18832         [ +  + ]:        2690 :     if (coninfo->contype == 'p' ||
   18833         [ +  + ]:        1319 :         coninfo->contype == 'u' ||
   18834         [ +  + ]:        1073 :         coninfo->contype == 'x')
   18835                 :        1627 :     {
   18836                 :             :         /* Index-related constraint */
   18837                 :             :         IndxInfo   *indxinfo;
   18838                 :             :         int         k;
   18839                 :             : 
   18840                 :        1627 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   18841                 :             : 
   18842         [ -  + ]:        1627 :         if (indxinfo == NULL)
   18843                 :           0 :             pg_fatal("missing index for constraint \"%s\"",
   18844                 :             :                      coninfo->dobj.name);
   18845                 :             : 
   18846         [ +  + ]:        1627 :         if (dopt->binary_upgrade)
   18847                 :         177 :             binary_upgrade_set_pg_class_oids(fout, q,
   18848                 :             :                                              indxinfo->dobj.catId.oid);
   18849                 :             : 
   18850                 :        1627 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   18851                 :        1627 :                           fmtQualifiedDumpable(tbinfo));
   18852                 :        1627 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   18853                 :        1627 :                           fmtId(coninfo->dobj.name));
   18854                 :             : 
   18855         [ +  + ]:        1627 :         if (coninfo->condef)
   18856                 :             :         {
   18857                 :             :             /* pg_get_constraintdef should have provided everything */
   18858                 :          10 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   18859                 :             :         }
   18860                 :             :         else
   18861                 :             :         {
   18862                 :        1617 :             appendPQExpBufferStr(q,
   18863         [ +  + ]:        1617 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   18864                 :             : 
   18865                 :             :             /*
   18866                 :             :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   18867                 :             :              * indexes. Being able to create this was fixed, but we need to
   18868                 :             :              * make the index distinct in order to be able to restore the
   18869                 :             :              * dump.
   18870                 :             :              */
   18871   [ -  +  -  - ]:        1617 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   18872                 :           0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   18873                 :        1617 :             appendPQExpBufferStr(q, " (");
   18874         [ +  + ]:        3865 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   18875                 :             :             {
   18876                 :        2248 :                 int         indkey = (int) indxinfo->indkeys[k];
   18877                 :             :                 const char *attname;
   18878                 :             : 
   18879         [ -  + ]:        2248 :                 if (indkey == InvalidAttrNumber)
   18880                 :           0 :                     break;
   18881                 :        2248 :                 attname = getAttrName(indkey, tbinfo);
   18882                 :             : 
   18883         [ +  + ]:        2248 :                 appendPQExpBuffer(q, "%s%s",
   18884                 :             :                                   (k == 0) ? "" : ", ",
   18885                 :             :                                   fmtId(attname));
   18886                 :             :             }
   18887         [ +  + ]:        1617 :             if (coninfo->conperiod)
   18888                 :         113 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   18889                 :             : 
   18890         [ +  + ]:        1617 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   18891                 :          20 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   18892                 :             : 
   18893         [ +  + ]:        1657 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   18894                 :             :             {
   18895                 :          40 :                 int         indkey = (int) indxinfo->indkeys[k];
   18896                 :             :                 const char *attname;
   18897                 :             : 
   18898         [ -  + ]:          40 :                 if (indkey == InvalidAttrNumber)
   18899                 :           0 :                     break;
   18900                 :          40 :                 attname = getAttrName(indkey, tbinfo);
   18901                 :             : 
   18902                 :          80 :                 appendPQExpBuffer(q, "%s%s",
   18903         [ +  + ]:          40 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   18904                 :             :                                   fmtId(attname));
   18905                 :             :             }
   18906                 :             : 
   18907                 :        1617 :             appendPQExpBufferChar(q, ')');
   18908                 :             : 
   18909         [ -  + ]:        1617 :             if (nonemptyReloptions(indxinfo->indreloptions))
   18910                 :             :             {
   18911                 :           0 :                 appendPQExpBufferStr(q, " WITH (");
   18912                 :           0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   18913                 :           0 :                 appendPQExpBufferChar(q, ')');
   18914                 :             :             }
   18915                 :             : 
   18916         [ +  + ]:        1617 :             if (coninfo->condeferrable)
   18917                 :             :             {
   18918                 :          25 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   18919         [ +  + ]:          25 :                 if (coninfo->condeferred)
   18920                 :          15 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   18921                 :             :             }
   18922                 :             : 
   18923                 :        1617 :             appendPQExpBufferStr(q, ";\n");
   18924                 :             :         }
   18925                 :             : 
   18926                 :             :         /*
   18927                 :             :          * Append ALTER TABLE commands as needed to set properties that we
   18928                 :             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   18929                 :             :          * similar code in dumpIndex!
   18930                 :             :          */
   18931                 :             : 
   18932                 :             :         /* If the index is clustered, we need to record that. */
   18933         [ +  + ]:        1627 :         if (indxinfo->indisclustered)
   18934                 :             :         {
   18935                 :          34 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   18936                 :          34 :                               fmtQualifiedDumpable(tbinfo));
   18937                 :             :             /* index name is not qualified in this syntax */
   18938                 :          34 :             appendPQExpBuffer(q, " ON %s;\n",
   18939                 :          34 :                               fmtId(indxinfo->dobj.name));
   18940                 :             :         }
   18941                 :             : 
   18942                 :             :         /* If the index defines identity, we need to record that. */
   18943         [ -  + ]:        1627 :         if (indxinfo->indisreplident)
   18944                 :             :         {
   18945                 :           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   18946                 :           0 :                               fmtQualifiedDumpable(tbinfo));
   18947                 :             :             /* index name is not qualified in this syntax */
   18948                 :           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   18949                 :           0 :                               fmtId(indxinfo->dobj.name));
   18950                 :             :         }
   18951                 :             : 
   18952                 :             :         /* Indexes can depend on extensions */
   18953                 :        1627 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   18954                 :             :                                     "pg_catalog.pg_class", "INDEX",
   18955                 :        1627 :                                     fmtQualifiedDumpable(indxinfo));
   18956                 :             : 
   18957                 :        1627 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   18958                 :        1627 :                           fmtQualifiedDumpable(tbinfo));
   18959                 :        1627 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   18960                 :        1627 :                           fmtId(coninfo->dobj.name));
   18961                 :             : 
   18962                 :        1627 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   18963                 :             : 
   18964         [ +  - ]:        1627 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18965                 :        1627 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   18966                 :        1627 :                          ARCHIVE_OPTS(.tag = tag,
   18967                 :             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   18968                 :             :                                       .tablespace = indxinfo->tablespace,
   18969                 :             :                                       .owner = tbinfo->rolname,
   18970                 :             :                                       .description = "CONSTRAINT",
   18971                 :             :                                       .section = SECTION_POST_DATA,
   18972                 :             :                                       .createStmt = q->data,
   18973                 :             :                                       .dropStmt = delq->data));
   18974                 :             :     }
   18975         [ +  + ]:        1063 :     else if (coninfo->contype == 'f')
   18976                 :             :     {
   18977                 :             :         char       *only;
   18978                 :             : 
   18979                 :             :         /*
   18980                 :             :          * Foreign keys on partitioned tables are always declared as
   18981                 :             :          * inheriting to partitions; for all other cases, emit them as
   18982                 :             :          * applying ONLY directly to the named table, because that's how they
   18983                 :             :          * work for regular inherited tables.
   18984                 :             :          */
   18985         [ +  + ]:         223 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   18986                 :             : 
   18987                 :             :         /*
   18988                 :             :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   18989                 :             :          * current table data is not processed
   18990                 :             :          */
   18991                 :         223 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   18992                 :         223 :                           only, fmtQualifiedDumpable(tbinfo));
   18993                 :         223 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   18994                 :         223 :                           fmtId(coninfo->dobj.name),
   18995                 :         223 :                           coninfo->condef);
   18996                 :             : 
   18997                 :         223 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   18998                 :         223 :                           only, fmtQualifiedDumpable(tbinfo));
   18999                 :         223 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19000                 :         223 :                           fmtId(coninfo->dobj.name));
   19001                 :             : 
   19002                 :         223 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19003                 :             : 
   19004         [ +  - ]:         223 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19005                 :         223 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19006                 :         223 :                          ARCHIVE_OPTS(.tag = tag,
   19007                 :             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   19008                 :             :                                       .owner = tbinfo->rolname,
   19009                 :             :                                       .description = "FK CONSTRAINT",
   19010                 :             :                                       .section = SECTION_POST_DATA,
   19011                 :             :                                       .createStmt = q->data,
   19012                 :             :                                       .dropStmt = delq->data));
   19013                 :             :     }
   19014   [ +  +  +  -  :         840 :     else if ((coninfo->contype == 'c' || coninfo->contype == 'n') && tbinfo)
                   +  + ]
   19015                 :             :     {
   19016                 :             :         /* CHECK or invalid not-null constraint on a table */
   19017                 :             : 
   19018                 :             :         /* Ignore if not to be dumped separately, or if it was inherited */
   19019   [ +  +  +  + ]:         662 :         if (coninfo->separate && coninfo->conislocal)
   19020                 :             :         {
   19021                 :             :             const char *keyword;
   19022                 :             : 
   19023         [ +  + ]:         109 :             if (coninfo->contype == 'c')
   19024                 :          45 :                 keyword = "CHECK CONSTRAINT";
   19025                 :             :             else
   19026                 :          64 :                 keyword = "CONSTRAINT";
   19027                 :             : 
   19028                 :             :             /* not ONLY since we want it to propagate to children */
   19029                 :         109 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   19030                 :         109 :                               fmtQualifiedDumpable(tbinfo));
   19031                 :         109 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19032                 :         109 :                               fmtId(coninfo->dobj.name),
   19033                 :         109 :                               coninfo->condef);
   19034                 :             : 
   19035                 :         109 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   19036                 :         109 :                               fmtQualifiedDumpable(tbinfo));
   19037                 :         109 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19038                 :         109 :                               fmtId(coninfo->dobj.name));
   19039                 :             : 
   19040                 :         109 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   19041                 :             : 
   19042         [ +  - ]:         109 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19043                 :         109 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19044                 :         109 :                              ARCHIVE_OPTS(.tag = tag,
   19045                 :             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19046                 :             :                                           .owner = tbinfo->rolname,
   19047                 :             :                                           .description = keyword,
   19048                 :             :                                           .section = SECTION_POST_DATA,
   19049                 :             :                                           .createStmt = q->data,
   19050                 :             :                                           .dropStmt = delq->data));
   19051                 :             :         }
   19052                 :             :     }
   19053         [ +  - ]:         178 :     else if (tbinfo == NULL)
   19054                 :             :     {
   19055                 :             :         /* CHECK, NOT NULL constraint on a domain */
   19056                 :         178 :         TypeInfo   *tyinfo = coninfo->condomain;
   19057                 :             : 
   19058                 :             :         Assert(coninfo->contype == 'c' || coninfo->contype == 'n');
   19059                 :             : 
   19060                 :             :         /* Ignore if not to be dumped separately */
   19061         [ +  + ]:         178 :         if (coninfo->separate)
   19062                 :             :         {
   19063                 :             :             const char *keyword;
   19064                 :             : 
   19065         [ +  - ]:           5 :             if (coninfo->contype == 'c')
   19066                 :           5 :                 keyword = "CHECK CONSTRAINT";
   19067                 :             :             else
   19068                 :           0 :                 keyword = "CONSTRAINT";
   19069                 :             : 
   19070                 :           5 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   19071                 :           5 :                               fmtQualifiedDumpable(tyinfo));
   19072                 :           5 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   19073                 :           5 :                               fmtId(coninfo->dobj.name),
   19074                 :           5 :                               coninfo->condef);
   19075                 :             : 
   19076                 :           5 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   19077                 :           5 :                               fmtQualifiedDumpable(tyinfo));
   19078                 :           5 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   19079                 :           5 :                               fmtId(coninfo->dobj.name));
   19080                 :             : 
   19081                 :           5 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   19082                 :             : 
   19083         [ +  - ]:           5 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19084                 :           5 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   19085                 :           5 :                              ARCHIVE_OPTS(.tag = tag,
   19086                 :             :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   19087                 :             :                                           .owner = tyinfo->rolname,
   19088                 :             :                                           .description = keyword,
   19089                 :             :                                           .section = SECTION_POST_DATA,
   19090                 :             :                                           .createStmt = q->data,
   19091                 :             :                                           .dropStmt = delq->data));
   19092                 :             : 
   19093         [ +  - ]:           5 :             if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19094                 :             :             {
   19095                 :           5 :                 PQExpBuffer conprefix = createPQExpBuffer();
   19096                 :           5 :                 char       *qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   19097                 :             : 
   19098                 :           5 :                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   19099                 :           5 :                                   fmtId(coninfo->dobj.name));
   19100                 :             : 
   19101                 :           5 :                 dumpComment(fout, conprefix->data, qtypname,
   19102                 :           5 :                             tyinfo->dobj.namespace->dobj.name,
   19103                 :             :                             tyinfo->rolname,
   19104                 :           5 :                             coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
   19105                 :           5 :                 destroyPQExpBuffer(conprefix);
   19106                 :           5 :                 pg_free(qtypname);
   19107                 :             :             }
   19108                 :             :         }
   19109                 :             :     }
   19110                 :             :     else
   19111                 :             :     {
   19112                 :           0 :         pg_fatal("unrecognized constraint type: %c",
   19113                 :             :                  coninfo->contype);
   19114                 :             :     }
   19115                 :             : 
   19116                 :             :     /* Dump Constraint Comments --- only works for table constraints */
   19117   [ +  +  +  + ]:        2690 :     if (tbinfo && coninfo->separate &&
   19118         [ +  + ]:        1989 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19119                 :          49 :         dumpTableConstraintComment(fout, coninfo);
   19120                 :             : 
   19121                 :        2690 :     pfree(tag);
   19122                 :        2690 :     destroyPQExpBuffer(q);
   19123                 :        2690 :     destroyPQExpBuffer(delq);
   19124                 :             : }
   19125                 :             : 
   19126                 :             : /*
   19127                 :             :  * dumpTableConstraintComment --- dump a constraint's comment if any
   19128                 :             :  *
   19129                 :             :  * This is split out because we need the function in two different places
   19130                 :             :  * depending on whether the constraint is dumped as part of CREATE TABLE
   19131                 :             :  * or as a separate ALTER command.
   19132                 :             :  */
   19133                 :             : static void
   19134                 :          88 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   19135                 :             : {
   19136                 :          88 :     TableInfo  *tbinfo = coninfo->contable;
   19137                 :          88 :     PQExpBuffer conprefix = createPQExpBuffer();
   19138                 :             :     char       *qtabname;
   19139                 :             : 
   19140                 :          88 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19141                 :             : 
   19142                 :          88 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   19143                 :          88 :                       fmtId(coninfo->dobj.name));
   19144                 :             : 
   19145         [ +  - ]:          88 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19146                 :          88 :         dumpComment(fout, conprefix->data, qtabname,
   19147                 :          88 :                     tbinfo->dobj.namespace->dobj.name,
   19148                 :             :                     tbinfo->rolname,
   19149                 :             :                     coninfo->dobj.catId, 0,
   19150         [ +  + ]:          88 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   19151                 :             : 
   19152                 :          88 :     destroyPQExpBuffer(conprefix);
   19153                 :          88 :     pg_free(qtabname);
   19154                 :          88 : }
   19155                 :             : 
   19156                 :             : static inline SeqType
   19157                 :         647 : parse_sequence_type(const char *name)
   19158                 :             : {
   19159         [ +  - ]:        1443 :     for (size_t i = 0; i < lengthof(SeqTypeNames); i++)
   19160                 :             :     {
   19161         [ +  + ]:        1443 :         if (strcmp(SeqTypeNames[i], name) == 0)
   19162                 :         647 :             return (SeqType) i;
   19163                 :             :     }
   19164                 :             : 
   19165                 :           0 :     pg_fatal("unrecognized sequence type: %s", name);
   19166                 :             :     return (SeqType) 0;         /* keep compiler quiet */
   19167                 :             : }
   19168                 :             : 
   19169                 :             : /*
   19170                 :             :  * bsearch() comparator for SequenceItem
   19171                 :             :  */
   19172                 :             : static int
   19173                 :        2976 : SequenceItemCmp(const void *p1, const void *p2)
   19174                 :             : {
   19175                 :        2976 :     SequenceItem v1 = *((const SequenceItem *) p1);
   19176                 :        2976 :     SequenceItem v2 = *((const SequenceItem *) p2);
   19177                 :             : 
   19178                 :        2976 :     return pg_cmp_u32(v1.oid, v2.oid);
   19179                 :             : }
   19180                 :             : 
   19181                 :             : /*
   19182                 :             :  * collectSequences
   19183                 :             :  *
   19184                 :             :  * Construct a table of sequence information.  This table is sorted by OID for
   19185                 :             :  * speed in lookup.
   19186                 :             :  */
   19187                 :             : static void
   19188                 :         191 : collectSequences(Archive *fout)
   19189                 :             : {
   19190                 :             :     PGresult   *res;
   19191                 :             :     const char *query;
   19192                 :             : 
   19193                 :             :     /*
   19194                 :             :      * Since version 18, we can gather the sequence data in this query with
   19195                 :             :      * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   19196                 :             :      */
   19197         [ +  - ]:         191 :     if (fout->remoteVersion < 180000 ||
   19198   [ +  +  +  + ]:         191 :         (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   19199                 :           9 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   19200                 :             :             "seqstart, seqincrement, "
   19201                 :             :             "seqmax, seqmin, "
   19202                 :             :             "seqcache, seqcycle, "
   19203                 :             :             "NULL, 'f' "
   19204                 :             :             "FROM pg_catalog.pg_sequence "
   19205                 :             :             "ORDER BY seqrelid";
   19206                 :             :     else
   19207                 :         182 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   19208                 :             :             "seqstart, seqincrement, "
   19209                 :             :             "seqmax, seqmin, "
   19210                 :             :             "seqcache, seqcycle, "
   19211                 :             :             "last_value, is_called "
   19212                 :             :             "FROM pg_catalog.pg_sequence, "
   19213                 :             :             "pg_get_sequence_data(seqrelid) "
   19214                 :             :             "ORDER BY seqrelid;";
   19215                 :             : 
   19216                 :         191 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   19217                 :             : 
   19218                 :         191 :     nsequences = PQntuples(res);
   19219                 :         191 :     sequences = pg_malloc_array(SequenceItem, nsequences);
   19220                 :             : 
   19221         [ +  + ]:         838 :     for (int i = 0; i < nsequences; i++)
   19222                 :             :     {
   19223                 :         647 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   19224                 :         647 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   19225                 :         647 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   19226                 :         647 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   19227                 :         647 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   19228                 :         647 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   19229                 :         647 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   19230                 :         647 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   19231                 :         647 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   19232                 :         647 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   19233   [ +  +  -  + ]:         647 :         sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
   19234                 :             :     }
   19235                 :             : 
   19236                 :         191 :     PQclear(res);
   19237                 :         191 : }
   19238                 :             : 
   19239                 :             : /*
   19240                 :             :  * dumpSequence
   19241                 :             :  *    write the declaration (not data) of one user-defined sequence
   19242                 :             :  */
   19243                 :             : static void
   19244                 :         381 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   19245                 :             : {
   19246                 :         381 :     DumpOptions *dopt = fout->dopt;
   19247                 :             :     SequenceItem *seq;
   19248                 :             :     bool        is_ascending;
   19249                 :             :     int64       default_minv,
   19250                 :             :                 default_maxv;
   19251                 :         381 :     PQExpBuffer query = createPQExpBuffer();
   19252                 :         381 :     PQExpBuffer delqry = createPQExpBuffer();
   19253                 :             :     char       *qseqname;
   19254                 :         381 :     TableInfo  *owning_tab = NULL;
   19255                 :         381 :     SequenceItem key = {0};
   19256                 :             : 
   19257                 :         381 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   19258                 :             : 
   19259                 :             :     /*
   19260                 :             :      * The sequence information is gathered in a sorted table before any calls
   19261                 :             :      * to dumpSequence().  See collectSequences() for more information.
   19262                 :             :      */
   19263                 :             :     Assert(sequences);
   19264                 :             : 
   19265                 :         381 :     key.oid = tbinfo->dobj.catId.oid;
   19266                 :         381 :     seq = bsearch(&key, sequences, nsequences,
   19267                 :             :                   sizeof(SequenceItem), SequenceItemCmp);
   19268                 :             : 
   19269                 :             :     /* Calculate default limits for a sequence of this type */
   19270                 :         381 :     is_ascending = (seq->incby >= 0);
   19271         [ +  + ]:         381 :     if (seq->seqtype == SEQTYPE_SMALLINT)
   19272                 :             :     {
   19273         [ +  + ]:          25 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   19274         [ +  + ]:          25 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   19275                 :             :     }
   19276         [ +  + ]:         356 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   19277                 :             :     {
   19278         [ +  + ]:         290 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   19279         [ +  + ]:         290 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   19280                 :             :     }
   19281         [ +  - ]:          66 :     else if (seq->seqtype == SEQTYPE_BIGINT)
   19282                 :             :     {
   19283         [ +  + ]:          66 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   19284         [ +  + ]:          66 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   19285                 :             :     }
   19286                 :             :     else
   19287                 :             :     {
   19288                 :           0 :         pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   19289                 :             :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   19290                 :             :     }
   19291                 :             : 
   19292                 :             :     /*
   19293                 :             :      * Identity sequences are not to be dropped separately.
   19294                 :             :      */
   19295         [ +  + ]:         381 :     if (!tbinfo->is_identity_sequence)
   19296                 :             :     {
   19297                 :         237 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   19298                 :         237 :                           fmtQualifiedDumpable(tbinfo));
   19299                 :             :     }
   19300                 :             : 
   19301                 :         381 :     resetPQExpBuffer(query);
   19302                 :             : 
   19303         [ +  + ]:         381 :     if (dopt->binary_upgrade)
   19304                 :             :     {
   19305                 :          66 :         binary_upgrade_set_pg_class_oids(fout, query,
   19306                 :          66 :                                          tbinfo->dobj.catId.oid);
   19307                 :             : 
   19308                 :             :         /*
   19309                 :             :          * In older PG versions a sequence will have a pg_type entry, but v14
   19310                 :             :          * and up don't use that, so don't attempt to preserve the type OID.
   19311                 :             :          */
   19312                 :             :     }
   19313                 :             : 
   19314         [ +  + ]:         381 :     if (tbinfo->is_identity_sequence)
   19315                 :             :     {
   19316                 :         144 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19317                 :             : 
   19318                 :         144 :         appendPQExpBuffer(query,
   19319                 :             :                           "ALTER TABLE %s ",
   19320                 :         144 :                           fmtQualifiedDumpable(owning_tab));
   19321                 :         144 :         appendPQExpBuffer(query,
   19322                 :             :                           "ALTER COLUMN %s ADD GENERATED ",
   19323                 :         144 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19324         [ +  + ]:         144 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   19325                 :         104 :             appendPQExpBufferStr(query, "ALWAYS");
   19326         [ +  - ]:          40 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   19327                 :          40 :             appendPQExpBufferStr(query, "BY DEFAULT");
   19328                 :         144 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   19329                 :         144 :                           fmtQualifiedDumpable(tbinfo));
   19330                 :             : 
   19331                 :             :         /*
   19332                 :             :          * Emit persistence option only if it's different from the owning
   19333                 :             :          * table's.  This avoids using this new syntax unnecessarily.
   19334                 :             :          */
   19335         [ +  + ]:         144 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   19336                 :          10 :             appendPQExpBuffer(query, "    %s\n",
   19337         [ +  + ]:          10 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19338                 :             :                               "UNLOGGED" : "LOGGED");
   19339                 :             :     }
   19340                 :             :     else
   19341                 :             :     {
   19342                 :         237 :         appendPQExpBuffer(query,
   19343                 :             :                           "CREATE %sSEQUENCE %s\n",
   19344         [ +  + ]:         237 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   19345                 :             :                           "UNLOGGED " : "",
   19346                 :         237 :                           fmtQualifiedDumpable(tbinfo));
   19347                 :             : 
   19348         [ +  + ]:         237 :         if (seq->seqtype != SEQTYPE_BIGINT)
   19349                 :         186 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   19350                 :             :     }
   19351                 :             : 
   19352                 :         381 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   19353                 :             : 
   19354                 :         381 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   19355                 :             : 
   19356         [ +  + ]:         381 :     if (seq->minv != default_minv)
   19357                 :          15 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   19358                 :             :     else
   19359                 :         366 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   19360                 :             : 
   19361         [ +  + ]:         381 :     if (seq->maxv != default_maxv)
   19362                 :          15 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   19363                 :             :     else
   19364                 :         366 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   19365                 :             : 
   19366                 :         381 :     appendPQExpBuffer(query,
   19367                 :             :                       "    CACHE " INT64_FORMAT "%s",
   19368         [ +  + ]:         381 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   19369                 :             : 
   19370         [ +  + ]:         381 :     if (tbinfo->is_identity_sequence)
   19371                 :         144 :         appendPQExpBufferStr(query, "\n);\n");
   19372                 :             :     else
   19373                 :         237 :         appendPQExpBufferStr(query, ";\n");
   19374                 :             : 
   19375                 :             :     /* binary_upgrade:  no need to clear TOAST table oid */
   19376                 :             : 
   19377         [ +  + ]:         381 :     if (dopt->binary_upgrade)
   19378                 :          66 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   19379                 :             :                                         "SEQUENCE", qseqname,
   19380                 :          66 :                                         tbinfo->dobj.namespace->dobj.name);
   19381                 :             : 
   19382         [ +  - ]:         381 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19383                 :         381 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   19384                 :         381 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19385                 :             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19386                 :             :                                   .owner = tbinfo->rolname,
   19387                 :             :                                   .description = "SEQUENCE",
   19388                 :             :                                   .section = SECTION_PRE_DATA,
   19389                 :             :                                   .createStmt = query->data,
   19390                 :             :                                   .dropStmt = delqry->data));
   19391                 :             : 
   19392                 :             :     /*
   19393                 :             :      * If the sequence is owned by a table column, emit the ALTER for it as a
   19394                 :             :      * separate TOC entry immediately following the sequence's own entry. It's
   19395                 :             :      * OK to do this rather than using full sorting logic, because the
   19396                 :             :      * dependency that tells us it's owned will have forced the table to be
   19397                 :             :      * created first.  We can't just include the ALTER in the TOC entry
   19398                 :             :      * because it will fail if we haven't reassigned the sequence owner to
   19399                 :             :      * match the table's owner.
   19400                 :             :      *
   19401                 :             :      * We need not schema-qualify the table reference because both sequence
   19402                 :             :      * and table must be in the same schema.
   19403                 :             :      */
   19404   [ +  +  +  + ]:         381 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   19405                 :             :     {
   19406                 :         141 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   19407                 :             : 
   19408         [ -  + ]:         141 :         if (owning_tab == NULL)
   19409                 :           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   19410                 :             :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   19411                 :             : 
   19412         [ +  + ]:         141 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19413                 :             :         {
   19414                 :         139 :             resetPQExpBuffer(query);
   19415                 :         139 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   19416                 :         139 :                               fmtQualifiedDumpable(tbinfo));
   19417                 :         139 :             appendPQExpBuffer(query, " OWNED BY %s",
   19418                 :         139 :                               fmtQualifiedDumpable(owning_tab));
   19419                 :         139 :             appendPQExpBuffer(query, ".%s;\n",
   19420                 :         139 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   19421                 :             : 
   19422         [ +  - ]:         139 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19423                 :         139 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19424                 :         139 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19425                 :             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   19426                 :             :                                           .owner = tbinfo->rolname,
   19427                 :             :                                           .description = "SEQUENCE OWNED BY",
   19428                 :             :                                           .section = SECTION_PRE_DATA,
   19429                 :             :                                           .createStmt = query->data,
   19430                 :             :                                           .deps = &(tbinfo->dobj.dumpId),
   19431                 :             :                                           .nDeps = 1));
   19432                 :             :         }
   19433                 :             :     }
   19434                 :             : 
   19435                 :             :     /* Dump Sequence Comments and Security Labels */
   19436         [ -  + ]:         381 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19437                 :           0 :         dumpComment(fout, "SEQUENCE", qseqname,
   19438                 :           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19439                 :           0 :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19440                 :             : 
   19441         [ -  + ]:         381 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19442                 :           0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   19443                 :           0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19444                 :           0 :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   19445                 :             : 
   19446                 :         381 :     destroyPQExpBuffer(query);
   19447                 :         381 :     destroyPQExpBuffer(delqry);
   19448                 :         381 :     pg_free(qseqname);
   19449                 :         381 : }
   19450                 :             : 
   19451                 :             : /*
   19452                 :             :  * dumpSequenceData
   19453                 :             :  *    write the data of one user-defined sequence
   19454                 :             :  */
   19455                 :             : static void
   19456                 :         399 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   19457                 :             : {
   19458                 :         399 :     TableInfo  *tbinfo = tdinfo->tdtable;
   19459                 :             :     int64       last;
   19460                 :             :     bool        called;
   19461                 :             :     PQExpBuffer query;
   19462                 :             : 
   19463                 :             :     /* needn't bother if not dumping sequence data */
   19464   [ +  +  +  + ]:         399 :     if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
   19465                 :           1 :         return;
   19466                 :             : 
   19467                 :         398 :     query = createPQExpBuffer();
   19468                 :             : 
   19469                 :             :     /*
   19470                 :             :      * For versions >= 18, the sequence information is gathered in the sorted
   19471                 :             :      * array before any calls to dumpSequenceData().  See collectSequences()
   19472                 :             :      * for more information.
   19473                 :             :      *
   19474                 :             :      * For older versions, we have to query the sequence relations
   19475                 :             :      * individually.
   19476                 :             :      */
   19477         [ -  + ]:         398 :     if (fout->remoteVersion < 180000)
   19478                 :             :     {
   19479                 :             :         PGresult   *res;
   19480                 :             : 
   19481                 :           0 :         appendPQExpBuffer(query,
   19482                 :             :                           "SELECT last_value, is_called FROM %s",
   19483                 :           0 :                           fmtQualifiedDumpable(tbinfo));
   19484                 :             : 
   19485                 :           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19486                 :             : 
   19487         [ #  # ]:           0 :         if (PQntuples(res) != 1)
   19488                 :           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   19489                 :             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   19490                 :             :                               PQntuples(res)),
   19491                 :             :                      tbinfo->dobj.name, PQntuples(res));
   19492                 :             : 
   19493                 :           0 :         last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   19494                 :           0 :         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   19495                 :             : 
   19496                 :           0 :         PQclear(res);
   19497                 :             :     }
   19498                 :             :     else
   19499                 :             :     {
   19500                 :         398 :         SequenceItem key = {0};
   19501                 :             :         SequenceItem *entry;
   19502                 :             : 
   19503                 :             :         Assert(sequences);
   19504                 :             :         Assert(tbinfo->dobj.catId.oid);
   19505                 :             : 
   19506                 :         398 :         key.oid = tbinfo->dobj.catId.oid;
   19507                 :         398 :         entry = bsearch(&key, sequences, nsequences,
   19508                 :             :                         sizeof(SequenceItem), SequenceItemCmp);
   19509                 :             : 
   19510         [ -  + ]:         398 :         if (entry->null_seqtuple)
   19511                 :           0 :             pg_fatal("failed to get data for sequence \"%s\"; user may lack "
   19512                 :             :                      "SELECT privilege on the sequence or the sequence may "
   19513                 :             :                      "have been concurrently dropped",
   19514                 :             :                      tbinfo->dobj.name);
   19515                 :             : 
   19516                 :         398 :         last = entry->last_value;
   19517                 :         398 :         called = entry->is_called;
   19518                 :             :     }
   19519                 :             : 
   19520                 :         398 :     resetPQExpBuffer(query);
   19521                 :         398 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   19522                 :         398 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   19523         [ +  + ]:         398 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   19524                 :             :                       last, (called ? "true" : "false"));
   19525                 :             : 
   19526         [ +  - ]:         398 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   19527                 :         398 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   19528                 :         398 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   19529                 :             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19530                 :             :                                   .owner = tbinfo->rolname,
   19531                 :             :                                   .description = "SEQUENCE SET",
   19532                 :             :                                   .section = SECTION_DATA,
   19533                 :             :                                   .createStmt = query->data,
   19534                 :             :                                   .deps = &(tbinfo->dobj.dumpId),
   19535                 :             :                                   .nDeps = 1));
   19536                 :             : 
   19537                 :         398 :     destroyPQExpBuffer(query);
   19538                 :             : }
   19539                 :             : 
   19540                 :             : /*
   19541                 :             :  * dumpTrigger
   19542                 :             :  *    write the declaration of one user-defined table trigger
   19543                 :             :  */
   19544                 :             : static void
   19545                 :         535 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   19546                 :             : {
   19547                 :         535 :     DumpOptions *dopt = fout->dopt;
   19548                 :         535 :     TableInfo  *tbinfo = tginfo->tgtable;
   19549                 :             :     PQExpBuffer query;
   19550                 :             :     PQExpBuffer delqry;
   19551                 :             :     PQExpBuffer trigprefix;
   19552                 :             :     PQExpBuffer trigidentity;
   19553                 :             :     char       *qtabname;
   19554                 :             :     char       *tag;
   19555                 :             : 
   19556                 :             :     /* Do nothing if not dumping schema */
   19557         [ +  + ]:         535 :     if (!dopt->dumpSchema)
   19558                 :          33 :         return;
   19559                 :             : 
   19560                 :         502 :     query = createPQExpBuffer();
   19561                 :         502 :     delqry = createPQExpBuffer();
   19562                 :         502 :     trigprefix = createPQExpBuffer();
   19563                 :         502 :     trigidentity = createPQExpBuffer();
   19564                 :             : 
   19565                 :         502 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19566                 :             : 
   19567                 :         502 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   19568                 :         502 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   19569                 :             : 
   19570                 :         502 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   19571                 :         502 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   19572                 :             : 
   19573                 :             :     /* Triggers can depend on extensions */
   19574                 :         502 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   19575                 :             :                                 "pg_catalog.pg_trigger", "TRIGGER",
   19576                 :         502 :                                 trigidentity->data);
   19577                 :             : 
   19578         [ +  + ]:         502 :     if (tginfo->tgispartition)
   19579                 :             :     {
   19580                 :             :         Assert(tbinfo->ispartition);
   19581                 :             : 
   19582                 :             :         /*
   19583                 :             :          * Partition triggers only appear here because their 'tgenabled' flag
   19584                 :             :          * differs from its parent's.  The trigger is created already, so
   19585                 :             :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   19586                 :             :          * DROP query too, so that pg_dump --create does not cause errors.)
   19587                 :             :          */
   19588                 :         115 :         resetPQExpBuffer(query);
   19589                 :         115 :         resetPQExpBuffer(delqry);
   19590                 :         115 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19591         [ -  + ]:         115 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19592                 :         115 :                           fmtQualifiedDumpable(tbinfo));
   19593   [ +  -  +  +  :         115 :         switch (tginfo->tgenabled)
                      - ]
   19594                 :             :         {
   19595                 :          40 :             case 'f':
   19596                 :             :             case 'D':
   19597                 :          40 :                 appendPQExpBufferStr(query, "DISABLE");
   19598                 :          40 :                 break;
   19599                 :           0 :             case 't':
   19600                 :             :             case 'O':
   19601                 :           0 :                 appendPQExpBufferStr(query, "ENABLE");
   19602                 :           0 :                 break;
   19603                 :          35 :             case 'R':
   19604                 :          35 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19605                 :          35 :                 break;
   19606                 :          40 :             case 'A':
   19607                 :          40 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19608                 :          40 :                 break;
   19609                 :             :         }
   19610                 :         115 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19611                 :         115 :                           fmtId(tginfo->dobj.name));
   19612                 :             :     }
   19613   [ +  -  -  + ]:         387 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   19614                 :             :     {
   19615                 :           0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   19616         [ #  # ]:           0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   19617                 :           0 :                           fmtQualifiedDumpable(tbinfo));
   19618   [ #  #  #  # ]:           0 :         switch (tginfo->tgenabled)
   19619                 :             :         {
   19620                 :           0 :             case 'D':
   19621                 :             :             case 'f':
   19622                 :           0 :                 appendPQExpBufferStr(query, "DISABLE");
   19623                 :           0 :                 break;
   19624                 :           0 :             case 'A':
   19625                 :           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19626                 :           0 :                 break;
   19627                 :           0 :             case 'R':
   19628                 :           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19629                 :           0 :                 break;
   19630                 :           0 :             default:
   19631                 :           0 :                 appendPQExpBufferStr(query, "ENABLE");
   19632                 :           0 :                 break;
   19633                 :             :         }
   19634                 :           0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   19635                 :           0 :                           fmtId(tginfo->dobj.name));
   19636                 :             :     }
   19637                 :             : 
   19638                 :         502 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   19639                 :         502 :                       fmtId(tginfo->dobj.name));
   19640                 :             : 
   19641                 :         502 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   19642                 :             : 
   19643         [ +  - ]:         502 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19644                 :         502 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   19645                 :         502 :                      ARCHIVE_OPTS(.tag = tag,
   19646                 :             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19647                 :             :                                   .owner = tbinfo->rolname,
   19648                 :             :                                   .description = "TRIGGER",
   19649                 :             :                                   .section = SECTION_POST_DATA,
   19650                 :             :                                   .createStmt = query->data,
   19651                 :             :                                   .dropStmt = delqry->data));
   19652                 :             : 
   19653         [ -  + ]:         502 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19654                 :           0 :         dumpComment(fout, trigprefix->data, qtabname,
   19655                 :           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   19656                 :           0 :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   19657                 :             : 
   19658                 :         502 :     pfree(tag);
   19659                 :         502 :     destroyPQExpBuffer(query);
   19660                 :         502 :     destroyPQExpBuffer(delqry);
   19661                 :         502 :     destroyPQExpBuffer(trigprefix);
   19662                 :         502 :     destroyPQExpBuffer(trigidentity);
   19663                 :         502 :     pg_free(qtabname);
   19664                 :             : }
   19665                 :             : 
   19666                 :             : /*
   19667                 :             :  * dumpEventTrigger
   19668                 :             :  *    write the declaration of one user-defined event trigger
   19669                 :             :  */
   19670                 :             : static void
   19671                 :          44 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   19672                 :             : {
   19673                 :          44 :     DumpOptions *dopt = fout->dopt;
   19674                 :             :     PQExpBuffer query;
   19675                 :             :     PQExpBuffer delqry;
   19676                 :             :     char       *qevtname;
   19677                 :             : 
   19678                 :             :     /* Do nothing if not dumping schema */
   19679         [ +  + ]:          44 :     if (!dopt->dumpSchema)
   19680                 :           6 :         return;
   19681                 :             : 
   19682                 :          38 :     query = createPQExpBuffer();
   19683                 :          38 :     delqry = createPQExpBuffer();
   19684                 :             : 
   19685                 :          38 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   19686                 :             : 
   19687                 :          38 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   19688                 :          38 :     appendPQExpBufferStr(query, qevtname);
   19689                 :          38 :     appendPQExpBufferStr(query, " ON ");
   19690                 :          38 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   19691                 :             : 
   19692         [ +  + ]:          38 :     if (strcmp("", evtinfo->evttags) != 0)
   19693                 :             :     {
   19694                 :           5 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   19695                 :           5 :         appendPQExpBufferStr(query, evtinfo->evttags);
   19696                 :           5 :         appendPQExpBufferChar(query, ')');
   19697                 :             :     }
   19698                 :             : 
   19699                 :          38 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   19700                 :          38 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   19701                 :          38 :     appendPQExpBufferStr(query, "();\n");
   19702                 :             : 
   19703         [ -  + ]:          38 :     if (evtinfo->evtenabled != 'O')
   19704                 :             :     {
   19705                 :           0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   19706                 :             :                           qevtname);
   19707   [ #  #  #  # ]:           0 :         switch (evtinfo->evtenabled)
   19708                 :             :         {
   19709                 :           0 :             case 'D':
   19710                 :           0 :                 appendPQExpBufferStr(query, "DISABLE");
   19711                 :           0 :                 break;
   19712                 :           0 :             case 'A':
   19713                 :           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   19714                 :           0 :                 break;
   19715                 :           0 :             case 'R':
   19716                 :           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   19717                 :           0 :                 break;
   19718                 :           0 :             default:
   19719                 :           0 :                 appendPQExpBufferStr(query, "ENABLE");
   19720                 :           0 :                 break;
   19721                 :             :         }
   19722                 :           0 :         appendPQExpBufferStr(query, ";\n");
   19723                 :             :     }
   19724                 :             : 
   19725                 :          38 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   19726                 :             :                       qevtname);
   19727                 :             : 
   19728         [ +  + ]:          38 :     if (dopt->binary_upgrade)
   19729                 :           2 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   19730                 :             :                                         "EVENT TRIGGER", qevtname, NULL);
   19731                 :             : 
   19732         [ +  - ]:          38 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19733                 :          38 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   19734                 :          38 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   19735                 :             :                                   .owner = evtinfo->evtowner,
   19736                 :             :                                   .description = "EVENT TRIGGER",
   19737                 :             :                                   .section = SECTION_POST_DATA,
   19738                 :             :                                   .createStmt = query->data,
   19739                 :             :                                   .dropStmt = delqry->data));
   19740                 :             : 
   19741         [ -  + ]:          38 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19742                 :           0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   19743                 :           0 :                     NULL, evtinfo->evtowner,
   19744                 :           0 :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   19745                 :             : 
   19746         [ -  + ]:          38 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   19747                 :           0 :         dumpSecLabel(fout, "EVENT TRIGGER", qevtname,
   19748                 :           0 :                      NULL, evtinfo->evtowner,
   19749                 :           0 :                      evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   19750                 :             : 
   19751                 :          38 :     destroyPQExpBuffer(query);
   19752                 :          38 :     destroyPQExpBuffer(delqry);
   19753                 :          38 :     pg_free(qevtname);
   19754                 :             : }
   19755                 :             : 
   19756                 :             : /*
   19757                 :             :  * dumpRule
   19758                 :             :  *      Dump a rule
   19759                 :             :  */
   19760                 :             : static void
   19761                 :        1197 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   19762                 :             : {
   19763                 :        1197 :     DumpOptions *dopt = fout->dopt;
   19764                 :        1197 :     TableInfo  *tbinfo = rinfo->ruletable;
   19765                 :             :     bool        is_view;
   19766                 :             :     PQExpBuffer query;
   19767                 :             :     PQExpBuffer cmd;
   19768                 :             :     PQExpBuffer delcmd;
   19769                 :             :     PQExpBuffer ruleprefix;
   19770                 :             :     char       *qtabname;
   19771                 :             :     PGresult   *res;
   19772                 :             :     char       *tag;
   19773                 :             : 
   19774                 :             :     /* Do nothing if not dumping schema */
   19775         [ +  + ]:        1197 :     if (!dopt->dumpSchema)
   19776                 :          70 :         return;
   19777                 :             : 
   19778                 :             :     /*
   19779                 :             :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   19780                 :             :      * we do not want to dump it as a separate object.
   19781                 :             :      */
   19782         [ +  + ]:        1127 :     if (!rinfo->separate)
   19783                 :         916 :         return;
   19784                 :             : 
   19785                 :             :     /*
   19786                 :             :      * If it's an ON SELECT rule, we want to print it as a view definition,
   19787                 :             :      * instead of a rule.
   19788                 :             :      */
   19789   [ +  +  +  - ]:         211 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   19790                 :             : 
   19791                 :         211 :     query = createPQExpBuffer();
   19792                 :         211 :     cmd = createPQExpBuffer();
   19793                 :         211 :     delcmd = createPQExpBuffer();
   19794                 :         211 :     ruleprefix = createPQExpBuffer();
   19795                 :             : 
   19796                 :         211 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   19797                 :             : 
   19798         [ +  + ]:         211 :     if (is_view)
   19799                 :             :     {
   19800                 :             :         PQExpBuffer result;
   19801                 :             : 
   19802                 :             :         /*
   19803                 :             :          * We need OR REPLACE here because we'll be replacing a dummy view.
   19804                 :             :          * Otherwise this should look largely like the regular view dump code.
   19805                 :             :          */
   19806                 :          10 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   19807                 :          10 :                           fmtQualifiedDumpable(tbinfo));
   19808         [ -  + ]:          10 :         if (nonemptyReloptions(tbinfo->reloptions))
   19809                 :             :         {
   19810                 :           0 :             appendPQExpBufferStr(cmd, " WITH (");
   19811                 :           0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   19812                 :           0 :             appendPQExpBufferChar(cmd, ')');
   19813                 :             :         }
   19814                 :          10 :         result = createViewAsClause(fout, tbinfo);
   19815                 :          10 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   19816                 :          10 :         destroyPQExpBuffer(result);
   19817         [ -  + ]:          10 :         if (tbinfo->checkoption != NULL)
   19818                 :           0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   19819                 :             :                               tbinfo->checkoption);
   19820                 :          10 :         appendPQExpBufferStr(cmd, ";\n");
   19821                 :             :     }
   19822                 :             :     else
   19823                 :             :     {
   19824                 :             :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   19825                 :         201 :         appendPQExpBuffer(query,
   19826                 :             :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   19827                 :         201 :                           rinfo->dobj.catId.oid);
   19828                 :             : 
   19829                 :         201 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19830                 :             : 
   19831         [ -  + ]:         201 :         if (PQntuples(res) != 1)
   19832                 :           0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   19833                 :             :                      rinfo->dobj.name, tbinfo->dobj.name);
   19834                 :             : 
   19835                 :         201 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   19836                 :             : 
   19837                 :         201 :         PQclear(res);
   19838                 :             :     }
   19839                 :             : 
   19840                 :             :     /*
   19841                 :             :      * Add the command to alter the rules replication firing semantics if it
   19842                 :             :      * differs from the default.
   19843                 :             :      */
   19844         [ +  + ]:         211 :     if (rinfo->ev_enabled != 'O')
   19845                 :             :     {
   19846                 :          15 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   19847   [ -  -  +  - ]:          15 :         switch (rinfo->ev_enabled)
   19848                 :             :         {
   19849                 :           0 :             case 'A':
   19850                 :           0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   19851                 :           0 :                                   fmtId(rinfo->dobj.name));
   19852                 :           0 :                 break;
   19853                 :           0 :             case 'R':
   19854                 :           0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   19855                 :           0 :                                   fmtId(rinfo->dobj.name));
   19856                 :           0 :                 break;
   19857                 :          15 :             case 'D':
   19858                 :          15 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   19859                 :          15 :                                   fmtId(rinfo->dobj.name));
   19860                 :          15 :                 break;
   19861                 :             :         }
   19862                 :             :     }
   19863                 :             : 
   19864         [ +  + ]:         211 :     if (is_view)
   19865                 :             :     {
   19866                 :             :         /*
   19867                 :             :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   19868                 :             :          * REPLACE VIEW to replace the rule with something with minimal
   19869                 :             :          * dependencies.
   19870                 :             :          */
   19871                 :             :         PQExpBuffer result;
   19872                 :             : 
   19873                 :          10 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   19874                 :          10 :                           fmtQualifiedDumpable(tbinfo));
   19875                 :          10 :         result = createDummyViewAsClause(fout, tbinfo);
   19876                 :          10 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   19877                 :          10 :         destroyPQExpBuffer(result);
   19878                 :             :     }
   19879                 :             :     else
   19880                 :             :     {
   19881                 :         201 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   19882                 :         201 :                           fmtId(rinfo->dobj.name));
   19883                 :         201 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   19884                 :         201 :                           fmtQualifiedDumpable(tbinfo));
   19885                 :             :     }
   19886                 :             : 
   19887                 :         211 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   19888                 :         211 :                       fmtId(rinfo->dobj.name));
   19889                 :             : 
   19890                 :         211 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   19891                 :             : 
   19892         [ +  - ]:         211 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   19893                 :         211 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   19894                 :         211 :                      ARCHIVE_OPTS(.tag = tag,
   19895                 :             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   19896                 :             :                                   .owner = tbinfo->rolname,
   19897                 :             :                                   .description = "RULE",
   19898                 :             :                                   .section = SECTION_POST_DATA,
   19899                 :             :                                   .createStmt = cmd->data,
   19900                 :             :                                   .dropStmt = delcmd->data));
   19901                 :             : 
   19902                 :             :     /* Dump rule comments */
   19903         [ -  + ]:         211 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   19904                 :           0 :         dumpComment(fout, ruleprefix->data, qtabname,
   19905                 :           0 :                     tbinfo->dobj.namespace->dobj.name,
   19906                 :             :                     tbinfo->rolname,
   19907                 :           0 :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   19908                 :             : 
   19909                 :         211 :     pfree(tag);
   19910                 :         211 :     destroyPQExpBuffer(query);
   19911                 :         211 :     destroyPQExpBuffer(cmd);
   19912                 :         211 :     destroyPQExpBuffer(delcmd);
   19913                 :         211 :     destroyPQExpBuffer(ruleprefix);
   19914                 :         211 :     pg_free(qtabname);
   19915                 :             : }
   19916                 :             : 
   19917                 :             : /*
   19918                 :             :  * getExtensionMembership --- obtain extension membership data
   19919                 :             :  *
   19920                 :             :  * We need to identify objects that are extension members as soon as they're
   19921                 :             :  * loaded, so that we can correctly determine whether they need to be dumped.
   19922                 :             :  * Generally speaking, extension member objects will get marked as *not* to
   19923                 :             :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   19924                 :             :  * command.  However, in binary upgrade mode we still need to dump the members
   19925                 :             :  * individually.
   19926                 :             :  */
   19927                 :             : void
   19928                 :         192 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   19929                 :             :                        int numExtensions)
   19930                 :             : {
   19931                 :             :     PQExpBuffer query;
   19932                 :             :     PGresult   *res;
   19933                 :             :     int         ntups,
   19934                 :             :                 i;
   19935                 :             :     int         i_classid,
   19936                 :             :                 i_objid,
   19937                 :             :                 i_refobjid;
   19938                 :             :     ExtensionInfo *ext;
   19939                 :             : 
   19940                 :             :     /* Nothing to do if no extensions */
   19941         [ -  + ]:         192 :     if (numExtensions == 0)
   19942                 :           0 :         return;
   19943                 :             : 
   19944                 :         192 :     query = createPQExpBuffer();
   19945                 :             : 
   19946                 :             :     /* refclassid constraint is redundant but may speed the search */
   19947                 :         192 :     appendPQExpBufferStr(query, "SELECT "
   19948                 :             :                          "classid, objid, refobjid "
   19949                 :             :                          "FROM pg_depend "
   19950                 :             :                          "WHERE refclassid = 'pg_extension'::regclass "
   19951                 :             :                          "AND deptype = 'e' "
   19952                 :             :                          "ORDER BY 3");
   19953                 :             : 
   19954                 :         192 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19955                 :             : 
   19956                 :         192 :     ntups = PQntuples(res);
   19957                 :             : 
   19958                 :         192 :     i_classid = PQfnumber(res, "classid");
   19959                 :         192 :     i_objid = PQfnumber(res, "objid");
   19960                 :         192 :     i_refobjid = PQfnumber(res, "refobjid");
   19961                 :             : 
   19962                 :             :     /*
   19963                 :             :      * Since we ordered the SELECT by referenced ID, we can expect that
   19964                 :             :      * multiple entries for the same extension will appear together; this
   19965                 :             :      * saves on searches.
   19966                 :             :      */
   19967                 :         192 :     ext = NULL;
   19968                 :             : 
   19969         [ +  + ]:        1566 :     for (i = 0; i < ntups; i++)
   19970                 :             :     {
   19971                 :             :         CatalogId   objId;
   19972                 :             :         Oid         extId;
   19973                 :             : 
   19974                 :        1374 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   19975                 :        1374 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   19976                 :        1374 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   19977                 :             : 
   19978         [ +  + ]:        1374 :         if (ext == NULL ||
   19979         [ +  + ]:        1182 :             ext->dobj.catId.oid != extId)
   19980                 :         223 :             ext = findExtensionByOid(extId);
   19981                 :             : 
   19982         [ -  + ]:        1374 :         if (ext == NULL)
   19983                 :             :         {
   19984                 :             :             /* shouldn't happen */
   19985                 :           0 :             pg_log_warning("could not find referenced extension %u", extId);
   19986                 :           0 :             continue;
   19987                 :             :         }
   19988                 :             : 
   19989                 :        1374 :         recordExtensionMembership(objId, ext);
   19990                 :             :     }
   19991                 :             : 
   19992                 :         192 :     PQclear(res);
   19993                 :             : 
   19994                 :         192 :     destroyPQExpBuffer(query);
   19995                 :             : }
   19996                 :             : 
   19997                 :             : /*
   19998                 :             :  * processExtensionTables --- deal with extension configuration tables
   19999                 :             :  *
   20000                 :             :  * There are two parts to this process:
   20001                 :             :  *
   20002                 :             :  * 1. Identify and create dump records for extension configuration tables.
   20003                 :             :  *
   20004                 :             :  *    Extensions can mark tables as "configuration", which means that the user
   20005                 :             :  *    is able and expected to modify those tables after the extension has been
   20006                 :             :  *    loaded.  For these tables, we dump out only the data- the structure is
   20007                 :             :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   20008                 :             :  *    foreign keys, which brings us to-
   20009                 :             :  *
   20010                 :             :  * 2. Record FK dependencies between configuration tables.
   20011                 :             :  *
   20012                 :             :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   20013                 :             :  *    the data is loaded, we have to work out what the best order for reloading
   20014                 :             :  *    the data is, to avoid FK violations when the tables are restored.  This is
   20015                 :             :  *    not perfect- we can't handle circular dependencies and if any exist they
   20016                 :             :  *    will cause an invalid dump to be produced (though at least all of the data
   20017                 :             :  *    is included for a user to manually restore).  This is currently documented
   20018                 :             :  *    but perhaps we can provide a better solution in the future.
   20019                 :             :  */
   20020                 :             : void
   20021                 :         191 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   20022                 :             :                        int numExtensions)
   20023                 :             : {
   20024                 :         191 :     DumpOptions *dopt = fout->dopt;
   20025                 :             :     PQExpBuffer query;
   20026                 :             :     PGresult   *res;
   20027                 :             :     int         ntups,
   20028                 :             :                 i;
   20029                 :             :     int         i_conrelid,
   20030                 :             :                 i_confrelid;
   20031                 :             : 
   20032                 :             :     /* Nothing to do if no extensions */
   20033         [ -  + ]:         191 :     if (numExtensions == 0)
   20034                 :           0 :         return;
   20035                 :             : 
   20036                 :             :     /*
   20037                 :             :      * Identify extension configuration tables and create TableDataInfo
   20038                 :             :      * objects for them, ensuring their data will be dumped even though the
   20039                 :             :      * tables themselves won't be.
   20040                 :             :      *
   20041                 :             :      * Note that we create TableDataInfo objects even in schema-only mode, ie,
   20042                 :             :      * user data in a configuration table is treated like schema data. This
   20043                 :             :      * seems appropriate since system data in a config table would get
   20044                 :             :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   20045                 :             :      * list of extensions to be included, none of its data is dumped.
   20046                 :             :      */
   20047         [ +  + ]:         413 :     for (i = 0; i < numExtensions; i++)
   20048                 :             :     {
   20049                 :         222 :         ExtensionInfo *curext = &(extinfo[i]);
   20050                 :         222 :         char       *extconfig = curext->extconfig;
   20051                 :         222 :         char       *extcondition = curext->extcondition;
   20052                 :         222 :         char      **extconfigarray = NULL;
   20053                 :         222 :         char      **extconditionarray = NULL;
   20054                 :         222 :         int         nconfigitems = 0;
   20055                 :         222 :         int         nconditionitems = 0;
   20056                 :             : 
   20057                 :             :         /*
   20058                 :             :          * Check if this extension is listed as to include in the dump.  If
   20059                 :             :          * not, any table data associated with it is discarded.
   20060                 :             :          */
   20061         [ +  + ]:         222 :         if (extension_include_oids.head != NULL &&
   20062         [ +  + ]:           8 :             !simple_oid_list_member(&extension_include_oids,
   20063                 :             :                                     curext->dobj.catId.oid))
   20064                 :           6 :             continue;
   20065                 :             : 
   20066                 :             :         /*
   20067                 :             :          * Check if this extension is listed as to exclude in the dump.  If
   20068                 :             :          * yes, any table data associated with it is discarded.
   20069                 :             :          */
   20070   [ +  +  +  + ]:         222 :         if (extension_exclude_oids.head != NULL &&
   20071                 :           4 :             simple_oid_list_member(&extension_exclude_oids,
   20072                 :             :                                    curext->dobj.catId.oid))
   20073                 :           2 :             continue;
   20074                 :             : 
   20075   [ +  +  -  + ]:         216 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   20076                 :             :         {
   20077                 :             :             int         j;
   20078                 :             : 
   20079         [ -  + ]:          20 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   20080                 :           0 :                 pg_fatal("could not parse %s array", "extconfig");
   20081         [ -  + ]:          20 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   20082                 :           0 :                 pg_fatal("could not parse %s array", "extcondition");
   20083         [ -  + ]:          20 :             if (nconfigitems != nconditionitems)
   20084                 :           0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   20085                 :             : 
   20086         [ +  + ]:          60 :             for (j = 0; j < nconfigitems; j++)
   20087                 :             :             {
   20088                 :             :                 TableInfo  *configtbl;
   20089                 :          40 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   20090                 :          40 :                 bool        dumpobj =
   20091                 :          40 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   20092                 :             : 
   20093                 :          40 :                 configtbl = findTableByOid(configtbloid);
   20094         [ -  + ]:          40 :                 if (configtbl == NULL)
   20095                 :           0 :                     continue;
   20096                 :             : 
   20097                 :             :                 /*
   20098                 :             :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   20099                 :             :                  * unless the table or its schema is explicitly included
   20100                 :             :                  */
   20101         [ +  + ]:          40 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   20102                 :             :                 {
   20103                 :             :                     /* check table explicitly requested */
   20104   [ -  +  -  - ]:           2 :                     if (table_include_oids.head != NULL &&
   20105                 :           0 :                         simple_oid_list_member(&table_include_oids,
   20106                 :             :                                                configtbloid))
   20107                 :           0 :                         dumpobj = true;
   20108                 :             : 
   20109                 :             :                     /* check table's schema explicitly requested */
   20110         [ +  - ]:           2 :                     if (configtbl->dobj.namespace->dobj.dump &
   20111                 :             :                         DUMP_COMPONENT_DATA)
   20112                 :           2 :                         dumpobj = true;
   20113                 :             :                 }
   20114                 :             : 
   20115                 :             :                 /* check table excluded by an exclusion switch */
   20116   [ +  +  +  + ]:          44 :                 if (table_exclude_oids.head != NULL &&
   20117                 :           4 :                     simple_oid_list_member(&table_exclude_oids,
   20118                 :             :                                            configtbloid))
   20119                 :           1 :                     dumpobj = false;
   20120                 :             : 
   20121                 :             :                 /* check schema excluded by an exclusion switch */
   20122         [ -  + ]:          40 :                 if (simple_oid_list_member(&schema_exclude_oids,
   20123                 :          40 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   20124                 :           0 :                     dumpobj = false;
   20125                 :             : 
   20126         [ +  + ]:          40 :                 if (dumpobj)
   20127                 :             :                 {
   20128                 :          39 :                     makeTableDataInfo(dopt, configtbl);
   20129         [ +  - ]:          39 :                     if (configtbl->dataObj != NULL)
   20130                 :             :                     {
   20131         [ -  + ]:          39 :                         if (strlen(extconditionarray[j]) > 0)
   20132                 :           0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   20133                 :             :                     }
   20134                 :             :                 }
   20135                 :             :             }
   20136                 :             :         }
   20137         [ +  + ]:         216 :         if (extconfigarray)
   20138                 :          20 :             free(extconfigarray);
   20139         [ +  + ]:         216 :         if (extconditionarray)
   20140                 :          20 :             free(extconditionarray);
   20141                 :             :     }
   20142                 :             : 
   20143                 :             :     /*
   20144                 :             :      * Now that all the TableDataInfo objects have been created for all the
   20145                 :             :      * extensions, check their FK dependencies and register them to try and
   20146                 :             :      * dump the data out in an order that they can be restored in.
   20147                 :             :      *
   20148                 :             :      * Note that this is not a problem for user tables as their FKs are
   20149                 :             :      * recreated after the data has been loaded.
   20150                 :             :      */
   20151                 :             : 
   20152                 :         191 :     query = createPQExpBuffer();
   20153                 :             : 
   20154                 :         191 :     printfPQExpBuffer(query,
   20155                 :             :                       "SELECT conrelid, confrelid "
   20156                 :             :                       "FROM pg_constraint "
   20157                 :             :                       "JOIN pg_depend ON (objid = confrelid) "
   20158                 :             :                       "WHERE contype = 'f' "
   20159                 :             :                       "AND refclassid = 'pg_extension'::regclass "
   20160                 :             :                       "AND classid = 'pg_class'::regclass;");
   20161                 :             : 
   20162                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20163                 :         191 :     ntups = PQntuples(res);
   20164                 :             : 
   20165                 :         191 :     i_conrelid = PQfnumber(res, "conrelid");
   20166                 :         191 :     i_confrelid = PQfnumber(res, "confrelid");
   20167                 :             : 
   20168                 :             :     /* Now get the dependencies and register them */
   20169         [ -  + ]:         191 :     for (i = 0; i < ntups; i++)
   20170                 :             :     {
   20171                 :             :         Oid         conrelid,
   20172                 :             :                     confrelid;
   20173                 :             :         TableInfo  *reftable,
   20174                 :             :                    *contable;
   20175                 :             : 
   20176                 :           0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   20177                 :           0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   20178                 :           0 :         contable = findTableByOid(conrelid);
   20179                 :           0 :         reftable = findTableByOid(confrelid);
   20180                 :             : 
   20181         [ #  # ]:           0 :         if (reftable == NULL ||
   20182   [ #  #  #  # ]:           0 :             reftable->dataObj == NULL ||
   20183                 :           0 :             contable == NULL ||
   20184         [ #  # ]:           0 :             contable->dataObj == NULL)
   20185                 :           0 :             continue;
   20186                 :             : 
   20187                 :             :         /*
   20188                 :             :          * Make referencing TABLE_DATA object depend on the referenced table's
   20189                 :             :          * TABLE_DATA object.
   20190                 :             :          */
   20191                 :           0 :         addObjectDependency(&contable->dataObj->dobj,
   20192                 :           0 :                             reftable->dataObj->dobj.dumpId);
   20193                 :             :     }
   20194                 :         191 :     PQclear(res);
   20195                 :         191 :     destroyPQExpBuffer(query);
   20196                 :             : }
   20197                 :             : 
   20198                 :             : /*
   20199                 :             :  * getDependencies --- obtain available dependency data
   20200                 :             :  */
   20201                 :             : static void
   20202                 :         191 : getDependencies(Archive *fout)
   20203                 :             : {
   20204                 :             :     PQExpBuffer query;
   20205                 :             :     PGresult   *res;
   20206                 :             :     int         ntups,
   20207                 :             :                 i;
   20208                 :             :     int         i_classid,
   20209                 :             :                 i_objid,
   20210                 :             :                 i_refclassid,
   20211                 :             :                 i_refobjid,
   20212                 :             :                 i_deptype;
   20213                 :             :     DumpableObject *dobj,
   20214                 :             :                *refdobj;
   20215                 :             : 
   20216                 :         191 :     pg_log_info("reading dependency data");
   20217                 :             : 
   20218                 :         191 :     query = createPQExpBuffer();
   20219                 :             : 
   20220                 :             :     /*
   20221                 :             :      * Messy query to collect the dependency data we need.  Note that we
   20222                 :             :      * ignore the sub-object column, so that dependencies of or on a column
   20223                 :             :      * look the same as dependencies of or on a whole table.
   20224                 :             :      *
   20225                 :             :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   20226                 :             :      * already processed by getExtensionMembership.
   20227                 :             :      */
   20228                 :         191 :     appendPQExpBufferStr(query, "SELECT "
   20229                 :             :                          "classid, objid, refclassid, refobjid, deptype "
   20230                 :             :                          "FROM pg_depend "
   20231                 :             :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   20232                 :             : 
   20233                 :             :     /*
   20234                 :             :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   20235                 :             :      * have to translate their dependencies into dependencies of their parent
   20236                 :             :      * opfamily.  Ignore internal dependencies though, as those will point to
   20237                 :             :      * their parent opclass, which we needn't consider here (and if we did,
   20238                 :             :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   20239                 :             :      * entries will have dependencies on their parent opfamily, which we
   20240                 :             :      * should drop since they'd likewise become useless self-dependencies.
   20241                 :             :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   20242                 :             :      */
   20243                 :         191 :     appendPQExpBufferStr(query, "UNION ALL\n"
   20244                 :             :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   20245                 :             :                          "FROM pg_depend d, pg_amop o "
   20246                 :             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20247                 :             :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   20248                 :             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   20249                 :             : 
   20250                 :             :     /* Likewise for pg_amproc entries */
   20251                 :         191 :     appendPQExpBufferStr(query, "UNION ALL\n"
   20252                 :             :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   20253                 :             :                          "FROM pg_depend d, pg_amproc p "
   20254                 :             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20255                 :             :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   20256                 :             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   20257                 :             : 
   20258                 :             :     /*
   20259                 :             :      * Translate dependencies of pg_propgraph_element entries into
   20260                 :             :      * dependencies of their parent pg_class entry.
   20261                 :             :      */
   20262         [ +  - ]:         191 :     if (fout->remoteVersion >= 190000)
   20263                 :         191 :         appendPQExpBufferStr(query, "UNION ALL\n"
   20264                 :             :                              "SELECT 'pg_class'::regclass AS classid, pgepgid AS objid, refclassid, refobjid, deptype "
   20265                 :             :                              "FROM pg_depend d, pg_propgraph_element pge "
   20266                 :             :                              "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   20267                 :             :                              "classid = 'pg_propgraph_element'::regclass AND objid = pge.oid\n");
   20268                 :             : 
   20269                 :             :     /* Sort the output for efficiency below */
   20270                 :         191 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   20271                 :             : 
   20272                 :         191 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   20273                 :             : 
   20274                 :         191 :     ntups = PQntuples(res);
   20275                 :             : 
   20276                 :         191 :     i_classid = PQfnumber(res, "classid");
   20277                 :         191 :     i_objid = PQfnumber(res, "objid");
   20278                 :         191 :     i_refclassid = PQfnumber(res, "refclassid");
   20279                 :         191 :     i_refobjid = PQfnumber(res, "refobjid");
   20280                 :         191 :     i_deptype = PQfnumber(res, "deptype");
   20281                 :             : 
   20282                 :             :     /*
   20283                 :             :      * Since we ordered the SELECT by referencing ID, we can expect that
   20284                 :             :      * multiple entries for the same object will appear together; this saves
   20285                 :             :      * on searches.
   20286                 :             :      */
   20287                 :         191 :     dobj = NULL;
   20288                 :             : 
   20289         [ +  + ]:      462120 :     for (i = 0; i < ntups; i++)
   20290                 :             :     {
   20291                 :             :         CatalogId   objId;
   20292                 :             :         CatalogId   refobjId;
   20293                 :             :         char        deptype;
   20294                 :             : 
   20295                 :      461929 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   20296                 :      461929 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   20297                 :      461929 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   20298                 :      461929 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   20299                 :      461929 :         deptype = *(PQgetvalue(res, i, i_deptype));
   20300                 :             : 
   20301         [ +  + ]:      461929 :         if (dobj == NULL ||
   20302         [ +  + ]:      426743 :             dobj->catId.tableoid != objId.tableoid ||
   20303         [ +  + ]:      424638 :             dobj->catId.oid != objId.oid)
   20304                 :      204449 :             dobj = findObjectByCatalogId(objId);
   20305                 :             : 
   20306                 :             :         /*
   20307                 :             :          * Failure to find objects mentioned in pg_depend is not unexpected,
   20308                 :             :          * since for example we don't collect info about TOAST tables.
   20309                 :             :          */
   20310         [ +  + ]:      461929 :         if (dobj == NULL)
   20311                 :             :         {
   20312                 :             : #ifdef NOT_USED
   20313                 :             :             pg_log_warning("no referencing object %u %u",
   20314                 :             :                            objId.tableoid, objId.oid);
   20315                 :             : #endif
   20316                 :       36331 :             continue;
   20317                 :             :         }
   20318                 :             : 
   20319                 :      426927 :         refdobj = findObjectByCatalogId(refobjId);
   20320                 :             : 
   20321         [ +  + ]:      426927 :         if (refdobj == NULL)
   20322                 :             :         {
   20323                 :             : #ifdef NOT_USED
   20324                 :             :             pg_log_warning("no referenced object %u %u",
   20325                 :             :                            refobjId.tableoid, refobjId.oid);
   20326                 :             : #endif
   20327                 :        1329 :             continue;
   20328                 :             :         }
   20329                 :             : 
   20330                 :             :         /*
   20331                 :             :          * For 'x' dependencies, mark the object for later; we still add the
   20332                 :             :          * normal dependency, for possible ordering purposes.  Currently
   20333                 :             :          * pg_dump_sort.c knows to put extensions ahead of all object types
   20334                 :             :          * that could possibly depend on them, but this is safer.
   20335                 :             :          */
   20336         [ +  + ]:      425598 :         if (deptype == 'x')
   20337                 :          44 :             dobj->depends_on_ext = true;
   20338                 :             : 
   20339                 :             :         /*
   20340                 :             :          * Ordinarily, table rowtypes have implicit dependencies on their
   20341                 :             :          * tables.  However, for a composite type the implicit dependency goes
   20342                 :             :          * the other way in pg_depend; which is the right thing for DROP but
   20343                 :             :          * it doesn't produce the dependency ordering we need. So in that one
   20344                 :             :          * case, we reverse the direction of the dependency.
   20345                 :             :          */
   20346         [ +  + ]:      425598 :         if (deptype == 'i' &&
   20347         [ +  + ]:      119155 :             dobj->objType == DO_TABLE &&
   20348         [ +  + ]:        1304 :             refdobj->objType == DO_TYPE)
   20349                 :         185 :             addObjectDependency(refdobj, dobj->dumpId);
   20350                 :             :         else
   20351                 :             :             /* normal case */
   20352                 :      425413 :             addObjectDependency(dobj, refdobj->dumpId);
   20353                 :             :     }
   20354                 :             : 
   20355                 :         191 :     PQclear(res);
   20356                 :             : 
   20357                 :         191 :     destroyPQExpBuffer(query);
   20358                 :         191 : }
   20359                 :             : 
   20360                 :             : 
   20361                 :             : /*
   20362                 :             :  * createBoundaryObjects - create dummy DumpableObjects to represent
   20363                 :             :  * dump section boundaries.
   20364                 :             :  */
   20365                 :             : static DumpableObject *
   20366                 :         191 : createBoundaryObjects(void)
   20367                 :             : {
   20368                 :             :     DumpableObject *dobjs;
   20369                 :             : 
   20370                 :         191 :     dobjs = pg_malloc_array(DumpableObject, 2);
   20371                 :             : 
   20372                 :         191 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   20373                 :         191 :     dobjs[0].catId = nilCatalogId;
   20374                 :         191 :     AssignDumpId(dobjs + 0);
   20375                 :         191 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   20376                 :             : 
   20377                 :         191 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   20378                 :         191 :     dobjs[1].catId = nilCatalogId;
   20379                 :         191 :     AssignDumpId(dobjs + 1);
   20380                 :         191 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   20381                 :             : 
   20382                 :         191 :     return dobjs;
   20383                 :             : }
   20384                 :             : 
   20385                 :             : /*
   20386                 :             :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   20387                 :             :  * section boundaries.
   20388                 :             :  */
   20389                 :             : static void
   20390                 :         191 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   20391                 :             :                         DumpableObject *boundaryObjs)
   20392                 :             : {
   20393                 :         191 :     DumpableObject *preDataBound = boundaryObjs + 0;
   20394                 :         191 :     DumpableObject *postDataBound = boundaryObjs + 1;
   20395                 :             :     int         i;
   20396                 :             : 
   20397         [ +  + ]:      738561 :     for (i = 0; i < numObjs; i++)
   20398                 :             :     {
   20399                 :      738370 :         DumpableObject *dobj = dobjs[i];
   20400                 :             : 
   20401                 :             :         /*
   20402                 :             :          * The classification of object types here must match the SECTION_xxx
   20403                 :             :          * values assigned during subsequent ArchiveEntry calls!
   20404                 :             :          */
   20405   [ +  +  +  +  :      738370 :         switch (dobj->objType)
             +  +  +  +  
                      - ]
   20406                 :             :         {
   20407                 :      687214 :             case DO_NAMESPACE:
   20408                 :             :             case DO_EXTENSION:
   20409                 :             :             case DO_TYPE:
   20410                 :             :             case DO_SHELL_TYPE:
   20411                 :             :             case DO_FUNC:
   20412                 :             :             case DO_AGG:
   20413                 :             :             case DO_OPERATOR:
   20414                 :             :             case DO_ACCESS_METHOD:
   20415                 :             :             case DO_OPCLASS:
   20416                 :             :             case DO_OPFAMILY:
   20417                 :             :             case DO_COLLATION:
   20418                 :             :             case DO_CONVERSION:
   20419                 :             :             case DO_TABLE:
   20420                 :             :             case DO_TABLE_ATTACH:
   20421                 :             :             case DO_ATTRDEF:
   20422                 :             :             case DO_PROCLANG:
   20423                 :             :             case DO_CAST:
   20424                 :             :             case DO_DUMMY_TYPE:
   20425                 :             :             case DO_TSPARSER:
   20426                 :             :             case DO_TSDICT:
   20427                 :             :             case DO_TSTEMPLATE:
   20428                 :             :             case DO_TSCONFIG:
   20429                 :             :             case DO_FDW:
   20430                 :             :             case DO_FOREIGN_SERVER:
   20431                 :             :             case DO_TRANSFORM:
   20432                 :             :                 /* Pre-data objects: must come before the pre-data boundary */
   20433                 :      687214 :                 addObjectDependency(preDataBound, dobj->dumpId);
   20434                 :      687214 :                 break;
   20435                 :        5180 :             case DO_TABLE_DATA:
   20436                 :             :             case DO_SEQUENCE_SET:
   20437                 :             :             case DO_LARGE_OBJECT:
   20438                 :             :             case DO_LARGE_OBJECT_DATA:
   20439                 :             :                 /* Data objects: must come between the boundaries */
   20440                 :        5180 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20441                 :        5180 :                 addObjectDependency(postDataBound, dobj->dumpId);
   20442                 :        5180 :                 break;
   20443                 :        6350 :             case DO_INDEX:
   20444                 :             :             case DO_INDEX_ATTACH:
   20445                 :             :             case DO_STATSEXT:
   20446                 :             :             case DO_REFRESH_MATVIEW:
   20447                 :             :             case DO_TRIGGER:
   20448                 :             :             case DO_EVENT_TRIGGER:
   20449                 :             :             case DO_DEFAULT_ACL:
   20450                 :             :             case DO_POLICY:
   20451                 :             :             case DO_PUBLICATION:
   20452                 :             :             case DO_PUBLICATION_REL:
   20453                 :             :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   20454                 :             :             case DO_SUBSCRIPTION:
   20455                 :             :             case DO_SUBSCRIPTION_REL:
   20456                 :             :                 /* Post-data objects: must come after the post-data boundary */
   20457                 :        6350 :                 addObjectDependency(dobj, postDataBound->dumpId);
   20458                 :        6350 :                 break;
   20459                 :       32716 :             case DO_RULE:
   20460                 :             :                 /* Rules are post-data, but only if dumped separately */
   20461         [ +  + ]:       32716 :                 if (((RuleInfo *) dobj)->separate)
   20462                 :         655 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20463                 :       32716 :                 break;
   20464                 :        2844 :             case DO_CONSTRAINT:
   20465                 :             :             case DO_FK_CONSTRAINT:
   20466                 :             :                 /* Constraints are post-data, but only if dumped separately */
   20467         [ +  + ]:        2844 :                 if (((ConstraintInfo *) dobj)->separate)
   20468                 :        2090 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20469                 :        2844 :                 break;
   20470                 :         191 :             case DO_PRE_DATA_BOUNDARY:
   20471                 :             :                 /* nothing to do */
   20472                 :         191 :                 break;
   20473                 :         191 :             case DO_POST_DATA_BOUNDARY:
   20474                 :             :                 /* must come after the pre-data boundary */
   20475                 :         191 :                 addObjectDependency(dobj, preDataBound->dumpId);
   20476                 :         191 :                 break;
   20477                 :        3684 :             case DO_REL_STATS:
   20478                 :             :                 /* stats section varies by parent object type, DATA or POST */
   20479         [ +  + ]:        3684 :                 if (((RelStatsInfo *) dobj)->section == SECTION_DATA)
   20480                 :             :                 {
   20481                 :        2406 :                     addObjectDependency(dobj, preDataBound->dumpId);
   20482                 :        2406 :                     addObjectDependency(postDataBound, dobj->dumpId);
   20483                 :             :                 }
   20484                 :             :                 else
   20485                 :        1278 :                     addObjectDependency(dobj, postDataBound->dumpId);
   20486                 :        3684 :                 break;
   20487                 :             :         }
   20488                 :             :     }
   20489                 :         191 : }
   20490                 :             : 
   20491                 :             : 
   20492                 :             : /*
   20493                 :             :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   20494                 :             :  *
   20495                 :             :  * The raw dependency data obtained by getDependencies() is not terribly
   20496                 :             :  * useful in an archive dump, because in many cases there are dependency
   20497                 :             :  * chains linking through objects that don't appear explicitly in the dump.
   20498                 :             :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   20499                 :             :  * will depend on other objects --- but the rule will not appear as a separate
   20500                 :             :  * object in the dump.  We need to adjust the view's dependencies to include
   20501                 :             :  * whatever the rule depends on that is included in the dump.
   20502                 :             :  *
   20503                 :             :  * Just to make things more complicated, there are also "special" dependencies
   20504                 :             :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   20505                 :             :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   20506                 :             :  * its table.  In these cases we must leave the dependencies strictly as-is
   20507                 :             :  * even if they refer to not-to-be-dumped objects.
   20508                 :             :  *
   20509                 :             :  * To handle this, the convention is that "special" dependencies are created
   20510                 :             :  * during ArchiveEntry calls, and an archive TOC item that has any such
   20511                 :             :  * entries will not be touched here.  Otherwise, we recursively search the
   20512                 :             :  * DumpableObject data structures to build the correct dependencies for each
   20513                 :             :  * archive TOC item.
   20514                 :             :  */
   20515                 :             : static void
   20516                 :          63 : BuildArchiveDependencies(Archive *fout)
   20517                 :             : {
   20518                 :          63 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   20519                 :             :     TocEntry   *te;
   20520                 :             : 
   20521                 :             :     /* Scan all TOC entries in the archive */
   20522         [ +  + ]:        7867 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   20523                 :             :     {
   20524                 :             :         DumpableObject *dobj;
   20525                 :             :         DumpId     *dependencies;
   20526                 :             :         int         nDeps;
   20527                 :             :         int         allocDeps;
   20528                 :             : 
   20529                 :             :         /* No need to process entries that will not be dumped */
   20530         [ +  + ]:        7804 :         if (te->reqs == 0)
   20531                 :        3875 :             continue;
   20532                 :             :         /* Ignore entries that already have "special" dependencies */
   20533         [ +  + ]:        7796 :         if (te->nDeps > 0)
   20534                 :        3375 :             continue;
   20535                 :             :         /* Otherwise, look up the item's original DumpableObject, if any */
   20536                 :        4421 :         dobj = findObjectByDumpId(te->dumpId);
   20537         [ +  + ]:        4421 :         if (dobj == NULL)
   20538                 :         378 :             continue;
   20539                 :             :         /* No work if it has no dependencies */
   20540         [ +  + ]:        4043 :         if (dobj->nDeps <= 0)
   20541                 :         114 :             continue;
   20542                 :             :         /* Set up work array */
   20543                 :        3929 :         allocDeps = 64;
   20544                 :        3929 :         dependencies = pg_malloc_array(DumpId, allocDeps);
   20545                 :        3929 :         nDeps = 0;
   20546                 :             :         /* Recursively find all dumpable dependencies */
   20547                 :        3929 :         findDumpableDependencies(AH, dobj,
   20548                 :             :                                  &dependencies, &nDeps, &allocDeps);
   20549                 :             :         /* And save 'em ... */
   20550         [ +  + ]:        3929 :         if (nDeps > 0)
   20551                 :             :         {
   20552                 :        2993 :             dependencies = pg_realloc_array(dependencies, DumpId, nDeps);
   20553                 :        2993 :             te->dependencies = dependencies;
   20554                 :        2993 :             te->nDeps = nDeps;
   20555                 :             :         }
   20556                 :             :         else
   20557                 :         936 :             pg_free(dependencies);
   20558                 :             :     }
   20559                 :          63 : }
   20560                 :             : 
   20561                 :             : /* Recursive search subroutine for BuildArchiveDependencies */
   20562                 :             : static void
   20563                 :        9351 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   20564                 :             :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   20565                 :             : {
   20566                 :             :     int         i;
   20567                 :             : 
   20568                 :             :     /*
   20569                 :             :      * Ignore section boundary objects: if we search through them, we'll
   20570                 :             :      * report lots of bogus dependencies.
   20571                 :             :      */
   20572         [ +  + ]:        9351 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   20573         [ +  + ]:        9330 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   20574                 :        1677 :         return;
   20575                 :             : 
   20576         [ +  + ]:       19501 :     for (i = 0; i < dobj->nDeps; i++)
   20577                 :             :     {
   20578                 :       11827 :         DumpId      depid = dobj->dependencies[i];
   20579                 :             : 
   20580         [ +  + ]:       11827 :         if (TocIDRequired(AH, depid) != 0)
   20581                 :             :         {
   20582                 :             :             /* Object will be dumped, so just reference it as a dependency */
   20583         [ -  + ]:        6405 :             if (*nDeps >= *allocDeps)
   20584                 :             :             {
   20585                 :           0 :                 *allocDeps *= 2;
   20586                 :           0 :                 *dependencies = pg_realloc_array(*dependencies, DumpId, *allocDeps);
   20587                 :             :             }
   20588                 :        6405 :             (*dependencies)[*nDeps] = depid;
   20589                 :        6405 :             (*nDeps)++;
   20590                 :             :         }
   20591                 :             :         else
   20592                 :             :         {
   20593                 :             :             /*
   20594                 :             :              * Object will not be dumped, so recursively consider its deps. We
   20595                 :             :              * rely on the assumption that sortDumpableObjects already broke
   20596                 :             :              * any dependency loops, else we might recurse infinitely.
   20597                 :             :              */
   20598                 :        5422 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   20599                 :             : 
   20600         [ +  - ]:        5422 :             if (otherdobj)
   20601                 :        5422 :                 findDumpableDependencies(AH, otherdobj,
   20602                 :             :                                          dependencies, nDeps, allocDeps);
   20603                 :             :         }
   20604                 :             :     }
   20605                 :             : }
   20606                 :             : 
   20607                 :             : 
   20608                 :             : /*
   20609                 :             :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   20610                 :             :  * given type OID.
   20611                 :             :  *
   20612                 :             :  * This does not guarantee to schema-qualify the output, so it should not
   20613                 :             :  * be used to create the target object name for CREATE or ALTER commands.
   20614                 :             :  *
   20615                 :             :  * Note that the result is cached and must not be freed by the caller.
   20616                 :             :  */
   20617                 :             : static const char *
   20618                 :        2399 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   20619                 :             : {
   20620                 :             :     TypeInfo   *typeInfo;
   20621                 :             :     char       *result;
   20622                 :             :     PQExpBuffer query;
   20623                 :             :     PGresult   *res;
   20624                 :             : 
   20625         [ -  + ]:        2399 :     if (oid == 0)
   20626                 :             :     {
   20627         [ #  # ]:           0 :         if ((opts & zeroAsStar) != 0)
   20628                 :           0 :             return "*";
   20629         [ #  # ]:           0 :         else if ((opts & zeroAsNone) != 0)
   20630                 :           0 :             return "NONE";
   20631                 :             :     }
   20632                 :             : 
   20633                 :             :     /* see if we have the result cached in the type's TypeInfo record */
   20634                 :        2399 :     typeInfo = findTypeByOid(oid);
   20635   [ +  -  +  + ]:        2399 :     if (typeInfo && typeInfo->ftypname)
   20636                 :        1908 :         return typeInfo->ftypname;
   20637                 :             : 
   20638                 :         491 :     query = createPQExpBuffer();
   20639                 :         491 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   20640                 :             :                       oid);
   20641                 :             : 
   20642                 :         491 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   20643                 :             : 
   20644                 :             :     /* result of format_type is already quoted */
   20645                 :         491 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   20646                 :             : 
   20647                 :         491 :     PQclear(res);
   20648                 :         491 :     destroyPQExpBuffer(query);
   20649                 :             : 
   20650                 :             :     /*
   20651                 :             :      * Cache the result for re-use in later requests, if possible.  If we
   20652                 :             :      * don't have a TypeInfo for the type, the string will be leaked once the
   20653                 :             :      * caller is done with it ... but that case really should not happen, so
   20654                 :             :      * leaking if it does seems acceptable.
   20655                 :             :      */
   20656         [ +  - ]:         491 :     if (typeInfo)
   20657                 :         491 :         typeInfo->ftypname = result;
   20658                 :             : 
   20659                 :         491 :     return result;
   20660                 :             : }
   20661                 :             : 
   20662                 :             : /*
   20663                 :             :  * Return a column list clause for the given relation.
   20664                 :             :  *
   20665                 :             :  * Special case: if there are no undropped columns in the relation, return
   20666                 :             :  * "", not an invalid "()" column list.
   20667                 :             :  */
   20668                 :             : static const char *
   20669                 :        8950 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   20670                 :             : {
   20671                 :        8950 :     int         numatts = ti->numatts;
   20672                 :        8950 :     char      **attnames = ti->attnames;
   20673                 :        8950 :     bool       *attisdropped = ti->attisdropped;
   20674                 :        8950 :     char       *attgenerated = ti->attgenerated;
   20675                 :             :     bool        needComma;
   20676                 :             :     int         i;
   20677                 :             : 
   20678                 :        8950 :     appendPQExpBufferChar(buffer, '(');
   20679                 :        8950 :     needComma = false;
   20680         [ +  + ]:       42938 :     for (i = 0; i < numatts; i++)
   20681                 :             :     {
   20682         [ +  + ]:       33988 :         if (attisdropped[i])
   20683                 :         610 :             continue;
   20684         [ +  + ]:       33378 :         if (attgenerated[i])
   20685                 :        1200 :             continue;
   20686         [ +  + ]:       32178 :         if (needComma)
   20687                 :       23464 :             appendPQExpBufferStr(buffer, ", ");
   20688                 :       32178 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   20689                 :       32178 :         needComma = true;
   20690                 :             :     }
   20691                 :             : 
   20692         [ +  + ]:        8950 :     if (!needComma)
   20693                 :         236 :         return "";                /* no undropped columns */
   20694                 :             : 
   20695                 :        8714 :     appendPQExpBufferChar(buffer, ')');
   20696                 :        8714 :     return buffer->data;
   20697                 :             : }
   20698                 :             : 
   20699                 :             : /*
   20700                 :             :  * Check if a reloptions array is nonempty.
   20701                 :             :  */
   20702                 :             : static bool
   20703                 :       14747 : nonemptyReloptions(const char *reloptions)
   20704                 :             : {
   20705                 :             :     /* Don't want to print it if it's just "{}" */
   20706   [ +  -  +  + ]:       14747 :     return (reloptions != NULL && strlen(reloptions) > 2);
   20707                 :             : }
   20708                 :             : 
   20709                 :             : /*
   20710                 :             :  * Format a reloptions array and append it to the given buffer.
   20711                 :             :  *
   20712                 :             :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   20713                 :             :  */
   20714                 :             : static void
   20715                 :         223 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   20716                 :             :                         const char *prefix, Archive *fout)
   20717                 :             : {
   20718                 :             :     bool        res;
   20719                 :             : 
   20720                 :         223 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   20721                 :         223 :                                 fout->std_strings);
   20722         [ -  + ]:         223 :     if (!res)
   20723                 :           0 :         pg_log_warning("could not parse %s array", "reloptions");
   20724                 :         223 : }
   20725                 :             : 
   20726                 :             : /*
   20727                 :             :  * read_dump_filters - retrieve object identifier patterns from file
   20728                 :             :  *
   20729                 :             :  * Parse the specified filter file for include and exclude patterns, and add
   20730                 :             :  * them to the relevant lists.  If the filename is "-" then filters will be
   20731                 :             :  * read from STDIN rather than a file.
   20732                 :             :  */
   20733                 :             : static void
   20734                 :          26 : read_dump_filters(const char *filename, DumpOptions *dopt)
   20735                 :             : {
   20736                 :             :     FilterStateData fstate;
   20737                 :             :     char       *objname;
   20738                 :             :     FilterCommandType comtype;
   20739                 :             :     FilterObjectType objtype;
   20740                 :             : 
   20741                 :          26 :     filter_init(&fstate, filename, exit_nicely);
   20742                 :             : 
   20743         [ +  + ]:          84 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   20744                 :             :     {
   20745         [ +  + ]:          33 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   20746                 :             :         {
   20747   [ -  -  +  +  :          17 :             switch (objtype)
             +  +  +  - ]
   20748                 :             :             {
   20749                 :           0 :                 case FILTER_OBJECT_TYPE_NONE:
   20750                 :           0 :                     break;
   20751                 :           0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   20752                 :             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   20753                 :             :                 case FILTER_OBJECT_TYPE_INDEX:
   20754                 :             :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20755                 :             :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20756                 :             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   20757                 :           0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20758                 :             :                                         "include",
   20759                 :             :                                         filter_object_type_name(objtype));
   20760                 :           0 :                     exit_nicely(1);
   20761                 :             :                     break;      /* unreachable */
   20762                 :             : 
   20763                 :           1 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   20764                 :           1 :                     simple_string_list_append(&extension_include_patterns, objname);
   20765                 :           1 :                     break;
   20766                 :           1 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20767                 :           1 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   20768                 :           1 :                     break;
   20769                 :           1 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   20770                 :           1 :                     simple_string_list_append(&schema_include_patterns, objname);
   20771                 :           1 :                     dopt->include_everything = false;
   20772                 :           1 :                     break;
   20773                 :          13 :                 case FILTER_OBJECT_TYPE_TABLE:
   20774                 :          13 :                     simple_string_list_append(&table_include_patterns, objname);
   20775                 :          13 :                     dopt->include_everything = false;
   20776                 :          13 :                     break;
   20777                 :           1 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20778                 :           1 :                     simple_string_list_append(&table_include_patterns_and_children,
   20779                 :             :                                               objname);
   20780                 :           1 :                     dopt->include_everything = false;
   20781                 :           1 :                     break;
   20782                 :             :             }
   20783                 :             :         }
   20784         [ +  + ]:          16 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   20785                 :             :         {
   20786   [ -  +  +  +  :           9 :             switch (objtype)
             +  +  +  +  
                      - ]
   20787                 :             :             {
   20788                 :           0 :                 case FILTER_OBJECT_TYPE_NONE:
   20789                 :           0 :                     break;
   20790                 :           1 :                 case FILTER_OBJECT_TYPE_DATABASE:
   20791                 :             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   20792                 :             :                 case FILTER_OBJECT_TYPE_INDEX:
   20793                 :             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   20794                 :             :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   20795                 :           1 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   20796                 :             :                                         "exclude",
   20797                 :             :                                         filter_object_type_name(objtype));
   20798                 :           1 :                     exit_nicely(1);
   20799                 :             :                     break;
   20800                 :             : 
   20801                 :           1 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   20802                 :           1 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   20803                 :           1 :                     break;
   20804                 :           1 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   20805                 :           1 :                     simple_string_list_append(&tabledata_exclude_patterns,
   20806                 :             :                                               objname);
   20807                 :           1 :                     break;
   20808                 :           1 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   20809                 :           1 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   20810                 :             :                                               objname);
   20811                 :           1 :                     break;
   20812                 :           2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   20813                 :           2 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   20814                 :           2 :                     break;
   20815                 :           2 :                 case FILTER_OBJECT_TYPE_TABLE:
   20816                 :           2 :                     simple_string_list_append(&table_exclude_patterns, objname);
   20817                 :           2 :                     break;
   20818                 :           1 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   20819                 :           1 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   20820                 :             :                                               objname);
   20821                 :           1 :                     break;
   20822                 :             :             }
   20823                 :             :         }
   20824                 :             :         else
   20825                 :             :         {
   20826                 :             :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   20827                 :             :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   20828                 :             :         }
   20829                 :             : 
   20830         [ +  + ]:          32 :         if (objname)
   20831                 :          25 :             free(objname);
   20832                 :             :     }
   20833                 :             : 
   20834                 :          22 :     filter_free(&fstate);
   20835                 :          22 : }
        

Generated by: LCOV version 2.0-1