Header And Logo

PostgreSQL
| The world's most advanced open source database.

pg_dump.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pg_dump.c
00004  *    pg_dump is a utility for dumping out a postgres database
00005  *    into a script file.
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  *  pg_dump will read the system catalogs in a database and dump out a
00011  *  script that reproduces the schema in terms of SQL that is understood
00012  *  by PostgreSQL
00013  *
00014  *  Note that pg_dump runs in a transaction-snapshot mode transaction,
00015  *  so it sees a consistent snapshot of the database including system
00016  *  catalogs. However, it relies in part on various specialized backend
00017  *  functions like pg_get_indexdef(), and those things tend to run on
00018  *  SnapshotNow time, ie they look at the currently committed state.  So
00019  *  it is possible to get 'cache lookup failed' error if someone
00020  *  performs DDL changes while a dump is happening. The window for this
00021  *  sort of thing is from the acquisition of the transaction snapshot to
00022  *  getSchemaData() (when pg_dump acquires AccessShareLock on every
00023  *  table it intends to dump). It isn't very large, but it can happen.
00024  *
00025  *  http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
00026  *
00027  * IDENTIFICATION
00028  *    src/bin/pg_dump/pg_dump.c
00029  *
00030  *-------------------------------------------------------------------------
00031  */
00032 
00033 #include "postgres_fe.h"
00034 
00035 #include <unistd.h>
00036 #include <ctype.h>
00037 #ifdef ENABLE_NLS
00038 #include <locale.h>
00039 #endif
00040 #ifdef HAVE_TERMIOS_H
00041 #include <termios.h>
00042 #endif
00043 
00044 #include "getopt_long.h"
00045 
00046 #include "access/attnum.h"
00047 #include "access/sysattr.h"
00048 #include "access/transam.h"
00049 #include "catalog/pg_cast.h"
00050 #include "catalog/pg_class.h"
00051 #include "catalog/pg_default_acl.h"
00052 #include "catalog/pg_event_trigger.h"
00053 #include "catalog/pg_largeobject.h"
00054 #include "catalog/pg_largeobject_metadata.h"
00055 #include "catalog/pg_proc.h"
00056 #include "catalog/pg_trigger.h"
00057 #include "catalog/pg_type.h"
00058 #include "libpq/libpq-fs.h"
00059 
00060 #include "pg_backup_archiver.h"
00061 #include "pg_backup_db.h"
00062 #include "pg_backup_utils.h"
00063 #include "dumputils.h"
00064 #include "parallel.h"
00065 
00066 extern char *optarg;
00067 extern int  optind,
00068             opterr;
00069 
00070 
00071 typedef struct
00072 {
00073     const char *descr;          /* comment for an object */
00074     Oid         classoid;       /* object class (catalog OID) */
00075     Oid         objoid;         /* object OID */
00076     int         objsubid;       /* subobject (table column #) */
00077 } CommentItem;
00078 
00079 typedef struct
00080 {
00081     const char *provider;       /* label provider of this security label */
00082     const char *label;          /* security label for an object */
00083     Oid         classoid;       /* object class (catalog OID) */
00084     Oid         objoid;         /* object OID */
00085     int         objsubid;       /* subobject (table column #) */
00086 } SecLabelItem;
00087 
00088 /* global decls */
00089 bool        g_verbose;          /* User wants verbose narration of our
00090                                  * activities. */
00091 
00092 /* various user-settable parameters */
00093 bool        schemaOnly;
00094 bool        dataOnly;
00095 int         dumpSections;       /* bitmask of chosen sections */
00096 bool        aclsSkip;
00097 const char *lockWaitTimeout;
00098 
00099 /* subquery used to convert user ID (eg, datdba) to user name */
00100 static const char *username_subquery;
00101 
00102 /* obsolete as of 7.3: */
00103 static Oid  g_last_builtin_oid; /* value of the last builtin oid */
00104 
00105 /*
00106  * Object inclusion/exclusion lists
00107  *
00108  * The string lists record the patterns given by command-line switches,
00109  * which we then convert to lists of OIDs of matching objects.
00110  */
00111 static SimpleStringList schema_include_patterns = {NULL, NULL};
00112 static SimpleOidList schema_include_oids = {NULL, NULL};
00113 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
00114 static SimpleOidList schema_exclude_oids = {NULL, NULL};
00115 
00116 static SimpleStringList table_include_patterns = {NULL, NULL};
00117 static SimpleOidList table_include_oids = {NULL, NULL};
00118 static SimpleStringList table_exclude_patterns = {NULL, NULL};
00119 static SimpleOidList table_exclude_oids = {NULL, NULL};
00120 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
00121 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
00122 
00123 /* default, if no "inclusion" switches appear, is to dump everything */
00124 static bool include_everything = true;
00125 
00126 char        g_opaque_type[10];  /* name for the opaque type */
00127 
00128 /* placeholders for the delimiters for comments */
00129 char        g_comment_start[10];
00130 char        g_comment_end[10];
00131 
00132 static const CatalogId nilCatalogId = {0, 0};
00133 
00134 /* flags for various command-line long options */
00135 static int  binary_upgrade = 0;
00136 static int  disable_dollar_quoting = 0;
00137 static int  dump_inserts = 0;
00138 static int  column_inserts = 0;
00139 static int  no_security_labels = 0;
00140 static int  no_synchronized_snapshots = 0;
00141 static int  no_unlogged_table_data = 0;
00142 static int  serializable_deferrable = 0;
00143 
00144 
00145 static void help(const char *progname);
00146 static void setup_connection(Archive *AH, const char *dumpencoding,
00147                  char *use_role);
00148 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
00149 static void expand_schema_name_patterns(Archive *fout,
00150                             SimpleStringList *patterns,
00151                             SimpleOidList *oids);
00152 static void expand_table_name_patterns(Archive *fout,
00153                            SimpleStringList *patterns,
00154                            SimpleOidList *oids);
00155 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
00156 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
00157 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
00158 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
00159 static void dumpComment(Archive *fout, const char *target,
00160             const char *namespace, const char *owner,
00161             CatalogId catalogId, int subid, DumpId dumpId);
00162 static int findComments(Archive *fout, Oid classoid, Oid objoid,
00163              CommentItem **items);
00164 static int  collectComments(Archive *fout, CommentItem **items);
00165 static void dumpSecLabel(Archive *fout, const char *target,
00166              const char *namespace, const char *owner,
00167              CatalogId catalogId, int subid, DumpId dumpId);
00168 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
00169               SecLabelItem **items);
00170 static int  collectSecLabels(Archive *fout, SecLabelItem **items);
00171 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
00172 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
00173 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
00174 static void dumpType(Archive *fout, TypeInfo *tyinfo);
00175 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
00176 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
00177 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
00178 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
00179 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
00180 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
00181 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
00182 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
00183 static void dumpFunc(Archive *fout, FuncInfo *finfo);
00184 static void dumpCast(Archive *fout, CastInfo *cast);
00185 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
00186 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
00187 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
00188 static void dumpCollation(Archive *fout, CollInfo *convinfo);
00189 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
00190 static void dumpRule(Archive *fout, RuleInfo *rinfo);
00191 static void dumpAgg(Archive *fout, AggInfo *agginfo);
00192 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
00193 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
00194 static void dumpTable(Archive *fout, TableInfo *tbinfo);
00195 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
00196 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
00197 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
00198 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
00199 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
00200 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
00201 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
00202 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
00203 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
00204 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
00205 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
00206 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
00207 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
00208 static void dumpUserMappings(Archive *fout,
00209                  const char *servername, const char *namespace,
00210                  const char *owner, CatalogId catalogId, DumpId dumpId);
00211 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
00212 
00213 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
00214         const char *type, const char *name, const char *subname,
00215         const char *tag, const char *nspname, const char *owner,
00216         const char *acls);
00217 
00218 static void getDependencies(Archive *fout);
00219 static void BuildArchiveDependencies(Archive *fout);
00220 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
00221                          DumpId **dependencies, int *nDeps, int *allocDeps);
00222 
00223 static DumpableObject *createBoundaryObjects(void);
00224 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
00225                         DumpableObject *boundaryObjs);
00226 
00227 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
00228 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
00229 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
00230 static void buildMatViewRefreshDependencies(Archive *fout);
00231 static void getTableDataFKConstraints(void);
00232 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
00233 static char *format_function_arguments_old(Archive *fout,
00234                               FuncInfo *finfo, int nallargs,
00235                               char **allargtypes,
00236                               char **argmodes,
00237                               char **argnames);
00238 static char *format_function_signature(Archive *fout,
00239                           FuncInfo *finfo, bool honor_quotes);
00240 static const char *convertRegProcReference(Archive *fout,
00241                         const char *proc);
00242 static const char *convertOperatorReference(Archive *fout, const char *opr);
00243 static const char *convertTSFunction(Archive *fout, Oid funcOid);
00244 static Oid  findLastBuiltinOid_V71(Archive *fout, const char *);
00245 static Oid  findLastBuiltinOid_V70(Archive *fout);
00246 static void selectSourceSchema(Archive *fout, const char *schemaName);
00247 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
00248 static char *myFormatType(const char *typname, int32 typmod);
00249 static void getBlobs(Archive *fout);
00250 static void dumpBlob(Archive *fout, BlobInfo *binfo);
00251 static int  dumpBlobs(Archive *fout, void *arg);
00252 static void dumpDatabase(Archive *AH);
00253 static void dumpEncoding(Archive *AH);
00254 static void dumpStdStrings(Archive *AH);
00255 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
00256                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
00257 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
00258                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
00259 static void binary_upgrade_set_pg_class_oids(Archive *fout,
00260                                  PQExpBuffer upgrade_buffer,
00261                                  Oid pg_class_oid, bool is_index);
00262 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
00263                                 DumpableObject *dobj,
00264                                 const char *objlabel);
00265 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
00266 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
00267 static char *get_synchronized_snapshot(Archive *fout);
00268 static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
00269 static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt);
00270 
00271 
00272 int
00273 main(int argc, char **argv)
00274 {
00275     int         c;
00276     const char *filename = NULL;
00277     const char *format = "p";
00278     const char *dbname = NULL;
00279     const char *pghost = NULL;
00280     const char *pgport = NULL;
00281     const char *username = NULL;
00282     const char *dumpencoding = NULL;
00283     bool        oids = false;
00284     TableInfo  *tblinfo;
00285     int         numTables;
00286     DumpableObject **dobjs;
00287     int         numObjs;
00288     DumpableObject *boundaryObjs;
00289     int         i;
00290     int         numWorkers = 1;
00291     enum trivalue prompt_password = TRI_DEFAULT;
00292     int         compressLevel = -1;
00293     int         plainText = 0;
00294     int         outputClean = 0;
00295     int         outputCreateDB = 0;
00296     bool        outputBlobs = false;
00297     int         outputNoOwner = 0;
00298     char       *outputSuperuser = NULL;
00299     char       *use_role = NULL;
00300     int         optindex;
00301     RestoreOptions *ropt;
00302     ArchiveFormat archiveFormat = archUnknown;
00303     ArchiveMode archiveMode;
00304     Archive    *fout;           /* the script file */
00305 
00306     static int  disable_triggers = 0;
00307     static int  outputNoTablespaces = 0;
00308     static int  use_setsessauth = 0;
00309 
00310     static struct option long_options[] = {
00311         {"data-only", no_argument, NULL, 'a'},
00312         {"blobs", no_argument, NULL, 'b'},
00313         {"clean", no_argument, NULL, 'c'},
00314         {"create", no_argument, NULL, 'C'},
00315         {"dbname", required_argument, NULL, 'd'},
00316         {"file", required_argument, NULL, 'f'},
00317         {"format", required_argument, NULL, 'F'},
00318         {"host", required_argument, NULL, 'h'},
00319         {"ignore-version", no_argument, NULL, 'i'},
00320         {"jobs", 1, NULL, 'j'},
00321         {"no-reconnect", no_argument, NULL, 'R'},
00322         {"oids", no_argument, NULL, 'o'},
00323         {"no-owner", no_argument, NULL, 'O'},
00324         {"port", required_argument, NULL, 'p'},
00325         {"schema", required_argument, NULL, 'n'},
00326         {"exclude-schema", required_argument, NULL, 'N'},
00327         {"schema-only", no_argument, NULL, 's'},
00328         {"superuser", required_argument, NULL, 'S'},
00329         {"table", required_argument, NULL, 't'},
00330         {"exclude-table", required_argument, NULL, 'T'},
00331         {"no-password", no_argument, NULL, 'w'},
00332         {"password", no_argument, NULL, 'W'},
00333         {"username", required_argument, NULL, 'U'},
00334         {"verbose", no_argument, NULL, 'v'},
00335         {"no-privileges", no_argument, NULL, 'x'},
00336         {"no-acl", no_argument, NULL, 'x'},
00337         {"compress", required_argument, NULL, 'Z'},
00338         {"encoding", required_argument, NULL, 'E'},
00339         {"help", no_argument, NULL, '?'},
00340         {"version", no_argument, NULL, 'V'},
00341 
00342         /*
00343          * the following options don't have an equivalent short option letter
00344          */
00345         {"attribute-inserts", no_argument, &column_inserts, 1},
00346         {"binary-upgrade", no_argument, &binary_upgrade, 1},
00347         {"column-inserts", no_argument, &column_inserts, 1},
00348         {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
00349         {"disable-triggers", no_argument, &disable_triggers, 1},
00350         {"exclude-table-data", required_argument, NULL, 4},
00351         {"inserts", no_argument, &dump_inserts, 1},
00352         {"lock-wait-timeout", required_argument, NULL, 2},
00353         {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
00354         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
00355         {"role", required_argument, NULL, 3},
00356         {"section", required_argument, NULL, 5},
00357         {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
00358         {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
00359         {"no-security-labels", no_argument, &no_security_labels, 1},
00360         {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
00361         {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
00362 
00363         {NULL, 0, NULL, 0}
00364     };
00365 
00366     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
00367 
00368     /*
00369      * Initialize what we need for parallel execution, especially for thread
00370      * support on Windows.
00371      */
00372     init_parallel_dump_utils();
00373 
00374     g_verbose = false;
00375 
00376     strcpy(g_comment_start, "-- ");
00377     g_comment_end[0] = '\0';
00378     strcpy(g_opaque_type, "opaque");
00379 
00380     dataOnly = schemaOnly = false;
00381     dumpSections = DUMP_UNSECTIONED;
00382     lockWaitTimeout = NULL;
00383 
00384     progname = get_progname(argv[0]);
00385 
00386     /* Set default options based on progname */
00387     if (strcmp(progname, "pg_backup") == 0)
00388         format = "c";
00389 
00390     if (argc > 1)
00391     {
00392         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
00393         {
00394             help(progname);
00395             exit_nicely(0);
00396         }
00397         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
00398         {
00399             puts("pg_dump (PostgreSQL) " PG_VERSION);
00400             exit_nicely(0);
00401         }
00402     }
00403 
00404     while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:K:n:N:oOp:RsS:t:T:U:vwWxZ:",
00405                             long_options, &optindex)) != -1)
00406     {
00407         switch (c)
00408         {
00409             case 'a':           /* Dump data only */
00410                 dataOnly = true;
00411                 break;
00412 
00413             case 'b':           /* Dump blobs */
00414                 outputBlobs = true;
00415                 break;
00416 
00417             case 'c':           /* clean (i.e., drop) schema prior to create */
00418                 outputClean = 1;
00419                 break;
00420 
00421             case 'C':           /* Create DB */
00422                 outputCreateDB = 1;
00423                 break;
00424 
00425             case 'd':           /* database name */
00426                 dbname = pg_strdup(optarg);
00427                 break;
00428 
00429             case 'E':           /* Dump encoding */
00430                 dumpencoding = pg_strdup(optarg);
00431                 break;
00432 
00433             case 'f':
00434                 filename = pg_strdup(optarg);
00435                 break;
00436 
00437             case 'F':
00438                 format = pg_strdup(optarg);
00439                 break;
00440 
00441             case 'h':           /* server host */
00442                 pghost = pg_strdup(optarg);
00443                 break;
00444 
00445             case 'i':
00446                 /* ignored, deprecated option */
00447                 break;
00448 
00449             case 'j':           /* number of dump jobs */
00450                 numWorkers = atoi(optarg);
00451                 break;
00452 
00453             case 'n':           /* include schema(s) */
00454                 simple_string_list_append(&schema_include_patterns, optarg);
00455                 include_everything = false;
00456                 break;
00457 
00458             case 'N':           /* exclude schema(s) */
00459                 simple_string_list_append(&schema_exclude_patterns, optarg);
00460                 break;
00461 
00462             case 'o':           /* Dump oids */
00463                 oids = true;
00464                 break;
00465 
00466             case 'O':           /* Don't reconnect to match owner */
00467                 outputNoOwner = 1;
00468                 break;
00469 
00470             case 'p':           /* server port */
00471                 pgport = pg_strdup(optarg);
00472                 break;
00473 
00474             case 'R':
00475                 /* no-op, still accepted for backwards compatibility */
00476                 break;
00477 
00478             case 's':           /* dump schema only */
00479                 schemaOnly = true;
00480                 break;
00481 
00482             case 'S':           /* Username for superuser in plain text output */
00483                 outputSuperuser = pg_strdup(optarg);
00484                 break;
00485 
00486             case 't':           /* include table(s) */
00487                 simple_string_list_append(&table_include_patterns, optarg);
00488                 include_everything = false;
00489                 break;
00490 
00491             case 'T':           /* exclude table(s) */
00492                 simple_string_list_append(&table_exclude_patterns, optarg);
00493                 break;
00494 
00495             case 'U':
00496                 username = pg_strdup(optarg);
00497                 break;
00498 
00499             case 'v':           /* verbose */
00500                 g_verbose = true;
00501                 break;
00502 
00503             case 'w':
00504                 prompt_password = TRI_NO;
00505                 break;
00506 
00507             case 'W':
00508                 prompt_password = TRI_YES;
00509                 break;
00510 
00511             case 'x':           /* skip ACL dump */
00512                 aclsSkip = true;
00513                 break;
00514 
00515             case 'Z':           /* Compression Level */
00516                 compressLevel = atoi(optarg);
00517                 break;
00518 
00519             case 0:
00520                 /* This covers the long options. */
00521                 break;
00522 
00523             case 2:             /* lock-wait-timeout */
00524                 lockWaitTimeout = pg_strdup(optarg);
00525                 break;
00526 
00527             case 3:             /* SET ROLE */
00528                 use_role = pg_strdup(optarg);
00529                 break;
00530 
00531             case 4:             /* exclude table(s) data */
00532                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
00533                 break;
00534 
00535             case 5:             /* section */
00536                 set_dump_section(optarg, &dumpSections);
00537                 break;
00538 
00539             default:
00540                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
00541                 exit_nicely(1);
00542         }
00543     }
00544 
00545     /*
00546      * Non-option argument specifies database name as long as it wasn't
00547      * already specified with -d / --dbname
00548      */
00549     if (optind < argc && dbname == NULL)
00550         dbname = argv[optind++];
00551 
00552     /* Complain if any arguments remain */
00553     if (optind < argc)
00554     {
00555         fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
00556                 progname, argv[optind]);
00557         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
00558                 progname);
00559         exit_nicely(1);
00560     }
00561 
00562     /* --column-inserts implies --inserts */
00563     if (column_inserts)
00564         dump_inserts = 1;
00565 
00566     if (dataOnly && schemaOnly)
00567         exit_horribly(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
00568 
00569     if (dataOnly && outputClean)
00570         exit_horribly(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
00571 
00572     if (dump_inserts && oids)
00573     {
00574         write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
00575         write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
00576         exit_nicely(1);
00577     }
00578 
00579     /* Identify archive format to emit */
00580     archiveFormat = parseArchiveFormat(format, &archiveMode);
00581 
00582     /* archiveFormat specific setup */
00583     if (archiveFormat == archNull)
00584         plainText = 1;
00585 
00586     /* Custom and directory formats are compressed by default, others not */
00587     if (compressLevel == -1)
00588     {
00589         if (archiveFormat == archCustom || archiveFormat == archDirectory)
00590             compressLevel = Z_DEFAULT_COMPRESSION;
00591         else
00592             compressLevel = 0;
00593     }
00594 
00595     /*
00596      * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
00597      * parallel jobs because that's the maximum limit for the
00598      * WaitForMultipleObjects() call.
00599      */
00600     if (numWorkers <= 0
00601 #ifdef WIN32
00602         || numWorkers > MAXIMUM_WAIT_OBJECTS
00603 #endif
00604         )
00605         exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
00606 
00607     /* Parallel backup only in the directory archive format so far */
00608     if (archiveFormat != archDirectory && numWorkers > 1)
00609         exit_horribly(NULL, "parallel backup only supported by the directory format\n");
00610 
00611     /* Open the output file */
00612     fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
00613                          setupDumpWorker);
00614 
00615     /* Register the cleanup hook */
00616     on_exit_close_archive(fout);
00617 
00618     if (fout == NULL)
00619         exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
00620 
00621     /* Let the archiver know how noisy to be */
00622     fout->verbose = g_verbose;
00623 
00624     /*
00625      * We allow the server to be back to 7.0, and up to any minor release of
00626      * our own major version.  (See also version check in pg_dumpall.c.)
00627      */
00628     fout->minRemoteVersion = 70000;
00629     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
00630 
00631     fout->numWorkers = numWorkers;
00632 
00633     /*
00634      * Open the database using the Archiver, so it knows about it. Errors mean
00635      * death.
00636      */
00637     ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
00638     setup_connection(fout, dumpencoding, use_role);
00639 
00640     /*
00641      * Disable security label support if server version < v9.1.x (prevents
00642      * access to nonexistent pg_seclabel catalog)
00643      */
00644     if (fout->remoteVersion < 90100)
00645         no_security_labels = 1;
00646 
00647     /*
00648      * When running against 9.0 or later, check if we are in recovery mode,
00649      * which means we are on a hot standby.
00650      */
00651     if (fout->remoteVersion >= 90000)
00652     {
00653         PGresult   *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
00654 
00655         if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
00656         {
00657             /*
00658              * On hot standby slaves, never try to dump unlogged table data,
00659              * since it will just throw an error.
00660              */
00661             no_unlogged_table_data = true;
00662         }
00663         PQclear(res);
00664     }
00665 
00666     /* Select the appropriate subquery to convert user IDs to names */
00667     if (fout->remoteVersion >= 80100)
00668         username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
00669     else if (fout->remoteVersion >= 70300)
00670         username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
00671     else
00672         username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
00673 
00674     /* check the version for the synchronized snapshots feature */
00675     if (numWorkers > 1 && fout->remoteVersion < 90200
00676         && !no_synchronized_snapshots)
00677         exit_horribly(NULL,
00678                       "Synchronized snapshots are not supported by this server version.\n"
00679                       "Run with --no-synchronized-snapshots instead if you do not need\n"
00680                       "synchronized snapshots.\n");
00681 
00682     /* Find the last built-in OID, if needed */
00683     if (fout->remoteVersion < 70300)
00684     {
00685         if (fout->remoteVersion >= 70100)
00686             g_last_builtin_oid = findLastBuiltinOid_V71(fout,
00687                                                   PQdb(GetConnection(fout)));
00688         else
00689             g_last_builtin_oid = findLastBuiltinOid_V70(fout);
00690         if (g_verbose)
00691             write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
00692     }
00693 
00694     /* Expand schema selection patterns into OID lists */
00695     if (schema_include_patterns.head != NULL)
00696     {
00697         expand_schema_name_patterns(fout, &schema_include_patterns,
00698                                     &schema_include_oids);
00699         if (schema_include_oids.head == NULL)
00700             exit_horribly(NULL, "No matching schemas were found\n");
00701     }
00702     expand_schema_name_patterns(fout, &schema_exclude_patterns,
00703                                 &schema_exclude_oids);
00704     /* non-matching exclusion patterns aren't an error */
00705 
00706     /* Expand table selection patterns into OID lists */
00707     if (table_include_patterns.head != NULL)
00708     {
00709         expand_table_name_patterns(fout, &table_include_patterns,
00710                                    &table_include_oids);
00711         if (table_include_oids.head == NULL)
00712             exit_horribly(NULL, "No matching tables were found\n");
00713     }
00714     expand_table_name_patterns(fout, &table_exclude_patterns,
00715                                &table_exclude_oids);
00716 
00717     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
00718                                &tabledata_exclude_oids);
00719 
00720     /* non-matching exclusion patterns aren't an error */
00721 
00722     /*
00723      * Dumping blobs is now default unless we saw an inclusion switch or -s
00724      * ... but even if we did see one of these, -b turns it back on.
00725      */
00726     if (include_everything && !schemaOnly)
00727         outputBlobs = true;
00728 
00729     /*
00730      * Now scan the database and create DumpableObject structs for all the
00731      * objects we intend to dump.
00732      */
00733     tblinfo = getSchemaData(fout, &numTables);
00734 
00735     if (fout->remoteVersion < 80400)
00736         guessConstraintInheritance(tblinfo, numTables);
00737 
00738     if (!schemaOnly)
00739     {
00740         getTableData(tblinfo, numTables, oids);
00741         buildMatViewRefreshDependencies(fout);
00742         if (dataOnly)
00743             getTableDataFKConstraints();
00744     }
00745 
00746     if (outputBlobs)
00747         getBlobs(fout);
00748 
00749     /*
00750      * Collect dependency data to assist in ordering the objects.
00751      */
00752     getDependencies(fout);
00753 
00754     /* Lastly, create dummy objects to represent the section boundaries */
00755     boundaryObjs = createBoundaryObjects();
00756 
00757     /* Get pointers to all the known DumpableObjects */
00758     getDumpableObjects(&dobjs, &numObjs);
00759 
00760     /*
00761      * Add dummy dependencies to enforce the dump section ordering.
00762      */
00763     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
00764 
00765     /*
00766      * Sort the objects into a safe dump order (no forward references).
00767      *
00768      * In 7.3 or later, we can rely on dependency information to help us
00769      * determine a safe order, so the initial sort is mostly for cosmetic
00770      * purposes: we sort by name to ensure that logically identical schemas
00771      * will dump identically.  Before 7.3 we don't have dependencies and we
00772      * use OID ordering as an (unreliable) guide to creation order.
00773      */
00774     if (fout->remoteVersion >= 70300)
00775         sortDumpableObjectsByTypeName(dobjs, numObjs);
00776     else
00777         sortDumpableObjectsByTypeOid(dobjs, numObjs);
00778 
00779     /* If we do a parallel dump, we want the largest tables to go first */
00780     if (archiveFormat == archDirectory && numWorkers > 1)
00781         sortDataAndIndexObjectsBySize(dobjs, numObjs);
00782 
00783     sortDumpableObjects(dobjs, numObjs,
00784                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
00785 
00786     /*
00787      * Create archive TOC entries for all the objects to be dumped, in a safe
00788      * order.
00789      */
00790 
00791     /* First the special ENCODING and STDSTRINGS entries. */
00792     dumpEncoding(fout);
00793     dumpStdStrings(fout);
00794 
00795     /* The database item is always next, unless we don't want it at all */
00796     if (include_everything && !dataOnly)
00797         dumpDatabase(fout);
00798 
00799     /* Now the rearrangeable objects. */
00800     for (i = 0; i < numObjs; i++)
00801         dumpDumpableObject(fout, dobjs[i]);
00802 
00803     /*
00804      * Set up options info to ensure we dump what we want.
00805      */
00806     ropt = NewRestoreOptions();
00807     ropt->filename = filename;
00808     ropt->dropSchema = outputClean;
00809     ropt->dataOnly = dataOnly;
00810     ropt->schemaOnly = schemaOnly;
00811     ropt->dumpSections = dumpSections;
00812     ropt->aclsSkip = aclsSkip;
00813     ropt->superuser = outputSuperuser;
00814     ropt->createDB = outputCreateDB;
00815     ropt->noOwner = outputNoOwner;
00816     ropt->noTablespace = outputNoTablespaces;
00817     ropt->disable_triggers = disable_triggers;
00818     ropt->use_setsessauth = use_setsessauth;
00819 
00820     if (compressLevel == -1)
00821         ropt->compression = 0;
00822     else
00823         ropt->compression = compressLevel;
00824 
00825     ropt->suppressDumpWarnings = true;  /* We've already shown them */
00826 
00827     SetArchiveRestoreOptions(fout, ropt);
00828 
00829     /*
00830      * The archive's TOC entries are now marked as to which ones will actually
00831      * be output, so we can set up their dependency lists properly. This isn't
00832      * necessary for plain-text output, though.
00833      */
00834     if (!plainText)
00835         BuildArchiveDependencies(fout);
00836 
00837     /*
00838      * And finally we can do the actual output.
00839      *
00840      * Note: for non-plain-text output formats, the output file is written
00841      * inside CloseArchive().  This is, um, bizarre; but not worth changing
00842      * right now.
00843      */
00844     if (plainText)
00845         RestoreArchive(fout);
00846 
00847     CloseArchive(fout);
00848 
00849     exit_nicely(0);
00850 }
00851 
00852 
00853 static void
00854 help(const char *progname)
00855 {
00856     printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
00857     printf(_("Usage:\n"));
00858     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
00859 
00860     printf(_("\nGeneral options:\n"));
00861     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
00862     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
00863              "                               plain text (default))\n"));
00864     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
00865     printf(_("  -v, --verbose                verbose mode\n"));
00866     printf(_("  -V, --version                output version information, then exit\n"));
00867     printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
00868     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
00869     printf(_("  -?, --help                   show this help, then exit\n"));
00870 
00871     printf(_("\nOptions controlling the output content:\n"));
00872     printf(_("  -a, --data-only              dump only the data, not the schema\n"));
00873     printf(_("  -b, --blobs                  include large objects in dump\n"));
00874     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
00875     printf(_("  -C, --create                 include commands to create database in dump\n"));
00876     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
00877     printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
00878     printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
00879     printf(_("  -o, --oids                   include OIDs in dump\n"));
00880     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
00881              "                               plain-text format\n"));
00882     printf(_("  -s, --schema-only            dump only the schema, no data\n"));
00883     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
00884     printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
00885     printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
00886     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
00887     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
00888     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
00889     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
00890     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
00891     printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
00892     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
00893     printf(_("  --no-security-labels         do not dump security label assignments\n"));
00894     printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
00895     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
00896     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
00897     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
00898     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
00899     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
00900     printf(_("  --use-set-session-authorization\n"
00901              "                               use SET SESSION AUTHORIZATION commands instead of\n"
00902              "                               ALTER OWNER commands to set ownership\n"));
00903 
00904     printf(_("\nConnection options:\n"));
00905     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
00906     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
00907     printf(_("  -p, --port=PORT          database server port number\n"));
00908     printf(_("  -U, --username=NAME      connect as specified database user\n"));
00909     printf(_("  -w, --no-password        never prompt for password\n"));
00910     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
00911     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
00912 
00913     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
00914              "variable value is used.\n\n"));
00915     printf(_("Report bugs to <[email protected]>.\n"));
00916 }
00917 
00918 static void
00919 setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
00920 {
00921     PGconn     *conn = GetConnection(AH);
00922     const char *std_strings;
00923 
00924     /*
00925      * Set the client encoding if requested. If dumpencoding == NULL then
00926      * either it hasn't been requested or we're a cloned connection and then
00927      * this has already been set in CloneArchive according to the original
00928      * connection encoding.
00929      */
00930     if (dumpencoding)
00931     {
00932         if (PQsetClientEncoding(conn, dumpencoding) < 0)
00933             exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
00934                           dumpencoding);
00935     }
00936 
00937     /*
00938      * Get the active encoding and the standard_conforming_strings setting, so
00939      * we know how to escape strings.
00940      */
00941     AH->encoding = PQclientEncoding(conn);
00942 
00943     std_strings = PQparameterStatus(conn, "standard_conforming_strings");
00944     AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
00945 
00946     /* Set the role if requested */
00947     if (!use_role && AH->use_role)
00948         use_role = AH->use_role;
00949 
00950     /* Set the role if requested */
00951     if (use_role && AH->remoteVersion >= 80100)
00952     {
00953         PQExpBuffer query = createPQExpBuffer();
00954 
00955         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
00956         ExecuteSqlStatement(AH, query->data);
00957         destroyPQExpBuffer(query);
00958 
00959         /* save this for later use on parallel connections */
00960         if (!AH->use_role)
00961             AH->use_role = strdup(use_role);
00962     }
00963 
00964     /* Set the datestyle to ISO to ensure the dump's portability */
00965     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
00966 
00967     /* Likewise, avoid using sql_standard intervalstyle */
00968     if (AH->remoteVersion >= 80400)
00969         ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
00970 
00971     /*
00972      * If supported, set extra_float_digits so that we can dump float data
00973      * exactly (given correctly implemented float I/O code, anyway)
00974      */
00975     if (AH->remoteVersion >= 90000)
00976         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
00977     else if (AH->remoteVersion >= 70400)
00978         ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
00979 
00980     /*
00981      * If synchronized scanning is supported, disable it, to prevent
00982      * unpredictable changes in row ordering across a dump and reload.
00983      */
00984     if (AH->remoteVersion >= 80300)
00985         ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
00986 
00987     /*
00988      * Disable timeouts if supported.
00989      */
00990     if (AH->remoteVersion >= 70300)
00991         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
00992     if (AH->remoteVersion >= 90300)
00993         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
00994 
00995     /*
00996      * Quote all identifiers, if requested.
00997      */
00998     if (quote_all_identifiers && AH->remoteVersion >= 90100)
00999         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
01000 
01001     /*
01002      * Start transaction-snapshot mode transaction to dump consistent data.
01003      */
01004     ExecuteSqlStatement(AH, "BEGIN");
01005     if (AH->remoteVersion >= 90100)
01006     {
01007         if (serializable_deferrable)
01008             ExecuteSqlStatement(AH,
01009                                 "SET TRANSACTION ISOLATION LEVEL "
01010                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
01011         else
01012             ExecuteSqlStatement(AH,
01013                                 "SET TRANSACTION ISOLATION LEVEL "
01014                                 "REPEATABLE READ, READ ONLY");
01015     }
01016     else if (AH->remoteVersion >= 70400)
01017     {
01018         /* note: comma was not accepted in SET TRANSACTION before 8.0 */
01019         ExecuteSqlStatement(AH,
01020                             "SET TRANSACTION ISOLATION LEVEL "
01021                             "SERIALIZABLE READ ONLY");
01022     }
01023     else
01024         ExecuteSqlStatement(AH,
01025                             "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
01026 
01027 
01028 
01029     if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots)
01030     {
01031         if (AH->sync_snapshot_id)
01032         {
01033             PQExpBuffer query = createPQExpBuffer();
01034 
01035             appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
01036             appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
01037             destroyPQExpBuffer(query);
01038         }
01039         else
01040             AH->sync_snapshot_id = get_synchronized_snapshot(AH);
01041     }
01042 }
01043 
01044 static void
01045 setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
01046 {
01047     setup_connection(AHX, NULL, NULL);
01048 }
01049 
01050 static char *
01051 get_synchronized_snapshot(Archive *fout)
01052 {
01053     char       *query = "SELECT pg_export_snapshot()";
01054     char       *result;
01055     PGresult   *res;
01056 
01057     res = ExecuteSqlQueryForSingleRow(fout, query);
01058     result = strdup(PQgetvalue(res, 0, 0));
01059     PQclear(res);
01060 
01061     return result;
01062 }
01063 
01064 static ArchiveFormat
01065 parseArchiveFormat(const char *format, ArchiveMode *mode)
01066 {
01067     ArchiveFormat archiveFormat;
01068 
01069     *mode = archModeWrite;
01070 
01071     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
01072     {
01073         /* This is used by pg_dumpall, and is not documented */
01074         archiveFormat = archNull;
01075         *mode = archModeAppend;
01076     }
01077     else if (pg_strcasecmp(format, "c") == 0)
01078         archiveFormat = archCustom;
01079     else if (pg_strcasecmp(format, "custom") == 0)
01080         archiveFormat = archCustom;
01081     else if (pg_strcasecmp(format, "d") == 0)
01082         archiveFormat = archDirectory;
01083     else if (pg_strcasecmp(format, "directory") == 0)
01084         archiveFormat = archDirectory;
01085     else if (pg_strcasecmp(format, "p") == 0)
01086         archiveFormat = archNull;
01087     else if (pg_strcasecmp(format, "plain") == 0)
01088         archiveFormat = archNull;
01089     else if (pg_strcasecmp(format, "t") == 0)
01090         archiveFormat = archTar;
01091     else if (pg_strcasecmp(format, "tar") == 0)
01092         archiveFormat = archTar;
01093     else
01094         exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
01095     return archiveFormat;
01096 }
01097 
01098 /*
01099  * Find the OIDs of all schemas matching the given list of patterns,
01100  * and append them to the given OID list.
01101  */
01102 static void
01103 expand_schema_name_patterns(Archive *fout,
01104                             SimpleStringList *patterns,
01105                             SimpleOidList *oids)
01106 {
01107     PQExpBuffer query;
01108     PGresult   *res;
01109     SimpleStringListCell *cell;
01110     int         i;
01111 
01112     if (patterns->head == NULL)
01113         return;                 /* nothing to do */
01114 
01115     if (fout->remoteVersion < 70300)
01116         exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
01117 
01118     query = createPQExpBuffer();
01119 
01120     /*
01121      * We use UNION ALL rather than UNION; this might sometimes result in
01122      * duplicate entries in the OID list, but we don't care.
01123      */
01124 
01125     for (cell = patterns->head; cell; cell = cell->next)
01126     {
01127         if (cell != patterns->head)
01128             appendPQExpBuffer(query, "UNION ALL\n");
01129         appendPQExpBuffer(query,
01130                           "SELECT oid FROM pg_catalog.pg_namespace n\n");
01131         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
01132                               false, NULL, "n.nspname", NULL, NULL);
01133     }
01134 
01135     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
01136 
01137     for (i = 0; i < PQntuples(res); i++)
01138     {
01139         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
01140     }
01141 
01142     PQclear(res);
01143     destroyPQExpBuffer(query);
01144 }
01145 
01146 /*
01147  * Find the OIDs of all tables matching the given list of patterns,
01148  * and append them to the given OID list.
01149  */
01150 static void
01151 expand_table_name_patterns(Archive *fout,
01152                            SimpleStringList *patterns, SimpleOidList *oids)
01153 {
01154     PQExpBuffer query;
01155     PGresult   *res;
01156     SimpleStringListCell *cell;
01157     int         i;
01158 
01159     if (patterns->head == NULL)
01160         return;                 /* nothing to do */
01161 
01162     query = createPQExpBuffer();
01163 
01164     /*
01165      * We use UNION ALL rather than UNION; this might sometimes result in
01166      * duplicate entries in the OID list, but we don't care.
01167      */
01168 
01169     for (cell = patterns->head; cell; cell = cell->next)
01170     {
01171         if (cell != patterns->head)
01172             appendPQExpBuffer(query, "UNION ALL\n");
01173         appendPQExpBuffer(query,
01174                           "SELECT c.oid"
01175                           "\nFROM pg_catalog.pg_class c"
01176         "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
01177                      "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
01178                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
01179                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
01180         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
01181                               false, "n.nspname", "c.relname", NULL,
01182                               "pg_catalog.pg_table_is_visible(c.oid)");
01183     }
01184 
01185     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
01186 
01187     for (i = 0; i < PQntuples(res); i++)
01188     {
01189         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
01190     }
01191 
01192     PQclear(res);
01193     destroyPQExpBuffer(query);
01194 }
01195 
01196 /*
01197  * selectDumpableNamespace: policy-setting subroutine
01198  *      Mark a namespace as to be dumped or not
01199  */
01200 static void
01201 selectDumpableNamespace(NamespaceInfo *nsinfo)
01202 {
01203     /*
01204      * If specific tables are being dumped, do not dump any complete
01205      * namespaces. If specific namespaces are being dumped, dump just those
01206      * namespaces. Otherwise, dump all non-system namespaces.
01207      */
01208     if (table_include_oids.head != NULL)
01209         nsinfo->dobj.dump = false;
01210     else if (schema_include_oids.head != NULL)
01211         nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
01212                                                    nsinfo->dobj.catId.oid);
01213     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
01214              strcmp(nsinfo->dobj.name, "information_schema") == 0)
01215         nsinfo->dobj.dump = false;
01216     else
01217         nsinfo->dobj.dump = true;
01218 
01219     /*
01220      * In any case, a namespace can be excluded by an exclusion switch
01221      */
01222     if (nsinfo->dobj.dump &&
01223         simple_oid_list_member(&schema_exclude_oids,
01224                                nsinfo->dobj.catId.oid))
01225         nsinfo->dobj.dump = false;
01226 }
01227 
01228 /*
01229  * selectDumpableTable: policy-setting subroutine
01230  *      Mark a table as to be dumped or not
01231  */
01232 static void
01233 selectDumpableTable(TableInfo *tbinfo)
01234 {
01235     /*
01236      * If specific tables are being dumped, dump just those tables; else, dump
01237      * according to the parent namespace's dump flag.
01238      */
01239     if (table_include_oids.head != NULL)
01240         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
01241                                                    tbinfo->dobj.catId.oid);
01242     else
01243         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
01244 
01245     /*
01246      * In any case, a table can be excluded by an exclusion switch
01247      */
01248     if (tbinfo->dobj.dump &&
01249         simple_oid_list_member(&table_exclude_oids,
01250                                tbinfo->dobj.catId.oid))
01251         tbinfo->dobj.dump = false;
01252 }
01253 
01254 /*
01255  * selectDumpableType: policy-setting subroutine
01256  *      Mark a type as to be dumped or not
01257  *
01258  * If it's a table's rowtype or an autogenerated array type, we also apply a
01259  * special type code to facilitate sorting into the desired order.  (We don't
01260  * want to consider those to be ordinary types because that would bring tables
01261  * up into the datatype part of the dump order.)  We still set the object's
01262  * dump flag; that's not going to cause the dummy type to be dumped, but we
01263  * need it so that casts involving such types will be dumped correctly -- see
01264  * dumpCast.  This means the flag should be set the same as for the underlying
01265  * object (the table or base type).
01266  */
01267 static void
01268 selectDumpableType(TypeInfo *tyinfo)
01269 {
01270     /* skip complex types, except for standalone composite types */
01271     if (OidIsValid(tyinfo->typrelid) &&
01272         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
01273     {
01274         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
01275 
01276         tyinfo->dobj.objType = DO_DUMMY_TYPE;
01277         if (tytable != NULL)
01278             tyinfo->dobj.dump = tytable->dobj.dump;
01279         else
01280             tyinfo->dobj.dump = false;
01281         return;
01282     }
01283 
01284     /* skip auto-generated array types */
01285     if (tyinfo->isArray)
01286     {
01287         tyinfo->dobj.objType = DO_DUMMY_TYPE;
01288 
01289         /*
01290          * Fall through to set the dump flag; we assume that the subsequent
01291          * rules will do the same thing as they would for the array's base
01292          * type.  (We cannot reliably look up the base type here, since
01293          * getTypes may not have processed it yet.)
01294          */
01295     }
01296 
01297     /* dump only types in dumpable namespaces */
01298     if (!tyinfo->dobj.namespace->dobj.dump)
01299         tyinfo->dobj.dump = false;
01300 
01301     /* skip undefined placeholder types */
01302     else if (!tyinfo->isDefined)
01303         tyinfo->dobj.dump = false;
01304 
01305     else
01306         tyinfo->dobj.dump = true;
01307 }
01308 
01309 /*
01310  * selectDumpableDefaultACL: policy-setting subroutine
01311  *      Mark a default ACL as to be dumped or not
01312  *
01313  * For per-schema default ACLs, dump if the schema is to be dumped.
01314  * Otherwise dump if we are dumping "everything".  Note that dataOnly
01315  * and aclsSkip are checked separately.
01316  */
01317 static void
01318 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
01319 {
01320     if (dinfo->dobj.namespace)
01321         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
01322     else
01323         dinfo->dobj.dump = include_everything;
01324 }
01325 
01326 /*
01327  * selectDumpableExtension: policy-setting subroutine
01328  *      Mark an extension as to be dumped or not
01329  *
01330  * Normally, we dump all extensions, or none of them if include_everything
01331  * is false (i.e., a --schema or --table switch was given).  However, in
01332  * binary-upgrade mode it's necessary to skip built-in extensions, since we
01333  * assume those will already be installed in the target database.  We identify
01334  * such extensions by their having OIDs in the range reserved for initdb.
01335  */
01336 static void
01337 selectDumpableExtension(ExtensionInfo *extinfo)
01338 {
01339     if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
01340         extinfo->dobj.dump = false;
01341     else
01342         extinfo->dobj.dump = include_everything;
01343 }
01344 
01345 /*
01346  * selectDumpableObject: policy-setting subroutine
01347  *      Mark a generic dumpable object as to be dumped or not
01348  *
01349  * Use this only for object types without a special-case routine above.
01350  */
01351 static void
01352 selectDumpableObject(DumpableObject *dobj)
01353 {
01354     /*
01355      * Default policy is to dump if parent namespace is dumpable, or always
01356      * for non-namespace-associated items.
01357      */
01358     if (dobj->namespace)
01359         dobj->dump = dobj->namespace->dobj.dump;
01360     else
01361         dobj->dump = true;
01362 }
01363 
01364 /*
01365  *  Dump a table's contents for loading using the COPY command
01366  *  - this routine is called by the Archiver when it wants the table
01367  *    to be dumped.
01368  */
01369 
01370 static int
01371 dumpTableData_copy(Archive *fout, void *dcontext)
01372 {
01373     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
01374     TableInfo  *tbinfo = tdinfo->tdtable;
01375     const char *classname = tbinfo->dobj.name;
01376     const bool  hasoids = tbinfo->hasoids;
01377     const bool  oids = tdinfo->oids;
01378     PQExpBuffer q = createPQExpBuffer();
01379 
01380     /*
01381      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
01382      * which uses it already.
01383      */
01384     PQExpBuffer clistBuf = createPQExpBuffer();
01385     PGconn     *conn = GetConnection(fout);
01386     PGresult   *res;
01387     int         ret;
01388     char       *copybuf;
01389     const char *column_list;
01390 
01391     if (g_verbose)
01392         write_msg(NULL, "dumping contents of table %s\n", classname);
01393 
01394     /*
01395      * Make sure we are in proper schema.  We will qualify the table name
01396      * below anyway (in case its name conflicts with a pg_catalog table); but
01397      * this ensures reproducible results in case the table contains regproc,
01398      * regclass, etc columns.
01399      */
01400     selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
01401 
01402     /*
01403      * If possible, specify the column list explicitly so that we have no
01404      * possibility of retrieving data in the wrong column order.  (The default
01405      * column ordering of COPY will not be what we want in certain corner
01406      * cases involving ADD COLUMN and inheritance.)
01407      */
01408     if (fout->remoteVersion >= 70300)
01409         column_list = fmtCopyColumnList(tbinfo, clistBuf);
01410     else
01411         column_list = "";       /* can't select columns in COPY */
01412 
01413     if (oids && hasoids)
01414     {
01415         appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
01416                           fmtQualifiedId(fout->remoteVersion,
01417                                          tbinfo->dobj.namespace->dobj.name,
01418                                          classname),
01419                           column_list);
01420     }
01421     else if (tdinfo->filtercond)
01422     {
01423         /* Note: this syntax is only supported in 8.2 and up */
01424         appendPQExpBufferStr(q, "COPY (SELECT ");
01425         /* klugery to get rid of parens in column list */
01426         if (strlen(column_list) > 2)
01427         {
01428             appendPQExpBufferStr(q, column_list + 1);
01429             q->data[q->len - 1] = ' ';
01430         }
01431         else
01432             appendPQExpBufferStr(q, "* ");
01433         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
01434                           fmtQualifiedId(fout->remoteVersion,
01435                                          tbinfo->dobj.namespace->dobj.name,
01436                                          classname),
01437                           tdinfo->filtercond);
01438     }
01439     else
01440     {
01441         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
01442                           fmtQualifiedId(fout->remoteVersion,
01443                                          tbinfo->dobj.namespace->dobj.name,
01444                                          classname),
01445                           column_list);
01446     }
01447     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
01448     PQclear(res);
01449     destroyPQExpBuffer(clistBuf);
01450 
01451     for (;;)
01452     {
01453         ret = PQgetCopyData(conn, &copybuf, 0);
01454 
01455         if (ret < 0)
01456             break;              /* done or error */
01457 
01458         if (copybuf)
01459         {
01460             WriteData(fout, copybuf, ret);
01461             PQfreemem(copybuf);
01462         }
01463 
01464         /* ----------
01465          * THROTTLE:
01466          *
01467          * There was considerable discussion in late July, 2000 regarding
01468          * slowing down pg_dump when backing up large tables. Users with both
01469          * slow & fast (multi-processor) machines experienced performance
01470          * degradation when doing a backup.
01471          *
01472          * Initial attempts based on sleeping for a number of ms for each ms
01473          * of work were deemed too complex, then a simple 'sleep in each loop'
01474          * implementation was suggested. The latter failed because the loop
01475          * was too tight. Finally, the following was implemented:
01476          *
01477          * If throttle is non-zero, then
01478          *      See how long since the last sleep.
01479          *      Work out how long to sleep (based on ratio).
01480          *      If sleep is more than 100ms, then
01481          *          sleep
01482          *          reset timer
01483          *      EndIf
01484          * EndIf
01485          *
01486          * where the throttle value was the number of ms to sleep per ms of
01487          * work. The calculation was done in each loop.
01488          *
01489          * Most of the hard work is done in the backend, and this solution
01490          * still did not work particularly well: on slow machines, the ratio
01491          * was 50:1, and on medium paced machines, 1:1, and on fast
01492          * multi-processor machines, it had little or no effect, for reasons
01493          * that were unclear.
01494          *
01495          * Further discussion ensued, and the proposal was dropped.
01496          *
01497          * For those people who want this feature, it can be implemented using
01498          * gettimeofday in each loop, calculating the time since last sleep,
01499          * multiplying that by the sleep ratio, then if the result is more
01500          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
01501          * function to sleep for a subsecond period ie.
01502          *
01503          * select(0, NULL, NULL, NULL, &tvi);
01504          *
01505          * This will return after the interval specified in the structure tvi.
01506          * Finally, call gettimeofday again to save the 'last sleep time'.
01507          * ----------
01508          */
01509     }
01510     archprintf(fout, "\\.\n\n\n");
01511 
01512     if (ret == -2)
01513     {
01514         /* copy data transfer failed */
01515         write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
01516         write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
01517         write_msg(NULL, "The command was: %s\n", q->data);
01518         exit_nicely(1);
01519     }
01520 
01521     /* Check command status and return to normal libpq state */
01522     res = PQgetResult(conn);
01523     if (PQresultStatus(res) != PGRES_COMMAND_OK)
01524     {
01525         write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
01526         write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
01527         write_msg(NULL, "The command was: %s\n", q->data);
01528         exit_nicely(1);
01529     }
01530     PQclear(res);
01531 
01532     destroyPQExpBuffer(q);
01533     return 1;
01534 }
01535 
01536 /*
01537  * Dump table data using INSERT commands.
01538  *
01539  * Caution: when we restore from an archive file direct to database, the
01540  * INSERT commands emitted by this function have to be parsed by
01541  * pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
01542  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
01543  */
01544 static int
01545 dumpTableData_insert(Archive *fout, void *dcontext)
01546 {
01547     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
01548     TableInfo  *tbinfo = tdinfo->tdtable;
01549     const char *classname = tbinfo->dobj.name;
01550     PQExpBuffer q = createPQExpBuffer();
01551     PGresult   *res;
01552     int         tuple;
01553     int         nfields;
01554     int         field;
01555 
01556     /*
01557      * Make sure we are in proper schema.  We will qualify the table name
01558      * below anyway (in case its name conflicts with a pg_catalog table); but
01559      * this ensures reproducible results in case the table contains regproc,
01560      * regclass, etc columns.
01561      */
01562     selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
01563 
01564     if (fout->remoteVersion >= 70100)
01565     {
01566         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
01567                           "SELECT * FROM ONLY %s",
01568                           fmtQualifiedId(fout->remoteVersion,
01569                                          tbinfo->dobj.namespace->dobj.name,
01570                                          classname));
01571     }
01572     else
01573     {
01574         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
01575                           "SELECT * FROM %s",
01576                           fmtQualifiedId(fout->remoteVersion,
01577                                          tbinfo->dobj.namespace->dobj.name,
01578                                          classname));
01579     }
01580     if (tdinfo->filtercond)
01581         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
01582 
01583     ExecuteSqlStatement(fout, q->data);
01584 
01585     while (1)
01586     {
01587         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
01588                               PGRES_TUPLES_OK);
01589         nfields = PQnfields(res);
01590         for (tuple = 0; tuple < PQntuples(res); tuple++)
01591         {
01592             archprintf(fout, "INSERT INTO %s ", fmtId(classname));
01593             if (nfields == 0)
01594             {
01595                 /* corner case for zero-column table */
01596                 archprintf(fout, "DEFAULT VALUES;\n");
01597                 continue;
01598             }
01599             if (column_inserts)
01600             {
01601                 resetPQExpBuffer(q);
01602                 appendPQExpBuffer(q, "(");
01603                 for (field = 0; field < nfields; field++)
01604                 {
01605                     if (field > 0)
01606                         appendPQExpBuffer(q, ", ");
01607                     appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
01608                 }
01609                 appendPQExpBuffer(q, ") ");
01610                 archputs(q->data, fout);
01611             }
01612             archprintf(fout, "VALUES (");
01613             for (field = 0; field < nfields; field++)
01614             {
01615                 if (field > 0)
01616                     archprintf(fout, ", ");
01617                 if (PQgetisnull(res, tuple, field))
01618                 {
01619                     archprintf(fout, "NULL");
01620                     continue;
01621                 }
01622 
01623                 /* XXX This code is partially duplicated in ruleutils.c */
01624                 switch (PQftype(res, field))
01625                 {
01626                     case INT2OID:
01627                     case INT4OID:
01628                     case INT8OID:
01629                     case OIDOID:
01630                     case FLOAT4OID:
01631                     case FLOAT8OID:
01632                     case NUMERICOID:
01633                         {
01634                             /*
01635                              * These types are printed without quotes unless
01636                              * they contain values that aren't accepted by the
01637                              * scanner unquoted (e.g., 'NaN').  Note that
01638                              * strtod() and friends might accept NaN, so we
01639                              * can't use that to test.
01640                              *
01641                              * In reality we only need to defend against
01642                              * infinity and NaN, so we need not get too crazy
01643                              * about pattern matching here.
01644                              */
01645                             const char *s = PQgetvalue(res, tuple, field);
01646 
01647                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
01648                                 archprintf(fout, "%s", s);
01649                             else
01650                                 archprintf(fout, "'%s'", s);
01651                         }
01652                         break;
01653 
01654                     case BITOID:
01655                     case VARBITOID:
01656                         archprintf(fout, "B'%s'",
01657                                    PQgetvalue(res, tuple, field));
01658                         break;
01659 
01660                     case BOOLOID:
01661                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
01662                             archprintf(fout, "true");
01663                         else
01664                             archprintf(fout, "false");
01665                         break;
01666 
01667                     default:
01668                         /* All other types are printed as string literals. */
01669                         resetPQExpBuffer(q);
01670                         appendStringLiteralAH(q,
01671                                               PQgetvalue(res, tuple, field),
01672                                               fout);
01673                         archputs(q->data, fout);
01674                         break;
01675                 }
01676             }
01677             archprintf(fout, ");\n");
01678         }
01679 
01680         if (PQntuples(res) <= 0)
01681         {
01682             PQclear(res);
01683             break;
01684         }
01685         PQclear(res);
01686     }
01687 
01688     archprintf(fout, "\n\n");
01689 
01690     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
01691 
01692     destroyPQExpBuffer(q);
01693     return 1;
01694 }
01695 
01696 
01697 /*
01698  * dumpTableData -
01699  *    dump the contents of a single table
01700  *
01701  * Actually, this just makes an ArchiveEntry for the table contents.
01702  */
01703 static void
01704 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
01705 {
01706     TableInfo  *tbinfo = tdinfo->tdtable;
01707     PQExpBuffer copyBuf = createPQExpBuffer();
01708     PQExpBuffer clistBuf = createPQExpBuffer();
01709     DataDumperPtr dumpFn;
01710     char       *copyStmt;
01711 
01712     if (!dump_inserts)
01713     {
01714         /* Dump/restore using COPY */
01715         dumpFn = dumpTableData_copy;
01716         /* must use 2 steps here 'cause fmtId is nonreentrant */
01717         appendPQExpBuffer(copyBuf, "COPY %s ",
01718                           fmtId(tbinfo->dobj.name));
01719         appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
01720                           fmtCopyColumnList(tbinfo, clistBuf),
01721                       (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
01722         copyStmt = copyBuf->data;
01723     }
01724     else
01725     {
01726         /* Restore using INSERT */
01727         dumpFn = dumpTableData_insert;
01728         copyStmt = NULL;
01729     }
01730 
01731     /*
01732      * Note: although the TableDataInfo is a full DumpableObject, we treat its
01733      * dependency on its table as "special" and pass it to ArchiveEntry now.
01734      * See comments for BuildArchiveDependencies.
01735      */
01736     ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
01737                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
01738                  NULL, tbinfo->rolname,
01739                  false, "TABLE DATA", SECTION_DATA,
01740                  "", "", copyStmt,
01741                  &(tbinfo->dobj.dumpId), 1,
01742                  dumpFn, tdinfo);
01743 
01744     destroyPQExpBuffer(copyBuf);
01745     destroyPQExpBuffer(clistBuf);
01746 }
01747 
01748 /*
01749  * refreshMatViewData -
01750  *    load or refresh the contents of a single materialized view
01751  *
01752  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
01753  * statement.
01754  */
01755 static void
01756 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
01757 {
01758     TableInfo  *tbinfo = tdinfo->tdtable;
01759     PQExpBuffer q;
01760 
01761     /* If the materialized view is not flagged as scannable, skip this. */
01762     if (!tbinfo->isscannable)
01763         return;
01764 
01765     q = createPQExpBuffer();
01766 
01767     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
01768                       fmtId(tbinfo->dobj.name));
01769 
01770     ArchiveEntry(fout,
01771                  tdinfo->dobj.catId,    /* catalog ID */
01772                  tdinfo->dobj.dumpId,   /* dump ID */
01773                  tbinfo->dobj.name,     /* Name */
01774                  tbinfo->dobj.namespace->dobj.name,     /* Namespace */
01775                  NULL,          /* Tablespace */
01776                  tbinfo->rolname,       /* Owner */
01777                  false,         /* with oids */
01778                  "MATERIALIZED VIEW DATA",      /* Desc */
01779                  SECTION_POST_DATA,     /* Section */
01780                  q->data,       /* Create */
01781                  "",            /* Del */
01782                  NULL,          /* Copy */
01783                  tdinfo->dobj.dependencies,     /* Deps */
01784                  tdinfo->dobj.nDeps,    /* # Deps */
01785                  NULL,          /* Dumper */
01786                  NULL);         /* Dumper Arg */
01787 
01788     destroyPQExpBuffer(q);
01789 }
01790 
01791 /*
01792  * getTableData -
01793  *    set up dumpable objects representing the contents of tables
01794  */
01795 static void
01796 getTableData(TableInfo *tblinfo, int numTables, bool oids)
01797 {
01798     int         i;
01799 
01800     for (i = 0; i < numTables; i++)
01801     {
01802         if (tblinfo[i].dobj.dump)
01803             makeTableDataInfo(&(tblinfo[i]), oids);
01804     }
01805 }
01806 
01807 /*
01808  * Make a dumpable object for the data of this specific table
01809  *
01810  * Note: we make a TableDataInfo if and only if we are going to dump the
01811  * table data; the "dump" flag in such objects isn't used.
01812  */
01813 static void
01814 makeTableDataInfo(TableInfo *tbinfo, bool oids)
01815 {
01816     TableDataInfo *tdinfo;
01817 
01818     /*
01819      * Nothing to do if we already decided to dump the table.  This will
01820      * happen for "config" tables.
01821      */
01822     if (tbinfo->dataObj != NULL)
01823         return;
01824 
01825     /* Skip VIEWs (no data to dump) */
01826     if (tbinfo->relkind == RELKIND_VIEW)
01827         return;
01828     /* Skip FOREIGN TABLEs (no data to dump) */
01829     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
01830         return;
01831 
01832     /* Don't dump data in unlogged tables, if so requested */
01833     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
01834         no_unlogged_table_data)
01835         return;
01836 
01837     /* Check that the data is not explicitly excluded */
01838     if (simple_oid_list_member(&tabledata_exclude_oids,
01839                                tbinfo->dobj.catId.oid))
01840         return;
01841 
01842     /* OK, let's dump it */
01843     tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
01844 
01845     if (tbinfo->relkind == RELKIND_MATVIEW)
01846         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
01847     else
01848         tdinfo->dobj.objType = DO_TABLE_DATA;
01849 
01850     /*
01851      * Note: use tableoid 0 so that this object won't be mistaken for
01852      * something that pg_depend entries apply to.
01853      */
01854     tdinfo->dobj.catId.tableoid = 0;
01855     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
01856     AssignDumpId(&tdinfo->dobj);
01857     tdinfo->dobj.name = tbinfo->dobj.name;
01858     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
01859     tdinfo->tdtable = tbinfo;
01860     tdinfo->oids = oids;
01861     tdinfo->filtercond = NULL;  /* might get set later */
01862     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
01863 
01864     tbinfo->dataObj = tdinfo;
01865 }
01866 
01867 /*
01868  * The refresh for a materialized view must be dependent on the refresh for
01869  * any materialized view that this one is dependent on.
01870  *
01871  * This must be called after all the objects are created, but before they are
01872  * sorted.
01873  */
01874 static void
01875 buildMatViewRefreshDependencies(Archive *fout)
01876 {
01877     PQExpBuffer query;
01878     PGresult   *res;
01879     int         ntups,
01880                 i;
01881     int         i_classid,
01882                 i_objid,
01883                 i_refobjid;
01884 
01885     /* No Mat Views before 9.3. */
01886     if (fout->remoteVersion < 90300)
01887         return;
01888 
01889     /* Make sure we are in proper schema */
01890     selectSourceSchema(fout, "pg_catalog");
01891 
01892     query = createPQExpBuffer();
01893 
01894     appendPQExpBuffer(query, "with recursive w as "
01895                       "( "
01896                     "select d1.objid, d2.refobjid, c2.relkind as refrelkind "
01897                       "from pg_depend d1 "
01898                       "join pg_class c1 on c1.oid = d1.objid "
01899                       "and c1.relkind = 'm' "
01900                       "join pg_rewrite r1 on r1.ev_class = d1.objid "
01901                   "join pg_depend d2 on d2.classid = 'pg_rewrite'::regclass "
01902                       "and d2.objid = r1.oid "
01903                       "and d2.refobjid <> d1.objid "
01904                       "join pg_class c2 on c2.oid = d2.refobjid "
01905                       "and c2.relkind in ('m','v') "
01906                       "where d1.classid = 'pg_class'::regclass "
01907                       "union "
01908                       "select w.objid, d3.refobjid, c3.relkind "
01909                       "from w "
01910                       "join pg_rewrite r3 on r3.ev_class = w.refobjid "
01911                   "join pg_depend d3 on d3.classid = 'pg_rewrite'::regclass "
01912                       "and d3.objid = r3.oid "
01913                       "and d3.refobjid <> w.refobjid "
01914                       "join pg_class c3 on c3.oid = d3.refobjid "
01915                       "and c3.relkind in ('m','v') "
01916                       ") "
01917               "select 'pg_class'::regclass::oid as classid, objid, refobjid "
01918                       "from w "
01919                       "where refrelkind = 'm'");
01920 
01921     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
01922 
01923     ntups = PQntuples(res);
01924 
01925     i_classid = PQfnumber(res, "classid");
01926     i_objid = PQfnumber(res, "objid");
01927     i_refobjid = PQfnumber(res, "refobjid");
01928 
01929     for (i = 0; i < ntups; i++)
01930     {
01931         CatalogId   objId;
01932         CatalogId   refobjId;
01933         DumpableObject *dobj;
01934         DumpableObject *refdobj;
01935         TableInfo  *tbinfo;
01936         TableInfo  *reftbinfo;
01937 
01938         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
01939         objId.oid = atooid(PQgetvalue(res, i, i_objid));
01940         refobjId.tableoid = objId.tableoid;
01941         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
01942 
01943         dobj = findObjectByCatalogId(objId);
01944         if (dobj == NULL)
01945             continue;
01946 
01947         Assert(dobj->objType == DO_TABLE);
01948         tbinfo = (TableInfo *) dobj;
01949         Assert(tbinfo->relkind == RELKIND_MATVIEW);
01950         dobj = (DumpableObject *) tbinfo->dataObj;
01951         if (dobj == NULL)
01952             continue;
01953         Assert(dobj->objType == DO_REFRESH_MATVIEW);
01954 
01955         refdobj = findObjectByCatalogId(refobjId);
01956         if (refdobj == NULL)
01957             continue;
01958 
01959         Assert(refdobj->objType == DO_TABLE);
01960         reftbinfo = (TableInfo *) refdobj;
01961         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
01962         refdobj = (DumpableObject *) reftbinfo->dataObj;
01963         if (refdobj == NULL)
01964             continue;
01965         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
01966 
01967         addObjectDependency(dobj, refdobj->dumpId);
01968 
01969         if (!reftbinfo->isscannable)
01970             tbinfo->isscannable = false;
01971     }
01972 
01973     PQclear(res);
01974 
01975     destroyPQExpBuffer(query);
01976 }
01977 
01978 /*
01979  * getTableDataFKConstraints -
01980  *    add dump-order dependencies reflecting foreign key constraints
01981  *
01982  * This code is executed only in a data-only dump --- in schema+data dumps
01983  * we handle foreign key issues by not creating the FK constraints until
01984  * after the data is loaded.  In a data-only dump, however, we want to
01985  * order the table data objects in such a way that a table's referenced
01986  * tables are restored first.  (In the presence of circular references or
01987  * self-references this may be impossible; we'll detect and complain about
01988  * that during the dependency sorting step.)
01989  */
01990 static void
01991 getTableDataFKConstraints(void)
01992 {
01993     DumpableObject **dobjs;
01994     int         numObjs;
01995     int         i;
01996 
01997     /* Search through all the dumpable objects for FK constraints */
01998     getDumpableObjects(&dobjs, &numObjs);
01999     for (i = 0; i < numObjs; i++)
02000     {
02001         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
02002         {
02003             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
02004             TableInfo  *ftable;
02005 
02006             /* Not interesting unless both tables are to be dumped */
02007             if (cinfo->contable == NULL ||
02008                 cinfo->contable->dataObj == NULL)
02009                 continue;
02010             ftable = findTableByOid(cinfo->confrelid);
02011             if (ftable == NULL ||
02012                 ftable->dataObj == NULL)
02013                 continue;
02014 
02015             /*
02016              * Okay, make referencing table's TABLE_DATA object depend on the
02017              * referenced table's TABLE_DATA object.
02018              */
02019             addObjectDependency(&cinfo->contable->dataObj->dobj,
02020                                 ftable->dataObj->dobj.dumpId);
02021         }
02022     }
02023     free(dobjs);
02024 }
02025 
02026 
02027 /*
02028  * guessConstraintInheritance:
02029  *  In pre-8.4 databases, we can't tell for certain which constraints
02030  *  are inherited.  We assume a CHECK constraint is inherited if its name
02031  *  matches the name of any constraint in the parent.  Originally this code
02032  *  tried to compare the expression texts, but that can fail for various
02033  *  reasons --- for example, if the parent and child tables are in different
02034  *  schemas, reverse-listing of function calls may produce different text
02035  *  (schema-qualified or not) depending on search path.
02036  *
02037  *  In 8.4 and up we can rely on the conislocal field to decide which
02038  *  constraints must be dumped; much safer.
02039  *
02040  *  This function assumes all conislocal flags were initialized to TRUE.
02041  *  It clears the flag on anything that seems to be inherited.
02042  */
02043 static void
02044 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
02045 {
02046     int         i,
02047                 j,
02048                 k;
02049 
02050     for (i = 0; i < numTables; i++)
02051     {
02052         TableInfo  *tbinfo = &(tblinfo[i]);
02053         int         numParents;
02054         TableInfo **parents;
02055         TableInfo  *parent;
02056 
02057         /* Sequences and views never have parents */
02058         if (tbinfo->relkind == RELKIND_SEQUENCE ||
02059             tbinfo->relkind == RELKIND_VIEW)
02060             continue;
02061 
02062         /* Don't bother computing anything for non-target tables, either */
02063         if (!tbinfo->dobj.dump)
02064             continue;
02065 
02066         numParents = tbinfo->numParents;
02067         parents = tbinfo->parents;
02068 
02069         if (numParents == 0)
02070             continue;           /* nothing to see here, move along */
02071 
02072         /* scan for inherited CHECK constraints */
02073         for (j = 0; j < tbinfo->ncheck; j++)
02074         {
02075             ConstraintInfo *constr;
02076 
02077             constr = &(tbinfo->checkexprs[j]);
02078 
02079             for (k = 0; k < numParents; k++)
02080             {
02081                 int         l;
02082 
02083                 parent = parents[k];
02084                 for (l = 0; l < parent->ncheck; l++)
02085                 {
02086                     ConstraintInfo *pconstr = &(parent->checkexprs[l]);
02087 
02088                     if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
02089                     {
02090                         constr->conislocal = false;
02091                         break;
02092                     }
02093                 }
02094                 if (!constr->conislocal)
02095                     break;
02096             }
02097         }
02098     }
02099 }
02100 
02101 
02102 /*
02103  * dumpDatabase:
02104  *  dump the database definition
02105  */
02106 static void
02107 dumpDatabase(Archive *fout)
02108 {
02109     PQExpBuffer dbQry = createPQExpBuffer();
02110     PQExpBuffer delQry = createPQExpBuffer();
02111     PQExpBuffer creaQry = createPQExpBuffer();
02112     PGconn     *conn = GetConnection(fout);
02113     PGresult   *res;
02114     int         i_tableoid,
02115                 i_oid,
02116                 i_dba,
02117                 i_encoding,
02118                 i_collate,
02119                 i_ctype,
02120                 i_frozenxid,
02121                 i_tablespace;
02122     CatalogId   dbCatId;
02123     DumpId      dbDumpId;
02124     const char *datname,
02125                *dba,
02126                *encoding,
02127                *collate,
02128                *ctype,
02129                *tablespace;
02130     uint32      frozenxid;
02131 
02132     datname = PQdb(conn);
02133 
02134     if (g_verbose)
02135         write_msg(NULL, "saving database definition\n");
02136 
02137     /* Make sure we are in proper schema */
02138     selectSourceSchema(fout, "pg_catalog");
02139 
02140     /* Get the database owner and parameters from pg_database */
02141     if (fout->remoteVersion >= 80400)
02142     {
02143         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
02144                           "(%s datdba) AS dba, "
02145                           "pg_encoding_to_char(encoding) AS encoding, "
02146                           "datcollate, datctype, datfrozenxid, "
02147                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
02148                       "shobj_description(oid, 'pg_database') AS description "
02149 
02150                           "FROM pg_database "
02151                           "WHERE datname = ",
02152                           username_subquery);
02153         appendStringLiteralAH(dbQry, datname, fout);
02154     }
02155     else if (fout->remoteVersion >= 80200)
02156     {
02157         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
02158                           "(%s datdba) AS dba, "
02159                           "pg_encoding_to_char(encoding) AS encoding, "
02160                        "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
02161                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
02162                       "shobj_description(oid, 'pg_database') AS description "
02163 
02164                           "FROM pg_database "
02165                           "WHERE datname = ",
02166                           username_subquery);
02167         appendStringLiteralAH(dbQry, datname, fout);
02168     }
02169     else if (fout->remoteVersion >= 80000)
02170     {
02171         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
02172                           "(%s datdba) AS dba, "
02173                           "pg_encoding_to_char(encoding) AS encoding, "
02174                        "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
02175                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
02176                           "FROM pg_database "
02177                           "WHERE datname = ",
02178                           username_subquery);
02179         appendStringLiteralAH(dbQry, datname, fout);
02180     }
02181     else if (fout->remoteVersion >= 70100)
02182     {
02183         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
02184                           "(%s datdba) AS dba, "
02185                           "pg_encoding_to_char(encoding) AS encoding, "
02186                           "NULL AS datcollate, NULL AS datctype, "
02187                           "0 AS datfrozenxid, "
02188                           "NULL AS tablespace "
02189                           "FROM pg_database "
02190                           "WHERE datname = ",
02191                           username_subquery);
02192         appendStringLiteralAH(dbQry, datname, fout);
02193     }
02194     else
02195     {
02196         appendPQExpBuffer(dbQry, "SELECT "
02197                           "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
02198                           "oid, "
02199                           "(%s datdba) AS dba, "
02200                           "pg_encoding_to_char(encoding) AS encoding, "
02201                           "NULL AS datcollate, NULL AS datctype, "
02202                           "0 AS datfrozenxid, "
02203                           "NULL AS tablespace "
02204                           "FROM pg_database "
02205                           "WHERE datname = ",
02206                           username_subquery);
02207         appendStringLiteralAH(dbQry, datname, fout);
02208     }
02209 
02210     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
02211 
02212     i_tableoid = PQfnumber(res, "tableoid");
02213     i_oid = PQfnumber(res, "oid");
02214     i_dba = PQfnumber(res, "dba");
02215     i_encoding = PQfnumber(res, "encoding");
02216     i_collate = PQfnumber(res, "datcollate");
02217     i_ctype = PQfnumber(res, "datctype");
02218     i_frozenxid = PQfnumber(res, "datfrozenxid");
02219     i_tablespace = PQfnumber(res, "tablespace");
02220 
02221     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
02222     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
02223     dba = PQgetvalue(res, 0, i_dba);
02224     encoding = PQgetvalue(res, 0, i_encoding);
02225     collate = PQgetvalue(res, 0, i_collate);
02226     ctype = PQgetvalue(res, 0, i_ctype);
02227     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
02228     tablespace = PQgetvalue(res, 0, i_tablespace);
02229 
02230     appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
02231                       fmtId(datname));
02232     if (strlen(encoding) > 0)
02233     {
02234         appendPQExpBuffer(creaQry, " ENCODING = ");
02235         appendStringLiteralAH(creaQry, encoding, fout);
02236     }
02237     if (strlen(collate) > 0)
02238     {
02239         appendPQExpBuffer(creaQry, " LC_COLLATE = ");
02240         appendStringLiteralAH(creaQry, collate, fout);
02241     }
02242     if (strlen(ctype) > 0)
02243     {
02244         appendPQExpBuffer(creaQry, " LC_CTYPE = ");
02245         appendStringLiteralAH(creaQry, ctype, fout);
02246     }
02247     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
02248         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
02249                           fmtId(tablespace));
02250     appendPQExpBuffer(creaQry, ";\n");
02251 
02252     if (binary_upgrade)
02253     {
02254         appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
02255         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
02256                           "SET datfrozenxid = '%u'\n"
02257                           "WHERE    datname = ",
02258                           frozenxid);
02259         appendStringLiteralAH(creaQry, datname, fout);
02260         appendPQExpBuffer(creaQry, ";\n");
02261 
02262     }
02263 
02264     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
02265                       fmtId(datname));
02266 
02267     dbDumpId = createDumpId();
02268 
02269     ArchiveEntry(fout,
02270                  dbCatId,       /* catalog ID */
02271                  dbDumpId,      /* dump ID */
02272                  datname,       /* Name */
02273                  NULL,          /* Namespace */
02274                  NULL,          /* Tablespace */
02275                  dba,           /* Owner */
02276                  false,         /* with oids */
02277                  "DATABASE",    /* Desc */
02278                  SECTION_PRE_DATA,      /* Section */
02279                  creaQry->data, /* Create */
02280                  delQry->data,  /* Del */
02281                  NULL,          /* Copy */
02282                  NULL,          /* Deps */
02283                  0,             /* # Deps */
02284                  NULL,          /* Dumper */
02285                  NULL);         /* Dumper Arg */
02286 
02287     /*
02288      * pg_largeobject and pg_largeobject_metadata come from the old system
02289      * intact, so set their relfrozenxids.
02290      */
02291     if (binary_upgrade)
02292     {
02293         PGresult   *lo_res;
02294         PQExpBuffer loFrozenQry = createPQExpBuffer();
02295         PQExpBuffer loOutQry = createPQExpBuffer();
02296         int         i_relfrozenxid;
02297 
02298         /*
02299          * pg_largeobject
02300          */
02301         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
02302                           "FROM pg_catalog.pg_class\n"
02303                           "WHERE oid = %u;\n",
02304                           LargeObjectRelationId);
02305 
02306         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
02307 
02308         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
02309 
02310         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
02311         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
02312                           "SET relfrozenxid = '%u'\n"
02313                           "WHERE oid = %u;\n",
02314                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
02315                           LargeObjectRelationId);
02316         ArchiveEntry(fout, nilCatalogId, createDumpId(),
02317                      "pg_largeobject", NULL, NULL, "",
02318                      false, "pg_largeobject", SECTION_PRE_DATA,
02319                      loOutQry->data, "", NULL,
02320                      NULL, 0,
02321                      NULL, NULL);
02322 
02323         PQclear(lo_res);
02324 
02325         /*
02326          * pg_largeobject_metadata
02327          */
02328         if (fout->remoteVersion >= 90000)
02329         {
02330             resetPQExpBuffer(loFrozenQry);
02331             resetPQExpBuffer(loOutQry);
02332 
02333             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
02334                               "FROM pg_catalog.pg_class\n"
02335                               "WHERE oid = %u;\n",
02336                               LargeObjectMetadataRelationId);
02337 
02338             lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
02339 
02340             i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
02341 
02342             appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
02343             appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
02344                               "SET relfrozenxid = '%u'\n"
02345                               "WHERE oid = %u;\n",
02346                               atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
02347                               LargeObjectMetadataRelationId);
02348             ArchiveEntry(fout, nilCatalogId, createDumpId(),
02349                          "pg_largeobject_metadata", NULL, NULL, "",
02350                          false, "pg_largeobject_metadata", SECTION_PRE_DATA,
02351                          loOutQry->data, "", NULL,
02352                          NULL, 0,
02353                          NULL, NULL);
02354 
02355             PQclear(lo_res);
02356         }
02357 
02358         destroyPQExpBuffer(loFrozenQry);
02359         destroyPQExpBuffer(loOutQry);
02360     }
02361 
02362     /* Dump DB comment if any */
02363     if (fout->remoteVersion >= 80200)
02364     {
02365         /*
02366          * 8.2 keeps comments on shared objects in a shared table, so we
02367          * cannot use the dumpComment used for other database objects.
02368          */
02369         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
02370 
02371         if (comment && strlen(comment))
02372         {
02373             resetPQExpBuffer(dbQry);
02374 
02375             /*
02376              * Generates warning when loaded into a differently-named
02377              * database.
02378              */
02379             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
02380             appendStringLiteralAH(dbQry, comment, fout);
02381             appendPQExpBuffer(dbQry, ";\n");
02382 
02383             ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
02384                          dba, false, "COMMENT", SECTION_NONE,
02385                          dbQry->data, "", NULL,
02386                          &dbDumpId, 1, NULL, NULL);
02387         }
02388     }
02389     else
02390     {
02391         resetPQExpBuffer(dbQry);
02392         appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
02393         dumpComment(fout, dbQry->data, NULL, "",
02394                     dbCatId, 0, dbDumpId);
02395     }
02396 
02397     PQclear(res);
02398 
02399     /* Dump shared security label. */
02400     if (!no_security_labels && fout->remoteVersion >= 90200)
02401     {
02402         PQExpBuffer seclabelQry = createPQExpBuffer();
02403 
02404         buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
02405         res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
02406         resetPQExpBuffer(seclabelQry);
02407         emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
02408         if (strlen(seclabelQry->data))
02409             ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
02410                          dba, false, "SECURITY LABEL", SECTION_NONE,
02411                          seclabelQry->data, "", NULL,
02412                          &dbDumpId, 1, NULL, NULL);
02413         destroyPQExpBuffer(seclabelQry);
02414     }
02415 
02416     destroyPQExpBuffer(dbQry);
02417     destroyPQExpBuffer(delQry);
02418     destroyPQExpBuffer(creaQry);
02419 }
02420 
02421 
02422 /*
02423  * dumpEncoding: put the correct encoding into the archive
02424  */
02425 static void
02426 dumpEncoding(Archive *AH)
02427 {
02428     const char *encname = pg_encoding_to_char(AH->encoding);
02429     PQExpBuffer qry = createPQExpBuffer();
02430 
02431     if (g_verbose)
02432         write_msg(NULL, "saving encoding = %s\n", encname);
02433 
02434     appendPQExpBuffer(qry, "SET client_encoding = ");
02435     appendStringLiteralAH(qry, encname, AH);
02436     appendPQExpBuffer(qry, ";\n");
02437 
02438     ArchiveEntry(AH, nilCatalogId, createDumpId(),
02439                  "ENCODING", NULL, NULL, "",
02440                  false, "ENCODING", SECTION_PRE_DATA,
02441                  qry->data, "", NULL,
02442                  NULL, 0,
02443                  NULL, NULL);
02444 
02445     destroyPQExpBuffer(qry);
02446 }
02447 
02448 
02449 /*
02450  * dumpStdStrings: put the correct escape string behavior into the archive
02451  */
02452 static void
02453 dumpStdStrings(Archive *AH)
02454 {
02455     const char *stdstrings = AH->std_strings ? "on" : "off";
02456     PQExpBuffer qry = createPQExpBuffer();
02457 
02458     if (g_verbose)
02459         write_msg(NULL, "saving standard_conforming_strings = %s\n",
02460                   stdstrings);
02461 
02462     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
02463                       stdstrings);
02464 
02465     ArchiveEntry(AH, nilCatalogId, createDumpId(),
02466                  "STDSTRINGS", NULL, NULL, "",
02467                  false, "STDSTRINGS", SECTION_PRE_DATA,
02468                  qry->data, "", NULL,
02469                  NULL, 0,
02470                  NULL, NULL);
02471 
02472     destroyPQExpBuffer(qry);
02473 }
02474 
02475 
02476 /*
02477  * getBlobs:
02478  *  Collect schema-level data about large objects
02479  */
02480 static void
02481 getBlobs(Archive *fout)
02482 {
02483     PQExpBuffer blobQry = createPQExpBuffer();
02484     BlobInfo   *binfo;
02485     DumpableObject *bdata;
02486     PGresult   *res;
02487     int         ntups;
02488     int         i;
02489 
02490     /* Verbose message */
02491     if (g_verbose)
02492         write_msg(NULL, "reading large objects\n");
02493 
02494     /* Make sure we are in proper schema */
02495     selectSourceSchema(fout, "pg_catalog");
02496 
02497     /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
02498     if (fout->remoteVersion >= 90000)
02499         appendPQExpBuffer(blobQry,
02500                           "SELECT oid, (%s lomowner) AS rolname, lomacl"
02501                           " FROM pg_largeobject_metadata",
02502                           username_subquery);
02503     else if (fout->remoteVersion >= 70100)
02504         appendPQExpBuffer(blobQry,
02505                           "SELECT DISTINCT loid, NULL::oid, NULL::oid"
02506                           " FROM pg_largeobject");
02507     else
02508         appendPQExpBuffer(blobQry,
02509                           "SELECT oid, NULL::oid, NULL::oid"
02510                           " FROM pg_class WHERE relkind = 'l'");
02511 
02512     res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
02513 
02514     ntups = PQntuples(res);
02515     if (ntups > 0)
02516     {
02517         /*
02518          * Each large object has its own BLOB archive entry.
02519          */
02520         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
02521 
02522         for (i = 0; i < ntups; i++)
02523         {
02524             binfo[i].dobj.objType = DO_BLOB;
02525             binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
02526             binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
02527             AssignDumpId(&binfo[i].dobj);
02528 
02529             binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
02530             if (!PQgetisnull(res, i, 1))
02531                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
02532             else
02533                 binfo[i].rolname = "";
02534             if (!PQgetisnull(res, i, 2))
02535                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
02536             else
02537                 binfo[i].blobacl = NULL;
02538         }
02539 
02540         /*
02541          * If we have any large objects, a "BLOBS" archive entry is needed.
02542          * This is just a placeholder for sorting; it carries no data now.
02543          */
02544         bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
02545         bdata->objType = DO_BLOB_DATA;
02546         bdata->catId = nilCatalogId;
02547         AssignDumpId(bdata);
02548         bdata->name = pg_strdup("BLOBS");
02549     }
02550 
02551     PQclear(res);
02552     destroyPQExpBuffer(blobQry);
02553 }
02554 
02555 /*
02556  * dumpBlob
02557  *
02558  * dump the definition (metadata) of the given large object
02559  */
02560 static void
02561 dumpBlob(Archive *fout, BlobInfo *binfo)
02562 {
02563     PQExpBuffer cquery = createPQExpBuffer();
02564     PQExpBuffer dquery = createPQExpBuffer();
02565 
02566     appendPQExpBuffer(cquery,
02567                       "SELECT pg_catalog.lo_create('%s');\n",
02568                       binfo->dobj.name);
02569 
02570     appendPQExpBuffer(dquery,
02571                       "SELECT pg_catalog.lo_unlink('%s');\n",
02572                       binfo->dobj.name);
02573 
02574     ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
02575                  binfo->dobj.name,
02576                  NULL, NULL,
02577                  binfo->rolname, false,
02578                  "BLOB", SECTION_PRE_DATA,
02579                  cquery->data, dquery->data, NULL,
02580                  NULL, 0,
02581                  NULL, NULL);
02582 
02583     /* set up tag for comment and/or ACL */
02584     resetPQExpBuffer(cquery);
02585     appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
02586 
02587     /* Dump comment if any */
02588     dumpComment(fout, cquery->data,
02589                 NULL, binfo->rolname,
02590                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
02591 
02592     /* Dump security label if any */
02593     dumpSecLabel(fout, cquery->data,
02594                  NULL, binfo->rolname,
02595                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
02596 
02597     /* Dump ACL if any */
02598     if (binfo->blobacl)
02599         dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
02600                 binfo->dobj.name, NULL, cquery->data,
02601                 NULL, binfo->rolname, binfo->blobacl);
02602 
02603     destroyPQExpBuffer(cquery);
02604     destroyPQExpBuffer(dquery);
02605 }
02606 
02607 /*
02608  * dumpBlobs:
02609  *  dump the data contents of all large objects
02610  */
02611 static int
02612 dumpBlobs(Archive *fout, void *arg)
02613 {
02614     const char *blobQry;
02615     const char *blobFetchQry;
02616     PGconn     *conn = GetConnection(fout);
02617     PGresult   *res;
02618     char        buf[LOBBUFSIZE];
02619     int         ntups;
02620     int         i;
02621     int         cnt;
02622 
02623     if (g_verbose)
02624         write_msg(NULL, "saving large objects\n");
02625 
02626     /* Make sure we are in proper schema */
02627     selectSourceSchema(fout, "pg_catalog");
02628 
02629     /*
02630      * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
02631      * the already-in-memory dumpable objects instead...
02632      */
02633     if (fout->remoteVersion >= 90000)
02634         blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
02635     else if (fout->remoteVersion >= 70100)
02636         blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
02637     else
02638         blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
02639 
02640     ExecuteSqlStatement(fout, blobQry);
02641 
02642     /* Command to fetch from cursor */
02643     blobFetchQry = "FETCH 1000 IN bloboid";
02644 
02645     do
02646     {
02647         /* Do a fetch */
02648         res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
02649 
02650         /* Process the tuples, if any */
02651         ntups = PQntuples(res);
02652         for (i = 0; i < ntups; i++)
02653         {
02654             Oid         blobOid;
02655             int         loFd;
02656 
02657             blobOid = atooid(PQgetvalue(res, i, 0));
02658             /* Open the BLOB */
02659             loFd = lo_open(conn, blobOid, INV_READ);
02660             if (loFd == -1)
02661                 exit_horribly(NULL, "could not open large object %u: %s",
02662                               blobOid, PQerrorMessage(conn));
02663 
02664             StartBlob(fout, blobOid);
02665 
02666             /* Now read it in chunks, sending data to archive */
02667             do
02668             {
02669                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
02670                 if (cnt < 0)
02671                     exit_horribly(NULL, "error reading large object %u: %s",
02672                                   blobOid, PQerrorMessage(conn));
02673 
02674                 WriteData(fout, buf, cnt);
02675             } while (cnt > 0);
02676 
02677             lo_close(conn, loFd);
02678 
02679             EndBlob(fout, blobOid);
02680         }
02681 
02682         PQclear(res);
02683     } while (ntups > 0);
02684 
02685     return 1;
02686 }
02687 
02688 static void
02689 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
02690                                          PQExpBuffer upgrade_buffer,
02691                                          Oid pg_type_oid)
02692 {
02693     PQExpBuffer upgrade_query = createPQExpBuffer();
02694     PGresult   *upgrade_res;
02695     Oid         pg_type_array_oid;
02696 
02697     appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
02698     appendPQExpBuffer(upgrade_buffer,
02699      "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
02700                       pg_type_oid);
02701 
02702     /* we only support old >= 8.3 for binary upgrades */
02703     appendPQExpBuffer(upgrade_query,
02704                       "SELECT typarray "
02705                       "FROM pg_catalog.pg_type "
02706                       "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
02707                       pg_type_oid);
02708 
02709     upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
02710 
02711     pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
02712 
02713     if (OidIsValid(pg_type_array_oid))
02714     {
02715         appendPQExpBuffer(upgrade_buffer,
02716                "\n-- For binary upgrade, must preserve pg_type array oid\n");
02717         appendPQExpBuffer(upgrade_buffer,
02718                           "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
02719                           pg_type_array_oid);
02720     }
02721 
02722     PQclear(upgrade_res);
02723     destroyPQExpBuffer(upgrade_query);
02724 }
02725 
02726 static bool
02727 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
02728                                         PQExpBuffer upgrade_buffer,
02729                                         Oid pg_rel_oid)
02730 {
02731     PQExpBuffer upgrade_query = createPQExpBuffer();
02732     PGresult   *upgrade_res;
02733     Oid         pg_type_oid;
02734     bool        toast_set = false;
02735 
02736     /* we only support old >= 8.3 for binary upgrades */
02737     appendPQExpBuffer(upgrade_query,
02738                       "SELECT c.reltype AS crel, t.reltype AS trel "
02739                       "FROM pg_catalog.pg_class c "
02740                       "LEFT JOIN pg_catalog.pg_class t ON "
02741                       "  (c.reltoastrelid = t.oid) "
02742                       "WHERE c.oid = '%u'::pg_catalog.oid;",
02743                       pg_rel_oid);
02744 
02745     upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
02746 
02747     pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
02748 
02749     binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
02750                                              pg_type_oid);
02751 
02752     if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
02753     {
02754         /* Toast tables do not have pg_type array rows */
02755         Oid         pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
02756                                             PQfnumber(upgrade_res, "trel")));
02757 
02758         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
02759         appendPQExpBuffer(upgrade_buffer,
02760                           "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
02761                           pg_type_toast_oid);
02762 
02763         toast_set = true;
02764     }
02765 
02766     PQclear(upgrade_res);
02767     destroyPQExpBuffer(upgrade_query);
02768 
02769     return toast_set;
02770 }
02771 
02772 static void
02773 binary_upgrade_set_pg_class_oids(Archive *fout,
02774                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
02775                                  bool is_index)
02776 {
02777     PQExpBuffer upgrade_query = createPQExpBuffer();
02778     PGresult   *upgrade_res;
02779     Oid         pg_class_reltoastrelid;
02780     Oid         pg_class_reltoastidxid;
02781 
02782     appendPQExpBuffer(upgrade_query,
02783                       "SELECT c.reltoastrelid, t.reltoastidxid "
02784                       "FROM pg_catalog.pg_class c LEFT JOIN "
02785                       "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
02786                       "WHERE c.oid = '%u'::pg_catalog.oid;",
02787                       pg_class_oid);
02788 
02789     upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
02790 
02791     pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
02792     pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
02793 
02794     appendPQExpBuffer(upgrade_buffer,
02795                    "\n-- For binary upgrade, must preserve pg_class oids\n");
02796 
02797     if (!is_index)
02798     {
02799         appendPQExpBuffer(upgrade_buffer,
02800                           "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
02801                           pg_class_oid);
02802         /* only tables have toast tables, not indexes */
02803         if (OidIsValid(pg_class_reltoastrelid))
02804         {
02805             /*
02806              * One complexity is that the table definition might not require
02807              * the creation of a TOAST table, and the TOAST table might have
02808              * been created long after table creation, when the table was
02809              * loaded with wide data.  By setting the TOAST oid we force
02810              * creation of the TOAST heap and TOAST index by the backend so we
02811              * can cleanly copy the files during binary upgrade.
02812              */
02813 
02814             appendPQExpBuffer(upgrade_buffer,
02815                               "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
02816                               pg_class_reltoastrelid);
02817 
02818             /* every toast table has an index */
02819             appendPQExpBuffer(upgrade_buffer,
02820                               "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
02821                               pg_class_reltoastidxid);
02822         }
02823     }
02824     else
02825         appendPQExpBuffer(upgrade_buffer,
02826                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
02827                           pg_class_oid);
02828 
02829     appendPQExpBuffer(upgrade_buffer, "\n");
02830 
02831     PQclear(upgrade_res);
02832     destroyPQExpBuffer(upgrade_query);
02833 }
02834 
02835 /*
02836  * If the DumpableObject is a member of an extension, add a suitable
02837  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
02838  */
02839 static void
02840 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
02841                                 DumpableObject *dobj,
02842                                 const char *objlabel)
02843 {
02844     DumpableObject *extobj = NULL;
02845     int         i;
02846 
02847     if (!dobj->ext_member)
02848         return;
02849 
02850     /*
02851      * Find the parent extension.  We could avoid this search if we wanted to
02852      * add a link field to DumpableObject, but the space costs of that would
02853      * be considerable.  We assume that member objects could only have a
02854      * direct dependency on their own extension, not any others.
02855      */
02856     for (i = 0; i < dobj->nDeps; i++)
02857     {
02858         extobj = findObjectByDumpId(dobj->dependencies[i]);
02859         if (extobj && extobj->objType == DO_EXTENSION)
02860             break;
02861         extobj = NULL;
02862     }
02863     if (extobj == NULL)
02864         exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
02865 
02866     appendPQExpBuffer(upgrade_buffer,
02867       "\n-- For binary upgrade, handle extension membership the hard way\n");
02868     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
02869                       fmtId(extobj->name),
02870                       objlabel);
02871 }
02872 
02873 /*
02874  * getNamespaces:
02875  *    read all namespaces in the system catalogs and return them in the
02876  * NamespaceInfo* structure
02877  *
02878  *  numNamespaces is set to the number of namespaces read in
02879  */
02880 NamespaceInfo *
02881 getNamespaces(Archive *fout, int *numNamespaces)
02882 {
02883     PGresult   *res;
02884     int         ntups;
02885     int         i;
02886     PQExpBuffer query;
02887     NamespaceInfo *nsinfo;
02888     int         i_tableoid;
02889     int         i_oid;
02890     int         i_nspname;
02891     int         i_rolname;
02892     int         i_nspacl;
02893 
02894     /*
02895      * Before 7.3, there are no real namespaces; create two dummy entries, one
02896      * for user stuff and one for system stuff.
02897      */
02898     if (fout->remoteVersion < 70300)
02899     {
02900         nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
02901 
02902         nsinfo[0].dobj.objType = DO_NAMESPACE;
02903         nsinfo[0].dobj.catId.tableoid = 0;
02904         nsinfo[0].dobj.catId.oid = 0;
02905         AssignDumpId(&nsinfo[0].dobj);
02906         nsinfo[0].dobj.name = pg_strdup("public");
02907         nsinfo[0].rolname = pg_strdup("");
02908         nsinfo[0].nspacl = pg_strdup("");
02909 
02910         selectDumpableNamespace(&nsinfo[0]);
02911 
02912         nsinfo[1].dobj.objType = DO_NAMESPACE;
02913         nsinfo[1].dobj.catId.tableoid = 0;
02914         nsinfo[1].dobj.catId.oid = 1;
02915         AssignDumpId(&nsinfo[1].dobj);
02916         nsinfo[1].dobj.name = pg_strdup("pg_catalog");
02917         nsinfo[1].rolname = pg_strdup("");
02918         nsinfo[1].nspacl = pg_strdup("");
02919 
02920         selectDumpableNamespace(&nsinfo[1]);
02921 
02922         *numNamespaces = 2;
02923 
02924         return nsinfo;
02925     }
02926 
02927     query = createPQExpBuffer();
02928 
02929     /* Make sure we are in proper schema */
02930     selectSourceSchema(fout, "pg_catalog");
02931 
02932     /*
02933      * we fetch all namespaces including system ones, so that every object we
02934      * read in can be linked to a containing namespace.
02935      */
02936     appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
02937                       "(%s nspowner) AS rolname, "
02938                       "nspacl FROM pg_namespace",
02939                       username_subquery);
02940 
02941     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
02942 
02943     ntups = PQntuples(res);
02944 
02945     nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
02946 
02947     i_tableoid = PQfnumber(res, "tableoid");
02948     i_oid = PQfnumber(res, "oid");
02949     i_nspname = PQfnumber(res, "nspname");
02950     i_rolname = PQfnumber(res, "rolname");
02951     i_nspacl = PQfnumber(res, "nspacl");
02952 
02953     for (i = 0; i < ntups; i++)
02954     {
02955         nsinfo[i].dobj.objType = DO_NAMESPACE;
02956         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
02957         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
02958         AssignDumpId(&nsinfo[i].dobj);
02959         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
02960         nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
02961         nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
02962 
02963         /* Decide whether to dump this namespace */
02964         selectDumpableNamespace(&nsinfo[i]);
02965 
02966         if (strlen(nsinfo[i].rolname) == 0)
02967             write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
02968                       nsinfo[i].dobj.name);
02969     }
02970 
02971     PQclear(res);
02972     destroyPQExpBuffer(query);
02973 
02974     *numNamespaces = ntups;
02975 
02976     return nsinfo;
02977 }
02978 
02979 /*
02980  * findNamespace:
02981  *      given a namespace OID and an object OID, look up the info read by
02982  *      getNamespaces
02983  *
02984  * NB: for pre-7.3 source database, we use object OID to guess whether it's
02985  * a system object or not.  In 7.3 and later there is no guessing, and we
02986  * don't use objoid at all.
02987  */
02988 static NamespaceInfo *
02989 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
02990 {
02991     NamespaceInfo *nsinfo;
02992 
02993     if (fout->remoteVersion >= 70300)
02994     {
02995         nsinfo = findNamespaceByOid(nsoid);
02996     }
02997     else
02998     {
02999         /* This code depends on the dummy objects set up by getNamespaces. */
03000         Oid         i;
03001 
03002         if (objoid > g_last_builtin_oid)
03003             i = 0;              /* user object */
03004         else
03005             i = 1;              /* system object */
03006         nsinfo = findNamespaceByOid(i);
03007     }
03008 
03009     if (nsinfo == NULL)
03010         exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
03011 
03012     return nsinfo;
03013 }
03014 
03015 /*
03016  * getExtensions:
03017  *    read all extensions in the system catalogs and return them in the
03018  * ExtensionInfo* structure
03019  *
03020  *  numExtensions is set to the number of extensions read in
03021  */
03022 ExtensionInfo *
03023 getExtensions(Archive *fout, int *numExtensions)
03024 {
03025     PGresult   *res;
03026     int         ntups;
03027     int         i;
03028     PQExpBuffer query;
03029     ExtensionInfo *extinfo;
03030     int         i_tableoid;
03031     int         i_oid;
03032     int         i_extname;
03033     int         i_nspname;
03034     int         i_extrelocatable;
03035     int         i_extversion;
03036     int         i_extconfig;
03037     int         i_extcondition;
03038 
03039     /*
03040      * Before 9.1, there are no extensions.
03041      */
03042     if (fout->remoteVersion < 90100)
03043     {
03044         *numExtensions = 0;
03045         return NULL;
03046     }
03047 
03048     query = createPQExpBuffer();
03049 
03050     /* Make sure we are in proper schema */
03051     selectSourceSchema(fout, "pg_catalog");
03052 
03053     appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
03054                       "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
03055                       "FROM pg_extension x "
03056                       "JOIN pg_namespace n ON n.oid = x.extnamespace");
03057 
03058     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
03059 
03060     ntups = PQntuples(res);
03061 
03062     extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
03063 
03064     i_tableoid = PQfnumber(res, "tableoid");
03065     i_oid = PQfnumber(res, "oid");
03066     i_extname = PQfnumber(res, "extname");
03067     i_nspname = PQfnumber(res, "nspname");
03068     i_extrelocatable = PQfnumber(res, "extrelocatable");
03069     i_extversion = PQfnumber(res, "extversion");
03070     i_extconfig = PQfnumber(res, "extconfig");
03071     i_extcondition = PQfnumber(res, "extcondition");
03072 
03073     for (i = 0; i < ntups; i++)
03074     {
03075         extinfo[i].dobj.objType = DO_EXTENSION;
03076         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
03077         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
03078         AssignDumpId(&extinfo[i].dobj);
03079         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
03080         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
03081         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
03082         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
03083         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
03084         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
03085 
03086         /* Decide whether we want to dump it */
03087         selectDumpableExtension(&(extinfo[i]));
03088     }
03089 
03090     PQclear(res);
03091     destroyPQExpBuffer(query);
03092 
03093     *numExtensions = ntups;
03094 
03095     return extinfo;
03096 }
03097 
03098 /*
03099  * getTypes:
03100  *    read all types in the system catalogs and return them in the
03101  * TypeInfo* structure
03102  *
03103  *  numTypes is set to the number of types read in
03104  *
03105  * NB: this must run after getFuncs() because we assume we can do
03106  * findFuncByOid().
03107  */
03108 TypeInfo *
03109 getTypes(Archive *fout, int *numTypes)
03110 {
03111     PGresult   *res;
03112     int         ntups;
03113     int         i;
03114     PQExpBuffer query = createPQExpBuffer();
03115     TypeInfo   *tyinfo;
03116     ShellTypeInfo *stinfo;
03117     int         i_tableoid;
03118     int         i_oid;
03119     int         i_typname;
03120     int         i_typnamespace;
03121     int         i_typacl;
03122     int         i_rolname;
03123     int         i_typinput;
03124     int         i_typoutput;
03125     int         i_typelem;
03126     int         i_typrelid;
03127     int         i_typrelkind;
03128     int         i_typtype;
03129     int         i_typisdefined;
03130     int         i_isarray;
03131 
03132     /*
03133      * we include even the built-in types because those may be used as array
03134      * elements by user-defined types
03135      *
03136      * we filter out the built-in types when we dump out the types
03137      *
03138      * same approach for undefined (shell) types and array types
03139      *
03140      * Note: as of 8.3 we can reliably detect whether a type is an
03141      * auto-generated array type by checking the element type's typarray.
03142      * (Before that the test is capable of generating false positives.) We
03143      * still check for name beginning with '_', though, so as to avoid the
03144      * cost of the subselect probe for all standard types.  This would have to
03145      * be revisited if the backend ever allows renaming of array types.
03146      */
03147 
03148     /* Make sure we are in proper schema */
03149     selectSourceSchema(fout, "pg_catalog");
03150 
03151     if (fout->remoteVersion >= 90200)
03152     {
03153         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
03154                           "typnamespace, typacl, "
03155                           "(%s typowner) AS rolname, "
03156                           "typinput::oid AS typinput, "
03157                           "typoutput::oid AS typoutput, typelem, typrelid, "
03158                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
03159                           "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
03160                           "typtype, typisdefined, "
03161                           "typname[0] = '_' AND typelem != 0 AND "
03162                           "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
03163                           "FROM pg_type",
03164                           username_subquery);
03165     }
03166     else if (fout->remoteVersion >= 80300)
03167     {
03168         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
03169                           "typnamespace, '{=U}' AS typacl, "
03170                           "(%s typowner) AS rolname, "
03171                           "typinput::oid AS typinput, "
03172                           "typoutput::oid AS typoutput, typelem, typrelid, "
03173                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
03174                           "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
03175                           "typtype, typisdefined, "
03176                           "typname[0] = '_' AND typelem != 0 AND "
03177                           "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
03178                           "FROM pg_type",
03179                           username_subquery);
03180     }
03181     else if (fout->remoteVersion >= 70300)
03182     {
03183         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
03184                           "typnamespace, '{=U}' AS typacl, "
03185                           "(%s typowner) AS rolname, "
03186                           "typinput::oid AS typinput, "
03187                           "typoutput::oid AS typoutput, typelem, typrelid, "
03188                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
03189                           "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
03190                           "typtype, typisdefined, "
03191                           "typname[0] = '_' AND typelem != 0 AS isarray "
03192                           "FROM pg_type",
03193                           username_subquery);
03194     }
03195     else if (fout->remoteVersion >= 70100)
03196     {
03197         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
03198                           "0::oid AS typnamespace, '{=U}' AS typacl, "
03199                           "(%s typowner) AS rolname, "
03200                           "typinput::oid AS typinput, "
03201                           "typoutput::oid AS typoutput, typelem, typrelid, "
03202                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
03203                           "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
03204                           "typtype, typisdefined, "
03205                           "typname[0] = '_' AND typelem != 0 AS isarray "
03206                           "FROM pg_type",
03207                           username_subquery);
03208     }
03209     else
03210     {
03211         appendPQExpBuffer(query, "SELECT "
03212          "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
03213                           "oid, typname, "
03214                           "0::oid AS typnamespace, '{=U}' AS typacl, "
03215                           "(%s typowner) AS rolname, "
03216                           "typinput::oid AS typinput, "
03217                           "typoutput::oid AS typoutput, typelem, typrelid, "
03218                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
03219                           "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
03220                           "typtype, typisdefined, "
03221                           "typname[0] = '_' AND typelem != 0 AS isarray "
03222                           "FROM pg_type",
03223                           username_subquery);
03224     }
03225 
03226     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
03227 
03228     ntups = PQntuples(res);
03229 
03230     tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
03231 
03232     i_tableoid = PQfnumber(res, "tableoid");
03233     i_oid = PQfnumber(res, "oid");
03234     i_typname = PQfnumber(res, "typname");
03235     i_typnamespace = PQfnumber(res, "typnamespace");
03236     i_typacl = PQfnumber(res, "typacl");
03237     i_rolname = PQfnumber(res, "rolname");
03238     i_typinput = PQfnumber(res, "typinput");
03239     i_typoutput = PQfnumber(res, "typoutput");
03240     i_typelem = PQfnumber(res, "typelem");
03241     i_typrelid = PQfnumber(res, "typrelid");
03242     i_typrelkind = PQfnumber(res, "typrelkind");
03243     i_typtype = PQfnumber(res, "typtype");
03244     i_typisdefined = PQfnumber(res, "typisdefined");
03245     i_isarray = PQfnumber(res, "isarray");
03246 
03247     for (i = 0; i < ntups; i++)
03248     {
03249         tyinfo[i].dobj.objType = DO_TYPE;
03250         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
03251         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
03252         AssignDumpId(&tyinfo[i].dobj);
03253         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
03254         tyinfo[i].dobj.namespace =
03255             findNamespace(fout,
03256                           atooid(PQgetvalue(res, i, i_typnamespace)),
03257                           tyinfo[i].dobj.catId.oid);
03258         tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
03259         tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
03260         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
03261         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
03262         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
03263         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
03264         tyinfo[i].shellType = NULL;
03265 
03266         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
03267             tyinfo[i].isDefined = true;
03268         else
03269             tyinfo[i].isDefined = false;
03270 
03271         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
03272             tyinfo[i].isArray = true;
03273         else
03274             tyinfo[i].isArray = false;
03275 
03276         /* Decide whether we want to dump it */
03277         selectDumpableType(&tyinfo[i]);
03278 
03279         /*
03280          * If it's a domain, fetch info about its constraints, if any
03281          */
03282         tyinfo[i].nDomChecks = 0;
03283         tyinfo[i].domChecks = NULL;
03284         if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
03285             getDomainConstraints(fout, &(tyinfo[i]));
03286 
03287         /*
03288          * If it's a base type, make a DumpableObject representing a shell
03289          * definition of the type.  We will need to dump that ahead of the I/O
03290          * functions for the type.  Similarly, range types need a shell
03291          * definition in case they have a canonicalize function.
03292          *
03293          * Note: the shell type doesn't have a catId.  You might think it
03294          * should copy the base type's catId, but then it might capture the
03295          * pg_depend entries for the type, which we don't want.
03296          */
03297         if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
03298                                     tyinfo[i].typtype == TYPTYPE_RANGE))
03299         {
03300             stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
03301             stinfo->dobj.objType = DO_SHELL_TYPE;
03302             stinfo->dobj.catId = nilCatalogId;
03303             AssignDumpId(&stinfo->dobj);
03304             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
03305             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
03306             stinfo->baseType = &(tyinfo[i]);
03307             tyinfo[i].shellType = stinfo;
03308 
03309             /*
03310              * Initially mark the shell type as not to be dumped.  We'll only
03311              * dump it if the I/O or canonicalize functions need to be dumped;
03312              * this is taken care of while sorting dependencies.
03313              */
03314             stinfo->dobj.dump = false;
03315 
03316             /*
03317              * However, if dumping from pre-7.3, there will be no dependency
03318              * info so we have to fake it here.  We only need to worry about
03319              * typinput and typoutput since the other functions only exist
03320              * post-7.3.
03321              */
03322             if (fout->remoteVersion < 70300)
03323             {
03324                 Oid         typinput;
03325                 Oid         typoutput;
03326                 FuncInfo   *funcInfo;
03327 
03328                 typinput = atooid(PQgetvalue(res, i, i_typinput));
03329                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
03330 
03331                 funcInfo = findFuncByOid(typinput);
03332                 if (funcInfo && funcInfo->dobj.dump)
03333                 {
03334                     /* base type depends on function */
03335                     addObjectDependency(&tyinfo[i].dobj,
03336                                         funcInfo->dobj.dumpId);
03337                     /* function depends on shell type */
03338                     addObjectDependency(&funcInfo->dobj,
03339                                         stinfo->dobj.dumpId);
03340                     /* mark shell type as to be dumped */
03341                     stinfo->dobj.dump = true;
03342                 }
03343 
03344                 funcInfo = findFuncByOid(typoutput);
03345                 if (funcInfo && funcInfo->dobj.dump)
03346                 {
03347                     /* base type depends on function */
03348                     addObjectDependency(&tyinfo[i].dobj,
03349                                         funcInfo->dobj.dumpId);
03350                     /* function depends on shell type */
03351                     addObjectDependency(&funcInfo->dobj,
03352                                         stinfo->dobj.dumpId);
03353                     /* mark shell type as to be dumped */
03354                     stinfo->dobj.dump = true;
03355                 }
03356             }
03357         }
03358 
03359         if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
03360             write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
03361                       tyinfo[i].dobj.name);
03362     }
03363 
03364     *numTypes = ntups;
03365 
03366     PQclear(res);
03367 
03368     destroyPQExpBuffer(query);
03369 
03370     return tyinfo;
03371 }
03372 
03373 /*
03374  * getOperators:
03375  *    read all operators in the system catalogs and return them in the
03376  * OprInfo* structure
03377  *
03378  *  numOprs is set to the number of operators read in
03379  */
03380 OprInfo *
03381 getOperators(Archive *fout, int *numOprs)
03382 {
03383     PGresult   *res;
03384     int         ntups;
03385     int         i;
03386     PQExpBuffer query = createPQExpBuffer();
03387     OprInfo    *oprinfo;
03388     int         i_tableoid;
03389     int         i_oid;
03390     int         i_oprname;
03391     int         i_oprnamespace;
03392     int         i_rolname;
03393     int         i_oprkind;
03394     int         i_oprcode;
03395 
03396     /*
03397      * find all operators, including builtin operators; we filter out
03398      * system-defined operators at dump-out time.
03399      */
03400 
03401     /* Make sure we are in proper schema */
03402     selectSourceSchema(fout, "pg_catalog");
03403 
03404     if (fout->remoteVersion >= 70300)
03405     {
03406         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
03407                           "oprnamespace, "
03408                           "(%s oprowner) AS rolname, "
03409                           "oprkind, "
03410                           "oprcode::oid AS oprcode "
03411                           "FROM pg_operator",
03412                           username_subquery);
03413     }
03414     else if (fout->remoteVersion >= 70100)
03415     {
03416         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
03417                           "0::oid AS oprnamespace, "
03418                           "(%s oprowner) AS rolname, "
03419                           "oprkind, "
03420                           "oprcode::oid AS oprcode "
03421                           "FROM pg_operator",
03422                           username_subquery);
03423     }
03424     else
03425     {
03426         appendPQExpBuffer(query, "SELECT "
03427                           "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
03428                           "oid, oprname, "
03429                           "0::oid AS oprnamespace, "
03430                           "(%s oprowner) AS rolname, "
03431                           "oprkind, "
03432                           "oprcode::oid AS oprcode "
03433                           "FROM pg_operator",
03434                           username_subquery);
03435     }
03436 
03437     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
03438 
03439     ntups = PQntuples(res);
03440     *numOprs = ntups;
03441 
03442     oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
03443 
03444     i_tableoid = PQfnumber(res, "tableoid");
03445     i_oid = PQfnumber(res, "oid");
03446     i_oprname = PQfnumber(res, "oprname");
03447     i_oprnamespace = PQfnumber(res, "oprnamespace");
03448     i_rolname = PQfnumber(res, "rolname");
03449     i_oprkind = PQfnumber(res, "oprkind");
03450     i_oprcode = PQfnumber(res, "oprcode");
03451 
03452     for (i = 0; i < ntups; i++)
03453     {
03454         oprinfo[i].dobj.objType = DO_OPERATOR;
03455         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
03456         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
03457         AssignDumpId(&oprinfo[i].dobj);
03458         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
03459         oprinfo[i].dobj.namespace =
03460             findNamespace(fout,
03461                           atooid(PQgetvalue(res, i, i_oprnamespace)),
03462                           oprinfo[i].dobj.catId.oid);
03463         oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
03464         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
03465         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
03466 
03467         /* Decide whether we want to dump it */
03468         selectDumpableObject(&(oprinfo[i].dobj));
03469 
03470         if (strlen(oprinfo[i].rolname) == 0)
03471             write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
03472                       oprinfo[i].dobj.name);
03473     }
03474 
03475     PQclear(res);
03476 
03477     destroyPQExpBuffer(query);
03478 
03479     return oprinfo;
03480 }
03481 
03482 /*
03483  * getCollations:
03484  *    read all collations in the system catalogs and return them in the
03485  * CollInfo* structure
03486  *
03487  *  numCollations is set to the number of collations read in
03488  */
03489 CollInfo *
03490 getCollations(Archive *fout, int *numCollations)
03491 {
03492     PGresult   *res;
03493     int         ntups;
03494     int         i;
03495     PQExpBuffer query;
03496     CollInfo   *collinfo;
03497     int         i_tableoid;
03498     int         i_oid;
03499     int         i_collname;
03500     int         i_collnamespace;
03501     int         i_rolname;
03502 
03503     /* Collations didn't exist pre-9.1 */
03504     if (fout->remoteVersion < 90100)
03505     {
03506         *numCollations = 0;
03507         return NULL;
03508     }
03509 
03510     query = createPQExpBuffer();
03511 
03512     /*
03513      * find all collations, including builtin collations; we filter out
03514      * system-defined collations at dump-out time.
03515      */
03516 
03517     /* Make sure we are in proper schema */
03518     selectSourceSchema(fout, "pg_catalog");
03519 
03520     appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
03521                       "collnamespace, "
03522                       "(%s collowner) AS rolname "
03523                       "FROM pg_collation",
03524                       username_subquery);
03525 
03526     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
03527 
03528     ntups = PQntuples(res);
03529     *numCollations = ntups;
03530 
03531     collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
03532 
03533     i_tableoid = PQfnumber(res, "tableoid");
03534     i_oid = PQfnumber(res, "oid");
03535     i_collname = PQfnumber(res, "collname");
03536     i_collnamespace = PQfnumber(res, "collnamespace");
03537     i_rolname = PQfnumber(res, "rolname");
03538 
03539     for (i = 0; i < ntups; i++)
03540     {
03541         collinfo[i].dobj.objType = DO_COLLATION;
03542         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
03543         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
03544         AssignDumpId(&collinfo[i].dobj);
03545         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
03546         collinfo[i].dobj.namespace =
03547             findNamespace(fout,
03548                           atooid(PQgetvalue(res, i, i_collnamespace)),
03549                           collinfo[i].dobj.catId.oid);
03550         collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
03551 
03552         /* Decide whether we want to dump it */
03553         selectDumpableObject(&(collinfo[i].dobj));
03554     }
03555 
03556     PQclear(res);
03557 
03558     destroyPQExpBuffer(query);
03559 
03560     return collinfo;
03561 }
03562 
03563 /*
03564  * getConversions:
03565  *    read all conversions in the system catalogs and return them in the
03566  * ConvInfo* structure
03567  *
03568  *  numConversions is set to the number of conversions read in
03569  */
03570 ConvInfo *
03571 getConversions(Archive *fout, int *numConversions)
03572 {
03573     PGresult   *res;
03574     int         ntups;
03575     int         i;
03576     PQExpBuffer query = createPQExpBuffer();
03577     ConvInfo   *convinfo;
03578     int         i_tableoid;
03579     int         i_oid;
03580     int         i_conname;
03581     int         i_connamespace;
03582     int         i_rolname;
03583 
03584     /* Conversions didn't exist pre-7.3 */
03585     if (fout->remoteVersion < 70300)
03586     {
03587         *numConversions = 0;
03588         return NULL;
03589     }
03590 
03591     /*
03592      * find all conversions, including builtin conversions; we filter out
03593      * system-defined conversions at dump-out time.
03594      */
03595 
03596     /* Make sure we are in proper schema */
03597     selectSourceSchema(fout, "pg_catalog");
03598 
03599     appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
03600                       "connamespace, "
03601                       "(%s conowner) AS rolname "
03602                       "FROM pg_conversion",
03603                       username_subquery);
03604 
03605     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
03606 
03607     ntups = PQntuples(res);
03608     *numConversions = ntups;
03609 
03610     convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
03611 
03612     i_tableoid = PQfnumber(res, "tableoid");
03613     i_oid = PQfnumber(res, "oid");
03614     i_conname = PQfnumber(res, "conname");
03615     i_connamespace = PQfnumber(res, "connamespace");
03616     i_rolname = PQfnumber(res, "rolname");
03617 
03618     for (i = 0; i < ntups; i++)
03619     {
03620         convinfo[i].dobj.objType = DO_CONVERSION;
03621         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
03622         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
03623         AssignDumpId(&convinfo[i].dobj);
03624         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
03625         convinfo[i].dobj.namespace =
03626             findNamespace(fout,
03627                           atooid(PQgetvalue(res, i, i_connamespace)),
03628                           convinfo[i].dobj.catId.oid);
03629         convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
03630 
03631         /* Decide whether we want to dump it */
03632         selectDumpableObject(&(convinfo[i].dobj));
03633     }
03634 
03635     PQclear(res);
03636 
03637     destroyPQExpBuffer(query);
03638 
03639     return convinfo;
03640 }
03641 
03642 /*
03643  * getOpclasses:
03644  *    read all opclasses in the system catalogs and return them in the
03645  * OpclassInfo* structure
03646  *
03647  *  numOpclasses is set to the number of opclasses read in
03648  */
03649 OpclassInfo *
03650 getOpclasses(Archive *fout, int *numOpclasses)
03651 {
03652     PGresult   *res;
03653     int         ntups;
03654     int         i;
03655     PQExpBuffer query = createPQExpBuffer();
03656     OpclassInfo *opcinfo;
03657     int         i_tableoid;
03658     int         i_oid;
03659     int         i_opcname;
03660     int         i_opcnamespace;
03661     int         i_rolname;
03662 
03663     /*
03664      * find all opclasses, including builtin opclasses; we filter out
03665      * system-defined opclasses at dump-out time.
03666      */
03667 
03668     /* Make sure we are in proper schema */
03669     selectSourceSchema(fout, "pg_catalog");
03670 
03671     if (fout->remoteVersion >= 70300)
03672     {
03673         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
03674                           "opcnamespace, "
03675                           "(%s opcowner) AS rolname "
03676                           "FROM pg_opclass",
03677                           username_subquery);
03678     }
03679     else if (fout->remoteVersion >= 70100)
03680     {
03681         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
03682                           "0::oid AS opcnamespace, "
03683                           "''::name AS rolname "
03684                           "FROM pg_opclass");
03685     }
03686     else
03687     {
03688         appendPQExpBuffer(query, "SELECT "
03689                           "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
03690                           "oid, opcname, "
03691                           "0::oid AS opcnamespace, "
03692                           "''::name AS rolname "
03693                           "FROM pg_opclass");
03694     }
03695 
03696     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
03697 
03698     ntups = PQntuples(res);
03699     *numOpclasses = ntups;
03700 
03701     opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
03702 
03703     i_tableoid = PQfnumber(res, "tableoid");
03704     i_oid = PQfnumber(res, "oid");
03705     i_opcname = PQfnumber(res, "opcname");
03706     i_opcnamespace = PQfnumber(res, "opcnamespace");
03707     i_rolname = PQfnumber(res, "rolname");
03708 
03709     for (i = 0; i < ntups; i++)
03710     {
03711         opcinfo[i].dobj.objType = DO_OPCLASS;
03712         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
03713         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
03714         AssignDumpId(&opcinfo[i].dobj);
03715         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
03716         opcinfo[i].dobj.namespace =
03717             findNamespace(fout,
03718                           atooid(PQgetvalue(res, i, i_opcnamespace)),
03719                           opcinfo[i].dobj.catId.oid);
03720         opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
03721 
03722         /* Decide whether we want to dump it */
03723         selectDumpableObject(&(opcinfo[i].dobj));
03724 
03725         if (fout->remoteVersion >= 70300)
03726         {
03727             if (strlen(opcinfo[i].rolname) == 0)
03728                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
03729                           opcinfo[i].dobj.name);
03730         }
03731     }
03732 
03733     PQclear(res);
03734 
03735     destroyPQExpBuffer(query);
03736 
03737     return opcinfo;
03738 }
03739 
03740 /*
03741  * getOpfamilies:
03742  *    read all opfamilies in the system catalogs and return them in the
03743  * OpfamilyInfo* structure
03744  *
03745  *  numOpfamilies is set to the number of opfamilies read in
03746  */
03747 OpfamilyInfo *
03748 getOpfamilies(Archive *fout, int *numOpfamilies)
03749 {
03750     PGresult   *res;
03751     int         ntups;
03752     int         i;
03753     PQExpBuffer query;
03754     OpfamilyInfo *opfinfo;
03755     int         i_tableoid;
03756     int         i_oid;
03757     int         i_opfname;
03758     int         i_opfnamespace;
03759     int         i_rolname;
03760 
03761     /* Before 8.3, there is no separate concept of opfamilies */
03762     if (fout->remoteVersion < 80300)
03763     {
03764         *numOpfamilies = 0;
03765         return NULL;
03766     }
03767 
03768     query = createPQExpBuffer();
03769 
03770     /*
03771      * find all opfamilies, including builtin opfamilies; we filter out
03772      * system-defined opfamilies at dump-out time.
03773      */
03774 
03775     /* Make sure we are in proper schema */
03776     selectSourceSchema(fout, "pg_catalog");
03777 
03778     appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
03779                       "opfnamespace, "
03780                       "(%s opfowner) AS rolname "
03781                       "FROM pg_opfamily",
03782                       username_subquery);
03783 
03784     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
03785 
03786     ntups = PQntuples(res);
03787     *numOpfamilies = ntups;
03788 
03789     opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
03790 
03791     i_tableoid = PQfnumber(res, "tableoid");
03792     i_oid = PQfnumber(res, "oid");
03793     i_opfname = PQfnumber(res, "opfname");
03794     i_opfnamespace = PQfnumber(res, "opfnamespace");
03795     i_rolname = PQfnumber(res, "rolname");
03796 
03797     for (i = 0; i < ntups; i++)
03798     {
03799         opfinfo[i].dobj.objType = DO_OPFAMILY;
03800         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
03801         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
03802         AssignDumpId(&opfinfo[i].dobj);
03803         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
03804         opfinfo[i].dobj.namespace =
03805             findNamespace(fout,
03806                           atooid(PQgetvalue(res, i, i_opfnamespace)),
03807                           opfinfo[i].dobj.catId.oid);
03808         opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
03809 
03810         /* Decide whether we want to dump it */
03811         selectDumpableObject(&(opfinfo[i].dobj));
03812 
03813         if (fout->remoteVersion >= 70300)
03814         {
03815             if (strlen(opfinfo[i].rolname) == 0)
03816                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
03817                           opfinfo[i].dobj.name);
03818         }
03819     }
03820 
03821     PQclear(res);
03822 
03823     destroyPQExpBuffer(query);
03824 
03825     return opfinfo;
03826 }
03827 
03828 /*
03829  * getAggregates:
03830  *    read all the user-defined aggregates in the system catalogs and
03831  * return them in the AggInfo* structure
03832  *
03833  * numAggs is set to the number of aggregates read in
03834  */
03835 AggInfo *
03836 getAggregates(Archive *fout, int *numAggs)
03837 {
03838     PGresult   *res;
03839     int         ntups;
03840     int         i;
03841     PQExpBuffer query = createPQExpBuffer();
03842     AggInfo    *agginfo;
03843     int         i_tableoid;
03844     int         i_oid;
03845     int         i_aggname;
03846     int         i_aggnamespace;
03847     int         i_pronargs;
03848     int         i_proargtypes;
03849     int         i_rolname;
03850     int         i_aggacl;
03851     int         i_proiargs;
03852 
03853     /* Make sure we are in proper schema */
03854     selectSourceSchema(fout, "pg_catalog");
03855 
03856     /*
03857      * Find all user-defined aggregates.  See comment in getFuncs() for the
03858      * rationale behind the filtering logic.
03859      */
03860 
03861     if (fout->remoteVersion >= 80400)
03862     {
03863         appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
03864                           "pronamespace AS aggnamespace, "
03865                           "pronargs, proargtypes, "
03866             "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
03867                           "(%s proowner) AS rolname, "
03868                           "proacl AS aggacl "
03869                           "FROM pg_proc p "
03870                           "WHERE proisagg AND ("
03871                           "pronamespace != "
03872                           "(SELECT oid FROM pg_namespace "
03873                           "WHERE nspname = 'pg_catalog')",
03874                           username_subquery);
03875         if (binary_upgrade && fout->remoteVersion >= 90100)
03876             appendPQExpBuffer(query,
03877                               " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
03878                               "classid = 'pg_proc'::regclass AND "
03879                               "objid = p.oid AND "
03880                               "refclassid = 'pg_extension'::regclass AND "
03881                               "deptype = 'e')");
03882         appendPQExpBuffer(query, ")");
03883     }
03884     else if (fout->remoteVersion >= 80200)
03885     {
03886         appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
03887                           "pronamespace AS aggnamespace, "
03888                           "pronargs, proargtypes, "
03889                           "NULL::text AS proiargs,"
03890                           "(%s proowner) AS rolname, "
03891                           "proacl AS aggacl "
03892                           "FROM pg_proc p "
03893                           "WHERE proisagg AND ("
03894                           "pronamespace != "
03895                           "(SELECT oid FROM pg_namespace "
03896                           "WHERE nspname = 'pg_catalog'))",
03897                           username_subquery);
03898     }
03899     else if (fout->remoteVersion >= 70300)
03900     {
03901         appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
03902                           "pronamespace AS aggnamespace, "
03903                           "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
03904                           "proargtypes, "
03905                           "NULL::text AS proiargs, "
03906                           "(%s proowner) AS rolname, "
03907                           "proacl AS aggacl "
03908                           "FROM pg_proc "
03909                           "WHERE proisagg "
03910                           "AND pronamespace != "
03911                "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
03912                           username_subquery);
03913     }
03914     else if (fout->remoteVersion >= 70100)
03915     {
03916         appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
03917                           "0::oid AS aggnamespace, "
03918                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
03919                           "aggbasetype AS proargtypes, "
03920                           "NULL::text AS proiargs, "
03921                           "(%s aggowner) AS rolname, "
03922                           "'{=X}' AS aggacl "
03923                           "FROM pg_aggregate "
03924                           "where oid > '%u'::oid",
03925                           username_subquery,
03926                           g_last_builtin_oid);
03927     }
03928     else
03929     {
03930         appendPQExpBuffer(query, "SELECT "
03931                           "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
03932                           "oid, aggname, "
03933                           "0::oid AS aggnamespace, "
03934                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
03935                           "aggbasetype AS proargtypes, "
03936                           "NULL::text AS proiargs, "
03937                           "(%s aggowner) AS rolname, "
03938                           "'{=X}' AS aggacl "
03939                           "FROM pg_aggregate "
03940                           "where oid > '%u'::oid",
03941                           username_subquery,
03942                           g_last_builtin_oid);
03943     }
03944 
03945     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
03946 
03947     ntups = PQntuples(res);
03948     *numAggs = ntups;
03949 
03950     agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
03951 
03952     i_tableoid = PQfnumber(res, "tableoid");
03953     i_oid = PQfnumber(res, "oid");
03954     i_aggname = PQfnumber(res, "aggname");
03955     i_aggnamespace = PQfnumber(res, "aggnamespace");
03956     i_pronargs = PQfnumber(res, "pronargs");
03957     i_proargtypes = PQfnumber(res, "proargtypes");
03958     i_rolname = PQfnumber(res, "rolname");
03959     i_aggacl = PQfnumber(res, "aggacl");
03960     i_proiargs = PQfnumber(res, "proiargs");
03961 
03962     for (i = 0; i < ntups; i++)
03963     {
03964         agginfo[i].aggfn.dobj.objType = DO_AGG;
03965         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
03966         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
03967         AssignDumpId(&agginfo[i].aggfn.dobj);
03968         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
03969         agginfo[i].aggfn.dobj.namespace =
03970             findNamespace(fout,
03971                           atooid(PQgetvalue(res, i, i_aggnamespace)),
03972                           agginfo[i].aggfn.dobj.catId.oid);
03973         agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
03974         if (strlen(agginfo[i].aggfn.rolname) == 0)
03975             write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
03976                       agginfo[i].aggfn.dobj.name);
03977         agginfo[i].aggfn.lang = InvalidOid;     /* not currently interesting */
03978         agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
03979         agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
03980         agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
03981         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
03982         if (agginfo[i].aggfn.nargs == 0)
03983             agginfo[i].aggfn.argtypes = NULL;
03984         else
03985         {
03986             agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
03987             if (fout->remoteVersion >= 70300)
03988                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
03989                               agginfo[i].aggfn.argtypes,
03990                               agginfo[i].aggfn.nargs);
03991             else
03992                 /* it's just aggbasetype */
03993                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
03994         }
03995 
03996         /* Decide whether we want to dump it */
03997         selectDumpableObject(&(agginfo[i].aggfn.dobj));
03998     }
03999 
04000     PQclear(res);
04001 
04002     destroyPQExpBuffer(query);
04003 
04004     return agginfo;
04005 }
04006 
04007 /*
04008  * getFuncs:
04009  *    read all the user-defined functions in the system catalogs and
04010  * return them in the FuncInfo* structure
04011  *
04012  * numFuncs is set to the number of functions read in
04013  */
04014 FuncInfo *
04015 getFuncs(Archive *fout, int *numFuncs)
04016 {
04017     PGresult   *res;
04018     int         ntups;
04019     int         i;
04020     PQExpBuffer query = createPQExpBuffer();
04021     FuncInfo   *finfo;
04022     int         i_tableoid;
04023     int         i_oid;
04024     int         i_proname;
04025     int         i_pronamespace;
04026     int         i_rolname;
04027     int         i_prolang;
04028     int         i_pronargs;
04029     int         i_proargtypes;
04030     int         i_prorettype;
04031     int         i_proacl;
04032     int         i_proiargs;
04033 
04034     /* Make sure we are in proper schema */
04035     selectSourceSchema(fout, "pg_catalog");
04036 
04037     /*
04038      * Find all user-defined functions.  Normally we can exclude functions in
04039      * pg_catalog, which is worth doing since there are several thousand of
04040      * 'em.  However, there are some extensions that create functions in
04041      * pg_catalog.  In normal dumps we can still ignore those --- but in
04042      * binary-upgrade mode, we must dump the member objects of the extension,
04043      * so be sure to fetch any such functions.
04044      *
04045      * Also, in 9.2 and up, exclude functions that are internally dependent on
04046      * something else, since presumably those will be created as a result of
04047      * creating the something else.  This currently only acts to suppress
04048      * constructor functions for range types.  Note that this is OK only
04049      * because the constructors don't have any dependencies the range type
04050      * doesn't have; otherwise we might not get creation ordering correct.
04051      */
04052 
04053     if (fout->remoteVersion >= 80400)
04054     {
04055         appendPQExpBuffer(query,
04056                           "SELECT tableoid, oid, proname, prolang, "
04057                           "pronargs, proargtypes, prorettype, proacl, "
04058                           "pronamespace, "
04059             "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
04060                           "(%s proowner) AS rolname "
04061                           "FROM pg_proc p "
04062                           "WHERE NOT proisagg AND ("
04063                           "pronamespace != "
04064                           "(SELECT oid FROM pg_namespace "
04065                           "WHERE nspname = 'pg_catalog')",
04066                           username_subquery);
04067         if (fout->remoteVersion >= 90200)
04068             appendPQExpBuffer(query,
04069                               "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
04070                               "WHERE classid = 'pg_proc'::regclass AND "
04071                               "objid = p.oid AND deptype = 'i')");
04072         if (binary_upgrade && fout->remoteVersion >= 90100)
04073             appendPQExpBuffer(query,
04074                               "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
04075                               "classid = 'pg_proc'::regclass AND "
04076                               "objid = p.oid AND "
04077                               "refclassid = 'pg_extension'::regclass AND "
04078                               "deptype = 'e')");
04079         appendPQExpBuffer(query, ")");
04080     }
04081     else if (fout->remoteVersion >= 70300)
04082     {
04083         appendPQExpBuffer(query,
04084                           "SELECT tableoid, oid, proname, prolang, "
04085                           "pronargs, proargtypes, prorettype, proacl, "
04086                           "pronamespace, "
04087                           "NULL::text AS proiargs,"
04088                           "(%s proowner) AS rolname "
04089                           "FROM pg_proc p "
04090                           "WHERE NOT proisagg AND ("
04091                           "pronamespace != "
04092                           "(SELECT oid FROM pg_namespace "
04093                           "WHERE nspname = 'pg_catalog'))",
04094                           username_subquery);
04095     }
04096     else if (fout->remoteVersion >= 70100)
04097     {
04098         appendPQExpBuffer(query,
04099                           "SELECT tableoid, oid, proname, prolang, "
04100                           "pronargs, proargtypes, prorettype, "
04101                           "'{=X}' AS proacl, "
04102                           "0::oid AS pronamespace, "
04103                           "NULL::text AS proiargs,"
04104                           "(%s proowner) AS rolname "
04105                           "FROM pg_proc "
04106                           "WHERE pg_proc.oid > '%u'::oid",
04107                           username_subquery,
04108                           g_last_builtin_oid);
04109     }
04110     else
04111     {
04112         appendPQExpBuffer(query,
04113                           "SELECT "
04114                           "(SELECT oid FROM pg_class "
04115                           " WHERE relname = 'pg_proc') AS tableoid, "
04116                           "oid, proname, prolang, "
04117                           "pronargs, proargtypes, prorettype, "
04118                           "'{=X}' AS proacl, "
04119                           "0::oid AS pronamespace, "
04120                           "NULL::text AS proiargs,"
04121                           "(%s proowner) AS rolname "
04122                           "FROM pg_proc "
04123                           "where pg_proc.oid > '%u'::oid",
04124                           username_subquery,
04125                           g_last_builtin_oid);
04126     }
04127 
04128     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
04129 
04130     ntups = PQntuples(res);
04131 
04132     *numFuncs = ntups;
04133 
04134     finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
04135 
04136     i_tableoid = PQfnumber(res, "tableoid");
04137     i_oid = PQfnumber(res, "oid");
04138     i_proname = PQfnumber(res, "proname");
04139     i_pronamespace = PQfnumber(res, "pronamespace");
04140     i_rolname = PQfnumber(res, "rolname");
04141     i_prolang = PQfnumber(res, "prolang");
04142     i_pronargs = PQfnumber(res, "pronargs");
04143     i_proargtypes = PQfnumber(res, "proargtypes");
04144     i_prorettype = PQfnumber(res, "prorettype");
04145     i_proacl = PQfnumber(res, "proacl");
04146     i_proiargs = PQfnumber(res, "proiargs");
04147 
04148     for (i = 0; i < ntups; i++)
04149     {
04150         finfo[i].dobj.objType = DO_FUNC;
04151         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
04152         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
04153         AssignDumpId(&finfo[i].dobj);
04154         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
04155         finfo[i].dobj.namespace =
04156             findNamespace(fout,
04157                           atooid(PQgetvalue(res, i, i_pronamespace)),
04158                           finfo[i].dobj.catId.oid);
04159         finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
04160         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
04161         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
04162         finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
04163         finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
04164         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
04165         if (finfo[i].nargs == 0)
04166             finfo[i].argtypes = NULL;
04167         else
04168         {
04169             finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
04170             parseOidArray(PQgetvalue(res, i, i_proargtypes),
04171                           finfo[i].argtypes, finfo[i].nargs);
04172         }
04173 
04174         /* Decide whether we want to dump it */
04175         selectDumpableObject(&(finfo[i].dobj));
04176 
04177         if (strlen(finfo[i].rolname) == 0)
04178             write_msg(NULL,
04179                  "WARNING: owner of function \"%s\" appears to be invalid\n",
04180                       finfo[i].dobj.name);
04181     }
04182 
04183     PQclear(res);
04184 
04185     destroyPQExpBuffer(query);
04186 
04187     return finfo;
04188 }
04189 
04190 /*
04191  * getTables
04192  *    read all the user-defined tables (no indexes, no catalogs)
04193  * in the system catalogs return them in the TableInfo* structure
04194  *
04195  * numTables is set to the number of tables read in
04196  */
04197 TableInfo *
04198 getTables(Archive *fout, int *numTables)
04199 {
04200     PGresult   *res;
04201     int         ntups;
04202     int         i;
04203     PQExpBuffer query = createPQExpBuffer();
04204     TableInfo  *tblinfo;
04205     int         i_reltableoid;
04206     int         i_reloid;
04207     int         i_relname;
04208     int         i_relnamespace;
04209     int         i_relkind;
04210     int         i_relacl;
04211     int         i_rolname;
04212     int         i_relchecks;
04213     int         i_relhastriggers;
04214     int         i_relhasindex;
04215     int         i_relhasrules;
04216     int         i_relhasoids;
04217     int         i_relfrozenxid;
04218     int         i_toastoid;
04219     int         i_toastfrozenxid;
04220     int         i_relpersistence;
04221     int         i_isscannable;
04222     int         i_owning_tab;
04223     int         i_owning_col;
04224     int         i_reltablespace;
04225     int         i_reloptions;
04226     int         i_toastreloptions;
04227     int         i_reloftype;
04228     int         i_relpages;
04229 
04230     /* Make sure we are in proper schema */
04231     selectSourceSchema(fout, "pg_catalog");
04232 
04233     /*
04234      * Find all the tables and table-like objects.
04235      *
04236      * We include system catalogs, so that we can work if a user table is
04237      * defined to inherit from a system catalog (pretty weird, but...)
04238      *
04239      * We ignore relations that are not ordinary tables, sequences, views,
04240      * materialized views, composite types, or foreign tables.
04241      *
04242      * Composite-type table entries won't be dumped as such, but we have to
04243      * make a DumpableObject for them so that we can track dependencies of the
04244      * composite type (pg_depend entries for columns of the composite type
04245      * link to the pg_class entry not the pg_type entry).
04246      *
04247      * Note: in this phase we should collect only a minimal amount of
04248      * information about each table, basically just enough to decide if it is
04249      * interesting. We must fetch all tables in this phase because otherwise
04250      * we cannot correctly identify inherited columns, owned sequences, etc.
04251      */
04252 
04253     if (fout->remoteVersion >= 90300)
04254     {
04255         /*
04256          * Left join to pick up dependency info linking sequences to their
04257          * owning column, if any (note this dependency is AUTO as of 8.2)
04258          */
04259         appendPQExpBuffer(query,
04260                           "SELECT c.tableoid, c.oid, c.relname, "
04261                           "c.relacl, c.relkind, c.relnamespace, "
04262                           "(%s c.relowner) AS rolname, "
04263                           "c.relchecks, c.relhastriggers, "
04264                           "c.relhasindex, c.relhasrules, c.relhasoids, "
04265                           "c.relfrozenxid, tc.oid AS toid, "
04266                           "tc.relfrozenxid AS tfrozenxid, "
04267                           "c.relpersistence, "
04268                           "CASE WHEN c.relkind = '%c' THEN pg_relation_is_scannable(c.oid) ELSE 't'::bool END as isscannable, "
04269                           "c.relpages, "
04270                           "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
04271                           "d.refobjid AS owning_tab, "
04272                           "d.refobjsubid AS owning_col, "
04273                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
04274                         "array_to_string(c.reloptions, ', ') AS reloptions, "
04275                           "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
04276                           "FROM pg_class c "
04277                           "LEFT JOIN pg_depend d ON "
04278                           "(c.relkind = '%c' AND "
04279                           "d.classid = c.tableoid AND d.objid = c.oid AND "
04280                           "d.objsubid = 0 AND "
04281                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
04282                        "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
04283                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
04284                           "ORDER BY c.oid",
04285                           username_subquery,
04286                           RELKIND_MATVIEW,
04287                           RELKIND_SEQUENCE,
04288                           RELKIND_RELATION, RELKIND_SEQUENCE,
04289                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
04290                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
04291     }
04292     else if (fout->remoteVersion >= 90100)
04293     {
04294         /*
04295          * Left join to pick up dependency info linking sequences to their
04296          * owning column, if any (note this dependency is AUTO as of 8.2)
04297          */
04298         appendPQExpBuffer(query,
04299                           "SELECT c.tableoid, c.oid, c.relname, "
04300                           "c.relacl, c.relkind, c.relnamespace, "
04301                           "(%s c.relowner) AS rolname, "
04302                           "c.relchecks, c.relhastriggers, "
04303                           "c.relhasindex, c.relhasrules, c.relhasoids, "
04304                           "c.relfrozenxid, tc.oid AS toid, "
04305                           "tc.relfrozenxid AS tfrozenxid, "
04306                           "c.relpersistence, 't'::bool as isscannable, "
04307                           "c.relpages, "
04308                           "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
04309                           "d.refobjid AS owning_tab, "
04310                           "d.refobjsubid AS owning_col, "
04311                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
04312                         "array_to_string(c.reloptions, ', ') AS reloptions, "
04313                           "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
04314                           "FROM pg_class c "
04315                           "LEFT JOIN pg_depend d ON "
04316                           "(c.relkind = '%c' AND "
04317                           "d.classid = c.tableoid AND d.objid = c.oid AND "
04318                           "d.objsubid = 0 AND "
04319                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
04320                        "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
04321                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
04322                           "ORDER BY c.oid",
04323                           username_subquery,
04324                           RELKIND_SEQUENCE,
04325                           RELKIND_RELATION, RELKIND_SEQUENCE,
04326                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
04327                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
04328     }
04329     else if (fout->remoteVersion >= 90000)
04330     {
04331         /*
04332          * Left join to pick up dependency info linking sequences to their
04333          * owning column, if any (note this dependency is AUTO as of 8.2)
04334          */
04335         appendPQExpBuffer(query,
04336                           "SELECT c.tableoid, c.oid, c.relname, "
04337                           "c.relacl, c.relkind, c.relnamespace, "
04338                           "(%s c.relowner) AS rolname, "
04339                           "c.relchecks, c.relhastriggers, "
04340                           "c.relhasindex, c.relhasrules, c.relhasoids, "
04341                           "c.relfrozenxid, tc.oid AS toid, "
04342                           "tc.relfrozenxid AS tfrozenxid, "
04343                           "'p' AS relpersistence, 't'::bool as isscannable, "
04344                           "c.relpages, "
04345                           "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
04346                           "d.refobjid AS owning_tab, "
04347                           "d.refobjsubid AS owning_col, "
04348                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
04349                         "array_to_string(c.reloptions, ', ') AS reloptions, "
04350                           "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
04351                           "FROM pg_class c "
04352                           "LEFT JOIN pg_depend d ON "
04353                           "(c.relkind = '%c' AND "
04354                           "d.classid = c.tableoid AND d.objid = c.oid AND "
04355                           "d.objsubid = 0 AND "
04356                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
04357                        "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
04358                           "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
04359                           "ORDER BY c.oid",
04360                           username_subquery,
04361                           RELKIND_SEQUENCE,
04362                           RELKIND_RELATION, RELKIND_SEQUENCE,
04363                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
04364     }
04365     else if (fout->remoteVersion >= 80400)
04366     {
04367         /*
04368          * Left join to pick up dependency info linking sequences to their
04369          * owning column, if any (note this dependency is AUTO as of 8.2)
04370          */
04371         appendPQExpBuffer(query,
04372                           "SELECT c.tableoid, c.oid, c.relname, "
04373                           "c.relacl, c.relkind, c.relnamespace, "
04374                           "(%s c.relowner) AS rolname, "
04375                           "c.relchecks, c.relhastriggers, "
04376                           "c.relhasindex, c.relhasrules, c.relhasoids, "
04377                           "c.relfrozenxid, tc.oid AS toid, "
04378                           "tc.relfrozenxid AS tfrozenxid, "
04379                           "'p' AS relpersistence, 't'::bool as isscannable, "
04380                           "c.relpages, "
04381                           "NULL AS reloftype, "
04382                           "d.refobjid AS owning_tab, "
04383                           "d.refobjsubid AS owning_col, "
04384                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
04385                         "array_to_string(c.reloptions, ', ') AS reloptions, "
04386                           "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
04387                           "FROM pg_class c "
04388                           "LEFT JOIN pg_depend d ON "
04389                           "(c.relkind = '%c' AND "
04390                           "d.classid = c.tableoid AND d.objid = c.oid AND "
04391                           "d.objsubid = 0 AND "
04392                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
04393                        "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
04394                           "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
04395                           "ORDER BY c.oid",
04396                           username_subquery,
04397                           RELKIND_SEQUENCE,
04398                           RELKIND_RELATION, RELKIND_SEQUENCE,
04399                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
04400     }
04401     else if (fout->remoteVersion >= 80200)
04402     {
04403         /*
04404          * Left join to pick up dependency info linking sequences to their
04405          * owning column, if any (note this dependency is AUTO as of 8.2)
04406          */
04407         appendPQExpBuffer(query,
04408                           "SELECT c.tableoid, c.oid, c.relname, "
04409                           "c.relacl, c.relkind, c.relnamespace, "
04410                           "(%s c.relowner) AS rolname, "
04411                       "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
04412                           "c.relhasindex, c.relhasrules, c.relhasoids, "
04413                           "c.relfrozenxid, tc.oid AS toid, "
04414                           "tc.relfrozenxid AS tfrozenxid, "
04415                           "'p' AS relpersistence, 't'::bool as isscannable, "
04416                           "c.relpages, "
04417                           "NULL AS reloftype, "
04418                           "d.refobjid AS owning_tab, "
04419                           "d.refobjsubid AS owning_col, "
04420                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
04421                         "array_to_string(c.reloptions, ', ') AS reloptions, "
04422                           "NULL AS toast_reloptions "
04423                           "FROM pg_class c "
04424                           "LEFT JOIN pg_depend d ON "
04425                           "(c.relkind = '%c' AND "
04426                           "d.classid = c.tableoid AND d.objid = c.oid AND "
04427                           "d.objsubid = 0 AND "
04428                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
04429                        "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
04430                           "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
04431                           "ORDER BY c.oid",
04432                           username_subquery,
04433                           RELKIND_SEQUENCE,
04434                           RELKIND_RELATION, RELKIND_SEQUENCE,
04435                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
04436     }
04437     else if (fout->remoteVersion >= 80000)
04438     {
04439         /*
04440          * Left join to pick up dependency info linking sequences to their
04441          * owning column, if any
04442          */
04443         appendPQExpBuffer(query,
04444                           "SELECT c.tableoid, c.oid, relname, "
04445                           "relacl, relkind, relnamespace, "
04446                           "(%s relowner) AS rolname, "
04447                           "relchecks, (reltriggers <> 0) AS relhastriggers, "
04448                           "relhasindex, relhasrules, relhasoids, "
04449                           "0 AS relfrozenxid, "
04450                           "0 AS toid, "
04451                           "0 AS tfrozenxid, "
04452                           "'p' AS relpersistence, 't'::bool as isscannable, "
04453                           "relpages, "
04454                           "NULL AS reloftype, "
04455                           "d.refobjid AS owning_tab, "
04456                           "d.refobjsubid AS owning_col, "
04457                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
04458                           "NULL AS reloptions, "
04459                           "NULL AS toast_reloptions "
04460                           "FROM pg_class c "
04461                           "LEFT JOIN pg_depend d ON "
04462                           "(c.relkind = '%c' AND "
04463                           "d.classid = c.tableoid AND d.objid = c.oid AND "
04464                           "d.objsubid = 0 AND "
04465                           "d.refclassid = c.tableoid AND d.deptype = 'i') "
04466                           "WHERE relkind in ('%c', '%c', '%c', '%c') "
04467                           "ORDER BY c.oid",
04468                           username_subquery,
04469                           RELKIND_SEQUENCE,
04470                           RELKIND_RELATION, RELKIND_SEQUENCE,
04471                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
04472     }
04473     else if (fout->remoteVersion >= 70300)
04474     {
04475         /*
04476          * Left join to pick up dependency info linking sequences to their
04477          * owning column, if any
04478          */
04479         appendPQExpBuffer(query,
04480                           "SELECT c.tableoid, c.oid, relname, "
04481                           "relacl, relkind, relnamespace, "
04482                           "(%s relowner) AS rolname, "
04483                           "relchecks, (reltriggers <> 0) AS relhastriggers, "
04484                           "relhasindex, relhasrules, relhasoids, "
04485                           "0 AS relfrozenxid, "
04486                           "0 AS toid, "
04487                           "0 AS tfrozenxid, "
04488                           "'p' AS relpersistence, 't'::bool as isscannable, "
04489                           "relpages, "
04490                           "NULL AS reloftype, "
04491                           "d.refobjid AS owning_tab, "
04492                           "d.refobjsubid AS owning_col, "
04493                           "NULL AS reltablespace, "
04494                           "NULL AS reloptions, "
04495                           "NULL AS toast_reloptions "
04496                           "FROM pg_class c "
04497                           "LEFT JOIN pg_depend d ON "
04498                           "(c.relkind = '%c' AND "
04499                           "d.classid = c.tableoid AND d.objid = c.oid AND "
04500                           "d.objsubid = 0 AND "
04501                           "d.refclassid = c.tableoid AND d.deptype = 'i') "
04502                           "WHERE relkind IN ('%c', '%c', '%c', '%c') "
04503                           "ORDER BY c.oid",
04504                           username_subquery,
04505                           RELKIND_SEQUENCE,
04506                           RELKIND_RELATION, RELKIND_SEQUENCE,
04507                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
04508     }
04509     else if (fout->remoteVersion >= 70200)
04510     {
04511         appendPQExpBuffer(query,
04512                           "SELECT tableoid, oid, relname, relacl, relkind, "
04513                           "0::oid AS relnamespace, "
04514                           "(%s relowner) AS rolname, "
04515                           "relchecks, (reltriggers <> 0) AS relhastriggers, "
04516                           "relhasindex, relhasrules, relhasoids, "
04517                           "0 AS relfrozenxid, "
04518                           "0 AS toid, "
04519                           "0 AS tfrozenxid, "
04520                           "'p' AS relpersistence, 't'::bool as isscannable, "
04521                           "relpages, "
04522                           "NULL AS reloftype, "
04523                           "NULL::oid AS owning_tab, "
04524                           "NULL::int4 AS owning_col, "
04525                           "NULL AS reltablespace, "
04526                           "NULL AS reloptions, "
04527                           "NULL AS toast_reloptions "
04528                           "FROM pg_class "
04529                           "WHERE relkind IN ('%c', '%c', '%c') "
04530                           "ORDER BY oid",
04531                           username_subquery,
04532                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
04533     }
04534     else if (fout->remoteVersion >= 70100)
04535     {
04536         /* all tables have oids in 7.1 */
04537         appendPQExpBuffer(query,
04538                           "SELECT tableoid, oid, relname, relacl, relkind, "
04539                           "0::oid AS relnamespace, "
04540                           "(%s relowner) AS rolname, "
04541                           "relchecks, (reltriggers <> 0) AS relhastriggers, "
04542                           "relhasindex, relhasrules, "
04543                           "'t'::bool AS relhasoids, "
04544                           "0 AS relfrozenxid, "
04545                           "0 AS toid, "
04546                           "0 AS tfrozenxid, "
04547                           "'p' AS relpersistence, 't'::bool as isscannable, "
04548                           "relpages, "
04549                           "NULL AS reloftype, "
04550                           "NULL::oid AS owning_tab, "
04551                           "NULL::int4 AS owning_col, "
04552                           "NULL AS reltablespace, "
04553                           "NULL AS reloptions, "
04554                           "NULL AS toast_reloptions "
04555                           "FROM pg_class "
04556                           "WHERE relkind IN ('%c', '%c', '%c') "
04557                           "ORDER BY oid",
04558                           username_subquery,
04559                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
04560     }
04561     else
04562     {
04563         /*
04564          * Before 7.1, view relkind was not set to 'v', so we must check if we
04565          * have a view by looking for a rule in pg_rewrite.
04566          */
04567         appendPQExpBuffer(query,
04568                           "SELECT "
04569         "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
04570                           "oid, relname, relacl, "
04571                           "CASE WHEN relhasrules and relkind = 'r' "
04572                       "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
04573                       "             r.ev_class = c.oid AND r.ev_type = '1') "
04574                           "THEN '%c'::\"char\" "
04575                           "ELSE relkind END AS relkind,"
04576                           "0::oid AS relnamespace, "
04577                           "(%s relowner) AS rolname, "
04578                           "relchecks, (reltriggers <> 0) AS relhastriggers, "
04579                           "relhasindex, relhasrules, "
04580                           "'t'::bool AS relhasoids, "
04581                           "0 as relfrozenxid, "
04582                           "0 AS toid, "
04583                           "0 AS tfrozenxid, "
04584                           "'p' AS relpersistence, 't'::bool as isscannable, "
04585                           "0 AS relpages, "
04586                           "NULL AS reloftype, "
04587                           "NULL::oid AS owning_tab, "
04588                           "NULL::int4 AS owning_col, "
04589                           "NULL AS reltablespace, "
04590                           "NULL AS reloptions, "
04591                           "NULL AS toast_reloptions "
04592                           "FROM pg_class c "
04593                           "WHERE relkind IN ('%c', '%c') "
04594                           "ORDER BY oid",
04595                           RELKIND_VIEW,
04596                           username_subquery,
04597                           RELKIND_RELATION, RELKIND_SEQUENCE);
04598     }
04599 
04600     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
04601 
04602     ntups = PQntuples(res);
04603 
04604     *numTables = ntups;
04605 
04606     /*
04607      * Extract data from result and lock dumpable tables.  We do the locking
04608      * before anything else, to minimize the window wherein a table could
04609      * disappear under us.
04610      *
04611      * Note that we have to save info about all tables here, even when dumping
04612      * only one, because we don't yet know which tables might be inheritance
04613      * ancestors of the target table.
04614      */
04615     tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
04616 
04617     i_reltableoid = PQfnumber(res, "tableoid");
04618     i_reloid = PQfnumber(res, "oid");
04619     i_relname = PQfnumber(res, "relname");
04620     i_relnamespace = PQfnumber(res, "relnamespace");
04621     i_relacl = PQfnumber(res, "relacl");
04622     i_relkind = PQfnumber(res, "relkind");
04623     i_rolname = PQfnumber(res, "rolname");
04624     i_relchecks = PQfnumber(res, "relchecks");
04625     i_relhastriggers = PQfnumber(res, "relhastriggers");
04626     i_relhasindex = PQfnumber(res, "relhasindex");
04627     i_relhasrules = PQfnumber(res, "relhasrules");
04628     i_relhasoids = PQfnumber(res, "relhasoids");
04629     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
04630     i_toastoid = PQfnumber(res, "toid");
04631     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
04632     i_relpersistence = PQfnumber(res, "relpersistence");
04633     i_isscannable = PQfnumber(res, "isscannable");
04634     i_relpages = PQfnumber(res, "relpages");
04635     i_owning_tab = PQfnumber(res, "owning_tab");
04636     i_owning_col = PQfnumber(res, "owning_col");
04637     i_reltablespace = PQfnumber(res, "reltablespace");
04638     i_reloptions = PQfnumber(res, "reloptions");
04639     i_toastreloptions = PQfnumber(res, "toast_reloptions");
04640     i_reloftype = PQfnumber(res, "reloftype");
04641 
04642     if (lockWaitTimeout && fout->remoteVersion >= 70300)
04643     {
04644         /*
04645          * Arrange to fail instead of waiting forever for a table lock.
04646          *
04647          * NB: this coding assumes that the only queries issued within the
04648          * following loop are LOCK TABLEs; else the timeout may be undesirably
04649          * applied to other things too.
04650          */
04651         resetPQExpBuffer(query);
04652         appendPQExpBuffer(query, "SET statement_timeout = ");
04653         appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
04654         ExecuteSqlStatement(fout, query->data);
04655     }
04656 
04657     for (i = 0; i < ntups; i++)
04658     {
04659         tblinfo[i].dobj.objType = DO_TABLE;
04660         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
04661         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
04662         AssignDumpId(&tblinfo[i].dobj);
04663         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
04664         tblinfo[i].dobj.namespace =
04665             findNamespace(fout,
04666                           atooid(PQgetvalue(res, i, i_relnamespace)),
04667                           tblinfo[i].dobj.catId.oid);
04668         tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
04669         tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
04670         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
04671         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
04672         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
04673         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
04674         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
04675         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
04676         tblinfo[i].isscannable = (strcmp(PQgetvalue(res, i, i_isscannable), "t") == 0);
04677         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
04678         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
04679         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
04680         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
04681         if (PQgetisnull(res, i, i_reloftype))
04682             tblinfo[i].reloftype = NULL;
04683         else
04684             tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
04685         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
04686         if (PQgetisnull(res, i, i_owning_tab))
04687         {
04688             tblinfo[i].owning_tab = InvalidOid;
04689             tblinfo[i].owning_col = 0;
04690         }
04691         else
04692         {
04693             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
04694             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
04695         }
04696         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
04697         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
04698         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
04699 
04700         /* other fields were zeroed above */
04701 
04702         /*
04703          * Decide whether we want to dump this table.
04704          */
04705         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
04706             tblinfo[i].dobj.dump = false;
04707         else
04708             selectDumpableTable(&tblinfo[i]);
04709         tblinfo[i].interesting = tblinfo[i].dobj.dump;
04710 
04711         /*
04712          * Read-lock target tables to make sure they aren't DROPPED or altered
04713          * in schema before we get around to dumping them.
04714          *
04715          * Note that we don't explicitly lock parents of the target tables; we
04716          * assume our lock on the child is enough to prevent schema
04717          * alterations to parent tables.
04718          *
04719          * NOTE: it'd be kinda nice to lock other relations too, not only
04720          * plain tables, but the backend doesn't presently allow that.
04721          */
04722         if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
04723         {
04724             resetPQExpBuffer(query);
04725             appendPQExpBuffer(query,
04726                               "LOCK TABLE %s IN ACCESS SHARE MODE",
04727                               fmtQualifiedId(fout->remoteVersion,
04728                                         tblinfo[i].dobj.namespace->dobj.name,
04729                                              tblinfo[i].dobj.name));
04730             ExecuteSqlStatement(fout, query->data);
04731         }
04732 
04733         /* Emit notice if join for owner failed */
04734         if (strlen(tblinfo[i].rolname) == 0)
04735             write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
04736                       tblinfo[i].dobj.name);
04737     }
04738 
04739     if (lockWaitTimeout && fout->remoteVersion >= 70300)
04740     {
04741         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
04742     }
04743 
04744     PQclear(res);
04745 
04746     destroyPQExpBuffer(query);
04747 
04748     return tblinfo;
04749 }
04750 
04751 /*
04752  * getOwnedSeqs
04753  *    identify owned sequences and mark them as dumpable if owning table is
04754  *
04755  * We used to do this in getTables(), but it's better to do it after the
04756  * index used by findTableByOid() has been set up.
04757  */
04758 void
04759 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
04760 {
04761     int         i;
04762 
04763     /*
04764      * Force sequences that are "owned" by table columns to be dumped whenever
04765      * their owning table is being dumped.
04766      */
04767     for (i = 0; i < numTables; i++)
04768     {
04769         TableInfo  *seqinfo = &tblinfo[i];
04770         TableInfo  *owning_tab;
04771 
04772         if (!OidIsValid(seqinfo->owning_tab))
04773             continue;           /* not an owned sequence */
04774         if (seqinfo->dobj.dump)
04775             continue;           /* no need to search */
04776         owning_tab = findTableByOid(seqinfo->owning_tab);
04777         if (owning_tab && owning_tab->dobj.dump)
04778         {
04779             seqinfo->interesting = true;
04780             seqinfo->dobj.dump = true;
04781         }
04782     }
04783 }
04784 
04785 /*
04786  * getInherits
04787  *    read all the inheritance information
04788  * from the system catalogs return them in the InhInfo* structure
04789  *
04790  * numInherits is set to the number of pairs read in
04791  */
04792 InhInfo *
04793 getInherits(Archive *fout, int *numInherits)
04794 {
04795     PGresult   *res;
04796     int         ntups;
04797     int         i;
04798     PQExpBuffer query = createPQExpBuffer();
04799     InhInfo    *inhinfo;
04800 
04801     int         i_inhrelid;
04802     int         i_inhparent;
04803 
04804     /* Make sure we are in proper schema */
04805     selectSourceSchema(fout, "pg_catalog");
04806 
04807     /* find all the inheritance information */
04808 
04809     appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
04810 
04811     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
04812 
04813     ntups = PQntuples(res);
04814 
04815     *numInherits = ntups;
04816 
04817     inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
04818 
04819     i_inhrelid = PQfnumber(res, "inhrelid");
04820     i_inhparent = PQfnumber(res, "inhparent");
04821 
04822     for (i = 0; i < ntups; i++)
04823     {
04824         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
04825         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
04826     }
04827 
04828     PQclear(res);
04829 
04830     destroyPQExpBuffer(query);
04831 
04832     return inhinfo;
04833 }
04834 
04835 /*
04836  * getIndexes
04837  *    get information about every index on a dumpable table
04838  *
04839  * Note: index data is not returned directly to the caller, but it
04840  * does get entered into the DumpableObject tables.
04841  */
04842 void
04843 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
04844 {
04845     int         i,
04846                 j;
04847     PQExpBuffer query = createPQExpBuffer();
04848     PGresult   *res;
04849     IndxInfo   *indxinfo;
04850     ConstraintInfo *constrinfo;
04851     int         i_tableoid,
04852                 i_oid,
04853                 i_indexname,
04854                 i_indexdef,
04855                 i_indnkeys,
04856                 i_indkey,
04857                 i_indisclustered,
04858                 i_contype,
04859                 i_conname,
04860                 i_condeferrable,
04861                 i_condeferred,
04862                 i_contableoid,
04863                 i_conoid,
04864                 i_condef,
04865                 i_tablespace,
04866                 i_options,
04867                 i_relpages;
04868     int         ntups;
04869 
04870     for (i = 0; i < numTables; i++)
04871     {
04872         TableInfo  *tbinfo = &tblinfo[i];
04873 
04874         /* Only plain tables and materialized views have indexes. */
04875         if (tbinfo->relkind != RELKIND_RELATION &&
04876             tbinfo->relkind != RELKIND_MATVIEW)
04877             continue;
04878         if (!tbinfo->hasindex)
04879             continue;
04880 
04881         /* Ignore indexes of tables not to be dumped */
04882         if (!tbinfo->dobj.dump)
04883             continue;
04884 
04885         if (g_verbose)
04886             write_msg(NULL, "reading indexes for table \"%s\"\n",
04887                       tbinfo->dobj.name);
04888 
04889         /* Make sure we are in proper schema so indexdef is right */
04890         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
04891 
04892         /*
04893          * The point of the messy-looking outer join is to find a constraint
04894          * that is related by an internal dependency link to the index. If we
04895          * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
04896          * assume an index won't have more than one internal dependency.
04897          *
04898          * As of 9.0 we don't need to look at pg_depend but can check for a
04899          * match to pg_constraint.conindid.  The check on conrelid is
04900          * redundant but useful because that column is indexed while conindid
04901          * is not.
04902          */
04903         resetPQExpBuffer(query);
04904         if (fout->remoteVersion >= 90000)
04905         {
04906             /*
04907              * the test on indisready is necessary in 9.2, and harmless in
04908              * earlier/later versions
04909              */
04910             appendPQExpBuffer(query,
04911                               "SELECT t.tableoid, t.oid, "
04912                               "t.relname AS indexname, "
04913                      "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
04914                               "t.relnatts AS indnkeys, "
04915                               "i.indkey, i.indisclustered, "
04916                               "t.relpages, "
04917                               "c.contype, c.conname, "
04918                               "c.condeferrable, c.condeferred, "
04919                               "c.tableoid AS contableoid, "
04920                               "c.oid AS conoid, "
04921                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
04922                               "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
04923                             "array_to_string(t.reloptions, ', ') AS options "
04924                               "FROM pg_catalog.pg_index i "
04925                       "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
04926                               "LEFT JOIN pg_catalog.pg_constraint c "
04927                               "ON (i.indrelid = c.conrelid AND "
04928                               "i.indexrelid = c.conindid AND "
04929                               "c.contype IN ('p','u','x')) "
04930                               "WHERE i.indrelid = '%u'::pg_catalog.oid "
04931                               "AND i.indisvalid AND i.indisready "
04932                               "ORDER BY indexname",
04933                               tbinfo->dobj.catId.oid);
04934         }
04935         else if (fout->remoteVersion >= 80200)
04936         {
04937             appendPQExpBuffer(query,
04938                               "SELECT t.tableoid, t.oid, "
04939                               "t.relname AS indexname, "
04940                      "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
04941                               "t.relnatts AS indnkeys, "
04942                               "i.indkey, i.indisclustered, "
04943                               "t.relpages, "
04944                               "c.contype, c.conname, "
04945                               "c.condeferrable, c.condeferred, "
04946                               "c.tableoid AS contableoid, "
04947                               "c.oid AS conoid, "
04948                               "null AS condef, "
04949                               "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
04950                             "array_to_string(t.reloptions, ', ') AS options "
04951                               "FROM pg_catalog.pg_index i "
04952                       "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
04953                               "LEFT JOIN pg_catalog.pg_depend d "
04954                               "ON (d.classid = t.tableoid "
04955                               "AND d.objid = t.oid "
04956                               "AND d.deptype = 'i') "
04957                               "LEFT JOIN pg_catalog.pg_constraint c "
04958                               "ON (d.refclassid = c.tableoid "
04959                               "AND d.refobjid = c.oid) "
04960                               "WHERE i.indrelid = '%u'::pg_catalog.oid "
04961                               "AND i.indisvalid "
04962                               "ORDER BY indexname",
04963                               tbinfo->dobj.catId.oid);
04964         }
04965         else if (fout->remoteVersion >= 80000)
04966         {
04967             appendPQExpBuffer(query,
04968                               "SELECT t.tableoid, t.oid, "
04969                               "t.relname AS indexname, "
04970                      "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
04971                               "t.relnatts AS indnkeys, "
04972                               "i.indkey, i.indisclustered, "
04973                               "t.relpages, "
04974                               "c.contype, c.conname, "
04975                               "c.condeferrable, c.condeferred, "
04976                               "c.tableoid AS contableoid, "
04977                               "c.oid AS conoid, "
04978                               "null AS condef, "
04979                               "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
04980                               "null AS options "
04981                               "FROM pg_catalog.pg_index i "
04982                       "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
04983                               "LEFT JOIN pg_catalog.pg_depend d "
04984                               "ON (d.classid = t.tableoid "
04985                               "AND d.objid = t.oid "
04986                               "AND d.deptype = 'i') "
04987                               "LEFT JOIN pg_catalog.pg_constraint c "
04988                               "ON (d.refclassid = c.tableoid "
04989                               "AND d.refobjid = c.oid) "
04990                               "WHERE i.indrelid = '%u'::pg_catalog.oid "
04991                               "ORDER BY indexname",
04992                               tbinfo->dobj.catId.oid);
04993         }
04994         else if (fout->remoteVersion >= 70300)
04995         {
04996             appendPQExpBuffer(query,
04997                               "SELECT t.tableoid, t.oid, "
04998                               "t.relname AS indexname, "
04999                      "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
05000                               "t.relnatts AS indnkeys, "
05001                               "i.indkey, i.indisclustered, "
05002                               "t.relpages, "
05003                               "c.contype, c.conname, "
05004                               "c.condeferrable, c.condeferred, "
05005                               "c.tableoid AS contableoid, "
05006                               "c.oid AS conoid, "
05007                               "null AS condef, "
05008                               "NULL AS tablespace, "
05009                               "null AS options "
05010                               "FROM pg_catalog.pg_index i "
05011                       "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
05012                               "LEFT JOIN pg_catalog.pg_depend d "
05013                               "ON (d.classid = t.tableoid "
05014                               "AND d.objid = t.oid "
05015                               "AND d.deptype = 'i') "
05016                               "LEFT JOIN pg_catalog.pg_constraint c "
05017                               "ON (d.refclassid = c.tableoid "
05018                               "AND d.refobjid = c.oid) "
05019                               "WHERE i.indrelid = '%u'::pg_catalog.oid "
05020                               "ORDER BY indexname",
05021                               tbinfo->dobj.catId.oid);
05022         }
05023         else if (fout->remoteVersion >= 70100)
05024         {
05025             appendPQExpBuffer(query,
05026                               "SELECT t.tableoid, t.oid, "
05027                               "t.relname AS indexname, "
05028                               "pg_get_indexdef(i.indexrelid) AS indexdef, "
05029                               "t.relnatts AS indnkeys, "
05030                               "i.indkey, false AS indisclustered, "
05031                               "t.relpages, "
05032                               "CASE WHEN i.indisprimary THEN 'p'::char "
05033                               "ELSE '0'::char END AS contype, "
05034                               "t.relname AS conname, "
05035                               "false AS condeferrable, "
05036                               "false AS condeferred, "
05037                               "0::oid AS contableoid, "
05038                               "t.oid AS conoid, "
05039                               "null AS condef, "
05040                               "NULL AS tablespace, "
05041                               "null AS options "
05042                               "FROM pg_index i, pg_class t "
05043                               "WHERE t.oid = i.indexrelid "
05044                               "AND i.indrelid = '%u'::oid "
05045                               "ORDER BY indexname",
05046                               tbinfo->dobj.catId.oid);
05047         }
05048         else
05049         {
05050             appendPQExpBuffer(query,
05051                               "SELECT "
05052                               "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
05053                               "t.oid, "
05054                               "t.relname AS indexname, "
05055                               "pg_get_indexdef(i.indexrelid) AS indexdef, "
05056                               "t.relnatts AS indnkeys, "
05057                               "i.indkey, false AS indisclustered, "
05058                               "t.relpages, "
05059                               "CASE WHEN i.indisprimary THEN 'p'::char "
05060                               "ELSE '0'::char END AS contype, "
05061                               "t.relname AS conname, "
05062                               "false AS condeferrable, "
05063                               "false AS condeferred, "
05064                               "0::oid AS contableoid, "
05065                               "t.oid AS conoid, "
05066                               "null AS condef, "
05067                               "NULL AS tablespace, "
05068                               "null AS options "
05069                               "FROM pg_index i, pg_class t "
05070                               "WHERE t.oid = i.indexrelid "
05071                               "AND i.indrelid = '%u'::oid "
05072                               "ORDER BY indexname",
05073                               tbinfo->dobj.catId.oid);
05074         }
05075 
05076         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
05077 
05078         ntups = PQntuples(res);
05079 
05080         i_tableoid = PQfnumber(res, "tableoid");
05081         i_oid = PQfnumber(res, "oid");
05082         i_indexname = PQfnumber(res, "indexname");
05083         i_indexdef = PQfnumber(res, "indexdef");
05084         i_indnkeys = PQfnumber(res, "indnkeys");
05085         i_indkey = PQfnumber(res, "indkey");
05086         i_indisclustered = PQfnumber(res, "indisclustered");
05087         i_relpages = PQfnumber(res, "relpages");
05088         i_contype = PQfnumber(res, "contype");
05089         i_conname = PQfnumber(res, "conname");
05090         i_condeferrable = PQfnumber(res, "condeferrable");
05091         i_condeferred = PQfnumber(res, "condeferred");
05092         i_contableoid = PQfnumber(res, "contableoid");
05093         i_conoid = PQfnumber(res, "conoid");
05094         i_condef = PQfnumber(res, "condef");
05095         i_tablespace = PQfnumber(res, "tablespace");
05096         i_options = PQfnumber(res, "options");
05097 
05098         indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
05099         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
05100 
05101         for (j = 0; j < ntups; j++)
05102         {
05103             char        contype;
05104 
05105             indxinfo[j].dobj.objType = DO_INDEX;
05106             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
05107             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
05108             AssignDumpId(&indxinfo[j].dobj);
05109             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
05110             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
05111             indxinfo[j].indextable = tbinfo;
05112             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
05113             indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
05114             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
05115             indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
05116 
05117             /*
05118              * In pre-7.4 releases, indkeys may contain more entries than
05119              * indnkeys says (since indnkeys will be 1 for a functional
05120              * index).  We don't actually care about this case since we don't
05121              * examine indkeys except for indexes associated with PRIMARY and
05122              * UNIQUE constraints, which are never functional indexes. But we
05123              * have to allocate enough space to keep parseOidArray from
05124              * complaining.
05125              */
05126             indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
05127             parseOidArray(PQgetvalue(res, j, i_indkey),
05128                           indxinfo[j].indkeys, INDEX_MAX_KEYS);
05129             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
05130             indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
05131             contype = *(PQgetvalue(res, j, i_contype));
05132 
05133             if (contype == 'p' || contype == 'u' || contype == 'x')
05134             {
05135                 /*
05136                  * If we found a constraint matching the index, create an
05137                  * entry for it.
05138                  *
05139                  * In a pre-7.3 database, we take this path iff the index was
05140                  * marked indisprimary.
05141                  */
05142                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
05143                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
05144                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
05145                 AssignDumpId(&constrinfo[j].dobj);
05146                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
05147                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
05148                 constrinfo[j].contable = tbinfo;
05149                 constrinfo[j].condomain = NULL;
05150                 constrinfo[j].contype = contype;
05151                 if (contype == 'x')
05152                     constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
05153                 else
05154                     constrinfo[j].condef = NULL;
05155                 constrinfo[j].confrelid = InvalidOid;
05156                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
05157                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
05158                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
05159                 constrinfo[j].conislocal = true;
05160                 constrinfo[j].separate = true;
05161 
05162                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
05163 
05164                 /* If pre-7.3 DB, better make sure table comes first */
05165                 addObjectDependency(&constrinfo[j].dobj,
05166                                     tbinfo->dobj.dumpId);
05167             }
05168             else
05169             {
05170                 /* Plain secondary index */
05171                 indxinfo[j].indexconstraint = 0;
05172             }
05173         }
05174 
05175         PQclear(res);
05176     }
05177 
05178     destroyPQExpBuffer(query);
05179 }
05180 
05181 /*
05182  * getConstraints
05183  *
05184  * Get info about constraints on dumpable tables.
05185  *
05186  * Currently handles foreign keys only.
05187  * Unique and primary key constraints are handled with indexes,
05188  * while check constraints are processed in getTableAttrs().
05189  */
05190 void
05191 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
05192 {
05193     int         i,
05194                 j;
05195     ConstraintInfo *constrinfo;
05196     PQExpBuffer query;
05197     PGresult   *res;
05198     int         i_contableoid,
05199                 i_conoid,
05200                 i_conname,
05201                 i_confrelid,
05202                 i_condef;
05203     int         ntups;
05204 
05205     /* pg_constraint was created in 7.3, so nothing to do if older */
05206     if (fout->remoteVersion < 70300)
05207         return;
05208 
05209     query = createPQExpBuffer();
05210 
05211     for (i = 0; i < numTables; i++)
05212     {
05213         TableInfo  *tbinfo = &tblinfo[i];
05214 
05215         if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
05216             continue;
05217 
05218         if (g_verbose)
05219             write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
05220                       tbinfo->dobj.name);
05221 
05222         /*
05223          * select table schema to ensure constraint expr is qualified if
05224          * needed
05225          */
05226         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
05227 
05228         resetPQExpBuffer(query);
05229         appendPQExpBuffer(query,
05230                           "SELECT tableoid, oid, conname, confrelid, "
05231                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
05232                           "FROM pg_catalog.pg_constraint "
05233                           "WHERE conrelid = '%u'::pg_catalog.oid "
05234                           "AND contype = 'f'",
05235                           tbinfo->dobj.catId.oid);
05236         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
05237 
05238         ntups = PQntuples(res);
05239 
05240         i_contableoid = PQfnumber(res, "tableoid");
05241         i_conoid = PQfnumber(res, "oid");
05242         i_conname = PQfnumber(res, "conname");
05243         i_confrelid = PQfnumber(res, "confrelid");
05244         i_condef = PQfnumber(res, "condef");
05245 
05246         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
05247 
05248         for (j = 0; j < ntups; j++)
05249         {
05250             constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
05251             constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
05252             constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
05253             AssignDumpId(&constrinfo[j].dobj);
05254             constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
05255             constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
05256             constrinfo[j].contable = tbinfo;
05257             constrinfo[j].condomain = NULL;
05258             constrinfo[j].contype = 'f';
05259             constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
05260             constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
05261             constrinfo[j].conindex = 0;
05262             constrinfo[j].condeferrable = false;
05263             constrinfo[j].condeferred = false;
05264             constrinfo[j].conislocal = true;
05265             constrinfo[j].separate = true;
05266         }
05267 
05268         PQclear(res);
05269     }
05270 
05271     destroyPQExpBuffer(query);
05272 }
05273 
05274 /*
05275  * getDomainConstraints
05276  *
05277  * Get info about constraints on a domain.
05278  */
05279 static void
05280 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
05281 {
05282     int         i;
05283     ConstraintInfo *constrinfo;
05284     PQExpBuffer query;
05285     PGresult   *res;
05286     int         i_tableoid,
05287                 i_oid,
05288                 i_conname,
05289                 i_consrc;
05290     int         ntups;
05291 
05292     /* pg_constraint was created in 7.3, so nothing to do if older */
05293     if (fout->remoteVersion < 70300)
05294         return;
05295 
05296     /*
05297      * select appropriate schema to ensure names in constraint are properly
05298      * qualified
05299      */
05300     selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
05301 
05302     query = createPQExpBuffer();
05303 
05304     if (fout->remoteVersion >= 90100)
05305         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
05306                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
05307                           "convalidated "
05308                           "FROM pg_catalog.pg_constraint "
05309                           "WHERE contypid = '%u'::pg_catalog.oid "
05310                           "ORDER BY conname",
05311                           tyinfo->dobj.catId.oid);
05312 
05313     else if (fout->remoteVersion >= 70400)
05314         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
05315                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
05316                           "true as convalidated "
05317                           "FROM pg_catalog.pg_constraint "
05318                           "WHERE contypid = '%u'::pg_catalog.oid "
05319                           "ORDER BY conname",
05320                           tyinfo->dobj.catId.oid);
05321     else
05322         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
05323                           "'CHECK (' || consrc || ')' AS consrc, "
05324                           "true as convalidated "
05325                           "FROM pg_catalog.pg_constraint "
05326                           "WHERE contypid = '%u'::pg_catalog.oid "
05327                           "ORDER BY conname",
05328                           tyinfo->dobj.catId.oid);
05329 
05330     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
05331 
05332     ntups = PQntuples(res);
05333 
05334     i_tableoid = PQfnumber(res, "tableoid");
05335     i_oid = PQfnumber(res, "oid");
05336     i_conname = PQfnumber(res, "conname");
05337     i_consrc = PQfnumber(res, "consrc");
05338 
05339     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
05340 
05341     tyinfo->nDomChecks = ntups;
05342     tyinfo->domChecks = constrinfo;
05343 
05344     for (i = 0; i < ntups; i++)
05345     {
05346         bool        validated = PQgetvalue(res, i, 4)[0] == 't';
05347 
05348         constrinfo[i].dobj.objType = DO_CONSTRAINT;
05349         constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
05350         constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
05351         AssignDumpId(&constrinfo[i].dobj);
05352         constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
05353         constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
05354         constrinfo[i].contable = NULL;
05355         constrinfo[i].condomain = tyinfo;
05356         constrinfo[i].contype = 'c';
05357         constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
05358         constrinfo[i].confrelid = InvalidOid;
05359         constrinfo[i].conindex = 0;
05360         constrinfo[i].condeferrable = false;
05361         constrinfo[i].condeferred = false;
05362         constrinfo[i].conislocal = true;
05363 
05364         constrinfo[i].separate = !validated;
05365 
05366         /*
05367          * Make the domain depend on the constraint, ensuring it won't be
05368          * output till any constraint dependencies are OK.  If the constraint
05369          * has not been validated, it's going to be dumped after the domain
05370          * anyway, so this doesn't matter.
05371          */
05372         if (validated)
05373             addObjectDependency(&tyinfo->dobj,
05374                                 constrinfo[i].dobj.dumpId);
05375     }
05376 
05377     PQclear(res);
05378 
05379     destroyPQExpBuffer(query);
05380 }
05381 
05382 /*
05383  * getRules
05384  *    get basic information about every rule in the system
05385  *
05386  * numRules is set to the number of rules read in
05387  */
05388 RuleInfo *
05389 getRules(Archive *fout, int *numRules)
05390 {
05391     PGresult   *res;
05392     int         ntups;
05393     int         i;
05394     PQExpBuffer query = createPQExpBuffer();
05395     RuleInfo   *ruleinfo;
05396     int         i_tableoid;
05397     int         i_oid;
05398     int         i_rulename;
05399     int         i_ruletable;
05400     int         i_ev_type;
05401     int         i_is_instead;
05402     int         i_ev_enabled;
05403 
05404     /* Make sure we are in proper schema */
05405     selectSourceSchema(fout, "pg_catalog");
05406 
05407     if (fout->remoteVersion >= 80300)
05408     {
05409         appendPQExpBuffer(query, "SELECT "
05410                           "tableoid, oid, rulename, "
05411                           "ev_class AS ruletable, ev_type, is_instead, "
05412                           "ev_enabled "
05413                           "FROM pg_rewrite "
05414                           "ORDER BY oid");
05415     }
05416     else if (fout->remoteVersion >= 70100)
05417     {
05418         appendPQExpBuffer(query, "SELECT "
05419                           "tableoid, oid, rulename, "
05420                           "ev_class AS ruletable, ev_type, is_instead, "
05421                           "'O'::char AS ev_enabled "
05422                           "FROM pg_rewrite "
05423                           "ORDER BY oid");
05424     }
05425     else
05426     {
05427         appendPQExpBuffer(query, "SELECT "
05428                           "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
05429                           "oid, rulename, "
05430                           "ev_class AS ruletable, ev_type, is_instead, "
05431                           "'O'::char AS ev_enabled "
05432                           "FROM pg_rewrite "
05433                           "ORDER BY oid");
05434     }
05435 
05436     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
05437 
05438     ntups = PQntuples(res);
05439 
05440     *numRules = ntups;
05441 
05442     ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
05443 
05444     i_tableoid = PQfnumber(res, "tableoid");
05445     i_oid = PQfnumber(res, "oid");
05446     i_rulename = PQfnumber(res, "rulename");
05447     i_ruletable = PQfnumber(res, "ruletable");
05448     i_ev_type = PQfnumber(res, "ev_type");
05449     i_is_instead = PQfnumber(res, "is_instead");
05450     i_ev_enabled = PQfnumber(res, "ev_enabled");
05451 
05452     for (i = 0; i < ntups; i++)
05453     {
05454         Oid         ruletableoid;
05455 
05456         ruleinfo[i].dobj.objType = DO_RULE;
05457         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
05458         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
05459         AssignDumpId(&ruleinfo[i].dobj);
05460         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
05461         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
05462         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
05463         if (ruleinfo[i].ruletable == NULL)
05464             exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
05465                           ruletableoid, ruleinfo[i].dobj.catId.oid);
05466         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
05467         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
05468         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
05469         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
05470         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
05471         if (ruleinfo[i].ruletable)
05472         {
05473             /*
05474              * If the table is a view or materialized view, force its ON
05475              * SELECT rule to be sorted before the view itself --- this
05476              * ensures that any dependencies for the rule affect the table's
05477              * positioning. Other rules are forced to appear after their
05478              * table.
05479              */
05480             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
05481                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
05482                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
05483             {
05484                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
05485                                     ruleinfo[i].dobj.dumpId);
05486                 /* We'll merge the rule into CREATE VIEW, if possible */
05487                 ruleinfo[i].separate = false;
05488             }
05489             else
05490             {
05491                 addObjectDependency(&ruleinfo[i].dobj,
05492                                     ruleinfo[i].ruletable->dobj.dumpId);
05493                 ruleinfo[i].separate = true;
05494             }
05495         }
05496         else
05497             ruleinfo[i].separate = true;
05498 
05499         /*
05500          * If we're forced to break a dependency loop by dumping a view as a
05501          * table and separate _RETURN rule, we'll move the view's reloptions
05502          * to the rule.  (This is necessary because tables and views have
05503          * different valid reloptions, so we can't apply the options until the
05504          * backend knows it's a view.)  Otherwise the rule's reloptions stay
05505          * NULL.
05506          */
05507         ruleinfo[i].reloptions = NULL;
05508     }
05509 
05510     PQclear(res);
05511 
05512     destroyPQExpBuffer(query);
05513 
05514     return ruleinfo;
05515 }
05516 
05517 /*
05518  * getTriggers
05519  *    get information about every trigger on a dumpable table
05520  *
05521  * Note: trigger data is not returned directly to the caller, but it
05522  * does get entered into the DumpableObject tables.
05523  */
05524 void
05525 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
05526 {
05527     int         i,
05528                 j;
05529     PQExpBuffer query = createPQExpBuffer();
05530     PGresult   *res;
05531     TriggerInfo *tginfo;
05532     int         i_tableoid,
05533                 i_oid,
05534                 i_tgname,
05535                 i_tgfname,
05536                 i_tgtype,
05537                 i_tgnargs,
05538                 i_tgargs,
05539                 i_tgisconstraint,
05540                 i_tgconstrname,
05541                 i_tgconstrrelid,
05542                 i_tgconstrrelname,
05543                 i_tgenabled,
05544                 i_tgdeferrable,
05545                 i_tginitdeferred,
05546                 i_tgdef;
05547     int         ntups;
05548 
05549     for (i = 0; i < numTables; i++)
05550     {
05551         TableInfo  *tbinfo = &tblinfo[i];
05552 
05553         if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
05554             continue;
05555 
05556         if (g_verbose)
05557             write_msg(NULL, "reading triggers for table \"%s\"\n",
05558                       tbinfo->dobj.name);
05559 
05560         /*
05561          * select table schema to ensure regproc name is qualified if needed
05562          */
05563         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
05564 
05565         resetPQExpBuffer(query);
05566         if (fout->remoteVersion >= 90000)
05567         {
05568             /*
05569              * NB: think not to use pretty=true in pg_get_triggerdef.  It
05570              * could result in non-forward-compatible dumps of WHEN clauses
05571              * due to under-parenthesization.
05572              */
05573             appendPQExpBuffer(query,
05574                               "SELECT tgname, "
05575                               "tgfoid::pg_catalog.regproc AS tgfname, "
05576                         "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
05577                               "tgenabled, tableoid, oid "
05578                               "FROM pg_catalog.pg_trigger t "
05579                               "WHERE tgrelid = '%u'::pg_catalog.oid "
05580                               "AND NOT tgisinternal",
05581                               tbinfo->dobj.catId.oid);
05582         }
05583         else if (fout->remoteVersion >= 80300)
05584         {
05585             /*
05586              * We ignore triggers that are tied to a foreign-key constraint
05587              */
05588             appendPQExpBuffer(query,
05589                               "SELECT tgname, "
05590                               "tgfoid::pg_catalog.regproc AS tgfname, "
05591                               "tgtype, tgnargs, tgargs, tgenabled, "
05592                               "tgisconstraint, tgconstrname, tgdeferrable, "
05593                               "tgconstrrelid, tginitdeferred, tableoid, oid, "
05594                      "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
05595                               "FROM pg_catalog.pg_trigger t "
05596                               "WHERE tgrelid = '%u'::pg_catalog.oid "
05597                               "AND tgconstraint = 0",
05598                               tbinfo->dobj.catId.oid);
05599         }
05600         else if (fout->remoteVersion >= 70300)
05601         {
05602             /*
05603              * We ignore triggers that are tied to a foreign-key constraint,
05604              * but in these versions we have to grovel through pg_constraint
05605              * to find out
05606              */
05607             appendPQExpBuffer(query,
05608                               "SELECT tgname, "
05609                               "tgfoid::pg_catalog.regproc AS tgfname, "
05610                               "tgtype, tgnargs, tgargs, tgenabled, "
05611                               "tgisconstraint, tgconstrname, tgdeferrable, "
05612                               "tgconstrrelid, tginitdeferred, tableoid, oid, "
05613                      "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
05614                               "FROM pg_catalog.pg_trigger t "
05615                               "WHERE tgrelid = '%u'::pg_catalog.oid "
05616                               "AND (NOT tgisconstraint "
05617                               " OR NOT EXISTS"
05618                               "  (SELECT 1 FROM pg_catalog.pg_depend d "
05619                               "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
05620                               "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
05621                               tbinfo->dobj.catId.oid);
05622         }
05623         else if (fout->remoteVersion >= 70100)
05624         {
05625             appendPQExpBuffer(query,
05626                               "SELECT tgname, tgfoid::regproc AS tgfname, "
05627                               "tgtype, tgnargs, tgargs, tgenabled, "
05628                               "tgisconstraint, tgconstrname, tgdeferrable, "
05629                               "tgconstrrelid, tginitdeferred, tableoid, oid, "
05630                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
05631                               "     AS tgconstrrelname "
05632                               "FROM pg_trigger "
05633                               "WHERE tgrelid = '%u'::oid",
05634                               tbinfo->dobj.catId.oid);
05635         }
05636         else
05637         {
05638             appendPQExpBuffer(query,
05639                               "SELECT tgname, tgfoid::regproc AS tgfname, "
05640                               "tgtype, tgnargs, tgargs, tgenabled, "
05641                               "tgisconstraint, tgconstrname, tgdeferrable, "
05642                               "tgconstrrelid, tginitdeferred, "
05643                               "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
05644                               "oid, "
05645                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
05646                               "     AS tgconstrrelname "
05647                               "FROM pg_trigger "
05648                               "WHERE tgrelid = '%u'::oid",
05649                               tbinfo->dobj.catId.oid);
05650         }
05651         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
05652 
05653         ntups = PQntuples(res);
05654 
05655         i_tableoid = PQfnumber(res, "tableoid");
05656         i_oid = PQfnumber(res, "oid");
05657         i_tgname = PQfnumber(res, "tgname");
05658         i_tgfname = PQfnumber(res, "tgfname");
05659         i_tgtype = PQfnumber(res, "tgtype");
05660         i_tgnargs = PQfnumber(res, "tgnargs");
05661         i_tgargs = PQfnumber(res, "tgargs");
05662         i_tgisconstraint = PQfnumber(res, "tgisconstraint");
05663         i_tgconstrname = PQfnumber(res, "tgconstrname");
05664         i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
05665         i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
05666         i_tgenabled = PQfnumber(res, "tgenabled");
05667         i_tgdeferrable = PQfnumber(res, "tgdeferrable");
05668         i_tginitdeferred = PQfnumber(res, "tginitdeferred");
05669         i_tgdef = PQfnumber(res, "tgdef");
05670 
05671         tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
05672 
05673         for (j = 0; j < ntups; j++)
05674         {
05675             tginfo[j].dobj.objType = DO_TRIGGER;
05676             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
05677             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
05678             AssignDumpId(&tginfo[j].dobj);
05679             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
05680             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
05681             tginfo[j].tgtable = tbinfo;
05682             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
05683             if (i_tgdef >= 0)
05684             {
05685                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
05686 
05687                 /* remaining fields are not valid if we have tgdef */
05688                 tginfo[j].tgfname = NULL;
05689                 tginfo[j].tgtype = 0;
05690                 tginfo[j].tgnargs = 0;
05691                 tginfo[j].tgargs = NULL;
05692                 tginfo[j].tgisconstraint = false;
05693                 tginfo[j].tgdeferrable = false;
05694                 tginfo[j].tginitdeferred = false;
05695                 tginfo[j].tgconstrname = NULL;
05696                 tginfo[j].tgconstrrelid = InvalidOid;
05697                 tginfo[j].tgconstrrelname = NULL;
05698             }
05699             else
05700             {
05701                 tginfo[j].tgdef = NULL;
05702 
05703                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
05704                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
05705                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
05706                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
05707                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
05708                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
05709                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
05710 
05711                 if (tginfo[j].tgisconstraint)
05712                 {
05713                     tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
05714                     tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
05715                     if (OidIsValid(tginfo[j].tgconstrrelid))
05716                     {
05717                         if (PQgetisnull(res, j, i_tgconstrrelname))
05718                             exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
05719                                           tginfo[j].dobj.name,
05720                                           tbinfo->dobj.name,
05721                                           tginfo[j].tgconstrrelid);
05722                         tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
05723                     }
05724                     else
05725                         tginfo[j].tgconstrrelname = NULL;
05726                 }
05727                 else
05728                 {
05729                     tginfo[j].tgconstrname = NULL;
05730                     tginfo[j].tgconstrrelid = InvalidOid;
05731                     tginfo[j].tgconstrrelname = NULL;
05732                 }
05733             }
05734         }
05735 
05736         PQclear(res);
05737     }
05738 
05739     destroyPQExpBuffer(query);
05740 }
05741 
05742 /*
05743  * getEventTriggers
05744  *    get information about event triggers
05745  */
05746 EventTriggerInfo *
05747 getEventTriggers(Archive *fout, int *numEventTriggers)
05748 {
05749     int         i;
05750     PQExpBuffer query = createPQExpBuffer();
05751     PGresult   *res;
05752     EventTriggerInfo *evtinfo;
05753     int         i_tableoid,
05754                 i_oid,
05755                 i_evtname,
05756                 i_evtevent,
05757                 i_evtowner,
05758                 i_evttags,
05759                 i_evtfname,
05760                 i_evtenabled;
05761     int         ntups;
05762 
05763     /* Before 9.3, there are no event triggers */
05764     if (fout->remoteVersion < 90300)
05765     {
05766         *numEventTriggers = 0;
05767         return NULL;
05768     }
05769 
05770     /* Make sure we are in proper schema */
05771     selectSourceSchema(fout, "pg_catalog");
05772 
05773     appendPQExpBuffer(query,
05774                       "SELECT e.tableoid, e.oid, evtname, evtenabled, "
05775                       "evtevent, (%s evtowner) AS evtowner, "
05776                       "array_to_string(array("
05777                       "select quote_literal(x) "
05778                       " from unnest(evttags) as t(x)), ', ') as evttags, "
05779                       "e.evtfoid::regproc as evtfname "
05780                       "FROM pg_event_trigger e "
05781                       "ORDER BY e.oid",
05782                       username_subquery);
05783 
05784     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
05785 
05786     ntups = PQntuples(res);
05787 
05788     *numEventTriggers = ntups;
05789 
05790     evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
05791 
05792     i_tableoid = PQfnumber(res, "tableoid");
05793     i_oid = PQfnumber(res, "oid");
05794     i_evtname = PQfnumber(res, "evtname");
05795     i_evtevent = PQfnumber(res, "evtevent");
05796     i_evtowner = PQfnumber(res, "evtowner");
05797     i_evttags = PQfnumber(res, "evttags");
05798     i_evtfname = PQfnumber(res, "evtfname");
05799     i_evtenabled = PQfnumber(res, "evtenabled");
05800 
05801     for (i = 0; i < ntups; i++)
05802     {
05803         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
05804         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
05805         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
05806         AssignDumpId(&evtinfo[i].dobj);
05807         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
05808         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
05809         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
05810         evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
05811         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
05812         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
05813         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
05814     }
05815 
05816     PQclear(res);
05817 
05818     destroyPQExpBuffer(query);
05819 
05820     return evtinfo;
05821 }
05822 
05823 /*
05824  * getProcLangs
05825  *    get basic information about every procedural language in the system
05826  *
05827  * numProcLangs is set to the number of langs read in
05828  *
05829  * NB: this must run after getFuncs() because we assume we can do
05830  * findFuncByOid().
05831  */
05832 ProcLangInfo *
05833 getProcLangs(Archive *fout, int *numProcLangs)
05834 {
05835     PGresult   *res;
05836     int         ntups;
05837     int         i;
05838     PQExpBuffer query = createPQExpBuffer();
05839     ProcLangInfo *planginfo;
05840     int         i_tableoid;
05841     int         i_oid;
05842     int         i_lanname;
05843     int         i_lanpltrusted;
05844     int         i_lanplcallfoid;
05845     int         i_laninline;
05846     int         i_lanvalidator;
05847     int         i_lanacl;
05848     int         i_lanowner;
05849 
05850     /* Make sure we are in proper schema */
05851     selectSourceSchema(fout, "pg_catalog");
05852 
05853     if (fout->remoteVersion >= 90000)
05854     {
05855         /* pg_language has a laninline column */
05856         appendPQExpBuffer(query, "SELECT tableoid, oid, "
05857                           "lanname, lanpltrusted, lanplcallfoid, "
05858                           "laninline, lanvalidator,  lanacl, "
05859                           "(%s lanowner) AS lanowner "
05860                           "FROM pg_language "
05861                           "WHERE lanispl "
05862                           "ORDER BY oid",
05863                           username_subquery);
05864     }
05865     else if (fout->remoteVersion >= 80300)
05866     {
05867         /* pg_language has a lanowner column */
05868         appendPQExpBuffer(query, "SELECT tableoid, oid, "
05869                           "lanname, lanpltrusted, lanplcallfoid, "
05870                           "lanvalidator,  lanacl, "
05871                           "(%s lanowner) AS lanowner "
05872                           "FROM pg_language "
05873                           "WHERE lanispl "
05874                           "ORDER BY oid",
05875                           username_subquery);
05876     }
05877     else if (fout->remoteVersion >= 80100)
05878     {
05879         /* Languages are owned by the bootstrap superuser, OID 10 */
05880         appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
05881                           "(%s '10') AS lanowner "
05882                           "FROM pg_language "
05883                           "WHERE lanispl "
05884                           "ORDER BY oid",
05885                           username_subquery);
05886     }
05887     else if (fout->remoteVersion >= 70400)
05888     {
05889         /* Languages are owned by the bootstrap superuser, sysid 1 */
05890         appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
05891                           "(%s '1') AS lanowner "
05892                           "FROM pg_language "
05893                           "WHERE lanispl "
05894                           "ORDER BY oid",
05895                           username_subquery);
05896     }
05897     else if (fout->remoteVersion >= 70100)
05898     {
05899         /* No clear notion of an owner at all before 7.4 ... */
05900         appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
05901                           "WHERE lanispl "
05902                           "ORDER BY oid");
05903     }
05904     else
05905     {
05906         appendPQExpBuffer(query, "SELECT "
05907                           "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
05908                           "oid, * FROM pg_language "
05909                           "WHERE lanispl "
05910                           "ORDER BY oid");
05911     }
05912 
05913     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
05914 
05915     ntups = PQntuples(res);
05916 
05917     *numProcLangs = ntups;
05918 
05919     planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
05920 
05921     i_tableoid = PQfnumber(res, "tableoid");
05922     i_oid = PQfnumber(res, "oid");
05923     i_lanname = PQfnumber(res, "lanname");
05924     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
05925     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
05926     /* these may fail and return -1: */
05927     i_laninline = PQfnumber(res, "laninline");
05928     i_lanvalidator = PQfnumber(res, "lanvalidator");
05929     i_lanacl = PQfnumber(res, "lanacl");
05930     i_lanowner = PQfnumber(res, "lanowner");
05931 
05932     for (i = 0; i < ntups; i++)
05933     {
05934         planginfo[i].dobj.objType = DO_PROCLANG;
05935         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
05936         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
05937         AssignDumpId(&planginfo[i].dobj);
05938 
05939         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
05940         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
05941         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
05942         if (i_laninline >= 0)
05943             planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
05944         else
05945             planginfo[i].laninline = InvalidOid;
05946         if (i_lanvalidator >= 0)
05947             planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
05948         else
05949             planginfo[i].lanvalidator = InvalidOid;
05950         if (i_lanacl >= 0)
05951             planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
05952         else
05953             planginfo[i].lanacl = pg_strdup("{=U}");
05954         if (i_lanowner >= 0)
05955             planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
05956         else
05957             planginfo[i].lanowner = pg_strdup("");
05958 
05959         if (fout->remoteVersion < 70300)
05960         {
05961             /*
05962              * We need to make a dependency to ensure the function will be
05963              * dumped first.  (In 7.3 and later the regular dependency
05964              * mechanism will handle this for us.)
05965              */
05966             FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
05967 
05968             if (funcInfo)
05969                 addObjectDependency(&planginfo[i].dobj,
05970                                     funcInfo->dobj.dumpId);
05971         }
05972     }
05973 
05974     PQclear(res);
05975 
05976     destroyPQExpBuffer(query);
05977 
05978     return planginfo;
05979 }
05980 
05981 /*
05982  * getCasts
05983  *    get basic information about every cast in the system
05984  *
05985  * numCasts is set to the number of casts read in
05986  */
05987 CastInfo *
05988 getCasts(Archive *fout, int *numCasts)
05989 {
05990     PGresult   *res;
05991     int         ntups;
05992     int         i;
05993     PQExpBuffer query = createPQExpBuffer();
05994     CastInfo   *castinfo;
05995     int         i_tableoid;
05996     int         i_oid;
05997     int         i_castsource;
05998     int         i_casttarget;
05999     int         i_castfunc;
06000     int         i_castcontext;
06001     int         i_castmethod;
06002 
06003     /* Make sure we are in proper schema */
06004     selectSourceSchema(fout, "pg_catalog");
06005 
06006     if (fout->remoteVersion >= 80400)
06007     {
06008         appendPQExpBuffer(query, "SELECT tableoid, oid, "
06009                           "castsource, casttarget, castfunc, castcontext, "
06010                           "castmethod "
06011                           "FROM pg_cast ORDER BY 3,4");
06012     }
06013     else if (fout->remoteVersion >= 70300)
06014     {
06015         appendPQExpBuffer(query, "SELECT tableoid, oid, "
06016                           "castsource, casttarget, castfunc, castcontext, "
06017                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
06018                           "FROM pg_cast ORDER BY 3,4");
06019     }
06020     else
06021     {
06022         appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
06023                           "t1.oid AS castsource, t2.oid AS casttarget, "
06024                           "p.oid AS castfunc, 'e' AS castcontext, "
06025                           "'f' AS castmethod "
06026                           "FROM pg_type t1, pg_type t2, pg_proc p "
06027                           "WHERE p.pronargs = 1 AND "
06028                           "p.proargtypes[0] = t1.oid AND "
06029                           "p.prorettype = t2.oid AND p.proname = t2.typname "
06030                           "ORDER BY 3,4");
06031     }
06032 
06033     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
06034 
06035     ntups = PQntuples(res);
06036 
06037     *numCasts = ntups;
06038 
06039     castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
06040 
06041     i_tableoid = PQfnumber(res, "tableoid");
06042     i_oid = PQfnumber(res, "oid");
06043     i_castsource = PQfnumber(res, "castsource");
06044     i_casttarget = PQfnumber(res, "casttarget");
06045     i_castfunc = PQfnumber(res, "castfunc");
06046     i_castcontext = PQfnumber(res, "castcontext");
06047     i_castmethod = PQfnumber(res, "castmethod");
06048 
06049     for (i = 0; i < ntups; i++)
06050     {
06051         PQExpBufferData namebuf;
06052         TypeInfo   *sTypeInfo;
06053         TypeInfo   *tTypeInfo;
06054 
06055         castinfo[i].dobj.objType = DO_CAST;
06056         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
06057         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
06058         AssignDumpId(&castinfo[i].dobj);
06059         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
06060         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
06061         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
06062         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
06063         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
06064 
06065         /*
06066          * Try to name cast as concatenation of typnames.  This is only used
06067          * for purposes of sorting.  If we fail to find either type, the name
06068          * will be an empty string.
06069          */
06070         initPQExpBuffer(&namebuf);
06071         sTypeInfo = findTypeByOid(castinfo[i].castsource);
06072         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
06073         if (sTypeInfo && tTypeInfo)
06074             appendPQExpBuffer(&namebuf, "%s %s",
06075                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
06076         castinfo[i].dobj.name = namebuf.data;
06077 
06078         if (OidIsValid(castinfo[i].castfunc))
06079         {
06080             /*
06081              * We need to make a dependency to ensure the function will be
06082              * dumped first.  (In 7.3 and later the regular dependency
06083              * mechanism will handle this for us.)
06084              */
06085             FuncInfo   *funcInfo;
06086 
06087             funcInfo = findFuncByOid(castinfo[i].castfunc);
06088             if (funcInfo)
06089                 addObjectDependency(&castinfo[i].dobj,
06090                                     funcInfo->dobj.dumpId);
06091         }
06092     }
06093 
06094     PQclear(res);
06095 
06096     destroyPQExpBuffer(query);
06097 
06098     return castinfo;
06099 }
06100 
06101 /*
06102  * getTableAttrs -
06103  *    for each interesting table, read info about its attributes
06104  *    (names, types, default values, CHECK constraints, etc)
06105  *
06106  * This is implemented in a very inefficient way right now, looping
06107  * through the tblinfo and doing a join per table to find the attrs and their
06108  * types.  However, because we want type names and so forth to be named
06109  * relative to the schema of each table, we couldn't do it in just one
06110  * query.  (Maybe one query per schema?)
06111  *
06112  *  modifies tblinfo
06113  */
06114 void
06115 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
06116 {
06117     int         i,
06118                 j;
06119     PQExpBuffer q = createPQExpBuffer();
06120     int         i_attnum;
06121     int         i_attname;
06122     int         i_atttypname;
06123     int         i_atttypmod;
06124     int         i_attstattarget;
06125     int         i_attstorage;
06126     int         i_typstorage;
06127     int         i_attnotnull;
06128     int         i_atthasdef;
06129     int         i_attisdropped;
06130     int         i_attlen;
06131     int         i_attalign;
06132     int         i_attislocal;
06133     int         i_attoptions;
06134     int         i_attcollation;
06135     int         i_attfdwoptions;
06136     PGresult   *res;
06137     int         ntups;
06138     bool        hasdefaults;
06139 
06140     for (i = 0; i < numTables; i++)
06141     {
06142         TableInfo  *tbinfo = &tblinfo[i];
06143 
06144         /* Don't bother to collect info for sequences */
06145         if (tbinfo->relkind == RELKIND_SEQUENCE)
06146             continue;
06147 
06148         /* Don't bother with uninteresting tables, either */
06149         if (!tbinfo->interesting)
06150             continue;
06151 
06152         /*
06153          * Make sure we are in proper schema for this table; this allows
06154          * correct retrieval of formatted type names and default exprs
06155          */
06156         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
06157 
06158         /* find all the user attributes and their types */
06159 
06160         /*
06161          * we must read the attribute names in attribute number order! because
06162          * we will use the attnum to index into the attnames array later.  We
06163          * actually ask to order by "attrelid, attnum" because (at least up to
06164          * 7.3) the planner is not smart enough to realize it needn't re-sort
06165          * the output of an indexscan on pg_attribute_relid_attnum_index.
06166          */
06167         if (g_verbose)
06168             write_msg(NULL, "finding the columns and types of table \"%s\"\n",
06169                       tbinfo->dobj.name);
06170 
06171         resetPQExpBuffer(q);
06172 
06173         if (fout->remoteVersion >= 90200)
06174         {
06175             /*
06176              * attfdwoptions is new in 9.2.
06177              */
06178             appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
06179                               "a.attstattarget, a.attstorage, t.typstorage, "
06180                               "a.attnotnull, a.atthasdef, a.attisdropped, "
06181                               "a.attlen, a.attalign, a.attislocal, "
06182                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
06183                         "array_to_string(a.attoptions, ', ') AS attoptions, "
06184                               "CASE WHEN a.attcollation <> t.typcollation "
06185                            "THEN a.attcollation ELSE 0 END AS attcollation, "
06186                               "pg_catalog.array_to_string(ARRAY("
06187                               "SELECT pg_catalog.quote_ident(option_name) || "
06188                               "' ' || pg_catalog.quote_literal(option_value) "
06189                         "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
06190                               "ORDER BY option_name"
06191                               "), E',\n    ') AS attfdwoptions "
06192              "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
06193                               "ON a.atttypid = t.oid "
06194                               "WHERE a.attrelid = '%u'::pg_catalog.oid "
06195                               "AND a.attnum > 0::pg_catalog.int2 "
06196                               "ORDER BY a.attrelid, a.attnum",
06197                               tbinfo->dobj.catId.oid);
06198         }
06199         else if (fout->remoteVersion >= 90100)
06200         {
06201             /*
06202              * attcollation is new in 9.1.  Since we only want to dump COLLATE
06203              * clauses for attributes whose collation is different from their
06204              * type's default, we use a CASE here to suppress uninteresting
06205              * attcollations cheaply.
06206              */
06207             appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
06208                               "a.attstattarget, a.attstorage, t.typstorage, "
06209                               "a.attnotnull, a.atthasdef, a.attisdropped, "
06210                               "a.attlen, a.attalign, a.attislocal, "
06211                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
06212                         "array_to_string(a.attoptions, ', ') AS attoptions, "
06213                               "CASE WHEN a.attcollation <> t.typcollation "
06214                            "THEN a.attcollation ELSE 0 END AS attcollation, "
06215                               "NULL AS attfdwoptions "
06216              "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
06217                               "ON a.atttypid = t.oid "
06218                               "WHERE a.attrelid = '%u'::pg_catalog.oid "
06219                               "AND a.attnum > 0::pg_catalog.int2 "
06220                               "ORDER BY a.attrelid, a.attnum",
06221                               tbinfo->dobj.catId.oid);
06222         }
06223         else if (fout->remoteVersion >= 90000)
06224         {
06225             /* attoptions is new in 9.0 */
06226             appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
06227                               "a.attstattarget, a.attstorage, t.typstorage, "
06228                               "a.attnotnull, a.atthasdef, a.attisdropped, "
06229                               "a.attlen, a.attalign, a.attislocal, "
06230                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
06231                         "array_to_string(a.attoptions, ', ') AS attoptions, "
06232                               "0 AS attcollation, "
06233                               "NULL AS attfdwoptions "
06234              "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
06235                               "ON a.atttypid = t.oid "
06236                               "WHERE a.attrelid = '%u'::pg_catalog.oid "
06237                               "AND a.attnum > 0::pg_catalog.int2 "
06238                               "ORDER BY a.attrelid, a.attnum",
06239                               tbinfo->dobj.catId.oid);
06240         }
06241         else if (fout->remoteVersion >= 70300)
06242         {
06243             /* need left join here to not fail on dropped columns ... */
06244             appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
06245                               "a.attstattarget, a.attstorage, t.typstorage, "
06246                               "a.attnotnull, a.atthasdef, a.attisdropped, "
06247                               "a.attlen, a.attalign, a.attislocal, "
06248                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
06249                               "'' AS attoptions, 0 AS attcollation, "
06250                               "NULL AS attfdwoptions "
06251              "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
06252                               "ON a.atttypid = t.oid "
06253                               "WHERE a.attrelid = '%u'::pg_catalog.oid "
06254                               "AND a.attnum > 0::pg_catalog.int2 "
06255                               "ORDER BY a.attrelid, a.attnum",
06256                               tbinfo->dobj.catId.oid);
06257         }
06258         else if (fout->remoteVersion >= 70100)
06259         {
06260             /*
06261              * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
06262              * we don't dump it because we can't tell whether it's been
06263              * explicitly set or was just a default.
06264              *
06265              * attislocal doesn't exist before 7.3, either; in older databases
06266              * we assume it's TRUE, else we'd fail to dump non-inherited atts.
06267              */
06268             appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
06269                               "-1 AS attstattarget, a.attstorage, "
06270                               "t.typstorage, a.attnotnull, a.atthasdef, "
06271                               "false AS attisdropped, a.attlen, "
06272                               "a.attalign, true AS attislocal, "
06273                               "format_type(t.oid,a.atttypmod) AS atttypname, "
06274                               "'' AS attoptions, 0 AS attcollation, "
06275                               "NULL AS attfdwoptions "
06276                               "FROM pg_attribute a LEFT JOIN pg_type t "
06277                               "ON a.atttypid = t.oid "
06278                               "WHERE a.attrelid = '%u'::oid "
06279                               "AND a.attnum > 0::int2 "
06280                               "ORDER BY a.attrelid, a.attnum",
06281                               tbinfo->dobj.catId.oid);
06282         }
06283         else
06284         {
06285             /* format_type not available before 7.1 */
06286             appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
06287                               "-1 AS attstattarget, "
06288                               "attstorage, attstorage AS typstorage, "
06289                               "attnotnull, atthasdef, false AS attisdropped, "
06290                               "attlen, attalign, "
06291                               "true AS attislocal, "
06292                               "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
06293                               "'' AS attoptions, 0 AS attcollation, "
06294                               "NULL AS attfdwoptions "
06295                               "FROM pg_attribute a "
06296                               "WHERE attrelid = '%u'::oid "
06297                               "AND attnum > 0::int2 "
06298                               "ORDER BY attrelid, attnum",
06299                               tbinfo->dobj.catId.oid);
06300         }
06301 
06302         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
06303 
06304         ntups = PQntuples(res);
06305 
06306         i_attnum = PQfnumber(res, "attnum");
06307         i_attname = PQfnumber(res, "attname");
06308         i_atttypname = PQfnumber(res, "atttypname");
06309         i_atttypmod = PQfnumber(res, "atttypmod");
06310         i_attstattarget = PQfnumber(res, "attstattarget");
06311         i_attstorage = PQfnumber(res, "attstorage");
06312         i_typstorage = PQfnumber(res, "typstorage");
06313         i_attnotnull = PQfnumber(res, "attnotnull");
06314         i_atthasdef = PQfnumber(res, "atthasdef");
06315         i_attisdropped = PQfnumber(res, "attisdropped");
06316         i_attlen = PQfnumber(res, "attlen");
06317         i_attalign = PQfnumber(res, "attalign");
06318         i_attislocal = PQfnumber(res, "attislocal");
06319         i_attoptions = PQfnumber(res, "attoptions");
06320         i_attcollation = PQfnumber(res, "attcollation");
06321         i_attfdwoptions = PQfnumber(res, "attfdwoptions");
06322 
06323         tbinfo->numatts = ntups;
06324         tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
06325         tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
06326         tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
06327         tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
06328         tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
06329         tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
06330         tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
06331         tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
06332         tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
06333         tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
06334         tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
06335         tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
06336         tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
06337         tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
06338         tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
06339         tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
06340         hasdefaults = false;
06341 
06342         for (j = 0; j < ntups; j++)
06343         {
06344             if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
06345                 exit_horribly(NULL,
06346                               "invalid column numbering in table \"%s\"\n",
06347                               tbinfo->dobj.name);
06348             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
06349             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
06350             tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
06351             tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
06352             tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
06353             tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
06354             tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
06355             tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
06356             tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
06357             tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
06358             tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
06359             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
06360             tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
06361             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
06362             tbinfo->attrdefs[j] = NULL; /* fix below */
06363             if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
06364                 hasdefaults = true;
06365             /* these flags will be set in flagInhAttrs() */
06366             tbinfo->inhNotNull[j] = false;
06367         }
06368 
06369         PQclear(res);
06370 
06371         /*
06372          * Get info about column defaults
06373          */
06374         if (hasdefaults)
06375         {
06376             AttrDefInfo *attrdefs;
06377             int         numDefaults;
06378 
06379             if (g_verbose)
06380                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
06381                           tbinfo->dobj.name);
06382 
06383             resetPQExpBuffer(q);
06384             if (fout->remoteVersion >= 70300)
06385             {
06386                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
06387                            "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
06388                                   "FROM pg_catalog.pg_attrdef "
06389                                   "WHERE adrelid = '%u'::pg_catalog.oid",
06390                                   tbinfo->dobj.catId.oid);
06391             }
06392             else if (fout->remoteVersion >= 70200)
06393             {
06394                 /* 7.2 did not have OIDs in pg_attrdef */
06395                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
06396                                   "pg_get_expr(adbin, adrelid) AS adsrc "
06397                                   "FROM pg_attrdef "
06398                                   "WHERE adrelid = '%u'::oid",
06399                                   tbinfo->dobj.catId.oid);
06400             }
06401             else if (fout->remoteVersion >= 70100)
06402             {
06403                 /* no pg_get_expr, so must rely on adsrc */
06404                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
06405                                   "FROM pg_attrdef "
06406                                   "WHERE adrelid = '%u'::oid",
06407                                   tbinfo->dobj.catId.oid);
06408             }
06409             else
06410             {
06411                 /* no pg_get_expr, no tableoid either */
06412                 appendPQExpBuffer(q, "SELECT "
06413                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
06414                                   "oid, adnum, adsrc "
06415                                   "FROM pg_attrdef "
06416                                   "WHERE adrelid = '%u'::oid",
06417                                   tbinfo->dobj.catId.oid);
06418             }
06419             res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
06420 
06421             numDefaults = PQntuples(res);
06422             attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
06423 
06424             for (j = 0; j < numDefaults; j++)
06425             {
06426                 int         adnum;
06427 
06428                 adnum = atoi(PQgetvalue(res, j, 2));
06429 
06430                 if (adnum <= 0 || adnum > ntups)
06431                     exit_horribly(NULL,
06432                                   "invalid adnum value %d for table \"%s\"\n",
06433                                   adnum, tbinfo->dobj.name);
06434 
06435                 /*
06436                  * dropped columns shouldn't have defaults, but just in case,
06437                  * ignore 'em
06438                  */
06439                 if (tbinfo->attisdropped[adnum - 1])
06440                     continue;
06441 
06442                 attrdefs[j].dobj.objType = DO_ATTRDEF;
06443                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
06444                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
06445                 AssignDumpId(&attrdefs[j].dobj);
06446                 attrdefs[j].adtable = tbinfo;
06447                 attrdefs[j].adnum = adnum;
06448                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
06449 
06450                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
06451                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
06452 
06453                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
06454 
06455                 /*
06456                  * Defaults on a VIEW must always be dumped as separate ALTER
06457                  * TABLE commands.  Defaults on regular tables are dumped as
06458                  * part of the CREATE TABLE if possible, which it won't be if
06459                  * the column is not going to be emitted explicitly.
06460                  */
06461                 if (tbinfo->relkind == RELKIND_VIEW)
06462                 {
06463                     attrdefs[j].separate = true;
06464                     /* needed in case pre-7.3 DB: */
06465                     addObjectDependency(&attrdefs[j].dobj,
06466                                         tbinfo->dobj.dumpId);
06467                 }
06468                 else if (!shouldPrintColumn(tbinfo, adnum - 1))
06469                 {
06470                     /* column will be suppressed, print default separately */
06471                     attrdefs[j].separate = true;
06472                     /* needed in case pre-7.3 DB: */
06473                     addObjectDependency(&attrdefs[j].dobj,
06474                                         tbinfo->dobj.dumpId);
06475                 }
06476                 else
06477                 {
06478                     attrdefs[j].separate = false;
06479 
06480                     /*
06481                      * Mark the default as needing to appear before the table,
06482                      * so that any dependencies it has must be emitted before
06483                      * the CREATE TABLE.  If this is not possible, we'll
06484                      * change to "separate" mode while sorting dependencies.
06485                      */
06486                     addObjectDependency(&tbinfo->dobj,
06487                                         attrdefs[j].dobj.dumpId);
06488                 }
06489 
06490                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
06491             }
06492             PQclear(res);
06493         }
06494 
06495         /*
06496          * Get info about table CHECK constraints
06497          */
06498         if (tbinfo->ncheck > 0)
06499         {
06500             ConstraintInfo *constrs;
06501             int         numConstrs;
06502 
06503             if (g_verbose)
06504                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
06505                           tbinfo->dobj.name);
06506 
06507             resetPQExpBuffer(q);
06508             if (fout->remoteVersion >= 90200)
06509             {
06510                 /*
06511                  * convalidated is new in 9.2 (actually, it is there in 9.1,
06512                  * but it wasn't ever false for check constraints until 9.2).
06513                  */
06514                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
06515                            "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
06516                                   "conislocal, convalidated "
06517                                   "FROM pg_catalog.pg_constraint "
06518                                   "WHERE conrelid = '%u'::pg_catalog.oid "
06519                                   "   AND contype = 'c' "
06520                                   "ORDER BY conname",
06521                                   tbinfo->dobj.catId.oid);
06522             }
06523             else if (fout->remoteVersion >= 80400)
06524             {
06525                 /* conislocal is new in 8.4 */
06526                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
06527                            "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
06528                                   "conislocal, true AS convalidated "
06529                                   "FROM pg_catalog.pg_constraint "
06530                                   "WHERE conrelid = '%u'::pg_catalog.oid "
06531                                   "   AND contype = 'c' "
06532                                   "ORDER BY conname",
06533                                   tbinfo->dobj.catId.oid);
06534             }
06535             else if (fout->remoteVersion >= 70400)
06536             {
06537                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
06538                            "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
06539                                   "true AS conislocal, true AS convalidated "
06540                                   "FROM pg_catalog.pg_constraint "
06541                                   "WHERE conrelid = '%u'::pg_catalog.oid "
06542                                   "   AND contype = 'c' "
06543                                   "ORDER BY conname",
06544                                   tbinfo->dobj.catId.oid);
06545             }
06546             else if (fout->remoteVersion >= 70300)
06547             {
06548                 /* no pg_get_constraintdef, must use consrc */
06549                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
06550                                   "'CHECK (' || consrc || ')' AS consrc, "
06551                                   "true AS conislocal, true AS convalidated "
06552                                   "FROM pg_catalog.pg_constraint "
06553                                   "WHERE conrelid = '%u'::pg_catalog.oid "
06554                                   "   AND contype = 'c' "
06555                                   "ORDER BY conname",
06556                                   tbinfo->dobj.catId.oid);
06557             }
06558             else if (fout->remoteVersion >= 70200)
06559             {
06560                 /* 7.2 did not have OIDs in pg_relcheck */
06561                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
06562                                   "rcname AS conname, "
06563                                   "'CHECK (' || rcsrc || ')' AS consrc, "
06564                                   "true AS conislocal, true AS convalidated "
06565                                   "FROM pg_relcheck "
06566                                   "WHERE rcrelid = '%u'::oid "
06567                                   "ORDER BY rcname",
06568                                   tbinfo->dobj.catId.oid);
06569             }
06570             else if (fout->remoteVersion >= 70100)
06571             {
06572                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
06573                                   "rcname AS conname, "
06574                                   "'CHECK (' || rcsrc || ')' AS consrc, "
06575                                   "true AS conislocal, true AS convalidated "
06576                                   "FROM pg_relcheck "
06577                                   "WHERE rcrelid = '%u'::oid "
06578                                   "ORDER BY rcname",
06579                                   tbinfo->dobj.catId.oid);
06580             }
06581             else
06582             {
06583                 /* no tableoid in 7.0 */
06584                 appendPQExpBuffer(q, "SELECT "
06585                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
06586                                   "oid, rcname AS conname, "
06587                                   "'CHECK (' || rcsrc || ')' AS consrc, "
06588                                   "true AS conislocal, true AS convalidated "
06589                                   "FROM pg_relcheck "
06590                                   "WHERE rcrelid = '%u'::oid "
06591                                   "ORDER BY rcname",
06592                                   tbinfo->dobj.catId.oid);
06593             }
06594             res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
06595 
06596             numConstrs = PQntuples(res);
06597             if (numConstrs != tbinfo->ncheck)
06598             {
06599                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
06600                                          "expected %d check constraints on table \"%s\" but found %d\n",
06601                                          tbinfo->ncheck),
06602                           tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
06603                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
06604                 exit_nicely(1);
06605             }
06606 
06607             constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
06608             tbinfo->checkexprs = constrs;
06609 
06610             for (j = 0; j < numConstrs; j++)
06611             {
06612                 bool        validated = PQgetvalue(res, j, 5)[0] == 't';
06613 
06614                 constrs[j].dobj.objType = DO_CONSTRAINT;
06615                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
06616                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
06617                 AssignDumpId(&constrs[j].dobj);
06618                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
06619                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
06620                 constrs[j].contable = tbinfo;
06621                 constrs[j].condomain = NULL;
06622                 constrs[j].contype = 'c';
06623                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
06624                 constrs[j].confrelid = InvalidOid;
06625                 constrs[j].conindex = 0;
06626                 constrs[j].condeferrable = false;
06627                 constrs[j].condeferred = false;
06628                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
06629 
06630                 /*
06631                  * An unvalidated constraint needs to be dumped separately, so
06632                  * that potentially-violating existing data is loaded before
06633                  * the constraint.
06634                  */
06635                 constrs[j].separate = !validated;
06636 
06637                 constrs[j].dobj.dump = tbinfo->dobj.dump;
06638 
06639                 /*
06640                  * Mark the constraint as needing to appear before the table
06641                  * --- this is so that any other dependencies of the
06642                  * constraint will be emitted before we try to create the
06643                  * table.  If the constraint is to be dumped separately, it
06644                  * will be dumped after data is loaded anyway, so don't do it.
06645                  * (There's an automatic dependency in the opposite direction
06646                  * anyway, so don't need to add one manually here.)
06647                  */
06648                 if (!constrs[j].separate)
06649                     addObjectDependency(&tbinfo->dobj,
06650                                         constrs[j].dobj.dumpId);
06651 
06652                 /*
06653                  * If the constraint is inherited, this will be detected later
06654                  * (in pre-8.4 databases).  We also detect later if the
06655                  * constraint must be split out from the table definition.
06656                  */
06657             }
06658             PQclear(res);
06659         }
06660     }
06661 
06662     destroyPQExpBuffer(q);
06663 }
06664 
06665 /*
06666  * Test whether a column should be printed as part of table's CREATE TABLE.
06667  * Column number is zero-based.
06668  *
06669  * Normally this is always true, but it's false for dropped columns, as well
06670  * as those that were inherited without any local definition.  (If we print
06671  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
06672  * However, in binary_upgrade mode, we must print all such columns anyway and
06673  * fix the attislocal/attisdropped state later, so as to keep control of the
06674  * physical column order.
06675  *
06676  * This function exists because there are scattered nonobvious places that
06677  * must be kept in sync with this decision.
06678  */
06679 bool
06680 shouldPrintColumn(TableInfo *tbinfo, int colno)
06681 {
06682     if (binary_upgrade)
06683         return true;
06684     return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
06685 }
06686 
06687 
06688 /*
06689  * getTSParsers:
06690  *    read all text search parsers in the system catalogs and return them
06691  *    in the TSParserInfo* structure
06692  *
06693  *  numTSParsers is set to the number of parsers read in
06694  */
06695 TSParserInfo *
06696 getTSParsers(Archive *fout, int *numTSParsers)
06697 {
06698     PGresult   *res;
06699     int         ntups;
06700     int         i;
06701     PQExpBuffer query;
06702     TSParserInfo *prsinfo;
06703     int         i_tableoid;
06704     int         i_oid;
06705     int         i_prsname;
06706     int         i_prsnamespace;
06707     int         i_prsstart;
06708     int         i_prstoken;
06709     int         i_prsend;
06710     int         i_prsheadline;
06711     int         i_prslextype;
06712 
06713     /* Before 8.3, there is no built-in text search support */
06714     if (fout->remoteVersion < 80300)
06715     {
06716         *numTSParsers = 0;
06717         return NULL;
06718     }
06719 
06720     query = createPQExpBuffer();
06721 
06722     /*
06723      * find all text search objects, including builtin ones; we filter out
06724      * system-defined objects at dump-out time.
06725      */
06726 
06727     /* Make sure we are in proper schema */
06728     selectSourceSchema(fout, "pg_catalog");
06729 
06730     appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
06731                       "prsstart::oid, prstoken::oid, "
06732                       "prsend::oid, prsheadline::oid, prslextype::oid "
06733                       "FROM pg_ts_parser");
06734 
06735     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
06736 
06737     ntups = PQntuples(res);
06738     *numTSParsers = ntups;
06739 
06740     prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
06741 
06742     i_tableoid = PQfnumber(res, "tableoid");
06743     i_oid = PQfnumber(res, "oid");
06744     i_prsname = PQfnumber(res, "prsname");
06745     i_prsnamespace = PQfnumber(res, "prsnamespace");
06746     i_prsstart = PQfnumber(res, "prsstart");
06747     i_prstoken = PQfnumber(res, "prstoken");
06748     i_prsend = PQfnumber(res, "prsend");
06749     i_prsheadline = PQfnumber(res, "prsheadline");
06750     i_prslextype = PQfnumber(res, "prslextype");
06751 
06752     for (i = 0; i < ntups; i++)
06753     {
06754         prsinfo[i].dobj.objType = DO_TSPARSER;
06755         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
06756         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
06757         AssignDumpId(&prsinfo[i].dobj);
06758         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
06759         prsinfo[i].dobj.namespace =
06760             findNamespace(fout,
06761                           atooid(PQgetvalue(res, i, i_prsnamespace)),
06762                           prsinfo[i].dobj.catId.oid);
06763         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
06764         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
06765         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
06766         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
06767         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
06768 
06769         /* Decide whether we want to dump it */
06770         selectDumpableObject(&(prsinfo[i].dobj));
06771     }
06772 
06773     PQclear(res);
06774 
06775     destroyPQExpBuffer(query);
06776 
06777     return prsinfo;
06778 }
06779 
06780 /*
06781  * getTSDictionaries:
06782  *    read all text search dictionaries in the system catalogs and return them
06783  *    in the TSDictInfo* structure
06784  *
06785  *  numTSDicts is set to the number of dictionaries read in
06786  */
06787 TSDictInfo *
06788 getTSDictionaries(Archive *fout, int *numTSDicts)
06789 {
06790     PGresult   *res;
06791     int         ntups;
06792     int         i;
06793     PQExpBuffer query;
06794     TSDictInfo *dictinfo;
06795     int         i_tableoid;
06796     int         i_oid;
06797     int         i_dictname;
06798     int         i_dictnamespace;
06799     int         i_rolname;
06800     int         i_dicttemplate;
06801     int         i_dictinitoption;
06802 
06803     /* Before 8.3, there is no built-in text search support */
06804     if (fout->remoteVersion < 80300)
06805     {
06806         *numTSDicts = 0;
06807         return NULL;
06808     }
06809 
06810     query = createPQExpBuffer();
06811 
06812     /* Make sure we are in proper schema */
06813     selectSourceSchema(fout, "pg_catalog");
06814 
06815     appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
06816                       "dictnamespace, (%s dictowner) AS rolname, "
06817                       "dicttemplate, dictinitoption "
06818                       "FROM pg_ts_dict",
06819                       username_subquery);
06820 
06821     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
06822 
06823     ntups = PQntuples(res);
06824     *numTSDicts = ntups;
06825 
06826     dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
06827 
06828     i_tableoid = PQfnumber(res, "tableoid");
06829     i_oid = PQfnumber(res, "oid");
06830     i_dictname = PQfnumber(res, "dictname");
06831     i_dictnamespace = PQfnumber(res, "dictnamespace");
06832     i_rolname = PQfnumber(res, "rolname");
06833     i_dictinitoption = PQfnumber(res, "dictinitoption");
06834     i_dicttemplate = PQfnumber(res, "dicttemplate");
06835 
06836     for (i = 0; i < ntups; i++)
06837     {
06838         dictinfo[i].dobj.objType = DO_TSDICT;
06839         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
06840         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
06841         AssignDumpId(&dictinfo[i].dobj);
06842         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
06843         dictinfo[i].dobj.namespace =
06844             findNamespace(fout,
06845                           atooid(PQgetvalue(res, i, i_dictnamespace)),
06846                           dictinfo[i].dobj.catId.oid);
06847         dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
06848         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
06849         if (PQgetisnull(res, i, i_dictinitoption))
06850             dictinfo[i].dictinitoption = NULL;
06851         else
06852             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
06853 
06854         /* Decide whether we want to dump it */
06855         selectDumpableObject(&(dictinfo[i].dobj));
06856     }
06857 
06858     PQclear(res);
06859 
06860     destroyPQExpBuffer(query);
06861 
06862     return dictinfo;
06863 }
06864 
06865 /*
06866  * getTSTemplates:
06867  *    read all text search templates in the system catalogs and return them
06868  *    in the TSTemplateInfo* structure
06869  *
06870  *  numTSTemplates is set to the number of templates read in
06871  */
06872 TSTemplateInfo *
06873 getTSTemplates(Archive *fout, int *numTSTemplates)
06874 {
06875     PGresult   *res;
06876     int         ntups;
06877     int         i;
06878     PQExpBuffer query;
06879     TSTemplateInfo *tmplinfo;
06880     int         i_tableoid;
06881     int         i_oid;
06882     int         i_tmplname;
06883     int         i_tmplnamespace;
06884     int         i_tmplinit;
06885     int         i_tmpllexize;
06886 
06887     /* Before 8.3, there is no built-in text search support */
06888     if (fout->remoteVersion < 80300)
06889     {
06890         *numTSTemplates = 0;
06891         return NULL;
06892     }
06893 
06894     query = createPQExpBuffer();
06895 
06896     /* Make sure we are in proper schema */
06897     selectSourceSchema(fout, "pg_catalog");
06898 
06899     appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
06900                       "tmplnamespace, tmplinit::oid, tmpllexize::oid "
06901                       "FROM pg_ts_template");
06902 
06903     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
06904 
06905     ntups = PQntuples(res);
06906     *numTSTemplates = ntups;
06907 
06908     tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
06909 
06910     i_tableoid = PQfnumber(res, "tableoid");
06911     i_oid = PQfnumber(res, "oid");
06912     i_tmplname = PQfnumber(res, "tmplname");
06913     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
06914     i_tmplinit = PQfnumber(res, "tmplinit");
06915     i_tmpllexize = PQfnumber(res, "tmpllexize");
06916 
06917     for (i = 0; i < ntups; i++)
06918     {
06919         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
06920         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
06921         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
06922         AssignDumpId(&tmplinfo[i].dobj);
06923         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
06924         tmplinfo[i].dobj.namespace =
06925             findNamespace(fout,
06926                           atooid(PQgetvalue(res, i, i_tmplnamespace)),
06927                           tmplinfo[i].dobj.catId.oid);
06928         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
06929         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
06930 
06931         /* Decide whether we want to dump it */
06932         selectDumpableObject(&(tmplinfo[i].dobj));
06933     }
06934 
06935     PQclear(res);
06936 
06937     destroyPQExpBuffer(query);
06938 
06939     return tmplinfo;
06940 }
06941 
06942 /*
06943  * getTSConfigurations:
06944  *    read all text search configurations in the system catalogs and return
06945  *    them in the TSConfigInfo* structure
06946  *
06947  *  numTSConfigs is set to the number of configurations read in
06948  */
06949 TSConfigInfo *
06950 getTSConfigurations(Archive *fout, int *numTSConfigs)
06951 {
06952     PGresult   *res;
06953     int         ntups;
06954     int         i;
06955     PQExpBuffer query;
06956     TSConfigInfo *cfginfo;
06957     int         i_tableoid;
06958     int         i_oid;
06959     int         i_cfgname;
06960     int         i_cfgnamespace;
06961     int         i_rolname;
06962     int         i_cfgparser;
06963 
06964     /* Before 8.3, there is no built-in text search support */
06965     if (fout->remoteVersion < 80300)
06966     {
06967         *numTSConfigs = 0;
06968         return NULL;
06969     }
06970 
06971     query = createPQExpBuffer();
06972 
06973     /* Make sure we are in proper schema */
06974     selectSourceSchema(fout, "pg_catalog");
06975 
06976     appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
06977                       "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
06978                       "FROM pg_ts_config",
06979                       username_subquery);
06980 
06981     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
06982 
06983     ntups = PQntuples(res);
06984     *numTSConfigs = ntups;
06985 
06986     cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
06987 
06988     i_tableoid = PQfnumber(res, "tableoid");
06989     i_oid = PQfnumber(res, "oid");
06990     i_cfgname = PQfnumber(res, "cfgname");
06991     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
06992     i_rolname = PQfnumber(res, "rolname");
06993     i_cfgparser = PQfnumber(res, "cfgparser");
06994 
06995     for (i = 0; i < ntups; i++)
06996     {
06997         cfginfo[i].dobj.objType = DO_TSCONFIG;
06998         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
06999         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
07000         AssignDumpId(&cfginfo[i].dobj);
07001         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
07002         cfginfo[i].dobj.namespace =
07003             findNamespace(fout,
07004                           atooid(PQgetvalue(res, i, i_cfgnamespace)),
07005                           cfginfo[i].dobj.catId.oid);
07006         cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
07007         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
07008 
07009         /* Decide whether we want to dump it */
07010         selectDumpableObject(&(cfginfo[i].dobj));
07011     }
07012 
07013     PQclear(res);
07014 
07015     destroyPQExpBuffer(query);
07016 
07017     return cfginfo;
07018 }
07019 
07020 /*
07021  * getForeignDataWrappers:
07022  *    read all foreign-data wrappers in the system catalogs and return
07023  *    them in the FdwInfo* structure
07024  *
07025  *  numForeignDataWrappers is set to the number of fdws read in
07026  */
07027 FdwInfo *
07028 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
07029 {
07030     PGresult   *res;
07031     int         ntups;
07032     int         i;
07033     PQExpBuffer query = createPQExpBuffer();
07034     FdwInfo    *fdwinfo;
07035     int         i_tableoid;
07036     int         i_oid;
07037     int         i_fdwname;
07038     int         i_rolname;
07039     int         i_fdwhandler;
07040     int         i_fdwvalidator;
07041     int         i_fdwacl;
07042     int         i_fdwoptions;
07043 
07044     /* Before 8.4, there are no foreign-data wrappers */
07045     if (fout->remoteVersion < 80400)
07046     {
07047         *numForeignDataWrappers = 0;
07048         return NULL;
07049     }
07050 
07051     /* Make sure we are in proper schema */
07052     selectSourceSchema(fout, "pg_catalog");
07053 
07054     if (fout->remoteVersion >= 90100)
07055     {
07056         appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
07057                           "(%s fdwowner) AS rolname, "
07058                           "fdwhandler::pg_catalog.regproc, "
07059                           "fdwvalidator::pg_catalog.regproc, fdwacl, "
07060                           "array_to_string(ARRAY("
07061                           "SELECT quote_ident(option_name) || ' ' || "
07062                           "quote_literal(option_value) "
07063                           "FROM pg_options_to_table(fdwoptions) "
07064                           "ORDER BY option_name"
07065                           "), E',\n    ') AS fdwoptions "
07066                           "FROM pg_foreign_data_wrapper",
07067                           username_subquery);
07068     }
07069     else
07070     {
07071         appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
07072                           "(%s fdwowner) AS rolname, "
07073                           "'-' AS fdwhandler, "
07074                           "fdwvalidator::pg_catalog.regproc, fdwacl, "
07075                           "array_to_string(ARRAY("
07076                           "SELECT quote_ident(option_name) || ' ' || "
07077                           "quote_literal(option_value) "
07078                           "FROM pg_options_to_table(fdwoptions) "
07079                           "ORDER BY option_name"
07080                           "), E',\n    ') AS fdwoptions "
07081                           "FROM pg_foreign_data_wrapper",
07082                           username_subquery);
07083     }
07084 
07085     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
07086 
07087     ntups = PQntuples(res);
07088     *numForeignDataWrappers = ntups;
07089 
07090     fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
07091 
07092     i_tableoid = PQfnumber(res, "tableoid");
07093     i_oid = PQfnumber(res, "oid");
07094     i_fdwname = PQfnumber(res, "fdwname");
07095     i_rolname = PQfnumber(res, "rolname");
07096     i_fdwhandler = PQfnumber(res, "fdwhandler");
07097     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
07098     i_fdwacl = PQfnumber(res, "fdwacl");
07099     i_fdwoptions = PQfnumber(res, "fdwoptions");
07100 
07101     for (i = 0; i < ntups; i++)
07102     {
07103         fdwinfo[i].dobj.objType = DO_FDW;
07104         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
07105         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
07106         AssignDumpId(&fdwinfo[i].dobj);
07107         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
07108         fdwinfo[i].dobj.namespace = NULL;
07109         fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
07110         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
07111         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
07112         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
07113         fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
07114 
07115         /* Decide whether we want to dump it */
07116         selectDumpableObject(&(fdwinfo[i].dobj));
07117     }
07118 
07119     PQclear(res);
07120 
07121     destroyPQExpBuffer(query);
07122 
07123     return fdwinfo;
07124 }
07125 
07126 /*
07127  * getForeignServers:
07128  *    read all foreign servers in the system catalogs and return
07129  *    them in the ForeignServerInfo * structure
07130  *
07131  *  numForeignServers is set to the number of servers read in
07132  */
07133 ForeignServerInfo *
07134 getForeignServers(Archive *fout, int *numForeignServers)
07135 {
07136     PGresult   *res;
07137     int         ntups;
07138     int         i;
07139     PQExpBuffer query = createPQExpBuffer();
07140     ForeignServerInfo *srvinfo;
07141     int         i_tableoid;
07142     int         i_oid;
07143     int         i_srvname;
07144     int         i_rolname;
07145     int         i_srvfdw;
07146     int         i_srvtype;
07147     int         i_srvversion;
07148     int         i_srvacl;
07149     int         i_srvoptions;
07150 
07151     /* Before 8.4, there are no foreign servers */
07152     if (fout->remoteVersion < 80400)
07153     {
07154         *numForeignServers = 0;
07155         return NULL;
07156     }
07157 
07158     /* Make sure we are in proper schema */
07159     selectSourceSchema(fout, "pg_catalog");
07160 
07161     appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
07162                       "(%s srvowner) AS rolname, "
07163                       "srvfdw, srvtype, srvversion, srvacl,"
07164                       "array_to_string(ARRAY("
07165                       "SELECT quote_ident(option_name) || ' ' || "
07166                       "quote_literal(option_value) "
07167                       "FROM pg_options_to_table(srvoptions) "
07168                       "ORDER BY option_name"
07169                       "), E',\n    ') AS srvoptions "
07170                       "FROM pg_foreign_server",
07171                       username_subquery);
07172 
07173     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
07174 
07175     ntups = PQntuples(res);
07176     *numForeignServers = ntups;
07177 
07178     srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
07179 
07180     i_tableoid = PQfnumber(res, "tableoid");
07181     i_oid = PQfnumber(res, "oid");
07182     i_srvname = PQfnumber(res, "srvname");
07183     i_rolname = PQfnumber(res, "rolname");
07184     i_srvfdw = PQfnumber(res, "srvfdw");
07185     i_srvtype = PQfnumber(res, "srvtype");
07186     i_srvversion = PQfnumber(res, "srvversion");
07187     i_srvacl = PQfnumber(res, "srvacl");
07188     i_srvoptions = PQfnumber(res, "srvoptions");
07189 
07190     for (i = 0; i < ntups; i++)
07191     {
07192         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
07193         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
07194         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
07195         AssignDumpId(&srvinfo[i].dobj);
07196         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
07197         srvinfo[i].dobj.namespace = NULL;
07198         srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
07199         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
07200         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
07201         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
07202         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
07203         srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
07204 
07205         /* Decide whether we want to dump it */
07206         selectDumpableObject(&(srvinfo[i].dobj));
07207     }
07208 
07209     PQclear(res);
07210 
07211     destroyPQExpBuffer(query);
07212 
07213     return srvinfo;
07214 }
07215 
07216 /*
07217  * getDefaultACLs:
07218  *    read all default ACL information in the system catalogs and return
07219  *    them in the DefaultACLInfo structure
07220  *
07221  *  numDefaultACLs is set to the number of ACLs read in
07222  */
07223 DefaultACLInfo *
07224 getDefaultACLs(Archive *fout, int *numDefaultACLs)
07225 {
07226     DefaultACLInfo *daclinfo;
07227     PQExpBuffer query;
07228     PGresult   *res;
07229     int         i_oid;
07230     int         i_tableoid;
07231     int         i_defaclrole;
07232     int         i_defaclnamespace;
07233     int         i_defaclobjtype;
07234     int         i_defaclacl;
07235     int         i,
07236                 ntups;
07237 
07238     if (fout->remoteVersion < 90000)
07239     {
07240         *numDefaultACLs = 0;
07241         return NULL;
07242     }
07243 
07244     query = createPQExpBuffer();
07245 
07246     /* Make sure we are in proper schema */
07247     selectSourceSchema(fout, "pg_catalog");
07248 
07249     appendPQExpBuffer(query, "SELECT oid, tableoid, "
07250                       "(%s defaclrole) AS defaclrole, "
07251                       "defaclnamespace, "
07252                       "defaclobjtype, "
07253                       "defaclacl "
07254                       "FROM pg_default_acl",
07255                       username_subquery);
07256 
07257     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
07258 
07259     ntups = PQntuples(res);
07260     *numDefaultACLs = ntups;
07261 
07262     daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
07263 
07264     i_oid = PQfnumber(res, "oid");
07265     i_tableoid = PQfnumber(res, "tableoid");
07266     i_defaclrole = PQfnumber(res, "defaclrole");
07267     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
07268     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
07269     i_defaclacl = PQfnumber(res, "defaclacl");
07270 
07271     for (i = 0; i < ntups; i++)
07272     {
07273         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
07274 
07275         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
07276         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
07277         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
07278         AssignDumpId(&daclinfo[i].dobj);
07279         /* cheesy ... is it worth coming up with a better object name? */
07280         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
07281 
07282         if (nspid != InvalidOid)
07283             daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
07284                                                  daclinfo[i].dobj.catId.oid);
07285         else
07286             daclinfo[i].dobj.namespace = NULL;
07287 
07288         daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
07289         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
07290         daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
07291 
07292         /* Decide whether we want to dump it */
07293         selectDumpableDefaultACL(&(daclinfo[i]));
07294     }
07295 
07296     PQclear(res);
07297 
07298     destroyPQExpBuffer(query);
07299 
07300     return daclinfo;
07301 }
07302 
07303 /*
07304  * dumpComment --
07305  *
07306  * This routine is used to dump any comments associated with the
07307  * object handed to this routine. The routine takes a constant character
07308  * string for the target part of the comment-creation command, plus
07309  * the namespace and owner of the object (for labeling the ArchiveEntry),
07310  * plus catalog ID and subid which are the lookup key for pg_description,
07311  * plus the dump ID for the object (for setting a dependency).
07312  * If a matching pg_description entry is found, it is dumped.
07313  *
07314  * Note: although this routine takes a dumpId for dependency purposes,
07315  * that purpose is just to mark the dependency in the emitted dump file
07316  * for possible future use by pg_restore.  We do NOT use it for determining
07317  * ordering of the comment in the dump file, because this routine is called
07318  * after dependency sorting occurs.  This routine should be called just after
07319  * calling ArchiveEntry() for the specified object.
07320  */
07321 static void
07322 dumpComment(Archive *fout, const char *target,
07323             const char *namespace, const char *owner,
07324             CatalogId catalogId, int subid, DumpId dumpId)
07325 {
07326     CommentItem *comments;
07327     int         ncomments;
07328 
07329     /* Comments are schema not data ... except blob comments are data */
07330     if (strncmp(target, "LARGE OBJECT ", 13) != 0)
07331     {
07332         if (dataOnly)
07333             return;
07334     }
07335     else
07336     {
07337         if (schemaOnly)
07338             return;
07339     }
07340 
07341     /* Search for comments associated with catalogId, using table */
07342     ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
07343                              &comments);
07344 
07345     /* Is there one matching the subid? */
07346     while (ncomments > 0)
07347     {
07348         if (comments->objsubid == subid)
07349             break;
07350         comments++;
07351         ncomments--;
07352     }
07353 
07354     /* If a comment exists, build COMMENT ON statement */
07355     if (ncomments > 0)
07356     {
07357         PQExpBuffer query = createPQExpBuffer();
07358 
07359         appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
07360         appendStringLiteralAH(query, comments->descr, fout);
07361         appendPQExpBuffer(query, ";\n");
07362 
07363         /*
07364          * We mark comments as SECTION_NONE because they really belong in the
07365          * same section as their parent, whether that is pre-data or
07366          * post-data.
07367          */
07368         ArchiveEntry(fout, nilCatalogId, createDumpId(),
07369                      target, namespace, NULL, owner,
07370                      false, "COMMENT", SECTION_NONE,
07371                      query->data, "", NULL,
07372                      &(dumpId), 1,
07373                      NULL, NULL);
07374 
07375         destroyPQExpBuffer(query);
07376     }
07377 }
07378 
07379 /*
07380  * dumpTableComment --
07381  *
07382  * As above, but dump comments for both the specified table (or view)
07383  * and its columns.
07384  */
07385 static void
07386 dumpTableComment(Archive *fout, TableInfo *tbinfo,
07387                  const char *reltypename)
07388 {
07389     CommentItem *comments;
07390     int         ncomments;
07391     PQExpBuffer query;
07392     PQExpBuffer target;
07393 
07394     /* Comments are SCHEMA not data */
07395     if (dataOnly)
07396         return;
07397 
07398     /* Search for comments associated with relation, using table */
07399     ncomments = findComments(fout,
07400                              tbinfo->dobj.catId.tableoid,
07401                              tbinfo->dobj.catId.oid,
07402                              &comments);
07403 
07404     /* If comments exist, build COMMENT ON statements */
07405     if (ncomments <= 0)
07406         return;
07407 
07408     query = createPQExpBuffer();
07409     target = createPQExpBuffer();
07410 
07411     while (ncomments > 0)
07412     {
07413         const char *descr = comments->descr;
07414         int         objsubid = comments->objsubid;
07415 
07416         if (objsubid == 0)
07417         {
07418             resetPQExpBuffer(target);
07419             appendPQExpBuffer(target, "%s %s", reltypename,
07420                               fmtId(tbinfo->dobj.name));
07421 
07422             resetPQExpBuffer(query);
07423             appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
07424             appendStringLiteralAH(query, descr, fout);
07425             appendPQExpBuffer(query, ";\n");
07426 
07427             ArchiveEntry(fout, nilCatalogId, createDumpId(),
07428                          target->data,
07429                          tbinfo->dobj.namespace->dobj.name,
07430                          NULL, tbinfo->rolname,
07431                          false, "COMMENT", SECTION_NONE,
07432                          query->data, "", NULL,
07433                          &(tbinfo->dobj.dumpId), 1,
07434                          NULL, NULL);
07435         }
07436         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
07437         {
07438             resetPQExpBuffer(target);
07439             appendPQExpBuffer(target, "COLUMN %s.",
07440                               fmtId(tbinfo->dobj.name));
07441             appendPQExpBuffer(target, "%s",
07442                               fmtId(tbinfo->attnames[objsubid - 1]));
07443 
07444             resetPQExpBuffer(query);
07445             appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
07446             appendStringLiteralAH(query, descr, fout);
07447             appendPQExpBuffer(query, ";\n");
07448 
07449             ArchiveEntry(fout, nilCatalogId, createDumpId(),
07450                          target->data,
07451                          tbinfo->dobj.namespace->dobj.name,
07452                          NULL, tbinfo->rolname,
07453                          false, "COMMENT", SECTION_NONE,
07454                          query->data, "", NULL,
07455                          &(tbinfo->dobj.dumpId), 1,
07456                          NULL, NULL);
07457         }
07458 
07459         comments++;
07460         ncomments--;
07461     }
07462 
07463     destroyPQExpBuffer(query);
07464     destroyPQExpBuffer(target);
07465 }
07466 
07467 /*
07468  * findComments --
07469  *
07470  * Find the comment(s), if any, associated with the given object.  All the
07471  * objsubid values associated with the given classoid/objoid are found with
07472  * one search.
07473  */
07474 static int
07475 findComments(Archive *fout, Oid classoid, Oid objoid,
07476              CommentItem **items)
07477 {
07478     /* static storage for table of comments */
07479     static CommentItem *comments = NULL;
07480     static int  ncomments = -1;
07481 
07482     CommentItem *middle = NULL;
07483     CommentItem *low;
07484     CommentItem *high;
07485     int         nmatch;
07486 
07487     /* Get comments if we didn't already */
07488     if (ncomments < 0)
07489         ncomments = collectComments(fout, &comments);
07490 
07491     /*
07492      * Pre-7.2, pg_description does not contain classoid, so collectComments
07493      * just stores a zero.  If there's a collision on object OID, well, you
07494      * get duplicate comments.
07495      */
07496     if (fout->remoteVersion < 70200)
07497         classoid = 0;
07498 
07499     /*
07500      * Do binary search to find some item matching the object.
07501      */
07502     low = &comments[0];
07503     high = &comments[ncomments - 1];
07504     while (low <= high)
07505     {
07506         middle = low + (high - low) / 2;
07507 
07508         if (classoid < middle->classoid)
07509             high = middle - 1;
07510         else if (classoid > middle->classoid)
07511             low = middle + 1;
07512         else if (objoid < middle->objoid)
07513             high = middle - 1;
07514         else if (objoid > middle->objoid)
07515             low = middle + 1;
07516         else
07517             break;              /* found a match */
07518     }
07519 
07520     if (low > high)             /* no matches */
07521     {
07522         *items = NULL;
07523         return 0;
07524     }
07525 
07526     /*
07527      * Now determine how many items match the object.  The search loop
07528      * invariant still holds: only items between low and high inclusive could
07529      * match.
07530      */
07531     nmatch = 1;
07532     while (middle > low)
07533     {
07534         if (classoid != middle[-1].classoid ||
07535             objoid != middle[-1].objoid)
07536             break;
07537         middle--;
07538         nmatch++;
07539     }
07540 
07541     *items = middle;
07542 
07543     middle += nmatch;
07544     while (middle <= high)
07545     {
07546         if (classoid != middle->classoid ||
07547             objoid != middle->objoid)
07548             break;
07549         middle++;
07550         nmatch++;
07551     }
07552 
07553     return nmatch;
07554 }
07555 
07556 /*
07557  * collectComments --
07558  *
07559  * Construct a table of all comments available for database objects.
07560  * We used to do per-object queries for the comments, but it's much faster
07561  * to pull them all over at once, and on most databases the memory cost
07562  * isn't high.
07563  *
07564  * The table is sorted by classoid/objid/objsubid for speed in lookup.
07565  */
07566 static int
07567 collectComments(Archive *fout, CommentItem **items)
07568 {
07569     PGresult   *res;
07570     PQExpBuffer query;
07571     int         i_description;
07572     int         i_classoid;
07573     int         i_objoid;
07574     int         i_objsubid;
07575     int         ntups;
07576     int         i;
07577     CommentItem *comments;
07578 
07579     /*
07580      * Note we do NOT change source schema here; preserve the caller's
07581      * setting, instead.
07582      */
07583 
07584     query = createPQExpBuffer();
07585 
07586     if (fout->remoteVersion >= 70300)
07587     {
07588         appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
07589                           "FROM pg_catalog.pg_description "
07590                           "ORDER BY classoid, objoid, objsubid");
07591     }
07592     else if (fout->remoteVersion >= 70200)
07593     {
07594         appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
07595                           "FROM pg_description "
07596                           "ORDER BY classoid, objoid, objsubid");
07597     }
07598     else
07599     {
07600         /* Note: this will fail to find attribute comments in pre-7.2... */
07601         appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
07602                           "FROM pg_description "
07603                           "ORDER BY objoid");
07604     }
07605 
07606     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
07607 
07608     /* Construct lookup table containing OIDs in numeric form */
07609 
07610     i_description = PQfnumber(res, "description");
07611     i_classoid = PQfnumber(res, "classoid");
07612     i_objoid = PQfnumber(res, "objoid");
07613     i_objsubid = PQfnumber(res, "objsubid");
07614 
07615     ntups = PQntuples(res);
07616 
07617     comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
07618 
07619     for (i = 0; i < ntups; i++)
07620     {
07621         comments[i].descr = PQgetvalue(res, i, i_description);
07622         comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
07623         comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
07624         comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
07625     }
07626 
07627     /* Do NOT free the PGresult since we are keeping pointers into it */
07628     destroyPQExpBuffer(query);
07629 
07630     *items = comments;
07631     return ntups;
07632 }
07633 
07634 /*
07635  * dumpDumpableObject
07636  *
07637  * This routine and its subsidiaries are responsible for creating
07638  * ArchiveEntries (TOC objects) for each object to be dumped.
07639  */
07640 static void
07641 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
07642 {
07643     switch (dobj->objType)
07644     {
07645         case DO_NAMESPACE:
07646             dumpNamespace(fout, (NamespaceInfo *) dobj);
07647             break;
07648         case DO_EXTENSION:
07649             dumpExtension(fout, (ExtensionInfo *) dobj);
07650             break;
07651         case DO_TYPE:
07652             dumpType(fout, (TypeInfo *) dobj);
07653             break;
07654         case DO_SHELL_TYPE:
07655             dumpShellType(fout, (ShellTypeInfo *) dobj);
07656             break;
07657         case DO_FUNC:
07658             dumpFunc(fout, (FuncInfo *) dobj);
07659             break;
07660         case DO_AGG:
07661             dumpAgg(fout, (AggInfo *) dobj);
07662             break;
07663         case DO_OPERATOR:
07664             dumpOpr(fout, (OprInfo *) dobj);
07665             break;
07666         case DO_OPCLASS:
07667             dumpOpclass(fout, (OpclassInfo *) dobj);
07668             break;
07669         case DO_OPFAMILY:
07670             dumpOpfamily(fout, (OpfamilyInfo *) dobj);
07671             break;
07672         case DO_COLLATION:
07673             dumpCollation(fout, (CollInfo *) dobj);
07674             break;
07675         case DO_CONVERSION:
07676             dumpConversion(fout, (ConvInfo *) dobj);
07677             break;
07678         case DO_TABLE:
07679             dumpTable(fout, (TableInfo *) dobj);
07680             break;
07681         case DO_ATTRDEF:
07682             dumpAttrDef(fout, (AttrDefInfo *) dobj);
07683             break;
07684         case DO_INDEX:
07685             dumpIndex(fout, (IndxInfo *) dobj);
07686             break;
07687         case DO_REFRESH_MATVIEW:
07688             refreshMatViewData(fout, (TableDataInfo *) dobj);
07689             break;
07690         case DO_RULE:
07691             dumpRule(fout, (RuleInfo *) dobj);
07692             break;
07693         case DO_TRIGGER:
07694             dumpTrigger(fout, (TriggerInfo *) dobj);
07695             break;
07696         case DO_EVENT_TRIGGER:
07697             dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
07698             break;
07699         case DO_CONSTRAINT:
07700             dumpConstraint(fout, (ConstraintInfo *) dobj);
07701             break;
07702         case DO_FK_CONSTRAINT:
07703             dumpConstraint(fout, (ConstraintInfo *) dobj);
07704             break;
07705         case DO_PROCLANG:
07706             dumpProcLang(fout, (ProcLangInfo *) dobj);
07707             break;
07708         case DO_CAST:
07709             dumpCast(fout, (CastInfo *) dobj);
07710             break;
07711         case DO_TABLE_DATA:
07712             if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
07713                 dumpSequenceData(fout, (TableDataInfo *) dobj);
07714             else
07715                 dumpTableData(fout, (TableDataInfo *) dobj);
07716             break;
07717         case DO_DUMMY_TYPE:
07718             /* table rowtypes and array types are never dumped separately */
07719             break;
07720         case DO_TSPARSER:
07721             dumpTSParser(fout, (TSParserInfo *) dobj);
07722             break;
07723         case DO_TSDICT:
07724             dumpTSDictionary(fout, (TSDictInfo *) dobj);
07725             break;
07726         case DO_TSTEMPLATE:
07727             dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
07728             break;
07729         case DO_TSCONFIG:
07730             dumpTSConfig(fout, (TSConfigInfo *) dobj);
07731             break;
07732         case DO_FDW:
07733             dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
07734             break;
07735         case DO_FOREIGN_SERVER:
07736             dumpForeignServer(fout, (ForeignServerInfo *) dobj);
07737             break;
07738         case DO_DEFAULT_ACL:
07739             dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
07740             break;
07741         case DO_BLOB:
07742             dumpBlob(fout, (BlobInfo *) dobj);
07743             break;
07744         case DO_BLOB_DATA:
07745             ArchiveEntry(fout, dobj->catId, dobj->dumpId,
07746                          dobj->name, NULL, NULL, "",
07747                          false, "BLOBS", SECTION_DATA,
07748                          "", "", NULL,
07749                          NULL, 0,
07750                          dumpBlobs, NULL);
07751             break;
07752         case DO_PRE_DATA_BOUNDARY:
07753         case DO_POST_DATA_BOUNDARY:
07754             /* never dumped, nothing to do */
07755             break;
07756     }
07757 }
07758 
07759 /*
07760  * dumpNamespace
07761  *    writes out to fout the queries to recreate a user-defined namespace
07762  */
07763 static void
07764 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
07765 {
07766     PQExpBuffer q;
07767     PQExpBuffer delq;
07768     PQExpBuffer labelq;
07769     char       *qnspname;
07770 
07771     /* Skip if not to be dumped */
07772     if (!nspinfo->dobj.dump || dataOnly)
07773         return;
07774 
07775     /* don't dump dummy namespace from pre-7.3 source */
07776     if (strlen(nspinfo->dobj.name) == 0)
07777         return;
07778 
07779     q = createPQExpBuffer();
07780     delq = createPQExpBuffer();
07781     labelq = createPQExpBuffer();
07782 
07783     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
07784 
07785     appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
07786 
07787     appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
07788 
07789     appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
07790 
07791     if (binary_upgrade)
07792         binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
07793 
07794     ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
07795                  nspinfo->dobj.name,
07796                  NULL, NULL,
07797                  nspinfo->rolname,
07798                  false, "SCHEMA", SECTION_PRE_DATA,
07799                  q->data, delq->data, NULL,
07800                  NULL, 0,
07801                  NULL, NULL);
07802 
07803     /* Dump Schema Comments and Security Labels */
07804     dumpComment(fout, labelq->data,
07805                 NULL, nspinfo->rolname,
07806                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
07807     dumpSecLabel(fout, labelq->data,
07808                  NULL, nspinfo->rolname,
07809                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
07810 
07811     dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
07812             qnspname, NULL, nspinfo->dobj.name, NULL,
07813             nspinfo->rolname, nspinfo->nspacl);
07814 
07815     free(qnspname);
07816 
07817     destroyPQExpBuffer(q);
07818     destroyPQExpBuffer(delq);
07819     destroyPQExpBuffer(labelq);
07820 }
07821 
07822 /*
07823  * dumpExtension
07824  *    writes out to fout the queries to recreate an extension
07825  */
07826 static void
07827 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
07828 {
07829     PQExpBuffer q;
07830     PQExpBuffer delq;
07831     PQExpBuffer labelq;
07832     char       *qextname;
07833 
07834     /* Skip if not to be dumped */
07835     if (!extinfo->dobj.dump || dataOnly)
07836         return;
07837 
07838     q = createPQExpBuffer();
07839     delq = createPQExpBuffer();
07840     labelq = createPQExpBuffer();
07841 
07842     qextname = pg_strdup(fmtId(extinfo->dobj.name));
07843 
07844     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
07845 
07846     if (!binary_upgrade)
07847     {
07848         /*
07849          * In a regular dump, we use IF NOT EXISTS so that there isn't a
07850          * problem if the extension already exists in the target database;
07851          * this is essential for installed-by-default extensions such as
07852          * plpgsql.
07853          *
07854          * In binary-upgrade mode, that doesn't work well, so instead we skip
07855          * built-in extensions based on their OIDs; see
07856          * selectDumpableExtension.
07857          */
07858         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
07859                           qextname, fmtId(extinfo->namespace));
07860     }
07861     else
07862     {
07863         int         i;
07864         int         n;
07865 
07866         appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
07867 
07868         /*
07869          * We unconditionally create the extension, so we must drop it if it
07870          * exists.  This could happen if the user deleted 'plpgsql' and then
07871          * readded it, causing its oid to be greater than FirstNormalObjectId.
07872          * The FirstNormalObjectId test was kept to avoid repeatedly dropping
07873          * and recreating extensions like 'plpgsql'.
07874          */
07875         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
07876 
07877         appendPQExpBuffer(q,
07878                           "SELECT binary_upgrade.create_empty_extension(");
07879         appendStringLiteralAH(q, extinfo->dobj.name, fout);
07880         appendPQExpBuffer(q, ", ");
07881         appendStringLiteralAH(q, extinfo->namespace, fout);
07882         appendPQExpBuffer(q, ", ");
07883         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
07884         appendStringLiteralAH(q, extinfo->extversion, fout);
07885         appendPQExpBuffer(q, ", ");
07886 
07887         /*
07888          * Note that we're pushing extconfig (an OID array) back into
07889          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
07890          * preserved in binary upgrade.
07891          */
07892         if (strlen(extinfo->extconfig) > 2)
07893             appendStringLiteralAH(q, extinfo->extconfig, fout);
07894         else
07895             appendPQExpBuffer(q, "NULL");
07896         appendPQExpBuffer(q, ", ");
07897         if (strlen(extinfo->extcondition) > 2)
07898             appendStringLiteralAH(q, extinfo->extcondition, fout);
07899         else
07900             appendPQExpBuffer(q, "NULL");
07901         appendPQExpBuffer(q, ", ");
07902         appendPQExpBuffer(q, "ARRAY[");
07903         n = 0;
07904         for (i = 0; i < extinfo->dobj.nDeps; i++)
07905         {
07906             DumpableObject *extobj;
07907 
07908             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
07909             if (extobj && extobj->objType == DO_EXTENSION)
07910             {
07911                 if (n++ > 0)
07912                     appendPQExpBuffer(q, ",");
07913                 appendStringLiteralAH(q, extobj->name, fout);
07914             }
07915         }
07916         appendPQExpBuffer(q, "]::pg_catalog.text[]");
07917         appendPQExpBuffer(q, ");\n");
07918     }
07919 
07920     appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
07921 
07922     ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
07923                  extinfo->dobj.name,
07924                  NULL, NULL,
07925                  "",
07926                  false, "EXTENSION", SECTION_PRE_DATA,
07927                  q->data, delq->data, NULL,
07928                  NULL, 0,
07929                  NULL, NULL);
07930 
07931     /* Dump Extension Comments and Security Labels */
07932     dumpComment(fout, labelq->data,
07933                 NULL, "",
07934                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
07935     dumpSecLabel(fout, labelq->data,
07936                  NULL, "",
07937                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
07938 
07939     free(qextname);
07940 
07941     destroyPQExpBuffer(q);
07942     destroyPQExpBuffer(delq);
07943     destroyPQExpBuffer(labelq);
07944 }
07945 
07946 /*
07947  * dumpType
07948  *    writes out to fout the queries to recreate a user-defined type
07949  */
07950 static void
07951 dumpType(Archive *fout, TypeInfo *tyinfo)
07952 {
07953     /* Skip if not to be dumped */
07954     if (!tyinfo->dobj.dump || dataOnly)
07955         return;
07956 
07957     /* Dump out in proper style */
07958     if (tyinfo->typtype == TYPTYPE_BASE)
07959         dumpBaseType(fout, tyinfo);
07960     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
07961         dumpDomain(fout, tyinfo);
07962     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
07963         dumpCompositeType(fout, tyinfo);
07964     else if (tyinfo->typtype == TYPTYPE_ENUM)
07965         dumpEnumType(fout, tyinfo);
07966     else if (tyinfo->typtype == TYPTYPE_RANGE)
07967         dumpRangeType(fout, tyinfo);
07968     else
07969         write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
07970                   tyinfo->dobj.name);
07971 }
07972 
07973 /*
07974  * dumpEnumType
07975  *    writes out to fout the queries to recreate a user-defined enum type
07976  */
07977 static void
07978 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
07979 {
07980     PQExpBuffer q = createPQExpBuffer();
07981     PQExpBuffer delq = createPQExpBuffer();
07982     PQExpBuffer labelq = createPQExpBuffer();
07983     PQExpBuffer query = createPQExpBuffer();
07984     PGresult   *res;
07985     int         num,
07986                 i;
07987     Oid         enum_oid;
07988     char       *qtypname;
07989     char       *label;
07990 
07991     /* Set proper schema search path */
07992     selectSourceSchema(fout, "pg_catalog");
07993 
07994     if (fout->remoteVersion >= 90100)
07995         appendPQExpBuffer(query, "SELECT oid, enumlabel "
07996                           "FROM pg_catalog.pg_enum "
07997                           "WHERE enumtypid = '%u'"
07998                           "ORDER BY enumsortorder",
07999                           tyinfo->dobj.catId.oid);
08000     else
08001         appendPQExpBuffer(query, "SELECT oid, enumlabel "
08002                           "FROM pg_catalog.pg_enum "
08003                           "WHERE enumtypid = '%u'"
08004                           "ORDER BY oid",
08005                           tyinfo->dobj.catId.oid);
08006 
08007     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
08008 
08009     num = PQntuples(res);
08010 
08011     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
08012 
08013     /*
08014      * DROP must be fully qualified in case same name appears in pg_catalog.
08015      * CASCADE shouldn't be required here as for normal types since the I/O
08016      * functions are generic and do not get dropped.
08017      */
08018     appendPQExpBuffer(delq, "DROP TYPE %s.",
08019                       fmtId(tyinfo->dobj.namespace->dobj.name));
08020     appendPQExpBuffer(delq, "%s;\n",
08021                       qtypname);
08022 
08023     if (binary_upgrade)
08024         binary_upgrade_set_type_oids_by_type_oid(fout, q,
08025                                                  tyinfo->dobj.catId.oid);
08026 
08027     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
08028                       qtypname);
08029 
08030     if (!binary_upgrade)
08031     {
08032         /* Labels with server-assigned oids */
08033         for (i = 0; i < num; i++)
08034         {
08035             label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
08036             if (i > 0)
08037                 appendPQExpBuffer(q, ",");
08038             appendPQExpBuffer(q, "\n    ");
08039             appendStringLiteralAH(q, label, fout);
08040         }
08041     }
08042 
08043     appendPQExpBuffer(q, "\n);\n");
08044 
08045     if (binary_upgrade)
08046     {
08047         /* Labels with dump-assigned (preserved) oids */
08048         for (i = 0; i < num; i++)
08049         {
08050             enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
08051             label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
08052 
08053             if (i == 0)
08054                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
08055             appendPQExpBuffer(q,
08056                               "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
08057                               enum_oid);
08058             appendPQExpBuffer(q, "ALTER TYPE %s.",
08059                               fmtId(tyinfo->dobj.namespace->dobj.name));
08060             appendPQExpBuffer(q, "%s ADD VALUE ",
08061                               qtypname);
08062             appendStringLiteralAH(q, label, fout);
08063             appendPQExpBuffer(q, ";\n\n");
08064         }
08065     }
08066 
08067     appendPQExpBuffer(labelq, "TYPE %s", qtypname);
08068 
08069     if (binary_upgrade)
08070         binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
08071 
08072     ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
08073                  tyinfo->dobj.name,
08074                  tyinfo->dobj.namespace->dobj.name,
08075                  NULL,
08076                  tyinfo->rolname, false,
08077                  "TYPE", SECTION_PRE_DATA,
08078                  q->data, delq->data, NULL,
08079                  NULL, 0,
08080                  NULL, NULL);
08081 
08082     /* Dump Type Comments and Security Labels */
08083     dumpComment(fout, labelq->data,
08084                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08085                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08086     dumpSecLabel(fout, labelq->data,
08087                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08088                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08089 
08090     dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
08091             qtypname, NULL, tyinfo->dobj.name,
08092             tyinfo->dobj.namespace->dobj.name,
08093             tyinfo->rolname, tyinfo->typacl);
08094 
08095     PQclear(res);
08096     destroyPQExpBuffer(q);
08097     destroyPQExpBuffer(delq);
08098     destroyPQExpBuffer(labelq);
08099     destroyPQExpBuffer(query);
08100 }
08101 
08102 /*
08103  * dumpRangeType
08104  *    writes out to fout the queries to recreate a user-defined range type
08105  */
08106 static void
08107 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
08108 {
08109     PQExpBuffer q = createPQExpBuffer();
08110     PQExpBuffer delq = createPQExpBuffer();
08111     PQExpBuffer labelq = createPQExpBuffer();
08112     PQExpBuffer query = createPQExpBuffer();
08113     PGresult   *res;
08114     Oid         collationOid;
08115     char       *qtypname;
08116     char       *procname;
08117 
08118     /*
08119      * select appropriate schema to ensure names in CREATE are properly
08120      * qualified
08121      */
08122     selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
08123 
08124     appendPQExpBuffer(query,
08125             "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
08126                       "opc.opcname AS opcname, "
08127                       "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
08128                       "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
08129                       "opc.opcdefault, "
08130                       "CASE WHEN rngcollation = st.typcollation THEN 0 "
08131                       "     ELSE rngcollation END AS collation, "
08132                       "rngcanonical, rngsubdiff "
08133                       "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
08134                       "     pg_catalog.pg_opclass opc "
08135                       "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
08136                       "rngtypid = '%u'",
08137                       tyinfo->dobj.catId.oid);
08138 
08139     res = ExecuteSqlQueryForSingleRow(fout, query->data);
08140 
08141     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
08142 
08143     /*
08144      * DROP must be fully qualified in case same name appears in pg_catalog.
08145      * CASCADE shouldn't be required here as for normal types since the I/O
08146      * functions are generic and do not get dropped.
08147      */
08148     appendPQExpBuffer(delq, "DROP TYPE %s.",
08149                       fmtId(tyinfo->dobj.namespace->dobj.name));
08150     appendPQExpBuffer(delq, "%s;\n",
08151                       qtypname);
08152 
08153     if (binary_upgrade)
08154         binary_upgrade_set_type_oids_by_type_oid(fout,
08155                                                  q, tyinfo->dobj.catId.oid);
08156 
08157     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
08158                       qtypname);
08159 
08160     appendPQExpBuffer(q, "\n    subtype = %s",
08161                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
08162 
08163     /* print subtype_opclass only if not default for subtype */
08164     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
08165     {
08166         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
08167         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
08168 
08169         /* always schema-qualify, don't try to be smart */
08170         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
08171                           fmtId(nspname));
08172         appendPQExpBuffer(q, "%s", fmtId(opcname));
08173     }
08174 
08175     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
08176     if (OidIsValid(collationOid))
08177     {
08178         CollInfo   *coll = findCollationByOid(collationOid);
08179 
08180         if (coll)
08181         {
08182             /* always schema-qualify, don't try to be smart */
08183             appendPQExpBuffer(q, ",\n    collation = %s.",
08184                               fmtId(coll->dobj.namespace->dobj.name));
08185             appendPQExpBuffer(q, "%s",
08186                               fmtId(coll->dobj.name));
08187         }
08188     }
08189 
08190     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
08191     if (strcmp(procname, "-") != 0)
08192         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
08193 
08194     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
08195     if (strcmp(procname, "-") != 0)
08196         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
08197 
08198     appendPQExpBuffer(q, "\n);\n");
08199 
08200     appendPQExpBuffer(labelq, "TYPE %s", qtypname);
08201 
08202     if (binary_upgrade)
08203         binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
08204 
08205     ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
08206                  tyinfo->dobj.name,
08207                  tyinfo->dobj.namespace->dobj.name,
08208                  NULL,
08209                  tyinfo->rolname, false,
08210                  "TYPE", SECTION_PRE_DATA,
08211                  q->data, delq->data, NULL,
08212                  NULL, 0,
08213                  NULL, NULL);
08214 
08215     /* Dump Type Comments and Security Labels */
08216     dumpComment(fout, labelq->data,
08217                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08218                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08219     dumpSecLabel(fout, labelq->data,
08220                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08221                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08222 
08223     dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
08224             qtypname, NULL, tyinfo->dobj.name,
08225             tyinfo->dobj.namespace->dobj.name,
08226             tyinfo->rolname, tyinfo->typacl);
08227 
08228     PQclear(res);
08229     destroyPQExpBuffer(q);
08230     destroyPQExpBuffer(delq);
08231     destroyPQExpBuffer(labelq);
08232     destroyPQExpBuffer(query);
08233 }
08234 
08235 /*
08236  * dumpBaseType
08237  *    writes out to fout the queries to recreate a user-defined base type
08238  */
08239 static void
08240 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
08241 {
08242     PQExpBuffer q = createPQExpBuffer();
08243     PQExpBuffer delq = createPQExpBuffer();
08244     PQExpBuffer labelq = createPQExpBuffer();
08245     PQExpBuffer query = createPQExpBuffer();
08246     PGresult   *res;
08247     char       *qtypname;
08248     char       *typlen;
08249     char       *typinput;
08250     char       *typoutput;
08251     char       *typreceive;
08252     char       *typsend;
08253     char       *typmodin;
08254     char       *typmodout;
08255     char       *typanalyze;
08256     Oid         typreceiveoid;
08257     Oid         typsendoid;
08258     Oid         typmodinoid;
08259     Oid         typmodoutoid;
08260     Oid         typanalyzeoid;
08261     char       *typcategory;
08262     char       *typispreferred;
08263     char       *typdelim;
08264     char       *typbyval;
08265     char       *typalign;
08266     char       *typstorage;
08267     char       *typcollatable;
08268     char       *typdefault;
08269     bool        typdefault_is_literal = false;
08270 
08271     /* Set proper schema search path so regproc references list correctly */
08272     selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
08273 
08274     /* Fetch type-specific details */
08275     if (fout->remoteVersion >= 90100)
08276     {
08277         appendPQExpBuffer(query, "SELECT typlen, "
08278                           "typinput, typoutput, typreceive, typsend, "
08279                           "typmodin, typmodout, typanalyze, "
08280                           "typreceive::pg_catalog.oid AS typreceiveoid, "
08281                           "typsend::pg_catalog.oid AS typsendoid, "
08282                           "typmodin::pg_catalog.oid AS typmodinoid, "
08283                           "typmodout::pg_catalog.oid AS typmodoutoid, "
08284                           "typanalyze::pg_catalog.oid AS typanalyzeoid, "
08285                           "typcategory, typispreferred, "
08286                           "typdelim, typbyval, typalign, typstorage, "
08287                           "(typcollation <> 0) AS typcollatable, "
08288                           "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
08289                           "FROM pg_catalog.pg_type "
08290                           "WHERE oid = '%u'::pg_catalog.oid",
08291                           tyinfo->dobj.catId.oid);
08292     }
08293     else if (fout->remoteVersion >= 80400)
08294     {
08295         appendPQExpBuffer(query, "SELECT typlen, "
08296                           "typinput, typoutput, typreceive, typsend, "
08297                           "typmodin, typmodout, typanalyze, "
08298                           "typreceive::pg_catalog.oid AS typreceiveoid, "
08299                           "typsend::pg_catalog.oid AS typsendoid, "
08300                           "typmodin::pg_catalog.oid AS typmodinoid, "
08301                           "typmodout::pg_catalog.oid AS typmodoutoid, "
08302                           "typanalyze::pg_catalog.oid AS typanalyzeoid, "
08303                           "typcategory, typispreferred, "
08304                           "typdelim, typbyval, typalign, typstorage, "
08305                           "false AS typcollatable, "
08306                           "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
08307                           "FROM pg_catalog.pg_type "
08308                           "WHERE oid = '%u'::pg_catalog.oid",
08309                           tyinfo->dobj.catId.oid);
08310     }
08311     else if (fout->remoteVersion >= 80300)
08312     {
08313         /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
08314         appendPQExpBuffer(query, "SELECT typlen, "
08315                           "typinput, typoutput, typreceive, typsend, "
08316                           "typmodin, typmodout, typanalyze, "
08317                           "typreceive::pg_catalog.oid AS typreceiveoid, "
08318                           "typsend::pg_catalog.oid AS typsendoid, "
08319                           "typmodin::pg_catalog.oid AS typmodinoid, "
08320                           "typmodout::pg_catalog.oid AS typmodoutoid, "
08321                           "typanalyze::pg_catalog.oid AS typanalyzeoid, "
08322                           "'U' AS typcategory, false AS typispreferred, "
08323                           "typdelim, typbyval, typalign, typstorage, "
08324                           "false AS typcollatable, "
08325                           "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
08326                           "FROM pg_catalog.pg_type "
08327                           "WHERE oid = '%u'::pg_catalog.oid",
08328                           tyinfo->dobj.catId.oid);
08329     }
08330     else if (fout->remoteVersion >= 80000)
08331     {
08332         appendPQExpBuffer(query, "SELECT typlen, "
08333                           "typinput, typoutput, typreceive, typsend, "
08334                           "'-' AS typmodin, '-' AS typmodout, "
08335                           "typanalyze, "
08336                           "typreceive::pg_catalog.oid AS typreceiveoid, "
08337                           "typsend::pg_catalog.oid AS typsendoid, "
08338                           "0 AS typmodinoid, 0 AS typmodoutoid, "
08339                           "typanalyze::pg_catalog.oid AS typanalyzeoid, "
08340                           "'U' AS typcategory, false AS typispreferred, "
08341                           "typdelim, typbyval, typalign, typstorage, "
08342                           "false AS typcollatable, "
08343                           "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
08344                           "FROM pg_catalog.pg_type "
08345                           "WHERE oid = '%u'::pg_catalog.oid",
08346                           tyinfo->dobj.catId.oid);
08347     }
08348     else if (fout->remoteVersion >= 70400)
08349     {
08350         appendPQExpBuffer(query, "SELECT typlen, "
08351                           "typinput, typoutput, typreceive, typsend, "
08352                           "'-' AS typmodin, '-' AS typmodout, "
08353                           "'-' AS typanalyze, "
08354                           "typreceive::pg_catalog.oid AS typreceiveoid, "
08355                           "typsend::pg_catalog.oid AS typsendoid, "
08356                           "0 AS typmodinoid, 0 AS typmodoutoid, "
08357                           "0 AS typanalyzeoid, "
08358                           "'U' AS typcategory, false AS typispreferred, "
08359                           "typdelim, typbyval, typalign, typstorage, "
08360                           "false AS typcollatable, "
08361                           "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
08362                           "FROM pg_catalog.pg_type "
08363                           "WHERE oid = '%u'::pg_catalog.oid",
08364                           tyinfo->dobj.catId.oid);
08365     }
08366     else if (fout->remoteVersion >= 70300)
08367     {
08368         appendPQExpBuffer(query, "SELECT typlen, "
08369                           "typinput, typoutput, "
08370                           "'-' AS typreceive, '-' AS typsend, "
08371                           "'-' AS typmodin, '-' AS typmodout, "
08372                           "'-' AS typanalyze, "
08373                           "0 AS typreceiveoid, 0 AS typsendoid, "
08374                           "0 AS typmodinoid, 0 AS typmodoutoid, "
08375                           "0 AS typanalyzeoid, "
08376                           "'U' AS typcategory, false AS typispreferred, "
08377                           "typdelim, typbyval, typalign, typstorage, "
08378                           "false AS typcollatable, "
08379                           "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
08380                           "FROM pg_catalog.pg_type "
08381                           "WHERE oid = '%u'::pg_catalog.oid",
08382                           tyinfo->dobj.catId.oid);
08383     }
08384     else if (fout->remoteVersion >= 70200)
08385     {
08386         /*
08387          * Note: although pre-7.3 catalogs contain typreceive and typsend,
08388          * ignore them because they are not right.
08389          */
08390         appendPQExpBuffer(query, "SELECT typlen, "
08391                           "typinput, typoutput, "
08392                           "'-' AS typreceive, '-' AS typsend, "
08393                           "'-' AS typmodin, '-' AS typmodout, "
08394                           "'-' AS typanalyze, "
08395                           "0 AS typreceiveoid, 0 AS typsendoid, "
08396                           "0 AS typmodinoid, 0 AS typmodoutoid, "
08397                           "0 AS typanalyzeoid, "
08398                           "'U' AS typcategory, false AS typispreferred, "
08399                           "typdelim, typbyval, typalign, typstorage, "
08400                           "false AS typcollatable, "
08401                           "NULL AS typdefaultbin, typdefault "
08402                           "FROM pg_type "
08403                           "WHERE oid = '%u'::oid",
08404                           tyinfo->dobj.catId.oid);
08405     }
08406     else if (fout->remoteVersion >= 70100)
08407     {
08408         /*
08409          * Ignore pre-7.2 typdefault; the field exists but has an unusable
08410          * representation.
08411          */
08412         appendPQExpBuffer(query, "SELECT typlen, "
08413                           "typinput, typoutput, "
08414                           "'-' AS typreceive, '-' AS typsend, "
08415                           "'-' AS typmodin, '-' AS typmodout, "
08416                           "'-' AS typanalyze, "
08417                           "0 AS typreceiveoid, 0 AS typsendoid, "
08418                           "0 AS typmodinoid, 0 AS typmodoutoid, "
08419                           "0 AS typanalyzeoid, "
08420                           "'U' AS typcategory, false AS typispreferred, "
08421                           "typdelim, typbyval, typalign, typstorage, "
08422                           "false AS typcollatable, "
08423                           "NULL AS typdefaultbin, NULL AS typdefault "
08424                           "FROM pg_type "
08425                           "WHERE oid = '%u'::oid",
08426                           tyinfo->dobj.catId.oid);
08427     }
08428     else
08429     {
08430         appendPQExpBuffer(query, "SELECT typlen, "
08431                           "typinput, typoutput, "
08432                           "'-' AS typreceive, '-' AS typsend, "
08433                           "'-' AS typmodin, '-' AS typmodout, "
08434                           "'-' AS typanalyze, "
08435                           "0 AS typreceiveoid, 0 AS typsendoid, "
08436                           "0 AS typmodinoid, 0 AS typmodoutoid, "
08437                           "0 AS typanalyzeoid, "
08438                           "'U' AS typcategory, false AS typispreferred, "
08439                           "typdelim, typbyval, typalign, "
08440                           "'p'::char AS typstorage, "
08441                           "false AS typcollatable, "
08442                           "NULL AS typdefaultbin, NULL AS typdefault "
08443                           "FROM pg_type "
08444                           "WHERE oid = '%u'::oid",
08445                           tyinfo->dobj.catId.oid);
08446     }
08447 
08448     res = ExecuteSqlQueryForSingleRow(fout, query->data);
08449 
08450     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
08451     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
08452     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
08453     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
08454     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
08455     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
08456     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
08457     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
08458     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
08459     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
08460     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
08461     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
08462     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
08463     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
08464     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
08465     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
08466     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
08467     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
08468     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
08469     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
08470     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
08471         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
08472     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
08473     {
08474         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
08475         typdefault_is_literal = true;   /* it needs quotes */
08476     }
08477     else
08478         typdefault = NULL;
08479 
08480     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
08481 
08482     /*
08483      * DROP must be fully qualified in case same name appears in pg_catalog.
08484      * The reason we include CASCADE is that the circular dependency between
08485      * the type and its I/O functions makes it impossible to drop the type any
08486      * other way.
08487      */
08488     appendPQExpBuffer(delq, "DROP TYPE %s.",
08489                       fmtId(tyinfo->dobj.namespace->dobj.name));
08490     appendPQExpBuffer(delq, "%s CASCADE;\n",
08491                       qtypname);
08492 
08493     /* We might already have a shell type, but setting pg_type_oid is harmless */
08494     if (binary_upgrade)
08495         binary_upgrade_set_type_oids_by_type_oid(fout, q,
08496                                                  tyinfo->dobj.catId.oid);
08497 
08498     appendPQExpBuffer(q,
08499                       "CREATE TYPE %s (\n"
08500                       "    INTERNALLENGTH = %s",
08501                       qtypname,
08502                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
08503 
08504     if (fout->remoteVersion >= 70300)
08505     {
08506         /* regproc result is correctly quoted as of 7.3 */
08507         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
08508         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
08509         if (OidIsValid(typreceiveoid))
08510             appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
08511         if (OidIsValid(typsendoid))
08512             appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
08513         if (OidIsValid(typmodinoid))
08514             appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
08515         if (OidIsValid(typmodoutoid))
08516             appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
08517         if (OidIsValid(typanalyzeoid))
08518             appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
08519     }
08520     else
08521     {
08522         /* regproc delivers an unquoted name before 7.3 */
08523         /* cannot combine these because fmtId uses static result area */
08524         appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
08525         appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
08526         /* receive/send/typmodin/typmodout/analyze need not be printed */
08527     }
08528 
08529     if (strcmp(typcollatable, "t") == 0)
08530         appendPQExpBuffer(q, ",\n    COLLATABLE = true");
08531 
08532     if (typdefault != NULL)
08533     {
08534         appendPQExpBuffer(q, ",\n    DEFAULT = ");
08535         if (typdefault_is_literal)
08536             appendStringLiteralAH(q, typdefault, fout);
08537         else
08538             appendPQExpBufferStr(q, typdefault);
08539     }
08540 
08541     if (OidIsValid(tyinfo->typelem))
08542     {
08543         char       *elemType;
08544 
08545         /* reselect schema in case changed by function dump */
08546         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
08547         elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
08548         appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
08549         free(elemType);
08550     }
08551 
08552     if (strcmp(typcategory, "U") != 0)
08553     {
08554         appendPQExpBuffer(q, ",\n    CATEGORY = ");
08555         appendStringLiteralAH(q, typcategory, fout);
08556     }
08557 
08558     if (strcmp(typispreferred, "t") == 0)
08559         appendPQExpBuffer(q, ",\n    PREFERRED = true");
08560 
08561     if (typdelim && strcmp(typdelim, ",") != 0)
08562     {
08563         appendPQExpBuffer(q, ",\n    DELIMITER = ");
08564         appendStringLiteralAH(q, typdelim, fout);
08565     }
08566 
08567     if (strcmp(typalign, "c") == 0)
08568         appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
08569     else if (strcmp(typalign, "s") == 0)
08570         appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
08571     else if (strcmp(typalign, "i") == 0)
08572         appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
08573     else if (strcmp(typalign, "d") == 0)
08574         appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
08575 
08576     if (strcmp(typstorage, "p") == 0)
08577         appendPQExpBuffer(q, ",\n    STORAGE = plain");
08578     else if (strcmp(typstorage, "e") == 0)
08579         appendPQExpBuffer(q, ",\n    STORAGE = external");
08580     else if (strcmp(typstorage, "x") == 0)
08581         appendPQExpBuffer(q, ",\n    STORAGE = extended");
08582     else if (strcmp(typstorage, "m") == 0)
08583         appendPQExpBuffer(q, ",\n    STORAGE = main");
08584 
08585     if (strcmp(typbyval, "t") == 0)
08586         appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
08587 
08588     appendPQExpBuffer(q, "\n);\n");
08589 
08590     appendPQExpBuffer(labelq, "TYPE %s", qtypname);
08591 
08592     if (binary_upgrade)
08593         binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
08594 
08595     ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
08596                  tyinfo->dobj.name,
08597                  tyinfo->dobj.namespace->dobj.name,
08598                  NULL,
08599                  tyinfo->rolname, false,
08600                  "TYPE", SECTION_PRE_DATA,
08601                  q->data, delq->data, NULL,
08602                  NULL, 0,
08603                  NULL, NULL);
08604 
08605     /* Dump Type Comments and Security Labels */
08606     dumpComment(fout, labelq->data,
08607                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08608                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08609     dumpSecLabel(fout, labelq->data,
08610                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08611                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08612 
08613     dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
08614             qtypname, NULL, tyinfo->dobj.name,
08615             tyinfo->dobj.namespace->dobj.name,
08616             tyinfo->rolname, tyinfo->typacl);
08617 
08618     PQclear(res);
08619     destroyPQExpBuffer(q);
08620     destroyPQExpBuffer(delq);
08621     destroyPQExpBuffer(labelq);
08622     destroyPQExpBuffer(query);
08623 }
08624 
08625 /*
08626  * dumpDomain
08627  *    writes out to fout the queries to recreate a user-defined domain
08628  */
08629 static void
08630 dumpDomain(Archive *fout, TypeInfo *tyinfo)
08631 {
08632     PQExpBuffer q = createPQExpBuffer();
08633     PQExpBuffer delq = createPQExpBuffer();
08634     PQExpBuffer labelq = createPQExpBuffer();
08635     PQExpBuffer query = createPQExpBuffer();
08636     PGresult   *res;
08637     int         i;
08638     char       *qtypname;
08639     char       *typnotnull;
08640     char       *typdefn;
08641     char       *typdefault;
08642     Oid         typcollation;
08643     bool        typdefault_is_literal = false;
08644 
08645     /* Set proper schema search path so type references list correctly */
08646     selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
08647 
08648     /* Fetch domain specific details */
08649     if (fout->remoteVersion >= 90100)
08650     {
08651         /* typcollation is new in 9.1 */
08652         appendPQExpBuffer(query, "SELECT t.typnotnull, "
08653             "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
08654                           "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
08655                           "t.typdefault, "
08656                           "CASE WHEN t.typcollation <> u.typcollation "
08657                           "THEN t.typcollation ELSE 0 END AS typcollation "
08658                           "FROM pg_catalog.pg_type t "
08659                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
08660                           "WHERE t.oid = '%u'::pg_catalog.oid",
08661                           tyinfo->dobj.catId.oid);
08662     }
08663     else
08664     {
08665         /* We assume here that remoteVersion must be at least 70300 */
08666         appendPQExpBuffer(query, "SELECT typnotnull, "
08667                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
08668                           "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
08669                           "typdefault, 0 AS typcollation "
08670                           "FROM pg_catalog.pg_type "
08671                           "WHERE oid = '%u'::pg_catalog.oid",
08672                           tyinfo->dobj.catId.oid);
08673     }
08674 
08675     res = ExecuteSqlQueryForSingleRow(fout, query->data);
08676 
08677     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
08678     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
08679     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
08680         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
08681     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
08682     {
08683         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
08684         typdefault_is_literal = true;   /* it needs quotes */
08685     }
08686     else
08687         typdefault = NULL;
08688     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
08689 
08690     if (binary_upgrade)
08691         binary_upgrade_set_type_oids_by_type_oid(fout, q,
08692                                                  tyinfo->dobj.catId.oid);
08693 
08694     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
08695 
08696     appendPQExpBuffer(q,
08697                       "CREATE DOMAIN %s AS %s",
08698                       qtypname,
08699                       typdefn);
08700 
08701     /* Print collation only if different from base type's collation */
08702     if (OidIsValid(typcollation))
08703     {
08704         CollInfo   *coll;
08705 
08706         coll = findCollationByOid(typcollation);
08707         if (coll)
08708         {
08709             /* always schema-qualify, don't try to be smart */
08710             appendPQExpBuffer(q, " COLLATE %s.",
08711                               fmtId(coll->dobj.namespace->dobj.name));
08712             appendPQExpBuffer(q, "%s",
08713                               fmtId(coll->dobj.name));
08714         }
08715     }
08716 
08717     if (typnotnull[0] == 't')
08718         appendPQExpBuffer(q, " NOT NULL");
08719 
08720     if (typdefault != NULL)
08721     {
08722         appendPQExpBuffer(q, " DEFAULT ");
08723         if (typdefault_is_literal)
08724             appendStringLiteralAH(q, typdefault, fout);
08725         else
08726             appendPQExpBufferStr(q, typdefault);
08727     }
08728 
08729     PQclear(res);
08730 
08731     /*
08732      * Add any CHECK constraints for the domain
08733      */
08734     for (i = 0; i < tyinfo->nDomChecks; i++)
08735     {
08736         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
08737 
08738         if (!domcheck->separate)
08739             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
08740                               fmtId(domcheck->dobj.name), domcheck->condef);
08741     }
08742 
08743     appendPQExpBuffer(q, ";\n");
08744 
08745     /*
08746      * DROP must be fully qualified in case same name appears in pg_catalog
08747      */
08748     appendPQExpBuffer(delq, "DROP DOMAIN %s.",
08749                       fmtId(tyinfo->dobj.namespace->dobj.name));
08750     appendPQExpBuffer(delq, "%s;\n",
08751                       qtypname);
08752 
08753     appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
08754 
08755     if (binary_upgrade)
08756         binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
08757 
08758     ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
08759                  tyinfo->dobj.name,
08760                  tyinfo->dobj.namespace->dobj.name,
08761                  NULL,
08762                  tyinfo->rolname, false,
08763                  "DOMAIN", SECTION_PRE_DATA,
08764                  q->data, delq->data, NULL,
08765                  NULL, 0,
08766                  NULL, NULL);
08767 
08768     /* Dump Domain Comments and Security Labels */
08769     dumpComment(fout, labelq->data,
08770                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08771                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08772     dumpSecLabel(fout, labelq->data,
08773                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08774                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08775 
08776     dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
08777             qtypname, NULL, tyinfo->dobj.name,
08778             tyinfo->dobj.namespace->dobj.name,
08779             tyinfo->rolname, tyinfo->typacl);
08780 
08781     destroyPQExpBuffer(q);
08782     destroyPQExpBuffer(delq);
08783     destroyPQExpBuffer(labelq);
08784     destroyPQExpBuffer(query);
08785 }
08786 
08787 /*
08788  * dumpCompositeType
08789  *    writes out to fout the queries to recreate a user-defined stand-alone
08790  *    composite type
08791  */
08792 static void
08793 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
08794 {
08795     PQExpBuffer q = createPQExpBuffer();
08796     PQExpBuffer dropped = createPQExpBuffer();
08797     PQExpBuffer delq = createPQExpBuffer();
08798     PQExpBuffer labelq = createPQExpBuffer();
08799     PQExpBuffer query = createPQExpBuffer();
08800     PGresult   *res;
08801     char       *qtypname;
08802     int         ntups;
08803     int         i_attname;
08804     int         i_atttypdefn;
08805     int         i_attlen;
08806     int         i_attalign;
08807     int         i_attisdropped;
08808     int         i_attcollation;
08809     int         i_typrelid;
08810     int         i;
08811     int         actual_atts;
08812 
08813     /* Set proper schema search path so type references list correctly */
08814     selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
08815 
08816     /* Fetch type specific details */
08817     if (fout->remoteVersion >= 90100)
08818     {
08819         /*
08820          * attcollation is new in 9.1.  Since we only want to dump COLLATE
08821          * clauses for attributes whose collation is different from their
08822          * type's default, we use a CASE here to suppress uninteresting
08823          * attcollations cheaply.  atttypid will be 0 for dropped columns;
08824          * collation does not matter for those.
08825          */
08826         appendPQExpBuffer(query, "SELECT a.attname, "
08827             "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
08828                           "a.attlen, a.attalign, a.attisdropped, "
08829                           "CASE WHEN a.attcollation <> at.typcollation "
08830                           "THEN a.attcollation ELSE 0 END AS attcollation, "
08831                           "ct.typrelid "
08832                           "FROM pg_catalog.pg_type ct "
08833                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
08834                     "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
08835                           "WHERE ct.oid = '%u'::pg_catalog.oid "
08836                           "ORDER BY a.attnum ",
08837                           tyinfo->dobj.catId.oid);
08838     }
08839     else
08840     {
08841         /*
08842          * We assume here that remoteVersion must be at least 70300.  Since
08843          * ALTER TYPE could not drop columns until 9.1, attisdropped should
08844          * always be false.
08845          */
08846         appendPQExpBuffer(query, "SELECT a.attname, "
08847             "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
08848                           "a.attlen, a.attalign, a.attisdropped, "
08849                           "0 AS attcollation, "
08850                           "ct.typrelid "
08851                      "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
08852                           "WHERE ct.oid = '%u'::pg_catalog.oid "
08853                           "AND a.attrelid = ct.typrelid "
08854                           "ORDER BY a.attnum ",
08855                           tyinfo->dobj.catId.oid);
08856     }
08857 
08858     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
08859 
08860     ntups = PQntuples(res);
08861 
08862     i_attname = PQfnumber(res, "attname");
08863     i_atttypdefn = PQfnumber(res, "atttypdefn");
08864     i_attlen = PQfnumber(res, "attlen");
08865     i_attalign = PQfnumber(res, "attalign");
08866     i_attisdropped = PQfnumber(res, "attisdropped");
08867     i_attcollation = PQfnumber(res, "attcollation");
08868     i_typrelid = PQfnumber(res, "typrelid");
08869 
08870     if (binary_upgrade)
08871     {
08872         Oid         typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
08873 
08874         binary_upgrade_set_type_oids_by_type_oid(fout, q,
08875                                                  tyinfo->dobj.catId.oid);
08876         binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
08877     }
08878 
08879     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
08880 
08881     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
08882                       qtypname);
08883 
08884     actual_atts = 0;
08885     for (i = 0; i < ntups; i++)
08886     {
08887         char       *attname;
08888         char       *atttypdefn;
08889         char       *attlen;
08890         char       *attalign;
08891         bool        attisdropped;
08892         Oid         attcollation;
08893 
08894         attname = PQgetvalue(res, i, i_attname);
08895         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
08896         attlen = PQgetvalue(res, i, i_attlen);
08897         attalign = PQgetvalue(res, i, i_attalign);
08898         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
08899         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
08900 
08901         if (attisdropped && !binary_upgrade)
08902             continue;
08903 
08904         /* Format properly if not first attr */
08905         if (actual_atts++ > 0)
08906             appendPQExpBuffer(q, ",");
08907         appendPQExpBuffer(q, "\n\t");
08908 
08909         if (!attisdropped)
08910         {
08911             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
08912 
08913             /* Add collation if not default for the column type */
08914             if (OidIsValid(attcollation))
08915             {
08916                 CollInfo   *coll;
08917 
08918                 coll = findCollationByOid(attcollation);
08919                 if (coll)
08920                 {
08921                     /* always schema-qualify, don't try to be smart */
08922                     appendPQExpBuffer(q, " COLLATE %s.",
08923                                       fmtId(coll->dobj.namespace->dobj.name));
08924                     appendPQExpBuffer(q, "%s",
08925                                       fmtId(coll->dobj.name));
08926                 }
08927             }
08928         }
08929         else
08930         {
08931             /*
08932              * This is a dropped attribute and we're in binary_upgrade mode.
08933              * Insert a placeholder for it in the CREATE TYPE command, and set
08934              * length and alignment with direct UPDATE to the catalogs
08935              * afterwards. See similar code in dumpTableSchema().
08936              */
08937             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
08938 
08939             /* stash separately for insertion after the CREATE TYPE */
08940             appendPQExpBuffer(dropped,
08941                       "\n-- For binary upgrade, recreate dropped column.\n");
08942             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
08943                               "SET attlen = %s, "
08944                               "attalign = '%s', attbyval = false\n"
08945                               "WHERE attname = ", attlen, attalign);
08946             appendStringLiteralAH(dropped, attname, fout);
08947             appendPQExpBuffer(dropped, "\n  AND attrelid = ");
08948             appendStringLiteralAH(dropped, qtypname, fout);
08949             appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
08950 
08951             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
08952                               qtypname);
08953             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
08954                               fmtId(attname));
08955         }
08956     }
08957     appendPQExpBuffer(q, "\n);\n");
08958     appendPQExpBufferStr(q, dropped->data);
08959 
08960     /*
08961      * DROP must be fully qualified in case same name appears in pg_catalog
08962      */
08963     appendPQExpBuffer(delq, "DROP TYPE %s.",
08964                       fmtId(tyinfo->dobj.namespace->dobj.name));
08965     appendPQExpBuffer(delq, "%s;\n",
08966                       qtypname);
08967 
08968     appendPQExpBuffer(labelq, "TYPE %s", qtypname);
08969 
08970     if (binary_upgrade)
08971         binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
08972 
08973     ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
08974                  tyinfo->dobj.name,
08975                  tyinfo->dobj.namespace->dobj.name,
08976                  NULL,
08977                  tyinfo->rolname, false,
08978                  "TYPE", SECTION_PRE_DATA,
08979                  q->data, delq->data, NULL,
08980                  NULL, 0,
08981                  NULL, NULL);
08982 
08983 
08984     /* Dump Type Comments and Security Labels */
08985     dumpComment(fout, labelq->data,
08986                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08987                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08988     dumpSecLabel(fout, labelq->data,
08989                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
08990                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
08991 
08992     dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
08993             qtypname, NULL, tyinfo->dobj.name,
08994             tyinfo->dobj.namespace->dobj.name,
08995             tyinfo->rolname, tyinfo->typacl);
08996 
08997     PQclear(res);
08998     destroyPQExpBuffer(q);
08999     destroyPQExpBuffer(dropped);
09000     destroyPQExpBuffer(delq);
09001     destroyPQExpBuffer(labelq);
09002     destroyPQExpBuffer(query);
09003 
09004     /* Dump any per-column comments */
09005     dumpCompositeTypeColComments(fout, tyinfo);
09006 }
09007 
09008 /*
09009  * dumpCompositeTypeColComments
09010  *    writes out to fout the queries to recreate comments on the columns of
09011  *    a user-defined stand-alone composite type
09012  */
09013 static void
09014 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
09015 {
09016     CommentItem *comments;
09017     int         ncomments;
09018     PGresult   *res;
09019     PQExpBuffer query;
09020     PQExpBuffer target;
09021     Oid         pgClassOid;
09022     int         i;
09023     int         ntups;
09024     int         i_attname;
09025     int         i_attnum;
09026 
09027     query = createPQExpBuffer();
09028 
09029     /* We assume here that remoteVersion must be at least 70300 */
09030     appendPQExpBuffer(query,
09031                       "SELECT c.tableoid, a.attname, a.attnum "
09032                       "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
09033                       "WHERE c.oid = '%u' AND c.oid = a.attrelid "
09034                       "  AND NOT a.attisdropped "
09035                       "ORDER BY a.attnum ",
09036                       tyinfo->typrelid);
09037 
09038     /* Fetch column attnames */
09039     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
09040 
09041     ntups = PQntuples(res);
09042     if (ntups < 1)
09043     {
09044         PQclear(res);
09045         destroyPQExpBuffer(query);
09046         return;
09047     }
09048 
09049     pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
09050 
09051     /* Search for comments associated with type's pg_class OID */
09052     ncomments = findComments(fout,
09053                              pgClassOid,
09054                              tyinfo->typrelid,
09055                              &comments);
09056 
09057     /* If no comments exist, we're done */
09058     if (ncomments <= 0)
09059     {
09060         PQclear(res);
09061         destroyPQExpBuffer(query);
09062         return;
09063     }
09064 
09065     /* Build COMMENT ON statements */
09066     target = createPQExpBuffer();
09067 
09068     i_attnum = PQfnumber(res, "attnum");
09069     i_attname = PQfnumber(res, "attname");
09070     while (ncomments > 0)
09071     {
09072         const char *attname;
09073 
09074         attname = NULL;
09075         for (i = 0; i < ntups; i++)
09076         {
09077             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
09078             {
09079                 attname = PQgetvalue(res, i, i_attname);
09080                 break;
09081             }
09082         }
09083         if (attname)            /* just in case we don't find it */
09084         {
09085             const char *descr = comments->descr;
09086 
09087             resetPQExpBuffer(target);
09088             appendPQExpBuffer(target, "COLUMN %s.",
09089                               fmtId(tyinfo->dobj.name));
09090             appendPQExpBuffer(target, "%s",
09091                               fmtId(attname));
09092 
09093             resetPQExpBuffer(query);
09094             appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
09095             appendStringLiteralAH(query, descr, fout);
09096             appendPQExpBuffer(query, ";\n");
09097 
09098             ArchiveEntry(fout, nilCatalogId, createDumpId(),
09099                          target->data,
09100                          tyinfo->dobj.namespace->dobj.name,
09101                          NULL, tyinfo->rolname,
09102                          false, "COMMENT", SECTION_NONE,
09103                          query->data, "", NULL,
09104                          &(tyinfo->dobj.dumpId), 1,
09105                          NULL, NULL);
09106         }
09107 
09108         comments++;
09109         ncomments--;
09110     }
09111 
09112     PQclear(res);
09113     destroyPQExpBuffer(query);
09114     destroyPQExpBuffer(target);
09115 }
09116 
09117 /*
09118  * dumpShellType
09119  *    writes out to fout the queries to create a shell type
09120  *
09121  * We dump a shell definition in advance of the I/O functions for the type.
09122  */
09123 static void
09124 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
09125 {
09126     PQExpBuffer q;
09127 
09128     /* Skip if not to be dumped */
09129     if (!stinfo->dobj.dump || dataOnly)
09130         return;
09131 
09132     q = createPQExpBuffer();
09133 
09134     /*
09135      * Note the lack of a DROP command for the shell type; any required DROP
09136      * is driven off the base type entry, instead.  This interacts with
09137      * _printTocEntry()'s use of the presence of a DROP command to decide
09138      * whether an entry needs an ALTER OWNER command.  We don't want to alter
09139      * the shell type's owner immediately on creation; that should happen only
09140      * after it's filled in, otherwise the backend complains.
09141      */
09142 
09143     if (binary_upgrade)
09144         binary_upgrade_set_type_oids_by_type_oid(fout, q,
09145                                            stinfo->baseType->dobj.catId.oid);
09146 
09147     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
09148                       fmtId(stinfo->dobj.name));
09149 
09150     ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
09151                  stinfo->dobj.name,
09152                  stinfo->dobj.namespace->dobj.name,
09153                  NULL,
09154                  stinfo->baseType->rolname, false,
09155                  "SHELL TYPE", SECTION_PRE_DATA,
09156                  q->data, "", NULL,
09157                  NULL, 0,
09158                  NULL, NULL);
09159 
09160     destroyPQExpBuffer(q);
09161 }
09162 
09163 /*
09164  * Determine whether we want to dump definitions for procedural languages.
09165  * Since the languages themselves don't have schemas, we can't rely on
09166  * the normal schema-based selection mechanism.  We choose to dump them
09167  * whenever neither --schema nor --table was given.  (Before 8.1, we used
09168  * the dump flag of the PL's call handler function, but in 8.1 this will
09169  * probably always be false since call handlers are created in pg_catalog.)
09170  *
09171  * For some backwards compatibility with the older behavior, we forcibly
09172  * dump a PL if its handler function (and validator if any) are in a
09173  * dumpable namespace.  That case is not checked here.
09174  *
09175  * Also, if the PL belongs to an extension, we do not use this heuristic.
09176  * That case isn't checked here either.
09177  */
09178 static bool
09179 shouldDumpProcLangs(void)
09180 {
09181     if (!include_everything)
09182         return false;
09183     /* And they're schema not data */
09184     if (dataOnly)
09185         return false;
09186     return true;
09187 }
09188 
09189 /*
09190  * dumpProcLang
09191  *        writes out to fout the queries to recreate a user-defined
09192  *        procedural language
09193  */
09194 static void
09195 dumpProcLang(Archive *fout, ProcLangInfo *plang)
09196 {
09197     PQExpBuffer defqry;
09198     PQExpBuffer delqry;
09199     PQExpBuffer labelq;
09200     bool        useParams;
09201     char       *qlanname;
09202     char       *lanschema;
09203     FuncInfo   *funcInfo;
09204     FuncInfo   *inlineInfo = NULL;
09205     FuncInfo   *validatorInfo = NULL;
09206 
09207     /* Skip if not to be dumped */
09208     if (!plang->dobj.dump || dataOnly)
09209         return;
09210 
09211     /*
09212      * Try to find the support function(s).  It is not an error if we don't
09213      * find them --- if the functions are in the pg_catalog schema, as is
09214      * standard in 8.1 and up, then we won't have loaded them. (In this case
09215      * we will emit a parameterless CREATE LANGUAGE command, which will
09216      * require PL template knowledge in the backend to reload.)
09217      */
09218 
09219     funcInfo = findFuncByOid(plang->lanplcallfoid);
09220     if (funcInfo != NULL && !funcInfo->dobj.dump)
09221         funcInfo = NULL;        /* treat not-dumped same as not-found */
09222 
09223     if (OidIsValid(plang->laninline))
09224     {
09225         inlineInfo = findFuncByOid(plang->laninline);
09226         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
09227             inlineInfo = NULL;
09228     }
09229 
09230     if (OidIsValid(plang->lanvalidator))
09231     {
09232         validatorInfo = findFuncByOid(plang->lanvalidator);
09233         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
09234             validatorInfo = NULL;
09235     }
09236 
09237     /*
09238      * If the functions are dumpable then emit a traditional CREATE LANGUAGE
09239      * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
09240      * dump it.
09241      *
09242      * However, for a language that belongs to an extension, we must not use
09243      * the shouldDumpProcLangs heuristic, but just dump the language iff we're
09244      * told to (via dobj.dump).  Generally the support functions will belong
09245      * to the same extension and so have the same dump flags ... if they
09246      * don't, this might not work terribly nicely.
09247      */
09248     useParams = (funcInfo != NULL &&
09249                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
09250                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
09251 
09252     if (!plang->dobj.ext_member)
09253     {
09254         if (!useParams && !shouldDumpProcLangs())
09255             return;
09256     }
09257 
09258     defqry = createPQExpBuffer();
09259     delqry = createPQExpBuffer();
09260     labelq = createPQExpBuffer();
09261 
09262     qlanname = pg_strdup(fmtId(plang->dobj.name));
09263 
09264     /*
09265      * If dumping a HANDLER clause, treat the language as being in the handler
09266      * function's schema; this avoids cluttering the HANDLER clause. Otherwise
09267      * it doesn't really have a schema.
09268      */
09269     if (useParams)
09270         lanschema = funcInfo->dobj.namespace->dobj.name;
09271     else
09272         lanschema = NULL;
09273 
09274     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
09275                       qlanname);
09276 
09277     if (useParams)
09278     {
09279         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
09280                           plang->lanpltrusted ? "TRUSTED " : "",
09281                           qlanname);
09282         appendPQExpBuffer(defqry, " HANDLER %s",
09283                           fmtId(funcInfo->dobj.name));
09284         if (OidIsValid(plang->laninline))
09285         {
09286             appendPQExpBuffer(defqry, " INLINE ");
09287             /* Cope with possibility that inline is in different schema */
09288             if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
09289                 appendPQExpBuffer(defqry, "%s.",
09290                                fmtId(inlineInfo->dobj.namespace->dobj.name));
09291             appendPQExpBuffer(defqry, "%s",
09292                               fmtId(inlineInfo->dobj.name));
09293         }
09294         if (OidIsValid(plang->lanvalidator))
09295         {
09296             appendPQExpBuffer(defqry, " VALIDATOR ");
09297             /* Cope with possibility that validator is in different schema */
09298             if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
09299                 appendPQExpBuffer(defqry, "%s.",
09300                             fmtId(validatorInfo->dobj.namespace->dobj.name));
09301             appendPQExpBuffer(defqry, "%s",
09302                               fmtId(validatorInfo->dobj.name));
09303         }
09304     }
09305     else
09306     {
09307         /*
09308          * If not dumping parameters, then use CREATE OR REPLACE so that the
09309          * command will not fail if the language is preinstalled in the target
09310          * database.  We restrict the use of REPLACE to this case so as to
09311          * eliminate the risk of replacing a language with incompatible
09312          * parameter settings: this command will only succeed at all if there
09313          * is a pg_pltemplate entry, and if there is one, the existing entry
09314          * must match it too.
09315          */
09316         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
09317                           qlanname);
09318     }
09319     appendPQExpBuffer(defqry, ";\n");
09320 
09321     appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
09322 
09323     if (binary_upgrade)
09324         binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
09325 
09326     ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
09327                  plang->dobj.name,
09328                  lanschema, NULL, plang->lanowner,
09329                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
09330                  defqry->data, delqry->data, NULL,
09331                  NULL, 0,
09332                  NULL, NULL);
09333 
09334     /* Dump Proc Lang Comments and Security Labels */
09335     dumpComment(fout, labelq->data,
09336                 NULL, "",
09337                 plang->dobj.catId, 0, plang->dobj.dumpId);
09338     dumpSecLabel(fout, labelq->data,
09339                  NULL, "",
09340                  plang->dobj.catId, 0, plang->dobj.dumpId);
09341 
09342     if (plang->lanpltrusted)
09343         dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
09344                 qlanname, NULL, plang->dobj.name,
09345                 lanschema,
09346                 plang->lanowner, plang->lanacl);
09347 
09348     free(qlanname);
09349 
09350     destroyPQExpBuffer(defqry);
09351     destroyPQExpBuffer(delqry);
09352     destroyPQExpBuffer(labelq);
09353 }
09354 
09355 /*
09356  * format_function_arguments: generate function name and argument list
09357  *
09358  * This is used when we can rely on pg_get_function_arguments to format
09359  * the argument list.
09360  */
09361 static char *
09362 format_function_arguments(FuncInfo *finfo, char *funcargs)
09363 {
09364     PQExpBufferData fn;
09365 
09366     initPQExpBuffer(&fn);
09367     appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
09368     return fn.data;
09369 }
09370 
09371 /*
09372  * format_function_arguments_old: generate function name and argument list
09373  *
09374  * The argument type names are qualified if needed.  The function name
09375  * is never qualified.
09376  *
09377  * This is used only with pre-8.4 servers, so we aren't expecting to see
09378  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
09379  *
09380  * Any or all of allargtypes, argmodes, argnames may be NULL.
09381  */
09382 static char *
09383 format_function_arguments_old(Archive *fout,
09384                               FuncInfo *finfo, int nallargs,
09385                               char **allargtypes,
09386                               char **argmodes,
09387                               char **argnames)
09388 {
09389     PQExpBufferData fn;
09390     int         j;
09391 
09392     initPQExpBuffer(&fn);
09393     appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
09394     for (j = 0; j < nallargs; j++)
09395     {
09396         Oid         typid;
09397         char       *typname;
09398         const char *argmode;
09399         const char *argname;
09400 
09401         typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
09402         typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
09403 
09404         if (argmodes)
09405         {
09406             switch (argmodes[j][0])
09407             {
09408                 case PROARGMODE_IN:
09409                     argmode = "";
09410                     break;
09411                 case PROARGMODE_OUT:
09412                     argmode = "OUT ";
09413                     break;
09414                 case PROARGMODE_INOUT:
09415                     argmode = "INOUT ";
09416                     break;
09417                 default:
09418                     write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
09419                     argmode = "";
09420                     break;
09421             }
09422         }
09423         else
09424             argmode = "";
09425 
09426         argname = argnames ? argnames[j] : (char *) NULL;
09427         if (argname && argname[0] == '\0')
09428             argname = NULL;
09429 
09430         appendPQExpBuffer(&fn, "%s%s%s%s%s",
09431                           (j > 0) ? ", " : "",
09432                           argmode,
09433                           argname ? fmtId(argname) : "",
09434                           argname ? " " : "",
09435                           typname);
09436         free(typname);
09437     }
09438     appendPQExpBuffer(&fn, ")");
09439     return fn.data;
09440 }
09441 
09442 /*
09443  * format_function_signature: generate function name and argument list
09444  *
09445  * This is like format_function_arguments_old except that only a minimal
09446  * list of input argument types is generated; this is sufficient to
09447  * reference the function, but not to define it.
09448  *
09449  * If honor_quotes is false then the function name is never quoted.
09450  * This is appropriate for use in TOC tags, but not in SQL commands.
09451  */
09452 static char *
09453 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
09454 {
09455     PQExpBufferData fn;
09456     int         j;
09457 
09458     initPQExpBuffer(&fn);
09459     if (honor_quotes)
09460         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
09461     else
09462         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
09463     for (j = 0; j < finfo->nargs; j++)
09464     {
09465         char       *typname;
09466 
09467         typname = getFormattedTypeName(fout, finfo->argtypes[j],
09468                                        zeroAsOpaque);
09469 
09470         appendPQExpBuffer(&fn, "%s%s",
09471                           (j > 0) ? ", " : "",
09472                           typname);
09473         free(typname);
09474     }
09475     appendPQExpBuffer(&fn, ")");
09476     return fn.data;
09477 }
09478 
09479 
09480 /*
09481  * dumpFunc:
09482  *    dump out one function
09483  */
09484 static void
09485 dumpFunc(Archive *fout, FuncInfo *finfo)
09486 {
09487     PQExpBuffer query;
09488     PQExpBuffer q;
09489     PQExpBuffer delqry;
09490     PQExpBuffer labelq;
09491     PQExpBuffer asPart;
09492     PGresult   *res;
09493     char       *funcsig;        /* identity signature */
09494     char       *funcfullsig;    /* full signature */
09495     char       *funcsig_tag;
09496     char       *proretset;
09497     char       *prosrc;
09498     char       *probin;
09499     char       *funcargs;
09500     char       *funciargs;
09501     char       *funcresult;
09502     char       *proallargtypes;
09503     char       *proargmodes;
09504     char       *proargnames;
09505     char       *proiswindow;
09506     char       *provolatile;
09507     char       *proisstrict;
09508     char       *prosecdef;
09509     char       *proleakproof;
09510     char       *proconfig;
09511     char       *procost;
09512     char       *prorows;
09513     char       *lanname;
09514     char       *rettypename;
09515     int         nallargs;
09516     char      **allargtypes = NULL;
09517     char      **argmodes = NULL;
09518     char      **argnames = NULL;
09519     char      **configitems = NULL;
09520     int         nconfigitems = 0;
09521     int         i;
09522 
09523     /* Skip if not to be dumped */
09524     if (!finfo->dobj.dump || dataOnly)
09525         return;
09526 
09527     query = createPQExpBuffer();
09528     q = createPQExpBuffer();
09529     delqry = createPQExpBuffer();
09530     labelq = createPQExpBuffer();
09531     asPart = createPQExpBuffer();
09532 
09533     /* Set proper schema search path so type references list correctly */
09534     selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
09535 
09536     /* Fetch function-specific details */
09537     if (fout->remoteVersion >= 90200)
09538     {
09539         /*
09540          * proleakproof was added at v9.2
09541          */
09542         appendPQExpBuffer(query,
09543                           "SELECT proretset, prosrc, probin, "
09544                     "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
09545           "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
09546                      "pg_catalog.pg_get_function_result(oid) AS funcresult, "
09547                           "proiswindow, provolatile, proisstrict, prosecdef, "
09548                           "proleakproof, proconfig, procost, prorows, "
09549                           "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
09550                           "FROM pg_catalog.pg_proc "
09551                           "WHERE oid = '%u'::pg_catalog.oid",
09552                           finfo->dobj.catId.oid);
09553     }
09554     else if (fout->remoteVersion >= 80400)
09555     {
09556         /*
09557          * In 8.4 and up we rely on pg_get_function_arguments and
09558          * pg_get_function_result instead of examining proallargtypes etc.
09559          */
09560         appendPQExpBuffer(query,
09561                           "SELECT proretset, prosrc, probin, "
09562                     "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
09563           "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
09564                      "pg_catalog.pg_get_function_result(oid) AS funcresult, "
09565                           "proiswindow, provolatile, proisstrict, prosecdef, "
09566                           "false AS proleakproof, "
09567                           " proconfig, procost, prorows, "
09568                           "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
09569                           "FROM pg_catalog.pg_proc "
09570                           "WHERE oid = '%u'::pg_catalog.oid",
09571                           finfo->dobj.catId.oid);
09572     }
09573     else if (fout->remoteVersion >= 80300)
09574     {
09575         appendPQExpBuffer(query,
09576                           "SELECT proretset, prosrc, probin, "
09577                           "proallargtypes, proargmodes, proargnames, "
09578                           "false AS proiswindow, "
09579                           "provolatile, proisstrict, prosecdef, "
09580                           "false AS proleakproof, "
09581                           "proconfig, procost, prorows, "
09582                           "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
09583                           "FROM pg_catalog.pg_proc "
09584                           "WHERE oid = '%u'::pg_catalog.oid",
09585                           finfo->dobj.catId.oid);
09586     }
09587     else if (fout->remoteVersion >= 80100)
09588     {
09589         appendPQExpBuffer(query,
09590                           "SELECT proretset, prosrc, probin, "
09591                           "proallargtypes, proargmodes, proargnames, "
09592                           "false AS proiswindow, "
09593                           "provolatile, proisstrict, prosecdef, "
09594                           "false AS proleakproof, "
09595                           "null AS proconfig, 0 AS procost, 0 AS prorows, "
09596                           "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
09597                           "FROM pg_catalog.pg_proc "
09598                           "WHERE oid = '%u'::pg_catalog.oid",
09599                           finfo->dobj.catId.oid);
09600     }
09601     else if (fout->remoteVersion >= 80000)
09602     {
09603         appendPQExpBuffer(query,
09604                           "SELECT proretset, prosrc, probin, "
09605                           "null AS proallargtypes, "
09606                           "null AS proargmodes, "
09607                           "proargnames, "
09608                           "false AS proiswindow, "
09609                           "provolatile, proisstrict, prosecdef, "
09610                           "false AS proleakproof, "
09611                           "null AS proconfig, 0 AS procost, 0 AS prorows, "
09612                           "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
09613                           "FROM pg_catalog.pg_proc "
09614                           "WHERE oid = '%u'::pg_catalog.oid",
09615                           finfo->dobj.catId.oid);
09616     }
09617     else if (fout->remoteVersion >= 70300)
09618     {
09619         appendPQExpBuffer(query,
09620                           "SELECT proretset, prosrc, probin, "
09621                           "null AS proallargtypes, "
09622                           "null AS proargmodes, "
09623                           "null AS proargnames, "
09624                           "false AS proiswindow, "
09625                           "provolatile, proisstrict, prosecdef, "
09626                           "false AS proleakproof, "
09627                           "null AS proconfig, 0 AS procost, 0 AS prorows, "
09628                           "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
09629                           "FROM pg_catalog.pg_proc "
09630                           "WHERE oid = '%u'::pg_catalog.oid",
09631                           finfo->dobj.catId.oid);
09632     }
09633     else if (fout->remoteVersion >= 70100)
09634     {
09635         appendPQExpBuffer(query,
09636                           "SELECT proretset, prosrc, probin, "
09637                           "null AS proallargtypes, "
09638                           "null AS proargmodes, "
09639                           "null AS proargnames, "
09640                           "false AS proiswindow, "
09641              "case when proiscachable then 'i' else 'v' end AS provolatile, "
09642                           "proisstrict, "
09643                           "false AS prosecdef, "
09644                           "false AS proleakproof, "
09645                           "null AS proconfig, 0 AS procost, 0 AS prorows, "
09646           "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
09647                           "FROM pg_proc "
09648                           "WHERE oid = '%u'::oid",
09649                           finfo->dobj.catId.oid);
09650     }
09651     else
09652     {
09653         appendPQExpBuffer(query,
09654                           "SELECT proretset, prosrc, probin, "
09655                           "null AS proallargtypes, "
09656                           "null AS proargmodes, "
09657                           "null AS proargnames, "
09658                           "false AS proiswindow, "
09659              "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
09660                           "false AS proisstrict, "
09661                           "false AS prosecdef, "
09662                           "false AS proleakproof, "
09663                           "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
09664           "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
09665                           "FROM pg_proc "
09666                           "WHERE oid = '%u'::oid",
09667                           finfo->dobj.catId.oid);
09668     }
09669 
09670     res = ExecuteSqlQueryForSingleRow(fout, query->data);
09671 
09672     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
09673     prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
09674     probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
09675     if (fout->remoteVersion >= 80400)
09676     {
09677         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
09678         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
09679         funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
09680         proallargtypes = proargmodes = proargnames = NULL;
09681     }
09682     else
09683     {
09684         proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
09685         proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
09686         proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
09687         funcargs = funciargs = funcresult = NULL;
09688     }
09689     proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
09690     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
09691     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
09692     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
09693     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
09694     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
09695     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
09696     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
09697     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
09698 
09699     /*
09700      * See backend/commands/functioncmds.c for details of how the 'AS' clause
09701      * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
09702      * versions would set it to "-".  There are no known cases in which prosrc
09703      * is unused, so the tests below for "-" are probably useless.
09704      */
09705     if (probin[0] != '\0' && strcmp(probin, "-") != 0)
09706     {
09707         appendPQExpBuffer(asPart, "AS ");
09708         appendStringLiteralAH(asPart, probin, fout);
09709         if (strcmp(prosrc, "-") != 0)
09710         {
09711             appendPQExpBuffer(asPart, ", ");
09712 
09713             /*
09714              * where we have bin, use dollar quoting if allowed and src
09715              * contains quote or backslash; else use regular quoting.
09716              */
09717             if (disable_dollar_quoting ||
09718               (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
09719                 appendStringLiteralAH(asPart, prosrc, fout);
09720             else
09721                 appendStringLiteralDQ(asPart, prosrc, NULL);
09722         }
09723     }
09724     else
09725     {
09726         if (strcmp(prosrc, "-") != 0)
09727         {
09728             appendPQExpBuffer(asPart, "AS ");
09729             /* with no bin, dollar quote src unconditionally if allowed */
09730             if (disable_dollar_quoting)
09731                 appendStringLiteralAH(asPart, prosrc, fout);
09732             else
09733                 appendStringLiteralDQ(asPart, prosrc, NULL);
09734         }
09735     }
09736 
09737     nallargs = finfo->nargs;    /* unless we learn different from allargs */
09738 
09739     if (proallargtypes && *proallargtypes)
09740     {
09741         int         nitems = 0;
09742 
09743         if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
09744             nitems < finfo->nargs)
09745         {
09746             write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
09747             if (allargtypes)
09748                 free(allargtypes);
09749             allargtypes = NULL;
09750         }
09751         else
09752             nallargs = nitems;
09753     }
09754 
09755     if (proargmodes && *proargmodes)
09756     {
09757         int         nitems = 0;
09758 
09759         if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
09760             nitems != nallargs)
09761         {
09762             write_msg(NULL, "WARNING: could not parse proargmodes array\n");
09763             if (argmodes)
09764                 free(argmodes);
09765             argmodes = NULL;
09766         }
09767     }
09768 
09769     if (proargnames && *proargnames)
09770     {
09771         int         nitems = 0;
09772 
09773         if (!parsePGArray(proargnames, &argnames, &nitems) ||
09774             nitems != nallargs)
09775         {
09776             write_msg(NULL, "WARNING: could not parse proargnames array\n");
09777             if (argnames)
09778                 free(argnames);
09779             argnames = NULL;
09780         }
09781     }
09782 
09783     if (proconfig && *proconfig)
09784     {
09785         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
09786         {
09787             write_msg(NULL, "WARNING: could not parse proconfig array\n");
09788             if (configitems)
09789                 free(configitems);
09790             configitems = NULL;
09791             nconfigitems = 0;
09792         }
09793     }
09794 
09795     if (funcargs)
09796     {
09797         /* 8.4 or later; we rely on server-side code for most of the work */
09798         funcfullsig = format_function_arguments(finfo, funcargs);
09799         funcsig = format_function_arguments(finfo, funciargs);
09800     }
09801     else
09802     {
09803         /* pre-8.4, do it ourselves */
09804         funcsig = format_function_arguments_old(fout,
09805                                                 finfo, nallargs, allargtypes,
09806                                                 argmodes, argnames);
09807         funcfullsig = funcsig;
09808     }
09809 
09810     funcsig_tag = format_function_signature(fout, finfo, false);
09811 
09812     /*
09813      * DROP must be fully qualified in case same name appears in pg_catalog
09814      */
09815     appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
09816                       fmtId(finfo->dobj.namespace->dobj.name),
09817                       funcsig);
09818 
09819     appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
09820     if (funcresult)
09821         appendPQExpBuffer(q, "RETURNS %s", funcresult);
09822     else
09823     {
09824         rettypename = getFormattedTypeName(fout, finfo->prorettype,
09825                                            zeroAsOpaque);
09826         appendPQExpBuffer(q, "RETURNS %s%s",
09827                           (proretset[0] == 't') ? "SETOF " : "",
09828                           rettypename);
09829         free(rettypename);
09830     }
09831 
09832     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
09833 
09834     if (proiswindow[0] == 't')
09835         appendPQExpBuffer(q, " WINDOW");
09836 
09837     if (provolatile[0] != PROVOLATILE_VOLATILE)
09838     {
09839         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
09840             appendPQExpBuffer(q, " IMMUTABLE");
09841         else if (provolatile[0] == PROVOLATILE_STABLE)
09842             appendPQExpBuffer(q, " STABLE");
09843         else if (provolatile[0] != PROVOLATILE_VOLATILE)
09844             exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
09845                           finfo->dobj.name);
09846     }
09847 
09848     if (proisstrict[0] == 't')
09849         appendPQExpBuffer(q, " STRICT");
09850 
09851     if (prosecdef[0] == 't')
09852         appendPQExpBuffer(q, " SECURITY DEFINER");
09853 
09854     if (proleakproof[0] == 't')
09855         appendPQExpBuffer(q, " LEAKPROOF");
09856 
09857     /*
09858      * COST and ROWS are emitted only if present and not default, so as not to
09859      * break backwards-compatibility of the dump without need.  Keep this code
09860      * in sync with the defaults in functioncmds.c.
09861      */
09862     if (strcmp(procost, "0") != 0)
09863     {
09864         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
09865         {
09866             /* default cost is 1 */
09867             if (strcmp(procost, "1") != 0)
09868                 appendPQExpBuffer(q, " COST %s", procost);
09869         }
09870         else
09871         {
09872             /* default cost is 100 */
09873             if (strcmp(procost, "100") != 0)
09874                 appendPQExpBuffer(q, " COST %s", procost);
09875         }
09876     }
09877     if (proretset[0] == 't' &&
09878         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
09879         appendPQExpBuffer(q, " ROWS %s", prorows);
09880 
09881     for (i = 0; i < nconfigitems; i++)
09882     {
09883         /* we feel free to scribble on configitems[] here */
09884         char       *configitem = configitems[i];
09885         char       *pos;
09886 
09887         pos = strchr(configitem, '=');
09888         if (pos == NULL)
09889             continue;
09890         *pos++ = '\0';
09891         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
09892 
09893         /*
09894          * Some GUC variable names are 'LIST' type and hence must not be
09895          * quoted.
09896          */
09897         if (pg_strcasecmp(configitem, "DateStyle") == 0
09898             || pg_strcasecmp(configitem, "search_path") == 0)
09899             appendPQExpBuffer(q, "%s", pos);
09900         else
09901             appendStringLiteralAH(q, pos, fout);
09902     }
09903 
09904     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
09905 
09906     appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
09907 
09908     if (binary_upgrade)
09909         binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
09910 
09911     ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
09912                  funcsig_tag,
09913                  finfo->dobj.namespace->dobj.name,
09914                  NULL,
09915                  finfo->rolname, false,
09916                  "FUNCTION", SECTION_PRE_DATA,
09917                  q->data, delqry->data, NULL,
09918                  NULL, 0,
09919                  NULL, NULL);
09920 
09921     /* Dump Function Comments and Security Labels */
09922     dumpComment(fout, labelq->data,
09923                 finfo->dobj.namespace->dobj.name, finfo->rolname,
09924                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
09925     dumpSecLabel(fout, labelq->data,
09926                  finfo->dobj.namespace->dobj.name, finfo->rolname,
09927                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
09928 
09929     dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
09930             funcsig, NULL, funcsig_tag,
09931             finfo->dobj.namespace->dobj.name,
09932             finfo->rolname, finfo->proacl);
09933 
09934     PQclear(res);
09935 
09936     destroyPQExpBuffer(query);
09937     destroyPQExpBuffer(q);
09938     destroyPQExpBuffer(delqry);
09939     destroyPQExpBuffer(labelq);
09940     destroyPQExpBuffer(asPart);
09941     free(funcsig);
09942     free(funcsig_tag);
09943     if (allargtypes)
09944         free(allargtypes);
09945     if (argmodes)
09946         free(argmodes);
09947     if (argnames)
09948         free(argnames);
09949     if (configitems)
09950         free(configitems);
09951 }
09952 
09953 
09954 /*
09955  * Dump a user-defined cast
09956  */
09957 static void
09958 dumpCast(Archive *fout, CastInfo *cast)
09959 {
09960     PQExpBuffer defqry;
09961     PQExpBuffer delqry;
09962     PQExpBuffer labelq;
09963     FuncInfo   *funcInfo = NULL;
09964 
09965     /* Skip if not to be dumped */
09966     if (!cast->dobj.dump || dataOnly)
09967         return;
09968 
09969     /* Cannot dump if we don't have the cast function's info */
09970     if (OidIsValid(cast->castfunc))
09971     {
09972         funcInfo = findFuncByOid(cast->castfunc);
09973         if (funcInfo == NULL)
09974             return;
09975     }
09976 
09977     /*
09978      * As per discussion we dump casts if one or more of the underlying
09979      * objects (the conversion function and the two data types) are not
09980      * builtin AND if all of the non-builtin objects are included in the dump.
09981      * Builtin meaning, the namespace name does not start with "pg_".
09982      *
09983      * However, for a cast that belongs to an extension, we must not use this
09984      * heuristic, but just dump the cast iff we're told to (via dobj.dump).
09985      */
09986     if (!cast->dobj.ext_member)
09987     {
09988         TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
09989         TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
09990 
09991         if (sourceInfo == NULL || targetInfo == NULL)
09992             return;
09993 
09994         /*
09995          * Skip this cast if all objects are from pg_
09996          */
09997         if ((funcInfo == NULL ||
09998              strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
09999             strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
10000             strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
10001             return;
10002 
10003         /*
10004          * Skip cast if function isn't from pg_ and is not to be dumped.
10005          */
10006         if (funcInfo &&
10007             strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10008             !funcInfo->dobj.dump)
10009             return;
10010 
10011         /*
10012          * Same for the source type
10013          */
10014         if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10015             !sourceInfo->dobj.dump)
10016             return;
10017 
10018         /*
10019          * and the target type.
10020          */
10021         if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10022             !targetInfo->dobj.dump)
10023             return;
10024     }
10025 
10026     /* Make sure we are in proper schema (needed for getFormattedTypeName) */
10027     selectSourceSchema(fout, "pg_catalog");
10028 
10029     defqry = createPQExpBuffer();
10030     delqry = createPQExpBuffer();
10031     labelq = createPQExpBuffer();
10032 
10033     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
10034                     getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10035                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10036 
10037     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
10038                     getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10039                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10040 
10041     switch (cast->castmethod)
10042     {
10043         case COERCION_METHOD_BINARY:
10044             appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
10045             break;
10046         case COERCION_METHOD_INOUT:
10047             appendPQExpBuffer(defqry, "WITH INOUT");
10048             break;
10049         case COERCION_METHOD_FUNCTION:
10050             if (funcInfo)
10051             {
10052                 char       *fsig = format_function_signature(fout, funcInfo, true);
10053 
10054                 /*
10055                  * Always qualify the function name, in case it is not in
10056                  * pg_catalog schema (format_function_signature won't qualify
10057                  * it).
10058                  */
10059                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
10060                            fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
10061                 free(fsig);
10062             }
10063             else
10064                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
10065             break;
10066         default:
10067             write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
10068     }
10069 
10070     if (cast->castcontext == 'a')
10071         appendPQExpBuffer(defqry, " AS ASSIGNMENT");
10072     else if (cast->castcontext == 'i')
10073         appendPQExpBuffer(defqry, " AS IMPLICIT");
10074     appendPQExpBuffer(defqry, ";\n");
10075 
10076     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
10077                     getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10078                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10079 
10080     if (binary_upgrade)
10081         binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
10082 
10083     ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
10084                  labelq->data,
10085                  "pg_catalog", NULL, "",
10086                  false, "CAST", SECTION_PRE_DATA,
10087                  defqry->data, delqry->data, NULL,
10088                  NULL, 0,
10089                  NULL, NULL);
10090 
10091     /* Dump Cast Comments */
10092     dumpComment(fout, labelq->data,
10093                 NULL, "",
10094                 cast->dobj.catId, 0, cast->dobj.dumpId);
10095 
10096     destroyPQExpBuffer(defqry);
10097     destroyPQExpBuffer(delqry);
10098     destroyPQExpBuffer(labelq);
10099 }
10100 
10101 /*
10102  * dumpOpr
10103  *    write out a single operator definition
10104  */
10105 static void
10106 dumpOpr(Archive *fout, OprInfo *oprinfo)
10107 {
10108     PQExpBuffer query;
10109     PQExpBuffer q;
10110     PQExpBuffer delq;
10111     PQExpBuffer labelq;
10112     PQExpBuffer oprid;
10113     PQExpBuffer details;
10114     const char *name;
10115     PGresult   *res;
10116     int         i_oprkind;
10117     int         i_oprcode;
10118     int         i_oprleft;
10119     int         i_oprright;
10120     int         i_oprcom;
10121     int         i_oprnegate;
10122     int         i_oprrest;
10123     int         i_oprjoin;
10124     int         i_oprcanmerge;
10125     int         i_oprcanhash;
10126     char       *oprkind;
10127     char       *oprcode;
10128     char       *oprleft;
10129     char       *oprright;
10130     char       *oprcom;
10131     char       *oprnegate;
10132     char       *oprrest;
10133     char       *oprjoin;
10134     char       *oprcanmerge;
10135     char       *oprcanhash;
10136 
10137     /* Skip if not to be dumped */
10138     if (!oprinfo->dobj.dump || dataOnly)
10139         return;
10140 
10141     /*
10142      * some operators are invalid because they were the result of user
10143      * defining operators before commutators exist
10144      */
10145     if (!OidIsValid(oprinfo->oprcode))
10146         return;
10147 
10148     query = createPQExpBuffer();
10149     q = createPQExpBuffer();
10150     delq = createPQExpBuffer();
10151     labelq = createPQExpBuffer();
10152     oprid = createPQExpBuffer();
10153     details = createPQExpBuffer();
10154 
10155     /* Make sure we are in proper schema so regoperator works correctly */
10156     selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
10157 
10158     if (fout->remoteVersion >= 80300)
10159     {
10160         appendPQExpBuffer(query, "SELECT oprkind, "
10161                           "oprcode::pg_catalog.regprocedure, "
10162                           "oprleft::pg_catalog.regtype, "
10163                           "oprright::pg_catalog.regtype, "
10164                           "oprcom::pg_catalog.regoperator, "
10165                           "oprnegate::pg_catalog.regoperator, "
10166                           "oprrest::pg_catalog.regprocedure, "
10167                           "oprjoin::pg_catalog.regprocedure, "
10168                           "oprcanmerge, oprcanhash "
10169                           "FROM pg_catalog.pg_operator "
10170                           "WHERE oid = '%u'::pg_catalog.oid",
10171                           oprinfo->dobj.catId.oid);
10172     }
10173     else if (fout->remoteVersion >= 70300)
10174     {
10175         appendPQExpBuffer(query, "SELECT oprkind, "
10176                           "oprcode::pg_catalog.regprocedure, "
10177                           "oprleft::pg_catalog.regtype, "
10178                           "oprright::pg_catalog.regtype, "
10179                           "oprcom::pg_catalog.regoperator, "
10180                           "oprnegate::pg_catalog.regoperator, "
10181                           "oprrest::pg_catalog.regprocedure, "
10182                           "oprjoin::pg_catalog.regprocedure, "
10183                           "(oprlsortop != 0) AS oprcanmerge, "
10184                           "oprcanhash "
10185                           "FROM pg_catalog.pg_operator "
10186                           "WHERE oid = '%u'::pg_catalog.oid",
10187                           oprinfo->dobj.catId.oid);
10188     }
10189     else if (fout->remoteVersion >= 70100)
10190     {
10191         appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10192                           "CASE WHEN oprleft = 0 THEN '-' "
10193                           "ELSE format_type(oprleft, NULL) END AS oprleft, "
10194                           "CASE WHEN oprright = 0 THEN '-' "
10195                           "ELSE format_type(oprright, NULL) END AS oprright, "
10196                           "oprcom, oprnegate, oprrest, oprjoin, "
10197                           "(oprlsortop != 0) AS oprcanmerge, "
10198                           "oprcanhash "
10199                           "FROM pg_operator "
10200                           "WHERE oid = '%u'::oid",
10201                           oprinfo->dobj.catId.oid);
10202     }
10203     else
10204     {
10205         appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10206                           "CASE WHEN oprleft = 0 THEN '-'::name "
10207                           "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
10208                           "CASE WHEN oprright = 0 THEN '-'::name "
10209                           "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
10210                           "oprcom, oprnegate, oprrest, oprjoin, "
10211                           "(oprlsortop != 0) AS oprcanmerge, "
10212                           "oprcanhash "
10213                           "FROM pg_operator "
10214                           "WHERE oid = '%u'::oid",
10215                           oprinfo->dobj.catId.oid);
10216     }
10217 
10218     res = ExecuteSqlQueryForSingleRow(fout, query->data);
10219 
10220     i_oprkind = PQfnumber(res, "oprkind");
10221     i_oprcode = PQfnumber(res, "oprcode");
10222     i_oprleft = PQfnumber(res, "oprleft");
10223     i_oprright = PQfnumber(res, "oprright");
10224     i_oprcom = PQfnumber(res, "oprcom");
10225     i_oprnegate = PQfnumber(res, "oprnegate");
10226     i_oprrest = PQfnumber(res, "oprrest");
10227     i_oprjoin = PQfnumber(res, "oprjoin");
10228     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
10229     i_oprcanhash = PQfnumber(res, "oprcanhash");
10230 
10231     oprkind = PQgetvalue(res, 0, i_oprkind);
10232     oprcode = PQgetvalue(res, 0, i_oprcode);
10233     oprleft = PQgetvalue(res, 0, i_oprleft);
10234     oprright = PQgetvalue(res, 0, i_oprright);
10235     oprcom = PQgetvalue(res, 0, i_oprcom);
10236     oprnegate = PQgetvalue(res, 0, i_oprnegate);
10237     oprrest = PQgetvalue(res, 0, i_oprrest);
10238     oprjoin = PQgetvalue(res, 0, i_oprjoin);
10239     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
10240     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
10241 
10242     appendPQExpBuffer(details, "    PROCEDURE = %s",
10243                       convertRegProcReference(fout, oprcode));
10244 
10245     appendPQExpBuffer(oprid, "%s (",
10246                       oprinfo->dobj.name);
10247 
10248     /*
10249      * right unary means there's a left arg and left unary means there's a
10250      * right arg
10251      */
10252     if (strcmp(oprkind, "r") == 0 ||
10253         strcmp(oprkind, "b") == 0)
10254     {
10255         if (fout->remoteVersion >= 70100)
10256             name = oprleft;
10257         else
10258             name = fmtId(oprleft);
10259         appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
10260         appendPQExpBuffer(oprid, "%s", name);
10261     }
10262     else
10263         appendPQExpBuffer(oprid, "NONE");
10264 
10265     if (strcmp(oprkind, "l") == 0 ||
10266         strcmp(oprkind, "b") == 0)
10267     {
10268         if (fout->remoteVersion >= 70100)
10269             name = oprright;
10270         else
10271             name = fmtId(oprright);
10272         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
10273         appendPQExpBuffer(oprid, ", %s)", name);
10274     }
10275     else
10276         appendPQExpBuffer(oprid, ", NONE)");
10277 
10278     name = convertOperatorReference(fout, oprcom);
10279     if (name)
10280         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
10281 
10282     name = convertOperatorReference(fout, oprnegate);
10283     if (name)
10284         appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
10285 
10286     if (strcmp(oprcanmerge, "t") == 0)
10287         appendPQExpBuffer(details, ",\n    MERGES");
10288 
10289     if (strcmp(oprcanhash, "t") == 0)
10290         appendPQExpBuffer(details, ",\n    HASHES");
10291 
10292     name = convertRegProcReference(fout, oprrest);
10293     if (name)
10294         appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
10295 
10296     name = convertRegProcReference(fout, oprjoin);
10297     if (name)
10298         appendPQExpBuffer(details, ",\n    JOIN = %s", name);
10299 
10300     /*
10301      * DROP must be fully qualified in case same name appears in pg_catalog
10302      */
10303     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
10304                       fmtId(oprinfo->dobj.namespace->dobj.name),
10305                       oprid->data);
10306 
10307     appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
10308                       oprinfo->dobj.name, details->data);
10309 
10310     appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
10311 
10312     if (binary_upgrade)
10313         binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
10314 
10315     ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
10316                  oprinfo->dobj.name,
10317                  oprinfo->dobj.namespace->dobj.name,
10318                  NULL,
10319                  oprinfo->rolname,
10320                  false, "OPERATOR", SECTION_PRE_DATA,
10321                  q->data, delq->data, NULL,
10322                  NULL, 0,
10323                  NULL, NULL);
10324 
10325     /* Dump Operator Comments */
10326     dumpComment(fout, labelq->data,
10327                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
10328                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
10329 
10330     PQclear(res);
10331 
10332     destroyPQExpBuffer(query);
10333     destroyPQExpBuffer(q);
10334     destroyPQExpBuffer(delq);
10335     destroyPQExpBuffer(labelq);
10336     destroyPQExpBuffer(oprid);
10337     destroyPQExpBuffer(details);
10338 }
10339 
10340 /*
10341  * Convert a function reference obtained from pg_operator
10342  *
10343  * Returns what to print, or NULL if function references is InvalidOid
10344  *
10345  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
10346  * argument-types part.  In prior versions, the input is a REGPROC display.
10347  */
10348 static const char *
10349 convertRegProcReference(Archive *fout, const char *proc)
10350 {
10351     /* In all cases "-" means a null reference */
10352     if (strcmp(proc, "-") == 0)
10353         return NULL;
10354 
10355     if (fout->remoteVersion >= 70300)
10356     {
10357         char       *name;
10358         char       *paren;
10359         bool        inquote;
10360 
10361         name = pg_strdup(proc);
10362         /* find non-double-quoted left paren */
10363         inquote = false;
10364         for (paren = name; *paren; paren++)
10365         {
10366             if (*paren == '(' && !inquote)
10367             {
10368                 *paren = '\0';
10369                 break;
10370             }
10371             if (*paren == '"')
10372                 inquote = !inquote;
10373         }
10374         return name;
10375     }
10376 
10377     /* REGPROC before 7.3 does not quote its result */
10378     return fmtId(proc);
10379 }
10380 
10381 /*
10382  * Convert an operator cross-reference obtained from pg_operator
10383  *
10384  * Returns what to print, or NULL to print nothing
10385  *
10386  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
10387  * argument-types part, and add OPERATOR() decoration if the name is
10388  * schema-qualified.  In older versions, the input is just a numeric OID,
10389  * which we search our operator list for.
10390  */
10391 static const char *
10392 convertOperatorReference(Archive *fout, const char *opr)
10393 {
10394     OprInfo    *oprInfo;
10395 
10396     /* In all cases "0" means a null reference */
10397     if (strcmp(opr, "0") == 0)
10398         return NULL;
10399 
10400     if (fout->remoteVersion >= 70300)
10401     {
10402         char       *name;
10403         char       *oname;
10404         char       *ptr;
10405         bool        inquote;
10406         bool        sawdot;
10407 
10408         name = pg_strdup(opr);
10409         /* find non-double-quoted left paren, and check for non-quoted dot */
10410         inquote = false;
10411         sawdot = false;
10412         for (ptr = name; *ptr; ptr++)
10413         {
10414             if (*ptr == '"')
10415                 inquote = !inquote;
10416             else if (*ptr == '.' && !inquote)
10417                 sawdot = true;
10418             else if (*ptr == '(' && !inquote)
10419             {
10420                 *ptr = '\0';
10421                 break;
10422             }
10423         }
10424         /* If not schema-qualified, don't need to add OPERATOR() */
10425         if (!sawdot)
10426             return name;
10427         oname = pg_malloc(strlen(name) + 11);
10428         sprintf(oname, "OPERATOR(%s)", name);
10429         free(name);
10430         return oname;
10431     }
10432 
10433     oprInfo = findOprByOid(atooid(opr));
10434     if (oprInfo == NULL)
10435     {
10436         write_msg(NULL, "WARNING: could not find operator with OID %s\n",
10437                   opr);
10438         return NULL;
10439     }
10440     return oprInfo->dobj.name;
10441 }
10442 
10443 /*
10444  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
10445  *
10446  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
10447  * argument lists of these functions are predetermined.  Note that the
10448  * caller should ensure we are in the proper schema, because the results
10449  * are search path dependent!
10450  */
10451 static const char *
10452 convertTSFunction(Archive *fout, Oid funcOid)
10453 {
10454     char       *result;
10455     char        query[128];
10456     PGresult   *res;
10457 
10458     snprintf(query, sizeof(query),
10459              "SELECT '%u'::pg_catalog.regproc", funcOid);
10460     res = ExecuteSqlQueryForSingleRow(fout, query);
10461 
10462     result = pg_strdup(PQgetvalue(res, 0, 0));
10463 
10464     PQclear(res);
10465 
10466     return result;
10467 }
10468 
10469 
10470 /*
10471  * dumpOpclass
10472  *    write out a single operator class definition
10473  */
10474 static void
10475 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
10476 {
10477     PQExpBuffer query;
10478     PQExpBuffer q;
10479     PQExpBuffer delq;
10480     PQExpBuffer labelq;
10481     PGresult   *res;
10482     int         ntups;
10483     int         i_opcintype;
10484     int         i_opckeytype;
10485     int         i_opcdefault;
10486     int         i_opcfamily;
10487     int         i_opcfamilyname;
10488     int         i_opcfamilynsp;
10489     int         i_amname;
10490     int         i_amopstrategy;
10491     int         i_amopreqcheck;
10492     int         i_amopopr;
10493     int         i_sortfamily;
10494     int         i_sortfamilynsp;
10495     int         i_amprocnum;
10496     int         i_amproc;
10497     int         i_amproclefttype;
10498     int         i_amprocrighttype;
10499     char       *opcintype;
10500     char       *opckeytype;
10501     char       *opcdefault;
10502     char       *opcfamily;
10503     char       *opcfamilyname;
10504     char       *opcfamilynsp;
10505     char       *amname;
10506     char       *amopstrategy;
10507     char       *amopreqcheck;
10508     char       *amopopr;
10509     char       *sortfamily;
10510     char       *sortfamilynsp;
10511     char       *amprocnum;
10512     char       *amproc;
10513     char       *amproclefttype;
10514     char       *amprocrighttype;
10515     bool        needComma;
10516     int         i;
10517 
10518     /* Skip if not to be dumped */
10519     if (!opcinfo->dobj.dump || dataOnly)
10520         return;
10521 
10522     /*
10523      * XXX currently we do not implement dumping of operator classes from
10524      * pre-7.3 databases.  This could be done but it seems not worth the
10525      * trouble.
10526      */
10527     if (fout->remoteVersion < 70300)
10528         return;
10529 
10530     query = createPQExpBuffer();
10531     q = createPQExpBuffer();
10532     delq = createPQExpBuffer();
10533     labelq = createPQExpBuffer();
10534 
10535     /* Make sure we are in proper schema so regoperator works correctly */
10536     selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
10537 
10538     /* Get additional fields from the pg_opclass row */
10539     if (fout->remoteVersion >= 80300)
10540     {
10541         appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10542                           "opckeytype::pg_catalog.regtype, "
10543                           "opcdefault, opcfamily, "
10544                           "opfname AS opcfamilyname, "
10545                           "nspname AS opcfamilynsp, "
10546                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10547                           "FROM pg_catalog.pg_opclass c "
10548                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10549                "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10550                           "WHERE c.oid = '%u'::pg_catalog.oid",
10551                           opcinfo->dobj.catId.oid);
10552     }
10553     else
10554     {
10555         appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10556                           "opckeytype::pg_catalog.regtype, "
10557                           "opcdefault, NULL AS opcfamily, "
10558                           "NULL AS opcfamilyname, "
10559                           "NULL AS opcfamilynsp, "
10560         "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10561                           "FROM pg_catalog.pg_opclass "
10562                           "WHERE oid = '%u'::pg_catalog.oid",
10563                           opcinfo->dobj.catId.oid);
10564     }
10565 
10566     res = ExecuteSqlQueryForSingleRow(fout, query->data);
10567 
10568     i_opcintype = PQfnumber(res, "opcintype");
10569     i_opckeytype = PQfnumber(res, "opckeytype");
10570     i_opcdefault = PQfnumber(res, "opcdefault");
10571     i_opcfamily = PQfnumber(res, "opcfamily");
10572     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10573     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10574     i_amname = PQfnumber(res, "amname");
10575 
10576     opcintype = PQgetvalue(res, 0, i_opcintype);
10577     opckeytype = PQgetvalue(res, 0, i_opckeytype);
10578     opcdefault = PQgetvalue(res, 0, i_opcdefault);
10579     /* opcfamily will still be needed after we PQclear res */
10580     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10581     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10582     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10583     /* amname will still be needed after we PQclear res */
10584     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10585 
10586     /*
10587      * DROP must be fully qualified in case same name appears in pg_catalog
10588      */
10589     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10590                       fmtId(opcinfo->dobj.namespace->dobj.name));
10591     appendPQExpBuffer(delq, ".%s",
10592                       fmtId(opcinfo->dobj.name));
10593     appendPQExpBuffer(delq, " USING %s;\n",
10594                       fmtId(amname));
10595 
10596     /* Build the fixed portion of the CREATE command */
10597     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10598                       fmtId(opcinfo->dobj.name));
10599     if (strcmp(opcdefault, "t") == 0)
10600         appendPQExpBuffer(q, "DEFAULT ");
10601     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10602                       opcintype,
10603                       fmtId(amname));
10604     if (strlen(opcfamilyname) > 0 &&
10605         (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10606          strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10607     {
10608         appendPQExpBuffer(q, " FAMILY ");
10609         if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10610             appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10611         appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10612     }
10613     appendPQExpBuffer(q, " AS\n    ");
10614 
10615     needComma = false;
10616 
10617     if (strcmp(opckeytype, "-") != 0)
10618     {
10619         appendPQExpBuffer(q, "STORAGE %s",
10620                           opckeytype);
10621         needComma = true;
10622     }
10623 
10624     PQclear(res);
10625 
10626     /*
10627      * Now fetch and print the OPERATOR entries (pg_amop rows).
10628      *
10629      * Print only those opfamily members that are tied to the opclass by
10630      * pg_depend entries.
10631      *
10632      * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10633      * older server's opclass in which it is used.  This is to avoid
10634      * hard-to-detect breakage if a newer pg_dump is used to dump from an
10635      * older server and then reload into that old version.  This can go away
10636      * once 8.3 is so old as to not be of interest to anyone.
10637      */
10638     resetPQExpBuffer(query);
10639 
10640     if (fout->remoteVersion >= 90100)
10641     {
10642         appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10643                           "amopopr::pg_catalog.regoperator, "
10644                           "opfname AS sortfamily, "
10645                           "nspname AS sortfamilynsp "
10646                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10647                           "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10648               "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10649                "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10650            "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10651                           "AND refobjid = '%u'::pg_catalog.oid "
10652                           "AND amopfamily = '%s'::pg_catalog.oid "
10653                           "ORDER BY amopstrategy",
10654                           opcinfo->dobj.catId.oid,
10655                           opcfamily);
10656     }
10657     else if (fout->remoteVersion >= 80400)
10658     {
10659         appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10660                           "amopopr::pg_catalog.regoperator, "
10661                           "NULL AS sortfamily, "
10662                           "NULL AS sortfamilynsp "
10663                           "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10664            "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10665                           "AND refobjid = '%u'::pg_catalog.oid "
10666                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10667                           "AND objid = ao.oid "
10668                           "ORDER BY amopstrategy",
10669                           opcinfo->dobj.catId.oid);
10670     }
10671     else if (fout->remoteVersion >= 80300)
10672     {
10673         appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10674                           "amopopr::pg_catalog.regoperator, "
10675                           "NULL AS sortfamily, "
10676                           "NULL AS sortfamilynsp "
10677                           "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10678            "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10679                           "AND refobjid = '%u'::pg_catalog.oid "
10680                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10681                           "AND objid = ao.oid "
10682                           "ORDER BY amopstrategy",
10683                           opcinfo->dobj.catId.oid);
10684     }
10685     else
10686     {
10687         /*
10688          * Here, we print all entries since there are no opfamilies and hence
10689          * no loose operators to worry about.
10690          */
10691         appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10692                           "amopopr::pg_catalog.regoperator, "
10693                           "NULL AS sortfamily, "
10694                           "NULL AS sortfamilynsp "
10695                           "FROM pg_catalog.pg_amop "
10696                           "WHERE amopclaid = '%u'::pg_catalog.oid "
10697                           "ORDER BY amopstrategy",
10698                           opcinfo->dobj.catId.oid);
10699     }
10700 
10701     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10702 
10703     ntups = PQntuples(res);
10704 
10705     i_amopstrategy = PQfnumber(res, "amopstrategy");
10706     i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10707     i_amopopr = PQfnumber(res, "amopopr");
10708     i_sortfamily = PQfnumber(res, "sortfamily");
10709     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10710 
10711     for (i = 0; i < ntups; i++)
10712     {
10713         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10714         amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10715         amopopr = PQgetvalue(res, i, i_amopopr);
10716         sortfamily = PQgetvalue(res, i, i_sortfamily);
10717         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10718 
10719         if (needComma)
10720             appendPQExpBuffer(q, " ,\n    ");
10721 
10722         appendPQExpBuffer(q, "OPERATOR %s %s",
10723                           amopstrategy, amopopr);
10724 
10725         if (strlen(sortfamily) > 0)
10726         {
10727             appendPQExpBuffer(q, " FOR ORDER BY ");
10728             if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10729                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10730             appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10731         }
10732 
10733         if (strcmp(amopreqcheck, "t") == 0)
10734             appendPQExpBuffer(q, " RECHECK");
10735 
10736         needComma = true;
10737     }
10738 
10739     PQclear(res);
10740 
10741     /*
10742      * Now fetch and print the FUNCTION entries (pg_amproc rows).
10743      *
10744      * Print only those opfamily members that are tied to the opclass by
10745      * pg_depend entries.
10746      *
10747      * We print the amproclefttype/amprocrighttype even though in most cases
10748      * the backend could deduce the right values, because of the corner case
10749      * of a btree sort support function for a cross-type comparison.  That's
10750      * only allowed in 9.2 and later, but for simplicity print them in all
10751      * versions that have the columns.
10752      */
10753     resetPQExpBuffer(query);
10754 
10755     if (fout->remoteVersion >= 80300)
10756     {
10757         appendPQExpBuffer(query, "SELECT amprocnum, "
10758                           "amproc::pg_catalog.regprocedure, "
10759                           "amproclefttype::pg_catalog.regtype, "
10760                           "amprocrighttype::pg_catalog.regtype "
10761                         "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10762            "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10763                           "AND refobjid = '%u'::pg_catalog.oid "
10764                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10765                           "AND objid = ap.oid "
10766                           "ORDER BY amprocnum",
10767                           opcinfo->dobj.catId.oid);
10768     }
10769     else
10770     {
10771         appendPQExpBuffer(query, "SELECT amprocnum, "
10772                           "amproc::pg_catalog.regprocedure, "
10773                           "'' AS amproclefttype, "
10774                           "'' AS amprocrighttype "
10775                           "FROM pg_catalog.pg_amproc "
10776                           "WHERE amopclaid = '%u'::pg_catalog.oid "
10777                           "ORDER BY amprocnum",
10778                           opcinfo->dobj.catId.oid);
10779     }
10780 
10781     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10782 
10783     ntups = PQntuples(res);
10784 
10785     i_amprocnum = PQfnumber(res, "amprocnum");
10786     i_amproc = PQfnumber(res, "amproc");
10787     i_amproclefttype = PQfnumber(res, "amproclefttype");
10788     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10789 
10790     for (i = 0; i < ntups; i++)
10791     {
10792         amprocnum = PQgetvalue(res, i, i_amprocnum);
10793         amproc = PQgetvalue(res, i, i_amproc);
10794         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10795         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10796 
10797         if (needComma)
10798             appendPQExpBuffer(q, " ,\n    ");
10799 
10800         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10801 
10802         if (*amproclefttype && *amprocrighttype)
10803             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10804 
10805         appendPQExpBuffer(q, " %s", amproc);
10806 
10807         needComma = true;
10808     }
10809 
10810     PQclear(res);
10811 
10812     appendPQExpBuffer(q, ";\n");
10813 
10814     appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10815                       fmtId(opcinfo->dobj.name));
10816     appendPQExpBuffer(labelq, " USING %s",
10817                       fmtId(amname));
10818 
10819     if (binary_upgrade)
10820         binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10821 
10822     ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10823                  opcinfo->dobj.name,
10824                  opcinfo->dobj.namespace->dobj.name,
10825                  NULL,
10826                  opcinfo->rolname,
10827                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10828                  q->data, delq->data, NULL,
10829                  NULL, 0,
10830                  NULL, NULL);
10831 
10832     /* Dump Operator Class Comments */
10833     dumpComment(fout, labelq->data,
10834                 NULL, opcinfo->rolname,
10835                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10836 
10837     free(amname);
10838     destroyPQExpBuffer(query);
10839     destroyPQExpBuffer(q);
10840     destroyPQExpBuffer(delq);
10841     destroyPQExpBuffer(labelq);
10842 }
10843 
10844 /*
10845  * dumpOpfamily
10846  *    write out a single operator family definition
10847  *
10848  * Note: this also dumps any "loose" operator members that aren't bound to a
10849  * specific opclass within the opfamily.
10850  */
10851 static void
10852 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10853 {
10854     PQExpBuffer query;
10855     PQExpBuffer q;
10856     PQExpBuffer delq;
10857     PQExpBuffer labelq;
10858     PGresult   *res;
10859     PGresult   *res_ops;
10860     PGresult   *res_procs;
10861     int         ntups;
10862     int         i_amname;
10863     int         i_amopstrategy;
10864     int         i_amopreqcheck;
10865     int         i_amopopr;
10866     int         i_sortfamily;
10867     int         i_sortfamilynsp;
10868     int         i_amprocnum;
10869     int         i_amproc;
10870     int         i_amproclefttype;
10871     int         i_amprocrighttype;
10872     char       *amname;
10873     char       *amopstrategy;
10874     char       *amopreqcheck;
10875     char       *amopopr;
10876     char       *sortfamily;
10877     char       *sortfamilynsp;
10878     char       *amprocnum;
10879     char       *amproc;
10880     char       *amproclefttype;
10881     char       *amprocrighttype;
10882     bool        needComma;
10883     int         i;
10884 
10885     /* Skip if not to be dumped */
10886     if (!opfinfo->dobj.dump || dataOnly)
10887         return;
10888 
10889     /*
10890      * We want to dump the opfamily only if (1) it contains "loose" operators
10891      * or functions, or (2) it contains an opclass with a different name or
10892      * owner.  Otherwise it's sufficient to let it be created during creation
10893      * of the contained opclass, and not dumping it improves portability of
10894      * the dump.  Since we have to fetch the loose operators/funcs anyway, do
10895      * that first.
10896      */
10897 
10898     query = createPQExpBuffer();
10899     q = createPQExpBuffer();
10900     delq = createPQExpBuffer();
10901     labelq = createPQExpBuffer();
10902 
10903     /* Make sure we are in proper schema so regoperator works correctly */
10904     selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
10905 
10906     /*
10907      * Fetch only those opfamily members that are tied directly to the
10908      * opfamily by pg_depend entries.
10909      *
10910      * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10911      * older server's opclass in which it is used.  This is to avoid
10912      * hard-to-detect breakage if a newer pg_dump is used to dump from an
10913      * older server and then reload into that old version.  This can go away
10914      * once 8.3 is so old as to not be of interest to anyone.
10915      */
10916     if (fout->remoteVersion >= 90100)
10917     {
10918         appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10919                           "amopopr::pg_catalog.regoperator, "
10920                           "opfname AS sortfamily, "
10921                           "nspname AS sortfamilynsp "
10922                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10923                           "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10924               "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10925                "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10926           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10927                           "AND refobjid = '%u'::pg_catalog.oid "
10928                           "AND amopfamily = '%u'::pg_catalog.oid "
10929                           "ORDER BY amopstrategy",
10930                           opfinfo->dobj.catId.oid,
10931                           opfinfo->dobj.catId.oid);
10932     }
10933     else if (fout->remoteVersion >= 80400)
10934     {
10935         appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10936                           "amopopr::pg_catalog.regoperator, "
10937                           "NULL AS sortfamily, "
10938                           "NULL AS sortfamilynsp "
10939                           "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10940           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10941                           "AND refobjid = '%u'::pg_catalog.oid "
10942                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10943                           "AND objid = ao.oid "
10944                           "ORDER BY amopstrategy",
10945                           opfinfo->dobj.catId.oid);
10946     }
10947     else
10948     {
10949         appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10950                           "amopopr::pg_catalog.regoperator, "
10951                           "NULL AS sortfamily, "
10952                           "NULL AS sortfamilynsp "
10953                           "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10954           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10955                           "AND refobjid = '%u'::pg_catalog.oid "
10956                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10957                           "AND objid = ao.oid "
10958                           "ORDER BY amopstrategy",
10959                           opfinfo->dobj.catId.oid);
10960     }
10961 
10962     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10963 
10964     resetPQExpBuffer(query);
10965 
10966     appendPQExpBuffer(query, "SELECT amprocnum, "
10967                       "amproc::pg_catalog.regprocedure, "
10968                       "amproclefttype::pg_catalog.regtype, "
10969                       "amprocrighttype::pg_catalog.regtype "
10970                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10971           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10972                       "AND refobjid = '%u'::pg_catalog.oid "
10973                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10974                       "AND objid = ap.oid "
10975                       "ORDER BY amprocnum",
10976                       opfinfo->dobj.catId.oid);
10977 
10978     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10979 
10980     if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
10981     {
10982         /* No loose members, so check contained opclasses */
10983         resetPQExpBuffer(query);
10984 
10985         appendPQExpBuffer(query, "SELECT 1 "
10986                           "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
10987                           "WHERE f.oid = '%u'::pg_catalog.oid "
10988             "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10989                           "AND refobjid = f.oid "
10990                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10991                           "AND objid = c.oid "
10992                           "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
10993                           "LIMIT 1",
10994                           opfinfo->dobj.catId.oid);
10995 
10996         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10997 
10998         if (PQntuples(res) == 0)
10999         {
11000             /* no need to dump it, so bail out */
11001             PQclear(res);
11002             PQclear(res_ops);
11003             PQclear(res_procs);
11004             destroyPQExpBuffer(query);
11005             destroyPQExpBuffer(q);
11006             destroyPQExpBuffer(delq);
11007             destroyPQExpBuffer(labelq);
11008             return;
11009         }
11010 
11011         PQclear(res);
11012     }
11013 
11014     /* Get additional fields from the pg_opfamily row */
11015     resetPQExpBuffer(query);
11016 
11017     appendPQExpBuffer(query, "SELECT "
11018      "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
11019                       "FROM pg_catalog.pg_opfamily "
11020                       "WHERE oid = '%u'::pg_catalog.oid",
11021                       opfinfo->dobj.catId.oid);
11022 
11023     res = ExecuteSqlQueryForSingleRow(fout, query->data);
11024 
11025     i_amname = PQfnumber(res, "amname");
11026 
11027     /* amname will still be needed after we PQclear res */
11028     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
11029 
11030     /*
11031      * DROP must be fully qualified in case same name appears in pg_catalog
11032      */
11033     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
11034                       fmtId(opfinfo->dobj.namespace->dobj.name));
11035     appendPQExpBuffer(delq, ".%s",
11036                       fmtId(opfinfo->dobj.name));
11037     appendPQExpBuffer(delq, " USING %s;\n",
11038                       fmtId(amname));
11039 
11040     /* Build the fixed portion of the CREATE command */
11041     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
11042                       fmtId(opfinfo->dobj.name));
11043     appendPQExpBuffer(q, " USING %s;\n",
11044                       fmtId(amname));
11045 
11046     PQclear(res);
11047 
11048     /* Do we need an ALTER to add loose members? */
11049     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
11050     {
11051         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
11052                           fmtId(opfinfo->dobj.name));
11053         appendPQExpBuffer(q, " USING %s ADD\n    ",
11054                           fmtId(amname));
11055 
11056         needComma = false;
11057 
11058         /*
11059          * Now fetch and print the OPERATOR entries (pg_amop rows).
11060          */
11061         ntups = PQntuples(res_ops);
11062 
11063         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
11064         i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
11065         i_amopopr = PQfnumber(res_ops, "amopopr");
11066         i_sortfamily = PQfnumber(res_ops, "sortfamily");
11067         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
11068 
11069         for (i = 0; i < ntups; i++)
11070         {
11071             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
11072             amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
11073             amopopr = PQgetvalue(res_ops, i, i_amopopr);
11074             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
11075             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
11076 
11077             if (needComma)
11078                 appendPQExpBuffer(q, " ,\n    ");
11079 
11080             appendPQExpBuffer(q, "OPERATOR %s %s",
11081                               amopstrategy, amopopr);
11082 
11083             if (strlen(sortfamily) > 0)
11084             {
11085                 appendPQExpBuffer(q, " FOR ORDER BY ");
11086                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
11087                     appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
11088                 appendPQExpBuffer(q, "%s", fmtId(sortfamily));
11089             }
11090 
11091             if (strcmp(amopreqcheck, "t") == 0)
11092                 appendPQExpBuffer(q, " RECHECK");
11093 
11094             needComma = true;
11095         }
11096 
11097         /*
11098          * Now fetch and print the FUNCTION entries (pg_amproc rows).
11099          */
11100         ntups = PQntuples(res_procs);
11101 
11102         i_amprocnum = PQfnumber(res_procs, "amprocnum");
11103         i_amproc = PQfnumber(res_procs, "amproc");
11104         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
11105         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
11106 
11107         for (i = 0; i < ntups; i++)
11108         {
11109             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
11110             amproc = PQgetvalue(res_procs, i, i_amproc);
11111             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
11112             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
11113 
11114             if (needComma)
11115                 appendPQExpBuffer(q, " ,\n    ");
11116 
11117             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
11118                               amprocnum, amproclefttype, amprocrighttype,
11119                               amproc);
11120 
11121             needComma = true;
11122         }
11123 
11124         appendPQExpBuffer(q, ";\n");
11125     }
11126 
11127     appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
11128                       fmtId(opfinfo->dobj.name));
11129     appendPQExpBuffer(labelq, " USING %s",
11130                       fmtId(amname));
11131 
11132     if (binary_upgrade)
11133         binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
11134 
11135     ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
11136                  opfinfo->dobj.name,
11137                  opfinfo->dobj.namespace->dobj.name,
11138                  NULL,
11139                  opfinfo->rolname,
11140                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
11141                  q->data, delq->data, NULL,
11142                  NULL, 0,
11143                  NULL, NULL);
11144 
11145     /* Dump Operator Family Comments */
11146     dumpComment(fout, labelq->data,
11147                 NULL, opfinfo->rolname,
11148                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
11149 
11150     free(amname);
11151     PQclear(res_ops);
11152     PQclear(res_procs);
11153     destroyPQExpBuffer(query);
11154     destroyPQExpBuffer(q);
11155     destroyPQExpBuffer(delq);
11156     destroyPQExpBuffer(labelq);
11157 }
11158 
11159 /*
11160  * dumpCollation
11161  *    write out a single collation definition
11162  */
11163 static void
11164 dumpCollation(Archive *fout, CollInfo *collinfo)
11165 {
11166     PQExpBuffer query;
11167     PQExpBuffer q;
11168     PQExpBuffer delq;
11169     PQExpBuffer labelq;
11170     PGresult   *res;
11171     int         i_collcollate;
11172     int         i_collctype;
11173     const char *collcollate;
11174     const char *collctype;
11175 
11176     /* Skip if not to be dumped */
11177     if (!collinfo->dobj.dump || dataOnly)
11178         return;
11179 
11180     query = createPQExpBuffer();
11181     q = createPQExpBuffer();
11182     delq = createPQExpBuffer();
11183     labelq = createPQExpBuffer();
11184 
11185     /* Make sure we are in proper schema */
11186     selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
11187 
11188     /* Get conversion-specific details */
11189     appendPQExpBuffer(query, "SELECT "
11190                       "collcollate, "
11191                       "collctype "
11192                       "FROM pg_catalog.pg_collation c "
11193                       "WHERE c.oid = '%u'::pg_catalog.oid",
11194                       collinfo->dobj.catId.oid);
11195 
11196     res = ExecuteSqlQueryForSingleRow(fout, query->data);
11197 
11198     i_collcollate = PQfnumber(res, "collcollate");
11199     i_collctype = PQfnumber(res, "collctype");
11200 
11201     collcollate = PQgetvalue(res, 0, i_collcollate);
11202     collctype = PQgetvalue(res, 0, i_collctype);
11203 
11204     /*
11205      * DROP must be fully qualified in case same name appears in pg_catalog
11206      */
11207     appendPQExpBuffer(delq, "DROP COLLATION %s",
11208                       fmtId(collinfo->dobj.namespace->dobj.name));
11209     appendPQExpBuffer(delq, ".%s;\n",
11210                       fmtId(collinfo->dobj.name));
11211 
11212     appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
11213                       fmtId(collinfo->dobj.name));
11214     appendStringLiteralAH(q, collcollate, fout);
11215     appendPQExpBuffer(q, ", lc_ctype = ");
11216     appendStringLiteralAH(q, collctype, fout);
11217     appendPQExpBuffer(q, ");\n");
11218 
11219     appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
11220 
11221     if (binary_upgrade)
11222         binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
11223 
11224     ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
11225                  collinfo->dobj.name,
11226                  collinfo->dobj.namespace->dobj.name,
11227                  NULL,
11228                  collinfo->rolname,
11229                  false, "COLLATION", SECTION_PRE_DATA,
11230                  q->data, delq->data, NULL,
11231                  NULL, 0,
11232                  NULL, NULL);
11233 
11234     /* Dump Collation Comments */
11235     dumpComment(fout, labelq->data,
11236                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
11237                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
11238 
11239     PQclear(res);
11240 
11241     destroyPQExpBuffer(query);
11242     destroyPQExpBuffer(q);
11243     destroyPQExpBuffer(delq);
11244     destroyPQExpBuffer(labelq);
11245 }
11246 
11247 /*
11248  * dumpConversion
11249  *    write out a single conversion definition
11250  */
11251 static void
11252 dumpConversion(Archive *fout, ConvInfo *convinfo)
11253 {
11254     PQExpBuffer query;
11255     PQExpBuffer q;
11256     PQExpBuffer delq;
11257     PQExpBuffer labelq;
11258     PGresult   *res;
11259     int         i_conforencoding;
11260     int         i_contoencoding;
11261     int         i_conproc;
11262     int         i_condefault;
11263     const char *conforencoding;
11264     const char *contoencoding;
11265     const char *conproc;
11266     bool        condefault;
11267 
11268     /* Skip if not to be dumped */
11269     if (!convinfo->dobj.dump || dataOnly)
11270         return;
11271 
11272     query = createPQExpBuffer();
11273     q = createPQExpBuffer();
11274     delq = createPQExpBuffer();
11275     labelq = createPQExpBuffer();
11276 
11277     /* Make sure we are in proper schema */
11278     selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
11279 
11280     /* Get conversion-specific details */
11281     appendPQExpBuffer(query, "SELECT "
11282          "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
11283            "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
11284                       "conproc, condefault "
11285                       "FROM pg_catalog.pg_conversion c "
11286                       "WHERE c.oid = '%u'::pg_catalog.oid",
11287                       convinfo->dobj.catId.oid);
11288 
11289     res = ExecuteSqlQueryForSingleRow(fout, query->data);
11290 
11291     i_conforencoding = PQfnumber(res, "conforencoding");
11292     i_contoencoding = PQfnumber(res, "contoencoding");
11293     i_conproc = PQfnumber(res, "conproc");
11294     i_condefault = PQfnumber(res, "condefault");
11295 
11296     conforencoding = PQgetvalue(res, 0, i_conforencoding);
11297     contoencoding = PQgetvalue(res, 0, i_contoencoding);
11298     conproc = PQgetvalue(res, 0, i_conproc);
11299     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
11300 
11301     /*
11302      * DROP must be fully qualified in case same name appears in pg_catalog
11303      */
11304     appendPQExpBuffer(delq, "DROP CONVERSION %s",
11305                       fmtId(convinfo->dobj.namespace->dobj.name));
11306     appendPQExpBuffer(delq, ".%s;\n",
11307                       fmtId(convinfo->dobj.name));
11308 
11309     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
11310                       (condefault) ? "DEFAULT " : "",
11311                       fmtId(convinfo->dobj.name));
11312     appendStringLiteralAH(q, conforencoding, fout);
11313     appendPQExpBuffer(q, " TO ");
11314     appendStringLiteralAH(q, contoencoding, fout);
11315     /* regproc is automatically quoted in 7.3 and above */
11316     appendPQExpBuffer(q, " FROM %s;\n", conproc);
11317 
11318     appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
11319 
11320     if (binary_upgrade)
11321         binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
11322 
11323     ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
11324                  convinfo->dobj.name,
11325                  convinfo->dobj.namespace->dobj.name,
11326                  NULL,
11327                  convinfo->rolname,
11328                  false, "CONVERSION", SECTION_PRE_DATA,
11329                  q->data, delq->data, NULL,
11330                  NULL, 0,
11331                  NULL, NULL);
11332 
11333     /* Dump Conversion Comments */
11334     dumpComment(fout, labelq->data,
11335                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
11336                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
11337 
11338     PQclear(res);
11339 
11340     destroyPQExpBuffer(query);
11341     destroyPQExpBuffer(q);
11342     destroyPQExpBuffer(delq);
11343     destroyPQExpBuffer(labelq);
11344 }
11345 
11346 /*
11347  * format_aggregate_signature: generate aggregate name and argument list
11348  *
11349  * The argument type names are qualified if needed.  The aggregate name
11350  * is never qualified.
11351  */
11352 static char *
11353 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
11354 {
11355     PQExpBufferData buf;
11356     int         j;
11357 
11358     initPQExpBuffer(&buf);
11359     if (honor_quotes)
11360         appendPQExpBuffer(&buf, "%s",
11361                           fmtId(agginfo->aggfn.dobj.name));
11362     else
11363         appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
11364 
11365     if (agginfo->aggfn.nargs == 0)
11366         appendPQExpBuffer(&buf, "(*)");
11367     else
11368     {
11369         appendPQExpBuffer(&buf, "(");
11370         for (j = 0; j < agginfo->aggfn.nargs; j++)
11371         {
11372             char       *typname;
11373 
11374             typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
11375                                            zeroAsOpaque);
11376 
11377             appendPQExpBuffer(&buf, "%s%s",
11378                               (j > 0) ? ", " : "",
11379                               typname);
11380             free(typname);
11381         }
11382         appendPQExpBuffer(&buf, ")");
11383     }
11384     return buf.data;
11385 }
11386 
11387 /*
11388  * dumpAgg
11389  *    write out a single aggregate definition
11390  */
11391 static void
11392 dumpAgg(Archive *fout, AggInfo *agginfo)
11393 {
11394     PQExpBuffer query;
11395     PQExpBuffer q;
11396     PQExpBuffer delq;
11397     PQExpBuffer labelq;
11398     PQExpBuffer details;
11399     char       *aggsig;
11400     char       *aggsig_tag;
11401     PGresult   *res;
11402     int         i_aggtransfn;
11403     int         i_aggfinalfn;
11404     int         i_aggsortop;
11405     int         i_aggtranstype;
11406     int         i_agginitval;
11407     int         i_convertok;
11408     const char *aggtransfn;
11409     const char *aggfinalfn;
11410     const char *aggsortop;
11411     const char *aggtranstype;
11412     const char *agginitval;
11413     bool        convertok;
11414 
11415     /* Skip if not to be dumped */
11416     if (!agginfo->aggfn.dobj.dump || dataOnly)
11417         return;
11418 
11419     query = createPQExpBuffer();
11420     q = createPQExpBuffer();
11421     delq = createPQExpBuffer();
11422     labelq = createPQExpBuffer();
11423     details = createPQExpBuffer();
11424 
11425     /* Make sure we are in proper schema */
11426     selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
11427 
11428     /* Get aggregate-specific details */
11429     if (fout->remoteVersion >= 80100)
11430     {
11431         appendPQExpBuffer(query, "SELECT aggtransfn, "
11432                           "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11433                           "aggsortop::pg_catalog.regoperator, "
11434                           "agginitval, "
11435                           "'t'::boolean AS convertok "
11436                       "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11437                           "WHERE a.aggfnoid = p.oid "
11438                           "AND p.oid = '%u'::pg_catalog.oid",
11439                           agginfo->aggfn.dobj.catId.oid);
11440     }
11441     else if (fout->remoteVersion >= 70300)
11442     {
11443         appendPQExpBuffer(query, "SELECT aggtransfn, "
11444                           "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11445                           "0 AS aggsortop, "
11446                           "agginitval, "
11447                           "'t'::boolean AS convertok "
11448                       "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11449                           "WHERE a.aggfnoid = p.oid "
11450                           "AND p.oid = '%u'::pg_catalog.oid",
11451                           agginfo->aggfn.dobj.catId.oid);
11452     }
11453     else if (fout->remoteVersion >= 70100)
11454     {
11455         appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
11456                           "format_type(aggtranstype, NULL) AS aggtranstype, "
11457                           "0 AS aggsortop, "
11458                           "agginitval, "
11459                           "'t'::boolean AS convertok "
11460                           "FROM pg_aggregate "
11461                           "WHERE oid = '%u'::oid",
11462                           agginfo->aggfn.dobj.catId.oid);
11463     }
11464     else
11465     {
11466         appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
11467                           "aggfinalfn, "
11468                           "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
11469                           "0 AS aggsortop, "
11470                           "agginitval1 AS agginitval, "
11471                           "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
11472                           "FROM pg_aggregate "
11473                           "WHERE oid = '%u'::oid",
11474                           agginfo->aggfn.dobj.catId.oid);
11475     }
11476 
11477     res = ExecuteSqlQueryForSingleRow(fout, query->data);
11478 
11479     i_aggtransfn = PQfnumber(res, "aggtransfn");
11480     i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11481     i_aggsortop = PQfnumber(res, "aggsortop");
11482     i_aggtranstype = PQfnumber(res, "aggtranstype");
11483     i_agginitval = PQfnumber(res, "agginitval");
11484     i_convertok = PQfnumber(res, "convertok");
11485 
11486     aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11487     aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11488     aggsortop = PQgetvalue(res, 0, i_aggsortop);
11489     aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11490     agginitval = PQgetvalue(res, 0, i_agginitval);
11491     convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11492 
11493     aggsig = format_aggregate_signature(agginfo, fout, true);
11494     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11495 
11496     if (!convertok)
11497     {
11498         write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11499                   aggsig);
11500         return;
11501     }
11502 
11503     if (fout->remoteVersion >= 70300)
11504     {
11505         /* If using 7.3's regproc or regtype, data is already quoted */
11506         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11507                           aggtransfn,
11508                           aggtranstype);
11509     }
11510     else if (fout->remoteVersion >= 70100)
11511     {
11512         /* format_type quotes, regproc does not */
11513         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11514                           fmtId(aggtransfn),
11515                           aggtranstype);
11516     }
11517     else
11518     {
11519         /* need quotes all around */
11520         appendPQExpBuffer(details, "    SFUNC = %s,\n",
11521                           fmtId(aggtransfn));
11522         appendPQExpBuffer(details, "    STYPE = %s",
11523                           fmtId(aggtranstype));
11524     }
11525 
11526     if (!PQgetisnull(res, 0, i_agginitval))
11527     {
11528         appendPQExpBuffer(details, ",\n    INITCOND = ");
11529         appendStringLiteralAH(details, agginitval, fout);
11530     }
11531 
11532     if (strcmp(aggfinalfn, "-") != 0)
11533     {
11534         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11535                           aggfinalfn);
11536     }
11537 
11538     aggsortop = convertOperatorReference(fout, aggsortop);
11539     if (aggsortop)
11540     {
11541         appendPQExpBuffer(details, ",\n    SORTOP = %s",
11542                           aggsortop);
11543     }
11544 
11545     /*
11546      * DROP must be fully qualified in case same name appears in pg_catalog
11547      */
11548     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11549                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11550                       aggsig);
11551 
11552     appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11553                       aggsig, details->data);
11554 
11555     appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11556 
11557     if (binary_upgrade)
11558         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11559 
11560     ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11561                  aggsig_tag,
11562                  agginfo->aggfn.dobj.namespace->dobj.name,
11563                  NULL,
11564                  agginfo->aggfn.rolname,
11565                  false, "AGGREGATE", SECTION_PRE_DATA,
11566                  q->data, delq->data, NULL,
11567                  NULL, 0,
11568                  NULL, NULL);
11569 
11570     /* Dump Aggregate Comments */
11571     dumpComment(fout, labelq->data,
11572             agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11573                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11574     dumpSecLabel(fout, labelq->data,
11575             agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11576                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11577 
11578     /*
11579      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11580      * command look like a function's GRANT; in particular this affects the
11581      * syntax for zero-argument aggregates.
11582      */
11583     free(aggsig);
11584     free(aggsig_tag);
11585 
11586     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
11587     aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
11588 
11589     dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11590             "FUNCTION",
11591             aggsig, NULL, aggsig_tag,
11592             agginfo->aggfn.dobj.namespace->dobj.name,
11593             agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11594 
11595     free(aggsig);
11596     free(aggsig_tag);
11597 
11598     PQclear(res);
11599 
11600     destroyPQExpBuffer(query);
11601     destroyPQExpBuffer(q);
11602     destroyPQExpBuffer(delq);
11603     destroyPQExpBuffer(labelq);
11604     destroyPQExpBuffer(details);
11605 }
11606 
11607 /*
11608  * dumpTSParser
11609  *    write out a single text search parser
11610  */
11611 static void
11612 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11613 {
11614     PQExpBuffer q;
11615     PQExpBuffer delq;
11616     PQExpBuffer labelq;
11617 
11618     /* Skip if not to be dumped */
11619     if (!prsinfo->dobj.dump || dataOnly)
11620         return;
11621 
11622     q = createPQExpBuffer();
11623     delq = createPQExpBuffer();
11624     labelq = createPQExpBuffer();
11625 
11626     /* Make sure we are in proper schema */
11627     selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
11628 
11629     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11630                       fmtId(prsinfo->dobj.name));
11631 
11632     appendPQExpBuffer(q, "    START = %s,\n",
11633                       convertTSFunction(fout, prsinfo->prsstart));
11634     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11635                       convertTSFunction(fout, prsinfo->prstoken));
11636     appendPQExpBuffer(q, "    END = %s,\n",
11637                       convertTSFunction(fout, prsinfo->prsend));
11638     if (prsinfo->prsheadline != InvalidOid)
11639         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11640                           convertTSFunction(fout, prsinfo->prsheadline));
11641     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11642                       convertTSFunction(fout, prsinfo->prslextype));
11643 
11644     /*
11645      * DROP must be fully qualified in case same name appears in pg_catalog
11646      */
11647     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11648                       fmtId(prsinfo->dobj.namespace->dobj.name));
11649     appendPQExpBuffer(delq, ".%s;\n",
11650                       fmtId(prsinfo->dobj.name));
11651 
11652     appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11653                       fmtId(prsinfo->dobj.name));
11654 
11655     if (binary_upgrade)
11656         binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11657 
11658     ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11659                  prsinfo->dobj.name,
11660                  prsinfo->dobj.namespace->dobj.name,
11661                  NULL,
11662                  "",
11663                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11664                  q->data, delq->data, NULL,
11665                  NULL, 0,
11666                  NULL, NULL);
11667 
11668     /* Dump Parser Comments */
11669     dumpComment(fout, labelq->data,
11670                 NULL, "",
11671                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11672 
11673     destroyPQExpBuffer(q);
11674     destroyPQExpBuffer(delq);
11675     destroyPQExpBuffer(labelq);
11676 }
11677 
11678 /*
11679  * dumpTSDictionary
11680  *    write out a single text search dictionary
11681  */
11682 static void
11683 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11684 {
11685     PQExpBuffer q;
11686     PQExpBuffer delq;
11687     PQExpBuffer labelq;
11688     PQExpBuffer query;
11689     PGresult   *res;
11690     char       *nspname;
11691     char       *tmplname;
11692 
11693     /* Skip if not to be dumped */
11694     if (!dictinfo->dobj.dump || dataOnly)
11695         return;
11696 
11697     q = createPQExpBuffer();
11698     delq = createPQExpBuffer();
11699     labelq = createPQExpBuffer();
11700     query = createPQExpBuffer();
11701 
11702     /* Fetch name and namespace of the dictionary's template */
11703     selectSourceSchema(fout, "pg_catalog");
11704     appendPQExpBuffer(query, "SELECT nspname, tmplname "
11705                       "FROM pg_ts_template p, pg_namespace n "
11706                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11707                       dictinfo->dicttemplate);
11708     res = ExecuteSqlQueryForSingleRow(fout, query->data);
11709     nspname = PQgetvalue(res, 0, 0);
11710     tmplname = PQgetvalue(res, 0, 1);
11711 
11712     /* Make sure we are in proper schema */
11713     selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
11714 
11715     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11716                       fmtId(dictinfo->dobj.name));
11717 
11718     appendPQExpBuffer(q, "    TEMPLATE = ");
11719     if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11720         appendPQExpBuffer(q, "%s.", fmtId(nspname));
11721     appendPQExpBuffer(q, "%s", fmtId(tmplname));
11722 
11723     PQclear(res);
11724 
11725     /* the dictinitoption can be dumped straight into the command */
11726     if (dictinfo->dictinitoption)
11727         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11728 
11729     appendPQExpBuffer(q, " );\n");
11730 
11731     /*
11732      * DROP must be fully qualified in case same name appears in pg_catalog
11733      */
11734     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11735                       fmtId(dictinfo->dobj.namespace->dobj.name));
11736     appendPQExpBuffer(delq, ".%s;\n",
11737                       fmtId(dictinfo->dobj.name));
11738 
11739     appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11740                       fmtId(dictinfo->dobj.name));
11741 
11742     if (binary_upgrade)
11743         binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11744 
11745     ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11746                  dictinfo->dobj.name,
11747                  dictinfo->dobj.namespace->dobj.name,
11748                  NULL,
11749                  dictinfo->rolname,
11750                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11751                  q->data, delq->data, NULL,
11752                  NULL, 0,
11753                  NULL, NULL);
11754 
11755     /* Dump Dictionary Comments */
11756     dumpComment(fout, labelq->data,
11757                 NULL, dictinfo->rolname,
11758                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11759 
11760     destroyPQExpBuffer(q);
11761     destroyPQExpBuffer(delq);
11762     destroyPQExpBuffer(labelq);
11763     destroyPQExpBuffer(query);
11764 }
11765 
11766 /*
11767  * dumpTSTemplate
11768  *    write out a single text search template
11769  */
11770 static void
11771 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11772 {
11773     PQExpBuffer q;
11774     PQExpBuffer delq;
11775     PQExpBuffer labelq;
11776 
11777     /* Skip if not to be dumped */
11778     if (!tmplinfo->dobj.dump || dataOnly)
11779         return;
11780 
11781     q = createPQExpBuffer();
11782     delq = createPQExpBuffer();
11783     labelq = createPQExpBuffer();
11784 
11785     /* Make sure we are in proper schema */
11786     selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
11787 
11788     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
11789                       fmtId(tmplinfo->dobj.name));
11790 
11791     if (tmplinfo->tmplinit != InvalidOid)
11792         appendPQExpBuffer(q, "    INIT = %s,\n",
11793                           convertTSFunction(fout, tmplinfo->tmplinit));
11794     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
11795                       convertTSFunction(fout, tmplinfo->tmpllexize));
11796 
11797     /*
11798      * DROP must be fully qualified in case same name appears in pg_catalog
11799      */
11800     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
11801                       fmtId(tmplinfo->dobj.namespace->dobj.name));
11802     appendPQExpBuffer(delq, ".%s;\n",
11803                       fmtId(tmplinfo->dobj.name));
11804 
11805     appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
11806                       fmtId(tmplinfo->dobj.name));
11807 
11808     if (binary_upgrade)
11809         binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
11810 
11811     ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
11812                  tmplinfo->dobj.name,
11813                  tmplinfo->dobj.namespace->dobj.name,
11814                  NULL,
11815                  "",
11816                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
11817                  q->data, delq->data, NULL,
11818                  NULL, 0,
11819                  NULL, NULL);
11820 
11821     /* Dump Template Comments */
11822     dumpComment(fout, labelq->data,
11823                 NULL, "",
11824                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
11825 
11826     destroyPQExpBuffer(q);
11827     destroyPQExpBuffer(delq);
11828     destroyPQExpBuffer(labelq);
11829 }
11830 
11831 /*
11832  * dumpTSConfig
11833  *    write out a single text search configuration
11834  */
11835 static void
11836 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
11837 {
11838     PQExpBuffer q;
11839     PQExpBuffer delq;
11840     PQExpBuffer labelq;
11841     PQExpBuffer query;
11842     PGresult   *res;
11843     char       *nspname;
11844     char       *prsname;
11845     int         ntups,
11846                 i;
11847     int         i_tokenname;
11848     int         i_dictname;
11849 
11850     /* Skip if not to be dumped */
11851     if (!cfginfo->dobj.dump || dataOnly)
11852         return;
11853 
11854     q = createPQExpBuffer();
11855     delq = createPQExpBuffer();
11856     labelq = createPQExpBuffer();
11857     query = createPQExpBuffer();
11858 
11859     /* Fetch name and namespace of the config's parser */
11860     selectSourceSchema(fout, "pg_catalog");
11861     appendPQExpBuffer(query, "SELECT nspname, prsname "
11862                       "FROM pg_ts_parser p, pg_namespace n "
11863                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
11864                       cfginfo->cfgparser);
11865     res = ExecuteSqlQueryForSingleRow(fout, query->data);
11866     nspname = PQgetvalue(res, 0, 0);
11867     prsname = PQgetvalue(res, 0, 1);
11868 
11869     /* Make sure we are in proper schema */
11870     selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
11871 
11872     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
11873                       fmtId(cfginfo->dobj.name));
11874 
11875     appendPQExpBuffer(q, "    PARSER = ");
11876     if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
11877         appendPQExpBuffer(q, "%s.", fmtId(nspname));
11878     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
11879 
11880     PQclear(res);
11881 
11882     resetPQExpBuffer(query);
11883     appendPQExpBuffer(query,
11884                       "SELECT \n"
11885                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
11886                       "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
11887                       "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
11888                       "FROM pg_catalog.pg_ts_config_map AS m \n"
11889                       "WHERE m.mapcfg = '%u' \n"
11890                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
11891                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
11892 
11893     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11894     ntups = PQntuples(res);
11895 
11896     i_tokenname = PQfnumber(res, "tokenname");
11897     i_dictname = PQfnumber(res, "dictname");
11898 
11899     for (i = 0; i < ntups; i++)
11900     {
11901         char       *tokenname = PQgetvalue(res, i, i_tokenname);
11902         char       *dictname = PQgetvalue(res, i, i_dictname);
11903 
11904         if (i == 0 ||
11905             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
11906         {
11907             /* starting a new token type, so start a new command */
11908             if (i > 0)
11909                 appendPQExpBuffer(q, ";\n");
11910             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
11911                               fmtId(cfginfo->dobj.name));
11912             /* tokenname needs quoting, dictname does NOT */
11913             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
11914                               fmtId(tokenname), dictname);
11915         }
11916         else
11917             appendPQExpBuffer(q, ", %s", dictname);
11918     }
11919 
11920     if (ntups > 0)
11921         appendPQExpBuffer(q, ";\n");
11922 
11923     PQclear(res);
11924 
11925     /*
11926      * DROP must be fully qualified in case same name appears in pg_catalog
11927      */
11928     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
11929                       fmtId(cfginfo->dobj.namespace->dobj.name));
11930     appendPQExpBuffer(delq, ".%s;\n",
11931                       fmtId(cfginfo->dobj.name));
11932 
11933     appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
11934                       fmtId(cfginfo->dobj.name));
11935 
11936     if (binary_upgrade)
11937         binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
11938 
11939     ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
11940                  cfginfo->dobj.name,
11941                  cfginfo->dobj.namespace->dobj.name,
11942                  NULL,
11943                  cfginfo->rolname,
11944                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
11945                  q->data, delq->data, NULL,
11946                  NULL, 0,
11947                  NULL, NULL);
11948 
11949     /* Dump Configuration Comments */
11950     dumpComment(fout, labelq->data,
11951                 NULL, cfginfo->rolname,
11952                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
11953 
11954     destroyPQExpBuffer(q);
11955     destroyPQExpBuffer(delq);
11956     destroyPQExpBuffer(labelq);
11957     destroyPQExpBuffer(query);
11958 }
11959 
11960 /*
11961  * dumpForeignDataWrapper
11962  *    write out a single foreign-data wrapper definition
11963  */
11964 static void
11965 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
11966 {
11967     PQExpBuffer q;
11968     PQExpBuffer delq;
11969     PQExpBuffer labelq;
11970     char       *qfdwname;
11971 
11972     /* Skip if not to be dumped */
11973     if (!fdwinfo->dobj.dump || dataOnly)
11974         return;
11975 
11976     /*
11977      * FDWs that belong to an extension are dumped based on their "dump"
11978      * field. Otherwise omit them if we are only dumping some specific object.
11979      */
11980     if (!fdwinfo->dobj.ext_member)
11981         if (!include_everything)
11982             return;
11983 
11984     q = createPQExpBuffer();
11985     delq = createPQExpBuffer();
11986     labelq = createPQExpBuffer();
11987 
11988     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
11989 
11990     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
11991                       qfdwname);
11992 
11993     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
11994         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
11995 
11996     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
11997         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
11998 
11999     if (strlen(fdwinfo->fdwoptions) > 0)
12000         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
12001 
12002     appendPQExpBuffer(q, ";\n");
12003 
12004     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
12005                       qfdwname);
12006 
12007     appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
12008                       qfdwname);
12009 
12010     if (binary_upgrade)
12011         binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
12012 
12013     ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12014                  fdwinfo->dobj.name,
12015                  NULL,
12016                  NULL,
12017                  fdwinfo->rolname,
12018                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
12019                  q->data, delq->data, NULL,
12020                  NULL, 0,
12021                  NULL, NULL);
12022 
12023     /* Handle the ACL */
12024     dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12025             "FOREIGN DATA WRAPPER",
12026             qfdwname, NULL, fdwinfo->dobj.name,
12027             NULL, fdwinfo->rolname,
12028             fdwinfo->fdwacl);
12029 
12030     /* Dump Foreign Data Wrapper Comments */
12031     dumpComment(fout, labelq->data,
12032                 NULL, fdwinfo->rolname,
12033                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
12034 
12035     free(qfdwname);
12036 
12037     destroyPQExpBuffer(q);
12038     destroyPQExpBuffer(delq);
12039     destroyPQExpBuffer(labelq);
12040 }
12041 
12042 /*
12043  * dumpForeignServer
12044  *    write out a foreign server definition
12045  */
12046 static void
12047 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
12048 {
12049     PQExpBuffer q;
12050     PQExpBuffer delq;
12051     PQExpBuffer labelq;
12052     PQExpBuffer query;
12053     PGresult   *res;
12054     char       *qsrvname;
12055     char       *fdwname;
12056 
12057     /* Skip if not to be dumped */
12058     if (!srvinfo->dobj.dump || dataOnly || !include_everything)
12059         return;
12060 
12061     q = createPQExpBuffer();
12062     delq = createPQExpBuffer();
12063     labelq = createPQExpBuffer();
12064     query = createPQExpBuffer();
12065 
12066     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
12067 
12068     /* look up the foreign-data wrapper */
12069     selectSourceSchema(fout, "pg_catalog");
12070     appendPQExpBuffer(query, "SELECT fdwname "
12071                       "FROM pg_foreign_data_wrapper w "
12072                       "WHERE w.oid = '%u'",
12073                       srvinfo->srvfdw);
12074     res = ExecuteSqlQueryForSingleRow(fout, query->data);
12075     fdwname = PQgetvalue(res, 0, 0);
12076 
12077     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
12078     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
12079     {
12080         appendPQExpBuffer(q, " TYPE ");
12081         appendStringLiteralAH(q, srvinfo->srvtype, fout);
12082     }
12083     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
12084     {
12085         appendPQExpBuffer(q, " VERSION ");
12086         appendStringLiteralAH(q, srvinfo->srvversion, fout);
12087     }
12088 
12089     appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
12090     appendPQExpBuffer(q, "%s", fmtId(fdwname));
12091 
12092     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
12093         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
12094 
12095     appendPQExpBuffer(q, ";\n");
12096 
12097     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
12098                       qsrvname);
12099 
12100     appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
12101 
12102     if (binary_upgrade)
12103         binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
12104 
12105     ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12106                  srvinfo->dobj.name,
12107                  NULL,
12108                  NULL,
12109                  srvinfo->rolname,
12110                  false, "SERVER", SECTION_PRE_DATA,
12111                  q->data, delq->data, NULL,
12112                  NULL, 0,
12113                  NULL, NULL);
12114 
12115     /* Handle the ACL */
12116     dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12117             "FOREIGN SERVER",
12118             qsrvname, NULL, srvinfo->dobj.name,
12119             NULL, srvinfo->rolname,
12120             srvinfo->srvacl);
12121 
12122     /* Dump user mappings */
12123     dumpUserMappings(fout,
12124                      srvinfo->dobj.name, NULL,
12125                      srvinfo->rolname,
12126                      srvinfo->dobj.catId, srvinfo->dobj.dumpId);
12127 
12128     /* Dump Foreign Server Comments */
12129     dumpComment(fout, labelq->data,
12130                 NULL, srvinfo->rolname,
12131                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
12132 
12133     free(qsrvname);
12134 
12135     destroyPQExpBuffer(q);
12136     destroyPQExpBuffer(delq);
12137     destroyPQExpBuffer(labelq);
12138 }
12139 
12140 /*
12141  * dumpUserMappings
12142  *
12143  * This routine is used to dump any user mappings associated with the
12144  * server handed to this routine. Should be called after ArchiveEntry()
12145  * for the server.
12146  */
12147 static void
12148 dumpUserMappings(Archive *fout,
12149                  const char *servername, const char *namespace,
12150                  const char *owner,
12151                  CatalogId catalogId, DumpId dumpId)
12152 {
12153     PQExpBuffer q;
12154     PQExpBuffer delq;
12155     PQExpBuffer query;
12156     PQExpBuffer tag;
12157     PGresult   *res;
12158     int         ntups;
12159     int         i_usename;
12160     int         i_umoptions;
12161     int         i;
12162 
12163     q = createPQExpBuffer();
12164     tag = createPQExpBuffer();
12165     delq = createPQExpBuffer();
12166     query = createPQExpBuffer();
12167 
12168     /*
12169      * We read from the publicly accessible view pg_user_mappings, so as not
12170      * to fail if run by a non-superuser.  Note that the view will show
12171      * umoptions as null if the user hasn't got privileges for the associated
12172      * server; this means that pg_dump will dump such a mapping, but with no
12173      * OPTIONS clause.  A possible alternative is to skip such mappings
12174      * altogether, but it's not clear that that's an improvement.
12175      */
12176     selectSourceSchema(fout, "pg_catalog");
12177 
12178     appendPQExpBuffer(query,
12179                       "SELECT usename, "
12180                       "array_to_string(ARRAY("
12181                       "SELECT quote_ident(option_name) || ' ' || "
12182                       "quote_literal(option_value) "
12183                       "FROM pg_options_to_table(umoptions) "
12184                       "ORDER BY option_name"
12185                       "), E',\n    ') AS umoptions "
12186                       "FROM pg_user_mappings "
12187                       "WHERE srvid = '%u' "
12188                       "ORDER BY usename",
12189                       catalogId.oid);
12190 
12191     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12192 
12193     ntups = PQntuples(res);
12194     i_usename = PQfnumber(res, "usename");
12195     i_umoptions = PQfnumber(res, "umoptions");
12196 
12197     for (i = 0; i < ntups; i++)
12198     {
12199         char       *usename;
12200         char       *umoptions;
12201 
12202         usename = PQgetvalue(res, i, i_usename);
12203         umoptions = PQgetvalue(res, i, i_umoptions);
12204 
12205         resetPQExpBuffer(q);
12206         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
12207         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
12208 
12209         if (umoptions && strlen(umoptions) > 0)
12210             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
12211 
12212         appendPQExpBuffer(q, ";\n");
12213 
12214         resetPQExpBuffer(delq);
12215         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
12216         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
12217 
12218         resetPQExpBuffer(tag);
12219         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
12220                           usename, servername);
12221 
12222         ArchiveEntry(fout, nilCatalogId, createDumpId(),
12223                      tag->data,
12224                      namespace,
12225                      NULL,
12226                      owner, false,
12227                      "USER MAPPING", SECTION_PRE_DATA,
12228                      q->data, delq->data, NULL,
12229                      &dumpId, 1,
12230                      NULL, NULL);
12231     }
12232 
12233     PQclear(res);
12234 
12235     destroyPQExpBuffer(query);
12236     destroyPQExpBuffer(delq);
12237     destroyPQExpBuffer(q);
12238 }
12239 
12240 /*
12241  * Write out default privileges information
12242  */
12243 static void
12244 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
12245 {
12246     PQExpBuffer q;
12247     PQExpBuffer tag;
12248     const char *type;
12249 
12250     /* Skip if not to be dumped */
12251     if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
12252         return;
12253 
12254     q = createPQExpBuffer();
12255     tag = createPQExpBuffer();
12256 
12257     switch (daclinfo->defaclobjtype)
12258     {
12259         case DEFACLOBJ_RELATION:
12260             type = "TABLES";
12261             break;
12262         case DEFACLOBJ_SEQUENCE:
12263             type = "SEQUENCES";
12264             break;
12265         case DEFACLOBJ_FUNCTION:
12266             type = "FUNCTIONS";
12267             break;
12268         case DEFACLOBJ_TYPE:
12269             type = "TYPES";
12270             break;
12271         default:
12272             /* shouldn't get here */
12273             exit_horribly(NULL,
12274                       "unrecognized object type in default privileges: %d\n",
12275                           (int) daclinfo->defaclobjtype);
12276             type = "";          /* keep compiler quiet */
12277     }
12278 
12279     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
12280 
12281     /* build the actual command(s) for this tuple */
12282     if (!buildDefaultACLCommands(type,
12283                                  daclinfo->dobj.namespace != NULL ?
12284                                  daclinfo->dobj.namespace->dobj.name : NULL,
12285                                  daclinfo->defaclacl,
12286                                  daclinfo->defaclrole,
12287                                  fout->remoteVersion,
12288                                  q))
12289         exit_horribly(NULL, "could not parse default ACL list (%s)\n",
12290                       daclinfo->defaclacl);
12291 
12292     ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
12293                  tag->data,
12294        daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
12295                  NULL,
12296                  daclinfo->defaclrole,
12297                  false, "DEFAULT ACL", SECTION_POST_DATA,
12298                  q->data, "", NULL,
12299                  NULL, 0,
12300                  NULL, NULL);
12301 
12302     destroyPQExpBuffer(tag);
12303     destroyPQExpBuffer(q);
12304 }
12305 
12306 /*----------
12307  * Write out grant/revoke information
12308  *
12309  * 'objCatId' is the catalog ID of the underlying object.
12310  * 'objDumpId' is the dump ID of the underlying object.
12311  * 'type' must be one of
12312  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
12313  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
12314  * 'name' is the formatted name of the object.  Must be quoted etc. already.
12315  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
12316  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
12317  * 'nspname' is the namespace the object is in (NULL if none).
12318  * 'owner' is the owner, NULL if there is no owner (for languages).
12319  * 'acls' is the string read out of the fooacl system catalog field;
12320  *      it will be parsed here.
12321  *----------
12322  */
12323 static void
12324 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
12325         const char *type, const char *name, const char *subname,
12326         const char *tag, const char *nspname, const char *owner,
12327         const char *acls)
12328 {
12329     PQExpBuffer sql;
12330 
12331     /* Do nothing if ACL dump is not enabled */
12332     if (aclsSkip)
12333         return;
12334 
12335     /* --data-only skips ACLs *except* BLOB ACLs */
12336     if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
12337         return;
12338 
12339     sql = createPQExpBuffer();
12340 
12341     if (!buildACLCommands(name, subname, type, acls, owner,
12342                           "", fout->remoteVersion, sql))
12343         exit_horribly(NULL,
12344                     "could not parse ACL list (%s) for object \"%s\" (%s)\n",
12345                       acls, name, type);
12346 
12347     if (sql->len > 0)
12348         ArchiveEntry(fout, nilCatalogId, createDumpId(),
12349                      tag, nspname,
12350                      NULL,
12351                      owner ? owner : "",
12352                      false, "ACL", SECTION_NONE,
12353                      sql->data, "", NULL,
12354                      &(objDumpId), 1,
12355                      NULL, NULL);
12356 
12357     destroyPQExpBuffer(sql);
12358 }
12359 
12360 /*
12361  * dumpSecLabel
12362  *
12363  * This routine is used to dump any security labels associated with the
12364  * object handed to this routine. The routine takes a constant character
12365  * string for the target part of the security-label command, plus
12366  * the namespace and owner of the object (for labeling the ArchiveEntry),
12367  * plus catalog ID and subid which are the lookup key for pg_seclabel,
12368  * plus the dump ID for the object (for setting a dependency).
12369  * If a matching pg_seclabel entry is found, it is dumped.
12370  *
12371  * Note: although this routine takes a dumpId for dependency purposes,
12372  * that purpose is just to mark the dependency in the emitted dump file
12373  * for possible future use by pg_restore.  We do NOT use it for determining
12374  * ordering of the label in the dump file, because this routine is called
12375  * after dependency sorting occurs.  This routine should be called just after
12376  * calling ArchiveEntry() for the specified object.
12377  */
12378 static void
12379 dumpSecLabel(Archive *fout, const char *target,
12380              const char *namespace, const char *owner,
12381              CatalogId catalogId, int subid, DumpId dumpId)
12382 {
12383     SecLabelItem *labels;
12384     int         nlabels;
12385     int         i;
12386     PQExpBuffer query;
12387 
12388     /* do nothing, if --no-security-labels is supplied */
12389     if (no_security_labels)
12390         return;
12391 
12392     /* Comments are schema not data ... except blob comments are data */
12393     if (strncmp(target, "LARGE OBJECT ", 13) != 0)
12394     {
12395         if (dataOnly)
12396             return;
12397     }
12398     else
12399     {
12400         if (schemaOnly)
12401             return;
12402     }
12403 
12404     /* Search for security labels associated with catalogId, using table */
12405     nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
12406 
12407     query = createPQExpBuffer();
12408 
12409     for (i = 0; i < nlabels; i++)
12410     {
12411         /*
12412          * Ignore label entries for which the subid doesn't match.
12413          */
12414         if (labels[i].objsubid != subid)
12415             continue;
12416 
12417         appendPQExpBuffer(query,
12418                           "SECURITY LABEL FOR %s ON %s IS ",
12419                           fmtId(labels[i].provider), target);
12420         appendStringLiteralAH(query, labels[i].label, fout);
12421         appendPQExpBuffer(query, ";\n");
12422     }
12423 
12424     if (query->len > 0)
12425     {
12426         ArchiveEntry(fout, nilCatalogId, createDumpId(),
12427                      target, namespace, NULL, owner,
12428                      false, "SECURITY LABEL", SECTION_NONE,
12429                      query->data, "", NULL,
12430                      &(dumpId), 1,
12431                      NULL, NULL);
12432     }
12433     destroyPQExpBuffer(query);
12434 }
12435 
12436 /*
12437  * dumpTableSecLabel
12438  *
12439  * As above, but dump security label for both the specified table (or view)
12440  * and its columns.
12441  */
12442 static void
12443 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
12444 {
12445     SecLabelItem *labels;
12446     int         nlabels;
12447     int         i;
12448     PQExpBuffer query;
12449     PQExpBuffer target;
12450 
12451     /* do nothing, if --no-security-labels is supplied */
12452     if (no_security_labels)
12453         return;
12454 
12455     /* SecLabel are SCHEMA not data */
12456     if (dataOnly)
12457         return;
12458 
12459     /* Search for comments associated with relation, using table */
12460     nlabels = findSecLabels(fout,
12461                             tbinfo->dobj.catId.tableoid,
12462                             tbinfo->dobj.catId.oid,
12463                             &labels);
12464 
12465     /* If security labels exist, build SECURITY LABEL statements */
12466     if (nlabels <= 0)
12467         return;
12468 
12469     query = createPQExpBuffer();
12470     target = createPQExpBuffer();
12471 
12472     for (i = 0; i < nlabels; i++)
12473     {
12474         const char *colname;
12475         const char *provider = labels[i].provider;
12476         const char *label = labels[i].label;
12477         int         objsubid = labels[i].objsubid;
12478 
12479         resetPQExpBuffer(target);
12480         if (objsubid == 0)
12481         {
12482             appendPQExpBuffer(target, "%s %s", reltypename,
12483                               fmtId(tbinfo->dobj.name));
12484         }
12485         else
12486         {
12487             colname = getAttrName(objsubid, tbinfo);
12488             /* first fmtId result must be consumed before calling it again */
12489             appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12490             appendPQExpBuffer(target, ".%s", fmtId(colname));
12491         }
12492         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12493                           fmtId(provider), target->data);
12494         appendStringLiteralAH(query, label, fout);
12495         appendPQExpBuffer(query, ";\n");
12496     }
12497     if (query->len > 0)
12498     {
12499         resetPQExpBuffer(target);
12500         appendPQExpBuffer(target, "%s %s", reltypename,
12501                           fmtId(tbinfo->dobj.name));
12502         ArchiveEntry(fout, nilCatalogId, createDumpId(),
12503                      target->data,
12504                      tbinfo->dobj.namespace->dobj.name,
12505                      NULL, tbinfo->rolname,
12506                      false, "SECURITY LABEL", SECTION_NONE,
12507                      query->data, "", NULL,
12508                      &(tbinfo->dobj.dumpId), 1,
12509                      NULL, NULL);
12510     }
12511     destroyPQExpBuffer(query);
12512     destroyPQExpBuffer(target);
12513 }
12514 
12515 /*
12516  * findSecLabels
12517  *
12518  * Find the security label(s), if any, associated with the given object.
12519  * All the objsubid values associated with the given classoid/objoid are
12520  * found with one search.
12521  */
12522 static int
12523 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12524 {
12525     /* static storage for table of security labels */
12526     static SecLabelItem *labels = NULL;
12527     static int  nlabels = -1;
12528 
12529     SecLabelItem *middle = NULL;
12530     SecLabelItem *low;
12531     SecLabelItem *high;
12532     int         nmatch;
12533 
12534     /* Get security labels if we didn't already */
12535     if (nlabels < 0)
12536         nlabels = collectSecLabels(fout, &labels);
12537 
12538     if (nlabels <= 0)           /* no labels, so no match is possible */
12539     {
12540         *items = NULL;
12541         return 0;
12542     }
12543 
12544     /*
12545      * Do binary search to find some item matching the object.
12546      */
12547     low = &labels[0];
12548     high = &labels[nlabels - 1];
12549     while (low <= high)
12550     {
12551         middle = low + (high - low) / 2;
12552 
12553         if (classoid < middle->classoid)
12554             high = middle - 1;
12555         else if (classoid > middle->classoid)
12556             low = middle + 1;
12557         else if (objoid < middle->objoid)
12558             high = middle - 1;
12559         else if (objoid > middle->objoid)
12560             low = middle + 1;
12561         else
12562             break;              /* found a match */
12563     }
12564 
12565     if (low > high)             /* no matches */
12566     {
12567         *items = NULL;
12568         return 0;
12569     }
12570 
12571     /*
12572      * Now determine how many items match the object.  The search loop
12573      * invariant still holds: only items between low and high inclusive could
12574      * match.
12575      */
12576     nmatch = 1;
12577     while (middle > low)
12578     {
12579         if (classoid != middle[-1].classoid ||
12580             objoid != middle[-1].objoid)
12581             break;
12582         middle--;
12583         nmatch++;
12584     }
12585 
12586     *items = middle;
12587 
12588     middle += nmatch;
12589     while (middle <= high)
12590     {
12591         if (classoid != middle->classoid ||
12592             objoid != middle->objoid)
12593             break;
12594         middle++;
12595         nmatch++;
12596     }
12597 
12598     return nmatch;
12599 }
12600 
12601 /*
12602  * collectSecLabels
12603  *
12604  * Construct a table of all security labels available for database objects.
12605  * It's much faster to pull them all at once.
12606  *
12607  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12608  */
12609 static int
12610 collectSecLabels(Archive *fout, SecLabelItem **items)
12611 {
12612     PGresult   *res;
12613     PQExpBuffer query;
12614     int         i_label;
12615     int         i_provider;
12616     int         i_classoid;
12617     int         i_objoid;
12618     int         i_objsubid;
12619     int         ntups;
12620     int         i;
12621     SecLabelItem *labels;
12622 
12623     query = createPQExpBuffer();
12624 
12625     appendPQExpBuffer(query,
12626                       "SELECT label, provider, classoid, objoid, objsubid "
12627                       "FROM pg_catalog.pg_seclabel "
12628                       "ORDER BY classoid, objoid, objsubid");
12629 
12630     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12631 
12632     /* Construct lookup table containing OIDs in numeric form */
12633     i_label = PQfnumber(res, "label");
12634     i_provider = PQfnumber(res, "provider");
12635     i_classoid = PQfnumber(res, "classoid");
12636     i_objoid = PQfnumber(res, "objoid");
12637     i_objsubid = PQfnumber(res, "objsubid");
12638 
12639     ntups = PQntuples(res);
12640 
12641     labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12642 
12643     for (i = 0; i < ntups; i++)
12644     {
12645         labels[i].label = PQgetvalue(res, i, i_label);
12646         labels[i].provider = PQgetvalue(res, i, i_provider);
12647         labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12648         labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12649         labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12650     }
12651 
12652     /* Do NOT free the PGresult since we are keeping pointers into it */
12653     destroyPQExpBuffer(query);
12654 
12655     *items = labels;
12656     return ntups;
12657 }
12658 
12659 /*
12660  * dumpTable
12661  *    write out to fout the declarations (not data) of a user-defined table
12662  */
12663 static void
12664 dumpTable(Archive *fout, TableInfo *tbinfo)
12665 {
12666     if (tbinfo->dobj.dump && !dataOnly)
12667     {
12668         char       *namecopy;
12669 
12670         if (tbinfo->relkind == RELKIND_SEQUENCE)
12671             dumpSequence(fout, tbinfo);
12672         else
12673             dumpTableSchema(fout, tbinfo);
12674 
12675         /* Handle the ACL here */
12676         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12677         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12678                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12679                 "TABLE",
12680                 namecopy, NULL, tbinfo->dobj.name,
12681                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12682                 tbinfo->relacl);
12683 
12684         /*
12685          * Handle column ACLs, if any.  Note: we pull these with a separate
12686          * query rather than trying to fetch them during getTableAttrs, so
12687          * that we won't miss ACLs on system columns.
12688          */
12689         if (fout->remoteVersion >= 80400)
12690         {
12691             PQExpBuffer query = createPQExpBuffer();
12692             PGresult   *res;
12693             int         i;
12694 
12695             appendPQExpBuffer(query,
12696                        "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12697                               "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12698                               "ORDER BY attnum",
12699                               tbinfo->dobj.catId.oid);
12700             res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12701 
12702             for (i = 0; i < PQntuples(res); i++)
12703             {
12704                 char       *attname = PQgetvalue(res, i, 0);
12705                 char       *attacl = PQgetvalue(res, i, 1);
12706                 char       *attnamecopy;
12707                 char       *acltag;
12708 
12709                 attnamecopy = pg_strdup(fmtId(attname));
12710                 acltag = pg_malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
12711                 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
12712                 /* Column's GRANT type is always TABLE */
12713                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12714                         namecopy, attnamecopy, acltag,
12715                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12716                         attacl);
12717                 free(attnamecopy);
12718                 free(acltag);
12719             }
12720             PQclear(res);
12721             destroyPQExpBuffer(query);
12722         }
12723 
12724         free(namecopy);
12725     }
12726 }
12727 
12728 /*
12729  * Create the AS clause for a view or materialized view. The semicolon is
12730  * stripped because a materialized view must add a WITH NO DATA clause.
12731  *
12732  * This returns a new buffer which must be freed by the caller.
12733  */
12734 static PQExpBuffer
12735 createViewAsClause(Archive *fout, TableInfo *tbinfo)
12736 {
12737     PQExpBuffer query = createPQExpBuffer();
12738     PQExpBuffer result = createPQExpBuffer();
12739     PGresult   *res;
12740     int         len;
12741 
12742     /* Fetch the view definition */
12743     if (fout->remoteVersion >= 70300)
12744     {
12745         /* Beginning in 7.3, viewname is not unique; rely on OID */
12746         appendPQExpBuffer(query,
12747          "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12748                           tbinfo->dobj.catId.oid);
12749     }
12750     else
12751     {
12752         appendPQExpBuffer(query, "SELECT definition AS viewdef "
12753                           "FROM pg_views WHERE viewname = ");
12754         appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12755         appendPQExpBuffer(query, ";");
12756     }
12757 
12758     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12759 
12760     if (PQntuples(res) != 1)
12761     {
12762         if (PQntuples(res) < 1)
12763             exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12764                           tbinfo->dobj.name);
12765         else
12766             exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12767                           tbinfo->dobj.name);
12768     }
12769 
12770     len = PQgetlength(res, 0, 0);
12771 
12772     if (len == 0)
12773         exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12774                       tbinfo->dobj.name);
12775 
12776     /* Strip off the trailing semicolon so that other things may follow. */
12777     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
12778     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
12779 
12780     PQclear(res);
12781     destroyPQExpBuffer(query);
12782 
12783     return result;
12784 }
12785 
12786 /*
12787  * dumpTableSchema
12788  *    write the declaration (not data) of one user-defined table or view
12789  */
12790 static void
12791 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
12792 {
12793     PQExpBuffer q = createPQExpBuffer();
12794     PQExpBuffer delq = createPQExpBuffer();
12795     PQExpBuffer labelq = createPQExpBuffer();
12796     int         numParents;
12797     TableInfo **parents;
12798     int         actual_atts;    /* number of attrs in this CREATE statement */
12799     const char *reltypename;
12800     char       *storage;
12801     char       *srvname;
12802     char       *ftoptions;
12803     int         j,
12804                 k;
12805 
12806     /* Make sure we are in proper schema */
12807     selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
12808 
12809     if (binary_upgrade)
12810         binary_upgrade_set_type_oids_by_rel_oid(fout, q,
12811                                                 tbinfo->dobj.catId.oid);
12812 
12813     /* Is it a table or a view? */
12814     if (tbinfo->relkind == RELKIND_VIEW)
12815     {
12816         PQExpBuffer result;
12817 
12818         reltypename = "VIEW";
12819 
12820         /*
12821          * DROP must be fully qualified in case same name appears in
12822          * pg_catalog
12823          */
12824         appendPQExpBuffer(delq, "DROP VIEW %s.",
12825                           fmtId(tbinfo->dobj.namespace->dobj.name));
12826         appendPQExpBuffer(delq, "%s;\n",
12827                           fmtId(tbinfo->dobj.name));
12828 
12829         if (binary_upgrade)
12830             binary_upgrade_set_pg_class_oids(fout, q,
12831                                              tbinfo->dobj.catId.oid, false);
12832 
12833         appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
12834         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12835             appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
12836         result = createViewAsClause(fout, tbinfo);
12837         appendPQExpBuffer(q, " AS\n%s;\n", result->data);
12838         destroyPQExpBuffer(result);
12839 
12840         appendPQExpBuffer(labelq, "VIEW %s",
12841                           fmtId(tbinfo->dobj.name));
12842     }
12843     else
12844     {
12845         switch (tbinfo->relkind)
12846         {
12847             case (RELKIND_FOREIGN_TABLE):
12848                 {
12849                     PQExpBuffer query = createPQExpBuffer();
12850                     PGresult   *res;
12851                     int         i_srvname;
12852                     int         i_ftoptions;
12853 
12854                     reltypename = "FOREIGN TABLE";
12855 
12856                     /* retrieve name of foreign server and generic options */
12857                     appendPQExpBuffer(query,
12858                                       "SELECT fs.srvname, "
12859                                       "pg_catalog.array_to_string(ARRAY("
12860                              "SELECT pg_catalog.quote_ident(option_name) || "
12861                              "' ' || pg_catalog.quote_literal(option_value) "
12862                             "FROM pg_catalog.pg_options_to_table(ftoptions) "
12863                                       "ORDER BY option_name"
12864                                       "), E',\n    ') AS ftoptions "
12865                                       "FROM pg_catalog.pg_foreign_table ft "
12866                                       "JOIN pg_catalog.pg_foreign_server fs "
12867                                       "ON (fs.oid = ft.ftserver) "
12868                                       "WHERE ft.ftrelid = '%u'",
12869                                       tbinfo->dobj.catId.oid);
12870                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
12871                     i_srvname = PQfnumber(res, "srvname");
12872                     i_ftoptions = PQfnumber(res, "ftoptions");
12873                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
12874                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
12875                     PQclear(res);
12876                     destroyPQExpBuffer(query);
12877                     break;
12878                 }
12879             case (RELKIND_MATVIEW):
12880                 reltypename = "MATERIALIZED VIEW";
12881                 srvname = NULL;
12882                 ftoptions = NULL;
12883                 break;
12884             default:
12885                 reltypename = "TABLE";
12886                 srvname = NULL;
12887                 ftoptions = NULL;
12888         }
12889 
12890         numParents = tbinfo->numParents;
12891         parents = tbinfo->parents;
12892 
12893         /*
12894          * DROP must be fully qualified in case same name appears in
12895          * pg_catalog
12896          */
12897         appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
12898                           fmtId(tbinfo->dobj.namespace->dobj.name));
12899         appendPQExpBuffer(delq, "%s;\n",
12900                           fmtId(tbinfo->dobj.name));
12901 
12902         appendPQExpBuffer(labelq, "%s %s", reltypename,
12903                           fmtId(tbinfo->dobj.name));
12904 
12905         if (binary_upgrade)
12906             binary_upgrade_set_pg_class_oids(fout, q,
12907                                              tbinfo->dobj.catId.oid, false);
12908 
12909         appendPQExpBuffer(q, "CREATE %s%s %s",
12910                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
12911                           "UNLOGGED " : "",
12912                           reltypename,
12913                           fmtId(tbinfo->dobj.name));
12914 
12915         /*
12916          * Attach to type, if reloftype; except in case of a binary upgrade,
12917          * we dump the table normally and attach it to the type afterward.
12918          */
12919         if (tbinfo->reloftype && !binary_upgrade)
12920             appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
12921 
12922         if (tbinfo->relkind != RELKIND_MATVIEW)
12923         {
12924             /* Dump the attributes */
12925             actual_atts = 0;
12926             for (j = 0; j < tbinfo->numatts; j++)
12927             {
12928                 /*
12929                  * Normally, dump if it's locally defined in this table, and
12930                  * not dropped.  But for binary upgrade, we'll dump all the
12931                  * columns, and then fix up the dropped and nonlocal cases
12932                  * below.
12933                  */
12934                 if (shouldPrintColumn(tbinfo, j))
12935                 {
12936                     /*
12937                      * Default value --- suppress if to be printed separately.
12938                      */
12939                     bool        has_default = (tbinfo->attrdefs[j] != NULL &&
12940                                              !tbinfo->attrdefs[j]->separate);
12941 
12942                     /*
12943                      * Not Null constraint --- suppress if inherited, except
12944                      * in binary-upgrade case where that won't work.
12945                      */
12946                     bool        has_notnull = (tbinfo->notnull[j] &&
12947                                                (!tbinfo->inhNotNull[j] ||
12948                                                 binary_upgrade));
12949 
12950                     /* Skip column if fully defined by reloftype */
12951                     if (tbinfo->reloftype &&
12952                         !has_default && !has_notnull && !binary_upgrade)
12953                         continue;
12954 
12955                     /* Format properly if not first attr */
12956                     if (actual_atts == 0)
12957                         appendPQExpBuffer(q, " (");
12958                     else
12959                         appendPQExpBuffer(q, ",");
12960                     appendPQExpBuffer(q, "\n    ");
12961                     actual_atts++;
12962 
12963                     /* Attribute name */
12964                     appendPQExpBuffer(q, "%s",
12965                                       fmtId(tbinfo->attnames[j]));
12966 
12967                     if (tbinfo->attisdropped[j])
12968                     {
12969                         /*
12970                          * ALTER TABLE DROP COLUMN clears
12971                          * pg_attribute.atttypid, so we will not have gotten a
12972                          * valid type name; insert INTEGER as a stopgap. We'll
12973                          * clean things up later.
12974                          */
12975                         appendPQExpBuffer(q, " INTEGER /* dummy */");
12976                         /* Skip all the rest, too */
12977                         continue;
12978                     }
12979 
12980                     /* Attribute type */
12981                     if (tbinfo->reloftype && !binary_upgrade)
12982                     {
12983                         appendPQExpBuffer(q, " WITH OPTIONS");
12984                     }
12985                     else if (fout->remoteVersion >= 70100)
12986                     {
12987                         appendPQExpBuffer(q, " %s",
12988                                           tbinfo->atttypnames[j]);
12989                     }
12990                     else
12991                     {
12992                         /* If no format_type, fake it */
12993                         appendPQExpBuffer(q, " %s",
12994                                           myFormatType(tbinfo->atttypnames[j],
12995                                                        tbinfo->atttypmod[j]));
12996                     }
12997 
12998                     /* Add collation if not default for the type */
12999                     if (OidIsValid(tbinfo->attcollation[j]))
13000                     {
13001                         CollInfo   *coll;
13002 
13003                         coll = findCollationByOid(tbinfo->attcollation[j]);
13004                         if (coll)
13005                         {
13006                             /* always schema-qualify, don't try to be smart */
13007                             appendPQExpBuffer(q, " COLLATE %s.",
13008                                      fmtId(coll->dobj.namespace->dobj.name));
13009                             appendPQExpBuffer(q, "%s",
13010                                               fmtId(coll->dobj.name));
13011                         }
13012                     }
13013 
13014                     if (has_default)
13015                         appendPQExpBuffer(q, " DEFAULT %s",
13016                                           tbinfo->attrdefs[j]->adef_expr);
13017 
13018                     if (has_notnull)
13019                         appendPQExpBuffer(q, " NOT NULL");
13020                 }
13021             }
13022 
13023             /*
13024              * Add non-inherited CHECK constraints, if any.
13025              */
13026             for (j = 0; j < tbinfo->ncheck; j++)
13027             {
13028                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13029 
13030                 if (constr->separate || !constr->conislocal)
13031                     continue;
13032 
13033                 if (actual_atts == 0)
13034                     appendPQExpBuffer(q, " (\n    ");
13035                 else
13036                     appendPQExpBuffer(q, ",\n    ");
13037 
13038                 appendPQExpBuffer(q, "CONSTRAINT %s ",
13039                                   fmtId(constr->dobj.name));
13040                 appendPQExpBuffer(q, "%s", constr->condef);
13041 
13042                 actual_atts++;
13043             }
13044 
13045             if (actual_atts)
13046                 appendPQExpBuffer(q, "\n)");
13047             else if (!(tbinfo->reloftype && !binary_upgrade))
13048             {
13049                 /*
13050                  * We must have a parenthesized attribute list, even though
13051                  * empty, when not using the OF TYPE syntax.
13052                  */
13053                 appendPQExpBuffer(q, " (\n)");
13054             }
13055 
13056             if (numParents > 0 && !binary_upgrade)
13057             {
13058                 appendPQExpBuffer(q, "\nINHERITS (");
13059                 for (k = 0; k < numParents; k++)
13060                 {
13061                     TableInfo  *parentRel = parents[k];
13062 
13063                     if (k > 0)
13064                         appendPQExpBuffer(q, ", ");
13065                     if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13066                         appendPQExpBuffer(q, "%s.",
13067                                 fmtId(parentRel->dobj.namespace->dobj.name));
13068                     appendPQExpBuffer(q, "%s",
13069                                       fmtId(parentRel->dobj.name));
13070                 }
13071                 appendPQExpBuffer(q, ")");
13072             }
13073 
13074             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
13075                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
13076         }
13077 
13078         if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
13079           (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
13080         {
13081             bool        addcomma = false;
13082 
13083             appendPQExpBuffer(q, "\nWITH (");
13084             if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13085             {
13086                 addcomma = true;
13087                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
13088             }
13089             if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
13090             {
13091                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
13092                                   tbinfo->toast_reloptions);
13093             }
13094             appendPQExpBuffer(q, ")");
13095         }
13096 
13097         /* Dump generic options if any */
13098         if (ftoptions && ftoptions[0])
13099             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
13100 
13101         /*
13102          * For materialized views, create the AS clause just like a view.
13103          */
13104         if (tbinfo->relkind == RELKIND_MATVIEW)
13105         {
13106             PQExpBuffer result;
13107 
13108             result = createViewAsClause(fout, tbinfo);
13109             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
13110                               result->data);
13111             destroyPQExpBuffer(result);
13112         }
13113         else
13114             appendPQExpBuffer(q, ";\n");
13115 
13116         /*
13117          * To create binary-compatible heap files, we have to ensure the same
13118          * physical column order, including dropped columns, as in the
13119          * original.  Therefore, we create dropped columns above and drop them
13120          * here, also updating their attlen/attalign values so that the
13121          * dropped column can be skipped properly.  (We do not bother with
13122          * restoring the original attbyval setting.)  Also, inheritance
13123          * relationships are set up by doing ALTER INHERIT rather than using
13124          * an INHERITS clause --- the latter would possibly mess up the column
13125          * order.  That also means we have to take care about setting
13126          * attislocal correctly, plus fix up any inherited CHECK constraints.
13127          * Analogously, we set up typed tables using ALTER TABLE / OF here.
13128          */
13129         if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION)
13130         {
13131             for (j = 0; j < tbinfo->numatts; j++)
13132             {
13133                 if (tbinfo->attisdropped[j])
13134                 {
13135                     appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
13136                     appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13137                                       "SET attlen = %d, "
13138                                       "attalign = '%c', attbyval = false\n"
13139                                       "WHERE attname = ",
13140                                       tbinfo->attlen[j],
13141                                       tbinfo->attalign[j]);
13142                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13143                     appendPQExpBuffer(q, "\n  AND attrelid = ");
13144                     appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13145                     appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13146 
13147                     appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13148                                       fmtId(tbinfo->dobj.name));
13149                     appendPQExpBuffer(q, "DROP COLUMN %s;\n",
13150                                       fmtId(tbinfo->attnames[j]));
13151                 }
13152                 else if (!tbinfo->attislocal[j])
13153                 {
13154                     appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
13155                     appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13156                                       "SET attislocal = false\n"
13157                                       "WHERE attname = ");
13158                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13159                     appendPQExpBuffer(q, "\n  AND attrelid = ");
13160                     appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13161                     appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13162                 }
13163             }
13164 
13165             for (k = 0; k < tbinfo->ncheck; k++)
13166             {
13167                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
13168 
13169                 if (constr->separate || constr->conislocal)
13170                     continue;
13171 
13172                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
13173                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13174                                   fmtId(tbinfo->dobj.name));
13175                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
13176                                   fmtId(constr->dobj.name));
13177                 appendPQExpBuffer(q, "%s;\n", constr->condef);
13178                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
13179                                   "SET conislocal = false\n"
13180                                   "WHERE contype = 'c' AND conname = ");
13181                 appendStringLiteralAH(q, constr->dobj.name, fout);
13182                 appendPQExpBuffer(q, "\n  AND conrelid = ");
13183                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13184                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13185             }
13186 
13187             if (numParents > 0)
13188             {
13189                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
13190                 for (k = 0; k < numParents; k++)
13191                 {
13192                     TableInfo  *parentRel = parents[k];
13193 
13194                     appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
13195                                       fmtId(tbinfo->dobj.name));
13196                     if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13197                         appendPQExpBuffer(q, "%s.",
13198                                 fmtId(parentRel->dobj.namespace->dobj.name));
13199                     appendPQExpBuffer(q, "%s;\n",
13200                                       fmtId(parentRel->dobj.name));
13201                 }
13202             }
13203 
13204             if (tbinfo->reloftype)
13205             {
13206                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
13207                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
13208                                   fmtId(tbinfo->dobj.name),
13209                                   tbinfo->reloftype);
13210             }
13211 
13212             appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
13213             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13214                               "SET relfrozenxid = '%u'\n"
13215                               "WHERE oid = ",
13216                               tbinfo->frozenxid);
13217             appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13218             appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13219 
13220             if (tbinfo->toast_oid)
13221             {
13222                 /* We preserve the toast oids, so we can use it during restore */
13223                 appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
13224                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13225                                   "SET relfrozenxid = '%u'\n"
13226                                   "WHERE oid = '%u';\n",
13227                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
13228             }
13229         }
13230 
13231         /*
13232          * Dump additional per-column properties that we can't handle in the
13233          * main CREATE TABLE command.
13234          */
13235         for (j = 0; j < tbinfo->numatts; j++)
13236         {
13237             /* None of this applies to dropped columns */
13238             if (tbinfo->attisdropped[j])
13239                 continue;
13240 
13241             /*
13242              * If we didn't dump the column definition explicitly above, and
13243              * it is NOT NULL and did not inherit that property from a parent,
13244              * we have to mark it separately.
13245              */
13246             if (!shouldPrintColumn(tbinfo, j) &&
13247                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
13248             {
13249                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13250                                   fmtId(tbinfo->dobj.name));
13251                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
13252                                   fmtId(tbinfo->attnames[j]));
13253             }
13254 
13255             /*
13256              * Dump per-column statistics information. We only issue an ALTER
13257              * TABLE statement if the attstattarget entry for this column is
13258              * non-negative (i.e. it's not the default value)
13259              */
13260             if (tbinfo->attstattarget[j] >= 0)
13261             {
13262                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13263                                   fmtId(tbinfo->dobj.name));
13264                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13265                                   fmtId(tbinfo->attnames[j]));
13266                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
13267                                   tbinfo->attstattarget[j]);
13268             }
13269 
13270             /*
13271              * Dump per-column storage information.  The statement is only
13272              * dumped if the storage has been changed from the type's default.
13273              */
13274             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
13275             {
13276                 switch (tbinfo->attstorage[j])
13277                 {
13278                     case 'p':
13279                         storage = "PLAIN";
13280                         break;
13281                     case 'e':
13282                         storage = "EXTERNAL";
13283                         break;
13284                     case 'm':
13285                         storage = "MAIN";
13286                         break;
13287                     case 'x':
13288                         storage = "EXTENDED";
13289                         break;
13290                     default:
13291                         storage = NULL;
13292                 }
13293 
13294                 /*
13295                  * Only dump the statement if it's a storage type we recognize
13296                  */
13297                 if (storage != NULL)
13298                 {
13299                     appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13300                                       fmtId(tbinfo->dobj.name));
13301                     appendPQExpBuffer(q, "ALTER COLUMN %s ",
13302                                       fmtId(tbinfo->attnames[j]));
13303                     appendPQExpBuffer(q, "SET STORAGE %s;\n",
13304                                       storage);
13305                 }
13306             }
13307 
13308             /*
13309              * Dump per-column attributes.
13310              */
13311             if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
13312             {
13313                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13314                                   fmtId(tbinfo->dobj.name));
13315                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13316                                   fmtId(tbinfo->attnames[j]));
13317                 appendPQExpBuffer(q, "SET (%s);\n",
13318                                   tbinfo->attoptions[j]);
13319             }
13320 
13321             /*
13322              * Dump per-column fdw options.
13323              */
13324             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
13325                 tbinfo->attfdwoptions[j] &&
13326                 tbinfo->attfdwoptions[j][0] != '\0')
13327             {
13328                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13329                                   fmtId(tbinfo->dobj.name));
13330                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13331                                   fmtId(tbinfo->attnames[j]));
13332                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
13333                                   tbinfo->attfdwoptions[j]);
13334             }
13335         }
13336     }
13337 
13338     if (binary_upgrade)
13339         binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
13340 
13341     ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13342                  tbinfo->dobj.name,
13343                  tbinfo->dobj.namespace->dobj.name,
13344             (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
13345                  tbinfo->rolname,
13346                (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
13347                  reltypename, SECTION_PRE_DATA,
13348                  q->data, delq->data, NULL,
13349                  NULL, 0,
13350                  NULL, NULL);
13351 
13352 
13353     /* Dump Table Comments */
13354     dumpTableComment(fout, tbinfo, reltypename);
13355 
13356     /* Dump Table Security Labels */
13357     dumpTableSecLabel(fout, tbinfo, reltypename);
13358 
13359     /* Dump comments on inlined table constraints */
13360     for (j = 0; j < tbinfo->ncheck; j++)
13361     {
13362         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13363 
13364         if (constr->separate || !constr->conislocal)
13365             continue;
13366 
13367         dumpTableConstraintComment(fout, constr);
13368     }
13369 
13370     destroyPQExpBuffer(q);
13371     destroyPQExpBuffer(delq);
13372     destroyPQExpBuffer(labelq);
13373 }
13374 
13375 /*
13376  * dumpAttrDef --- dump an attribute's default-value declaration
13377  */
13378 static void
13379 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
13380 {
13381     TableInfo  *tbinfo = adinfo->adtable;
13382     int         adnum = adinfo->adnum;
13383     PQExpBuffer q;
13384     PQExpBuffer delq;
13385 
13386     /* Skip if table definition not to be dumped */
13387     if (!tbinfo->dobj.dump || dataOnly)
13388         return;
13389 
13390     /* Skip if not "separate"; it was dumped in the table's definition */
13391     if (!adinfo->separate)
13392         return;
13393 
13394     q = createPQExpBuffer();
13395     delq = createPQExpBuffer();
13396 
13397     appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13398                       fmtId(tbinfo->dobj.name));
13399     appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
13400                       fmtId(tbinfo->attnames[adnum - 1]),
13401                       adinfo->adef_expr);
13402 
13403     /*
13404      * DROP must be fully qualified in case same name appears in pg_catalog
13405      */
13406     appendPQExpBuffer(delq, "ALTER TABLE %s.",
13407                       fmtId(tbinfo->dobj.namespace->dobj.name));
13408     appendPQExpBuffer(delq, "%s ",
13409                       fmtId(tbinfo->dobj.name));
13410     appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
13411                       fmtId(tbinfo->attnames[adnum - 1]));
13412 
13413     ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
13414                  tbinfo->attnames[adnum - 1],
13415                  tbinfo->dobj.namespace->dobj.name,
13416                  NULL,
13417                  tbinfo->rolname,
13418                  false, "DEFAULT", SECTION_PRE_DATA,
13419                  q->data, delq->data, NULL,
13420                  NULL, 0,
13421                  NULL, NULL);
13422 
13423     destroyPQExpBuffer(q);
13424     destroyPQExpBuffer(delq);
13425 }
13426 
13427 /*
13428  * getAttrName: extract the correct name for an attribute
13429  *
13430  * The array tblInfo->attnames[] only provides names of user attributes;
13431  * if a system attribute number is supplied, we have to fake it.
13432  * We also do a little bit of bounds checking for safety's sake.
13433  */
13434 static const char *
13435 getAttrName(int attrnum, TableInfo *tblInfo)
13436 {
13437     if (attrnum > 0 && attrnum <= tblInfo->numatts)
13438         return tblInfo->attnames[attrnum - 1];
13439     switch (attrnum)
13440     {
13441         case SelfItemPointerAttributeNumber:
13442             return "ctid";
13443         case ObjectIdAttributeNumber:
13444             return "oid";
13445         case MinTransactionIdAttributeNumber:
13446             return "xmin";
13447         case MinCommandIdAttributeNumber:
13448             return "cmin";
13449         case MaxTransactionIdAttributeNumber:
13450             return "xmax";
13451         case MaxCommandIdAttributeNumber:
13452             return "cmax";
13453         case TableOidAttributeNumber:
13454             return "tableoid";
13455     }
13456     exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
13457                   attrnum, tblInfo->dobj.name);
13458     return NULL;                /* keep compiler quiet */
13459 }
13460 
13461 /*
13462  * dumpIndex
13463  *    write out to fout a user-defined index
13464  */
13465 static void
13466 dumpIndex(Archive *fout, IndxInfo *indxinfo)
13467 {
13468     TableInfo  *tbinfo = indxinfo->indextable;
13469     PQExpBuffer q;
13470     PQExpBuffer delq;
13471     PQExpBuffer labelq;
13472 
13473     if (dataOnly)
13474         return;
13475 
13476     q = createPQExpBuffer();
13477     delq = createPQExpBuffer();
13478     labelq = createPQExpBuffer();
13479 
13480     appendPQExpBuffer(labelq, "INDEX %s",
13481                       fmtId(indxinfo->dobj.name));
13482 
13483     /*
13484      * If there's an associated constraint, don't dump the index per se, but
13485      * do dump any comment for it.  (This is safe because dependency ordering
13486      * will have ensured the constraint is emitted first.)
13487      */
13488     if (indxinfo->indexconstraint == 0)
13489     {
13490         if (binary_upgrade)
13491             binary_upgrade_set_pg_class_oids(fout, q,
13492                                              indxinfo->dobj.catId.oid, true);
13493 
13494         /* Plain secondary index */
13495         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
13496 
13497         /* If the index is clustered, we need to record that. */
13498         if (indxinfo->indisclustered)
13499         {
13500             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13501                               fmtId(tbinfo->dobj.name));
13502             appendPQExpBuffer(q, " ON %s;\n",
13503                               fmtId(indxinfo->dobj.name));
13504         }
13505 
13506         /*
13507          * DROP must be fully qualified in case same name appears in
13508          * pg_catalog
13509          */
13510         appendPQExpBuffer(delq, "DROP INDEX %s.",
13511                           fmtId(tbinfo->dobj.namespace->dobj.name));
13512         appendPQExpBuffer(delq, "%s;\n",
13513                           fmtId(indxinfo->dobj.name));
13514 
13515         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
13516                      indxinfo->dobj.name,
13517                      tbinfo->dobj.namespace->dobj.name,
13518                      indxinfo->tablespace,
13519                      tbinfo->rolname, false,
13520                      "INDEX", SECTION_POST_DATA,
13521                      q->data, delq->data, NULL,
13522                      NULL, 0,
13523                      NULL, NULL);
13524     }
13525 
13526     /* Dump Index Comments */
13527     dumpComment(fout, labelq->data,
13528                 tbinfo->dobj.namespace->dobj.name,
13529                 tbinfo->rolname,
13530                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
13531 
13532     destroyPQExpBuffer(q);
13533     destroyPQExpBuffer(delq);
13534     destroyPQExpBuffer(labelq);
13535 }
13536 
13537 /*
13538  * dumpConstraint
13539  *    write out to fout a user-defined constraint
13540  */
13541 static void
13542 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13543 {
13544     TableInfo  *tbinfo = coninfo->contable;
13545     PQExpBuffer q;
13546     PQExpBuffer delq;
13547 
13548     /* Skip if not to be dumped */
13549     if (!coninfo->dobj.dump || dataOnly)
13550         return;
13551 
13552     q = createPQExpBuffer();
13553     delq = createPQExpBuffer();
13554 
13555     if (coninfo->contype == 'p' ||
13556         coninfo->contype == 'u' ||
13557         coninfo->contype == 'x')
13558     {
13559         /* Index-related constraint */
13560         IndxInfo   *indxinfo;
13561         int         k;
13562 
13563         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13564 
13565         if (indxinfo == NULL)
13566             exit_horribly(NULL, "missing index for constraint \"%s\"\n",
13567                           coninfo->dobj.name);
13568 
13569         if (binary_upgrade)
13570             binary_upgrade_set_pg_class_oids(fout, q,
13571                                              indxinfo->dobj.catId.oid, true);
13572 
13573         appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13574                           fmtId(tbinfo->dobj.name));
13575         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13576                           fmtId(coninfo->dobj.name));
13577 
13578         if (coninfo->condef)
13579         {
13580             /* pg_get_constraintdef should have provided everything */
13581             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13582         }
13583         else
13584         {
13585             appendPQExpBuffer(q, "%s (",
13586                          coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13587             for (k = 0; k < indxinfo->indnkeys; k++)
13588             {
13589                 int         indkey = (int) indxinfo->indkeys[k];
13590                 const char *attname;
13591 
13592                 if (indkey == InvalidAttrNumber)
13593                     break;
13594                 attname = getAttrName(indkey, tbinfo);
13595 
13596                 appendPQExpBuffer(q, "%s%s",
13597                                   (k == 0) ? "" : ", ",
13598                                   fmtId(attname));
13599             }
13600 
13601             appendPQExpBuffer(q, ")");
13602 
13603             if (indxinfo->options && strlen(indxinfo->options) > 0)
13604                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13605 
13606             if (coninfo->condeferrable)
13607             {
13608                 appendPQExpBuffer(q, " DEFERRABLE");
13609                 if (coninfo->condeferred)
13610                     appendPQExpBuffer(q, " INITIALLY DEFERRED");
13611             }
13612 
13613             appendPQExpBuffer(q, ";\n");
13614         }
13615 
13616         /* If the index is clustered, we need to record that. */
13617         if (indxinfo->indisclustered)
13618         {
13619             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13620                               fmtId(tbinfo->dobj.name));
13621             appendPQExpBuffer(q, " ON %s;\n",
13622                               fmtId(indxinfo->dobj.name));
13623         }
13624 
13625         /*
13626          * DROP must be fully qualified in case same name appears in
13627          * pg_catalog
13628          */
13629         appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13630                           fmtId(tbinfo->dobj.namespace->dobj.name));
13631         appendPQExpBuffer(delq, "%s ",
13632                           fmtId(tbinfo->dobj.name));
13633         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13634                           fmtId(coninfo->dobj.name));
13635 
13636         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13637                      coninfo->dobj.name,
13638                      tbinfo->dobj.namespace->dobj.name,
13639                      indxinfo->tablespace,
13640                      tbinfo->rolname, false,
13641                      "CONSTRAINT", SECTION_POST_DATA,
13642                      q->data, delq->data, NULL,
13643                      NULL, 0,
13644                      NULL, NULL);
13645     }
13646     else if (coninfo->contype == 'f')
13647     {
13648         /*
13649          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13650          * current table data is not processed
13651          */
13652         appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13653                           fmtId(tbinfo->dobj.name));
13654         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13655                           fmtId(coninfo->dobj.name),
13656                           coninfo->condef);
13657 
13658         /*
13659          * DROP must be fully qualified in case same name appears in
13660          * pg_catalog
13661          */
13662         appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13663                           fmtId(tbinfo->dobj.namespace->dobj.name));
13664         appendPQExpBuffer(delq, "%s ",
13665                           fmtId(tbinfo->dobj.name));
13666         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13667                           fmtId(coninfo->dobj.name));
13668 
13669         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13670                      coninfo->dobj.name,
13671                      tbinfo->dobj.namespace->dobj.name,
13672                      NULL,
13673                      tbinfo->rolname, false,
13674                      "FK CONSTRAINT", SECTION_POST_DATA,
13675                      q->data, delq->data, NULL,
13676                      NULL, 0,
13677                      NULL, NULL);
13678     }
13679     else if (coninfo->contype == 'c' && tbinfo)
13680     {
13681         /* CHECK constraint on a table */
13682 
13683         /* Ignore if not to be dumped separately */
13684         if (coninfo->separate)
13685         {
13686             /* not ONLY since we want it to propagate to children */
13687             appendPQExpBuffer(q, "ALTER TABLE %s\n",
13688                               fmtId(tbinfo->dobj.name));
13689             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13690                               fmtId(coninfo->dobj.name),
13691                               coninfo->condef);
13692 
13693             /*
13694              * DROP must be fully qualified in case same name appears in
13695              * pg_catalog
13696              */
13697             appendPQExpBuffer(delq, "ALTER TABLE %s.",
13698                               fmtId(tbinfo->dobj.namespace->dobj.name));
13699             appendPQExpBuffer(delq, "%s ",
13700                               fmtId(tbinfo->dobj.name));
13701             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13702                               fmtId(coninfo->dobj.name));
13703 
13704             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13705                          coninfo->dobj.name,
13706                          tbinfo->dobj.namespace->dobj.name,
13707                          NULL,
13708                          tbinfo->rolname, false,
13709                          "CHECK CONSTRAINT", SECTION_POST_DATA,
13710                          q->data, delq->data, NULL,
13711                          NULL, 0,
13712                          NULL, NULL);
13713         }
13714     }
13715     else if (coninfo->contype == 'c' && tbinfo == NULL)
13716     {
13717         /* CHECK constraint on a domain */
13718         TypeInfo   *tyinfo = coninfo->condomain;
13719 
13720         /* Ignore if not to be dumped separately */
13721         if (coninfo->separate)
13722         {
13723             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
13724                               fmtId(tyinfo->dobj.name));
13725             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13726                               fmtId(coninfo->dobj.name),
13727                               coninfo->condef);
13728 
13729             /*
13730              * DROP must be fully qualified in case same name appears in
13731              * pg_catalog
13732              */
13733             appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
13734                               fmtId(tyinfo->dobj.namespace->dobj.name));
13735             appendPQExpBuffer(delq, "%s ",
13736                               fmtId(tyinfo->dobj.name));
13737             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13738                               fmtId(coninfo->dobj.name));
13739 
13740             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13741                          coninfo->dobj.name,
13742                          tyinfo->dobj.namespace->dobj.name,
13743                          NULL,
13744                          tyinfo->rolname, false,
13745                          "CHECK CONSTRAINT", SECTION_POST_DATA,
13746                          q->data, delq->data, NULL,
13747                          NULL, 0,
13748                          NULL, NULL);
13749         }
13750     }
13751     else
13752     {
13753         exit_horribly(NULL, "unrecognized constraint type: %c\n",
13754                       coninfo->contype);
13755     }
13756 
13757     /* Dump Constraint Comments --- only works for table constraints */
13758     if (tbinfo && coninfo->separate)
13759         dumpTableConstraintComment(fout, coninfo);
13760 
13761     destroyPQExpBuffer(q);
13762     destroyPQExpBuffer(delq);
13763 }
13764 
13765 /*
13766  * dumpTableConstraintComment --- dump a constraint's comment if any
13767  *
13768  * This is split out because we need the function in two different places
13769  * depending on whether the constraint is dumped as part of CREATE TABLE
13770  * or as a separate ALTER command.
13771  */
13772 static void
13773 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
13774 {
13775     TableInfo  *tbinfo = coninfo->contable;
13776     PQExpBuffer labelq = createPQExpBuffer();
13777 
13778     appendPQExpBuffer(labelq, "CONSTRAINT %s ",
13779                       fmtId(coninfo->dobj.name));
13780     appendPQExpBuffer(labelq, "ON %s",
13781                       fmtId(tbinfo->dobj.name));
13782     dumpComment(fout, labelq->data,
13783                 tbinfo->dobj.namespace->dobj.name,
13784                 tbinfo->rolname,
13785                 coninfo->dobj.catId, 0,
13786              coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
13787 
13788     destroyPQExpBuffer(labelq);
13789 }
13790 
13791 /*
13792  * findLastBuiltInOid -
13793  * find the last built in oid
13794  *
13795  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
13796  * pg_database entry for the current database
13797  */
13798 static Oid
13799 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
13800 {
13801     PGresult   *res;
13802     Oid         last_oid;
13803     PQExpBuffer query = createPQExpBuffer();
13804 
13805     resetPQExpBuffer(query);
13806     appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
13807     appendStringLiteralAH(query, dbname, fout);
13808 
13809     res = ExecuteSqlQueryForSingleRow(fout, query->data);
13810     last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
13811     PQclear(res);
13812     destroyPQExpBuffer(query);
13813     return last_oid;
13814 }
13815 
13816 /*
13817  * findLastBuiltInOid -
13818  * find the last built in oid
13819  *
13820  * For 7.0, we do this by assuming that the last thing that initdb does is to
13821  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
13822  * initdb won't be changing anymore, it'll do.
13823  */
13824 static Oid
13825 findLastBuiltinOid_V70(Archive *fout)
13826 {
13827     PGresult   *res;
13828     int         last_oid;
13829 
13830     res = ExecuteSqlQueryForSingleRow(fout,
13831                     "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
13832     last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
13833     PQclear(res);
13834     return last_oid;
13835 }
13836 
13837 /*
13838  * dumpSequence
13839  *    write the declaration (not data) of one user-defined sequence
13840  */
13841 static void
13842 dumpSequence(Archive *fout, TableInfo *tbinfo)
13843 {
13844     PGresult   *res;
13845     char       *startv,
13846                *incby,
13847                *maxv = NULL,
13848                *minv = NULL,
13849                *cache;
13850     char        bufm[100],
13851                 bufx[100];
13852     bool        cycled;
13853     PQExpBuffer query = createPQExpBuffer();
13854     PQExpBuffer delqry = createPQExpBuffer();
13855     PQExpBuffer labelq = createPQExpBuffer();
13856 
13857     /* Make sure we are in proper schema */
13858     selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13859 
13860     snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
13861     snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
13862 
13863     if (fout->remoteVersion >= 80400)
13864     {
13865         appendPQExpBuffer(query,
13866                           "SELECT sequence_name, "
13867                           "start_value, increment_by, "
13868                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13869                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13870                           "     ELSE max_value "
13871                           "END AS max_value, "
13872                     "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13873                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13874                           "     ELSE min_value "
13875                           "END AS min_value, "
13876                           "cache_value, is_cycled FROM %s",
13877                           bufx, bufm,
13878                           fmtId(tbinfo->dobj.name));
13879     }
13880     else
13881     {
13882         appendPQExpBuffer(query,
13883                           "SELECT sequence_name, "
13884                           "0 AS start_value, increment_by, "
13885                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13886                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13887                           "     ELSE max_value "
13888                           "END AS max_value, "
13889                     "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13890                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13891                           "     ELSE min_value "
13892                           "END AS min_value, "
13893                           "cache_value, is_cycled FROM %s",
13894                           bufx, bufm,
13895                           fmtId(tbinfo->dobj.name));
13896     }
13897 
13898     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13899 
13900     if (PQntuples(res) != 1)
13901     {
13902         write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
13903                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
13904                                  PQntuples(res)),
13905                   tbinfo->dobj.name, PQntuples(res));
13906         exit_nicely(1);
13907     }
13908 
13909     /* Disable this check: it fails if sequence has been renamed */
13910 #ifdef NOT_USED
13911     if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
13912     {
13913         write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
13914                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
13915         exit_nicely(1);
13916     }
13917 #endif
13918 
13919     startv = PQgetvalue(res, 0, 1);
13920     incby = PQgetvalue(res, 0, 2);
13921     if (!PQgetisnull(res, 0, 3))
13922         maxv = PQgetvalue(res, 0, 3);
13923     if (!PQgetisnull(res, 0, 4))
13924         minv = PQgetvalue(res, 0, 4);
13925     cache = PQgetvalue(res, 0, 5);
13926     cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
13927 
13928     /*
13929      * DROP must be fully qualified in case same name appears in pg_catalog
13930      */
13931     appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
13932                       fmtId(tbinfo->dobj.namespace->dobj.name));
13933     appendPQExpBuffer(delqry, "%s;\n",
13934                       fmtId(tbinfo->dobj.name));
13935 
13936     resetPQExpBuffer(query);
13937 
13938     if (binary_upgrade)
13939     {
13940         binary_upgrade_set_pg_class_oids(fout, query,
13941                                          tbinfo->dobj.catId.oid, false);
13942         binary_upgrade_set_type_oids_by_rel_oid(fout, query,
13943                                                 tbinfo->dobj.catId.oid);
13944     }
13945 
13946     appendPQExpBuffer(query,
13947                       "CREATE SEQUENCE %s\n",
13948                       fmtId(tbinfo->dobj.name));
13949 
13950     if (fout->remoteVersion >= 80400)
13951         appendPQExpBuffer(query, "    START WITH %s\n", startv);
13952 
13953     appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
13954 
13955     if (minv)
13956         appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
13957     else
13958         appendPQExpBuffer(query, "    NO MINVALUE\n");
13959 
13960     if (maxv)
13961         appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
13962     else
13963         appendPQExpBuffer(query, "    NO MAXVALUE\n");
13964 
13965     appendPQExpBuffer(query,
13966                       "    CACHE %s%s",
13967                       cache, (cycled ? "\n    CYCLE" : ""));
13968 
13969     appendPQExpBuffer(query, ";\n");
13970 
13971     appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
13972 
13973     /* binary_upgrade:  no need to clear TOAST table oid */
13974 
13975     if (binary_upgrade)
13976         binary_upgrade_extension_member(query, &tbinfo->dobj,
13977                                         labelq->data);
13978 
13979     ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13980                  tbinfo->dobj.name,
13981                  tbinfo->dobj.namespace->dobj.name,
13982                  NULL,
13983                  tbinfo->rolname,
13984                  false, "SEQUENCE", SECTION_PRE_DATA,
13985                  query->data, delqry->data, NULL,
13986                  NULL, 0,
13987                  NULL, NULL);
13988 
13989     /*
13990      * If the sequence is owned by a table column, emit the ALTER for it as a
13991      * separate TOC entry immediately following the sequence's own entry. It's
13992      * OK to do this rather than using full sorting logic, because the
13993      * dependency that tells us it's owned will have forced the table to be
13994      * created first.  We can't just include the ALTER in the TOC entry
13995      * because it will fail if we haven't reassigned the sequence owner to
13996      * match the table's owner.
13997      *
13998      * We need not schema-qualify the table reference because both sequence
13999      * and table must be in the same schema.
14000      */
14001     if (OidIsValid(tbinfo->owning_tab))
14002     {
14003         TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
14004 
14005         if (owning_tab && owning_tab->dobj.dump)
14006         {
14007             resetPQExpBuffer(query);
14008             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
14009                               fmtId(tbinfo->dobj.name));
14010             appendPQExpBuffer(query, " OWNED BY %s",
14011                               fmtId(owning_tab->dobj.name));
14012             appendPQExpBuffer(query, ".%s;\n",
14013                         fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
14014 
14015             ArchiveEntry(fout, nilCatalogId, createDumpId(),
14016                          tbinfo->dobj.name,
14017                          tbinfo->dobj.namespace->dobj.name,
14018                          NULL,
14019                          tbinfo->rolname,
14020                          false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
14021                          query->data, "", NULL,
14022                          &(tbinfo->dobj.dumpId), 1,
14023                          NULL, NULL);
14024         }
14025     }
14026 
14027     /* Dump Sequence Comments and Security Labels */
14028     dumpComment(fout, labelq->data,
14029                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14030                 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14031     dumpSecLabel(fout, labelq->data,
14032                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14033                  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14034 
14035     PQclear(res);
14036 
14037     destroyPQExpBuffer(query);
14038     destroyPQExpBuffer(delqry);
14039     destroyPQExpBuffer(labelq);
14040 }
14041 
14042 /*
14043  * dumpSequenceData
14044  *    write the data of one user-defined sequence
14045  */
14046 static void
14047 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
14048 {
14049     TableInfo  *tbinfo = tdinfo->tdtable;
14050     PGresult   *res;
14051     char       *last;
14052     bool        called;
14053     PQExpBuffer query = createPQExpBuffer();
14054 
14055     /* Make sure we are in proper schema */
14056     selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14057 
14058     appendPQExpBuffer(query,
14059                       "SELECT last_value, is_called FROM %s",
14060                       fmtId(tbinfo->dobj.name));
14061 
14062     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14063 
14064     if (PQntuples(res) != 1)
14065     {
14066         write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14067                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14068                                  PQntuples(res)),
14069                   tbinfo->dobj.name, PQntuples(res));
14070         exit_nicely(1);
14071     }
14072 
14073     last = PQgetvalue(res, 0, 0);
14074     called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
14075 
14076     resetPQExpBuffer(query);
14077     appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
14078     appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
14079     appendPQExpBuffer(query, ", %s, %s);\n",
14080                       last, (called ? "true" : "false"));
14081 
14082     ArchiveEntry(fout, nilCatalogId, createDumpId(),
14083                  tbinfo->dobj.name,
14084                  tbinfo->dobj.namespace->dobj.name,
14085                  NULL,
14086                  tbinfo->rolname,
14087                  false, "SEQUENCE SET", SECTION_DATA,
14088                  query->data, "", NULL,
14089                  &(tbinfo->dobj.dumpId), 1,
14090                  NULL, NULL);
14091 
14092     PQclear(res);
14093 
14094     destroyPQExpBuffer(query);
14095 }
14096 
14097 static void
14098 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
14099 {
14100     TableInfo  *tbinfo = tginfo->tgtable;
14101     PQExpBuffer query;
14102     PQExpBuffer delqry;
14103     PQExpBuffer labelq;
14104     char       *tgargs;
14105     size_t      lentgargs;
14106     const char *p;
14107     int         findx;
14108 
14109     if (dataOnly)
14110         return;
14111 
14112     query = createPQExpBuffer();
14113     delqry = createPQExpBuffer();
14114     labelq = createPQExpBuffer();
14115 
14116     /*
14117      * DROP must be fully qualified in case same name appears in pg_catalog
14118      */
14119     appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
14120                       fmtId(tginfo->dobj.name));
14121     appendPQExpBuffer(delqry, "ON %s.",
14122                       fmtId(tbinfo->dobj.namespace->dobj.name));
14123     appendPQExpBuffer(delqry, "%s;\n",
14124                       fmtId(tbinfo->dobj.name));
14125 
14126     if (tginfo->tgdef)
14127     {
14128         appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
14129     }
14130     else
14131     {
14132         if (tginfo->tgisconstraint)
14133         {
14134             appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
14135             appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
14136         }
14137         else
14138         {
14139             appendPQExpBuffer(query, "CREATE TRIGGER ");
14140             appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
14141         }
14142         appendPQExpBuffer(query, "\n    ");
14143 
14144         /* Trigger type */
14145         if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
14146             appendPQExpBuffer(query, "BEFORE");
14147         else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
14148             appendPQExpBuffer(query, "AFTER");
14149         else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
14150             appendPQExpBuffer(query, "INSTEAD OF");
14151         else
14152         {
14153             write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
14154             exit_nicely(1);
14155         }
14156 
14157         findx = 0;
14158         if (TRIGGER_FOR_INSERT(tginfo->tgtype))
14159         {
14160             appendPQExpBuffer(query, " INSERT");
14161             findx++;
14162         }
14163         if (TRIGGER_FOR_DELETE(tginfo->tgtype))
14164         {
14165             if (findx > 0)
14166                 appendPQExpBuffer(query, " OR DELETE");
14167             else
14168                 appendPQExpBuffer(query, " DELETE");
14169             findx++;
14170         }
14171         if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
14172         {
14173             if (findx > 0)
14174                 appendPQExpBuffer(query, " OR UPDATE");
14175             else
14176                 appendPQExpBuffer(query, " UPDATE");
14177             findx++;
14178         }
14179         if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
14180         {
14181             if (findx > 0)
14182                 appendPQExpBuffer(query, " OR TRUNCATE");
14183             else
14184                 appendPQExpBuffer(query, " TRUNCATE");
14185             findx++;
14186         }
14187         appendPQExpBuffer(query, " ON %s\n",
14188                           fmtId(tbinfo->dobj.name));
14189 
14190         if (tginfo->tgisconstraint)
14191         {
14192             if (OidIsValid(tginfo->tgconstrrelid))
14193             {
14194                 /* If we are using regclass, name is already quoted */
14195                 if (fout->remoteVersion >= 70300)
14196                     appendPQExpBuffer(query, "    FROM %s\n    ",
14197                                       tginfo->tgconstrrelname);
14198                 else
14199                     appendPQExpBuffer(query, "    FROM %s\n    ",
14200                                       fmtId(tginfo->tgconstrrelname));
14201             }
14202             if (!tginfo->tgdeferrable)
14203                 appendPQExpBuffer(query, "NOT ");
14204             appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
14205             if (tginfo->tginitdeferred)
14206                 appendPQExpBuffer(query, "DEFERRED\n");
14207             else
14208                 appendPQExpBuffer(query, "IMMEDIATE\n");
14209         }
14210 
14211         if (TRIGGER_FOR_ROW(tginfo->tgtype))
14212             appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
14213         else
14214             appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
14215 
14216         /* In 7.3, result of regproc is already quoted */
14217         if (fout->remoteVersion >= 70300)
14218             appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14219                               tginfo->tgfname);
14220         else
14221             appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14222                               fmtId(tginfo->tgfname));
14223 
14224         tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
14225                                           &lentgargs);
14226         p = tgargs;
14227         for (findx = 0; findx < tginfo->tgnargs; findx++)
14228         {
14229             /* find the embedded null that terminates this trigger argument */
14230             size_t      tlen = strlen(p);
14231 
14232             if (p + tlen >= tgargs + lentgargs)
14233             {
14234                 /* hm, not found before end of bytea value... */
14235                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
14236                           tginfo->tgargs,
14237                           tginfo->dobj.name,
14238                           tbinfo->dobj.name);
14239                 exit_nicely(1);
14240             }
14241 
14242             if (findx > 0)
14243                 appendPQExpBuffer(query, ", ");
14244             appendStringLiteralAH(query, p, fout);
14245             p += tlen + 1;
14246         }
14247         free(tgargs);
14248         appendPQExpBuffer(query, ");\n");
14249     }
14250 
14251     if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
14252     {
14253         appendPQExpBuffer(query, "\nALTER TABLE %s ",
14254                           fmtId(tbinfo->dobj.name));
14255         switch (tginfo->tgenabled)
14256         {
14257             case 'D':
14258             case 'f':
14259                 appendPQExpBuffer(query, "DISABLE");
14260                 break;
14261             case 'A':
14262                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14263                 break;
14264             case 'R':
14265                 appendPQExpBuffer(query, "ENABLE REPLICA");
14266                 break;
14267             default:
14268                 appendPQExpBuffer(query, "ENABLE");
14269                 break;
14270         }
14271         appendPQExpBuffer(query, " TRIGGER %s;\n",
14272                           fmtId(tginfo->dobj.name));
14273     }
14274 
14275     appendPQExpBuffer(labelq, "TRIGGER %s ",
14276                       fmtId(tginfo->dobj.name));
14277     appendPQExpBuffer(labelq, "ON %s",
14278                       fmtId(tbinfo->dobj.name));
14279 
14280     ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
14281                  tginfo->dobj.name,
14282                  tbinfo->dobj.namespace->dobj.name,
14283                  NULL,
14284                  tbinfo->rolname, false,
14285                  "TRIGGER", SECTION_POST_DATA,
14286                  query->data, delqry->data, NULL,
14287                  NULL, 0,
14288                  NULL, NULL);
14289 
14290     dumpComment(fout, labelq->data,
14291                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14292                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
14293 
14294     destroyPQExpBuffer(query);
14295     destroyPQExpBuffer(delqry);
14296     destroyPQExpBuffer(labelq);
14297 }
14298 
14299 static void
14300 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
14301 {
14302     PQExpBuffer query;
14303     PQExpBuffer labelq;
14304 
14305     query = createPQExpBuffer();
14306     labelq = createPQExpBuffer();
14307 
14308     appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
14309     appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
14310     appendPQExpBuffer(query, " ON ");
14311     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
14312     appendPQExpBufferStr(query, " ");
14313 
14314     if (strcmp("", evtinfo->evttags) != 0)
14315     {
14316         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
14317         appendPQExpBufferStr(query, evtinfo->evttags);
14318         appendPQExpBufferStr(query, ") ");
14319     }
14320 
14321     appendPQExpBuffer(query, "\n   EXECUTE PROCEDURE ");
14322     appendPQExpBufferStr(query, evtinfo->evtfname);
14323     appendPQExpBuffer(query, "();\n");
14324 
14325     if (evtinfo->evtenabled != 'O')
14326     {
14327         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
14328                           fmtId(evtinfo->dobj.name));
14329         switch (evtinfo->evtenabled)
14330         {
14331             case 'D':
14332                 appendPQExpBuffer(query, "DISABLE");
14333                 break;
14334             case 'A':
14335                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14336                 break;
14337             case 'R':
14338                 appendPQExpBuffer(query, "ENABLE REPLICA");
14339                 break;
14340             default:
14341                 appendPQExpBuffer(query, "ENABLE");
14342                 break;
14343         }
14344         appendPQExpBuffer(query, ";\n");
14345     }
14346     appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
14347                       fmtId(evtinfo->dobj.name));
14348 
14349     ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
14350                  evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
14351                  "EVENT TRIGGER", SECTION_POST_DATA,
14352                  query->data, "", NULL, NULL, 0, NULL, NULL);
14353 
14354     dumpComment(fout, labelq->data,
14355                 NULL, NULL,
14356                 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
14357 
14358     destroyPQExpBuffer(query);
14359     destroyPQExpBuffer(labelq);
14360 }
14361 
14362 /*
14363  * dumpRule
14364  *      Dump a rule
14365  */
14366 static void
14367 dumpRule(Archive *fout, RuleInfo *rinfo)
14368 {
14369     TableInfo  *tbinfo = rinfo->ruletable;
14370     PQExpBuffer query;
14371     PQExpBuffer cmd;
14372     PQExpBuffer delcmd;
14373     PQExpBuffer labelq;
14374     PGresult   *res;
14375 
14376     /* Skip if not to be dumped */
14377     if (!rinfo->dobj.dump || dataOnly)
14378         return;
14379 
14380     /*
14381      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
14382      * we do not want to dump it as a separate object.
14383      */
14384     if (!rinfo->separate)
14385         return;
14386 
14387     /*
14388      * Make sure we are in proper schema.
14389      */
14390     selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14391 
14392     query = createPQExpBuffer();
14393     cmd = createPQExpBuffer();
14394     delcmd = createPQExpBuffer();
14395     labelq = createPQExpBuffer();
14396 
14397     if (fout->remoteVersion >= 70300)
14398     {
14399         appendPQExpBuffer(query,
14400                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
14401                           rinfo->dobj.catId.oid);
14402     }
14403     else
14404     {
14405         /* Rule name was unique before 7.3 ... */
14406         appendPQExpBuffer(query,
14407                           "SELECT pg_get_ruledef('%s') AS definition",
14408                           rinfo->dobj.name);
14409     }
14410 
14411     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14412 
14413     if (PQntuples(res) != 1)
14414     {
14415         write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
14416                   rinfo->dobj.name, tbinfo->dobj.name);
14417         exit_nicely(1);
14418     }
14419 
14420     printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
14421 
14422     /*
14423      * Add the command to alter the rules replication firing semantics if it
14424      * differs from the default.
14425      */
14426     if (rinfo->ev_enabled != 'O')
14427     {
14428         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
14429         switch (rinfo->ev_enabled)
14430         {
14431             case 'A':
14432                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
14433                                   fmtId(rinfo->dobj.name));
14434                 break;
14435             case 'R':
14436                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
14437                                   fmtId(rinfo->dobj.name));
14438                 break;
14439             case 'D':
14440                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
14441                                   fmtId(rinfo->dobj.name));
14442                 break;
14443         }
14444     }
14445 
14446     /*
14447      * Apply view's reloptions when its ON SELECT rule is separate.
14448      */
14449     if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
14450     {
14451         appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
14452                           fmtId(tbinfo->dobj.name),
14453                           rinfo->reloptions);
14454     }
14455 
14456     /*
14457      * DROP must be fully qualified in case same name appears in pg_catalog
14458      */
14459     appendPQExpBuffer(delcmd, "DROP RULE %s ",
14460                       fmtId(rinfo->dobj.name));
14461     appendPQExpBuffer(delcmd, "ON %s.",
14462                       fmtId(tbinfo->dobj.namespace->dobj.name));
14463     appendPQExpBuffer(delcmd, "%s;\n",
14464                       fmtId(tbinfo->dobj.name));
14465 
14466     appendPQExpBuffer(labelq, "RULE %s",
14467                       fmtId(rinfo->dobj.name));
14468     appendPQExpBuffer(labelq, " ON %s",
14469                       fmtId(tbinfo->dobj.name));
14470 
14471     ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
14472                  rinfo->dobj.name,
14473                  tbinfo->dobj.namespace->dobj.name,
14474                  NULL,
14475                  tbinfo->rolname, false,
14476                  "RULE", SECTION_POST_DATA,
14477                  cmd->data, delcmd->data, NULL,
14478                  NULL, 0,
14479                  NULL, NULL);
14480 
14481     /* Dump rule comments */
14482     dumpComment(fout, labelq->data,
14483                 tbinfo->dobj.namespace->dobj.name,
14484                 tbinfo->rolname,
14485                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
14486 
14487     PQclear(res);
14488 
14489     destroyPQExpBuffer(query);
14490     destroyPQExpBuffer(cmd);
14491     destroyPQExpBuffer(delcmd);
14492     destroyPQExpBuffer(labelq);
14493 }
14494 
14495 /*
14496  * getExtensionMembership --- obtain extension membership data
14497  */
14498 void
14499 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
14500                        int numExtensions)
14501 {
14502     PQExpBuffer query;
14503     PGresult   *res;
14504     int         ntups,
14505                 i;
14506     int         i_classid,
14507                 i_objid,
14508                 i_refclassid,
14509                 i_refobjid;
14510     DumpableObject *dobj,
14511                *refdobj;
14512 
14513     /* Nothing to do if no extensions */
14514     if (numExtensions == 0)
14515         return;
14516 
14517     /* Make sure we are in proper schema */
14518     selectSourceSchema(fout, "pg_catalog");
14519 
14520     query = createPQExpBuffer();
14521 
14522     /* refclassid constraint is redundant but may speed the search */
14523     appendPQExpBuffer(query, "SELECT "
14524                       "classid, objid, refclassid, refobjid "
14525                       "FROM pg_depend "
14526                       "WHERE refclassid = 'pg_extension'::regclass "
14527                       "AND deptype = 'e' "
14528                       "ORDER BY 3,4");
14529 
14530     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14531 
14532     ntups = PQntuples(res);
14533 
14534     i_classid = PQfnumber(res, "classid");
14535     i_objid = PQfnumber(res, "objid");
14536     i_refclassid = PQfnumber(res, "refclassid");
14537     i_refobjid = PQfnumber(res, "refobjid");
14538 
14539     /*
14540      * Since we ordered the SELECT by referenced ID, we can expect that
14541      * multiple entries for the same extension will appear together; this
14542      * saves on searches.
14543      */
14544     refdobj = NULL;
14545 
14546     for (i = 0; i < ntups; i++)
14547     {
14548         CatalogId   objId;
14549         CatalogId   refobjId;
14550 
14551         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14552         objId.oid = atooid(PQgetvalue(res, i, i_objid));
14553         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14554         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14555 
14556         if (refdobj == NULL ||
14557             refdobj->catId.tableoid != refobjId.tableoid ||
14558             refdobj->catId.oid != refobjId.oid)
14559             refdobj = findObjectByCatalogId(refobjId);
14560 
14561         /*
14562          * Failure to find objects mentioned in pg_depend is not unexpected,
14563          * since for example we don't collect info about TOAST tables.
14564          */
14565         if (refdobj == NULL)
14566         {
14567 #ifdef NOT_USED
14568             fprintf(stderr, "no referenced object %u %u\n",
14569                     refobjId.tableoid, refobjId.oid);
14570 #endif
14571             continue;
14572         }
14573 
14574         dobj = findObjectByCatalogId(objId);
14575 
14576         if (dobj == NULL)
14577         {
14578 #ifdef NOT_USED
14579             fprintf(stderr, "no referencing object %u %u\n",
14580                     objId.tableoid, objId.oid);
14581 #endif
14582             continue;
14583         }
14584 
14585         /* Record dependency so that getDependencies needn't repeat this */
14586         addObjectDependency(dobj, refdobj->dumpId);
14587 
14588         dobj->ext_member = true;
14589 
14590         /*
14591          * Normally, mark the member object as not to be dumped.  But in
14592          * binary upgrades, we still dump the members individually, since the
14593          * idea is to exactly reproduce the database contents rather than
14594          * replace the extension contents with something different.
14595          */
14596         if (!binary_upgrade)
14597             dobj->dump = false;
14598         else
14599             dobj->dump = refdobj->dump;
14600     }
14601 
14602     PQclear(res);
14603 
14604     /*
14605      * Now identify extension configuration tables and create TableDataInfo
14606      * objects for them, ensuring their data will be dumped even though the
14607      * tables themselves won't be.
14608      *
14609      * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14610      * user data in a configuration table is treated like schema data. This
14611      * seems appropriate since system data in a config table would get
14612      * reloaded by CREATE EXTENSION.
14613      */
14614     for (i = 0; i < numExtensions; i++)
14615     {
14616         ExtensionInfo *curext = &(extinfo[i]);
14617         char       *extconfig = curext->extconfig;
14618         char       *extcondition = curext->extcondition;
14619         char      **extconfigarray = NULL;
14620         char      **extconditionarray = NULL;
14621         int         nconfigitems;
14622         int         nconditionitems;
14623 
14624         if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14625           parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14626             nconfigitems == nconditionitems)
14627         {
14628             int         j;
14629 
14630             for (j = 0; j < nconfigitems; j++)
14631             {
14632                 TableInfo  *configtbl;
14633                 Oid         configtbloid = atooid(extconfigarray[j]);
14634                 bool        dumpobj = curext->dobj.dump;
14635 
14636                 configtbl = findTableByOid(configtbloid);
14637                 if (configtbl == NULL)
14638                     continue;
14639 
14640                 /*
14641                  * Tables of not-to-be-dumped extensions shouldn't be dumped
14642                  * unless the table or its schema is explicitly included
14643                  */
14644                 if (!curext->dobj.dump)
14645                 {
14646                     /* check table explicitly requested */
14647                     if (table_include_oids.head != NULL &&
14648                         simple_oid_list_member(&table_include_oids,
14649                                                 configtbloid))
14650                         dumpobj = true;
14651 
14652                     /* check table's schema explicitly requested */
14653                     if (configtbl->dobj.namespace->dobj.dump)
14654                         dumpobj = true;
14655                 }
14656 
14657                 /* check table excluded by an exclusion switch */
14658                 if (table_exclude_oids.head != NULL &&
14659                     simple_oid_list_member(&table_exclude_oids,
14660                                             configtbloid))
14661                     dumpobj = false;
14662 
14663                 /* check schema excluded by an exclusion switch */
14664                 if (simple_oid_list_member(&schema_exclude_oids,
14665                     configtbl->dobj.namespace->dobj.catId.oid))
14666                     dumpobj = false;
14667 
14668                 if (dumpobj)
14669                 {
14670                     /*
14671                      * Note: config tables are dumped without OIDs regardless of
14672                      * the --oids setting.  This is because row filtering
14673                      * conditions aren't compatible with dumping OIDs.
14674                      */
14675                     makeTableDataInfo(configtbl, false);
14676                     if (configtbl->dataObj != NULL)
14677                     {
14678                         if (strlen(extconditionarray[j]) > 0)
14679                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14680                     }
14681                 }
14682             }
14683         }
14684         if (extconfigarray)
14685             free(extconfigarray);
14686         if (extconditionarray)
14687             free(extconditionarray);
14688     }
14689 
14690     destroyPQExpBuffer(query);
14691 }
14692 
14693 /*
14694  * getDependencies --- obtain available dependency data
14695  */
14696 static void
14697 getDependencies(Archive *fout)
14698 {
14699     PQExpBuffer query;
14700     PGresult   *res;
14701     int         ntups,
14702                 i;
14703     int         i_classid,
14704                 i_objid,
14705                 i_refclassid,
14706                 i_refobjid,
14707                 i_deptype;
14708     DumpableObject *dobj,
14709                *refdobj;
14710 
14711     /* No dependency info available before 7.3 */
14712     if (fout->remoteVersion < 70300)
14713         return;
14714 
14715     if (g_verbose)
14716         write_msg(NULL, "reading dependency data\n");
14717 
14718     /* Make sure we are in proper schema */
14719     selectSourceSchema(fout, "pg_catalog");
14720 
14721     query = createPQExpBuffer();
14722 
14723     /*
14724      * PIN dependencies aren't interesting, and EXTENSION dependencies were
14725      * already processed by getExtensionMembership.
14726      */
14727     appendPQExpBuffer(query, "SELECT "
14728                       "classid, objid, refclassid, refobjid, deptype "
14729                       "FROM pg_depend "
14730                       "WHERE deptype != 'p' AND deptype != 'e' "
14731                       "ORDER BY 1,2");
14732 
14733     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14734 
14735     ntups = PQntuples(res);
14736 
14737     i_classid = PQfnumber(res, "classid");
14738     i_objid = PQfnumber(res, "objid");
14739     i_refclassid = PQfnumber(res, "refclassid");
14740     i_refobjid = PQfnumber(res, "refobjid");
14741     i_deptype = PQfnumber(res, "deptype");
14742 
14743     /*
14744      * Since we ordered the SELECT by referencing ID, we can expect that
14745      * multiple entries for the same object will appear together; this saves
14746      * on searches.
14747      */
14748     dobj = NULL;
14749 
14750     for (i = 0; i < ntups; i++)
14751     {
14752         CatalogId   objId;
14753         CatalogId   refobjId;
14754         char        deptype;
14755 
14756         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14757         objId.oid = atooid(PQgetvalue(res, i, i_objid));
14758         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14759         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14760         deptype = *(PQgetvalue(res, i, i_deptype));
14761 
14762         if (dobj == NULL ||
14763             dobj->catId.tableoid != objId.tableoid ||
14764             dobj->catId.oid != objId.oid)
14765             dobj = findObjectByCatalogId(objId);
14766 
14767         /*
14768          * Failure to find objects mentioned in pg_depend is not unexpected,
14769          * since for example we don't collect info about TOAST tables.
14770          */
14771         if (dobj == NULL)
14772         {
14773 #ifdef NOT_USED
14774             fprintf(stderr, "no referencing object %u %u\n",
14775                     objId.tableoid, objId.oid);
14776 #endif
14777             continue;
14778         }
14779 
14780         refdobj = findObjectByCatalogId(refobjId);
14781 
14782         if (refdobj == NULL)
14783         {
14784 #ifdef NOT_USED
14785             fprintf(stderr, "no referenced object %u %u\n",
14786                     refobjId.tableoid, refobjId.oid);
14787 #endif
14788             continue;
14789         }
14790 
14791         /*
14792          * Ordinarily, table rowtypes have implicit dependencies on their
14793          * tables.  However, for a composite type the implicit dependency goes
14794          * the other way in pg_depend; which is the right thing for DROP but
14795          * it doesn't produce the dependency ordering we need. So in that one
14796          * case, we reverse the direction of the dependency.
14797          */
14798         if (deptype == 'i' &&
14799             dobj->objType == DO_TABLE &&
14800             refdobj->objType == DO_TYPE)
14801             addObjectDependency(refdobj, dobj->dumpId);
14802         else
14803             /* normal case */
14804             addObjectDependency(dobj, refdobj->dumpId);
14805     }
14806 
14807     PQclear(res);
14808 
14809     destroyPQExpBuffer(query);
14810 }
14811 
14812 
14813 /*
14814  * createBoundaryObjects - create dummy DumpableObjects to represent
14815  * dump section boundaries.
14816  */
14817 static DumpableObject *
14818 createBoundaryObjects(void)
14819 {
14820     DumpableObject *dobjs;
14821 
14822     dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
14823 
14824     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
14825     dobjs[0].catId = nilCatalogId;
14826     AssignDumpId(dobjs + 0);
14827     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
14828 
14829     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
14830     dobjs[1].catId = nilCatalogId;
14831     AssignDumpId(dobjs + 1);
14832     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
14833 
14834     return dobjs;
14835 }
14836 
14837 /*
14838  * addBoundaryDependencies - add dependencies as needed to enforce the dump
14839  * section boundaries.
14840  */
14841 static void
14842 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
14843                         DumpableObject *boundaryObjs)
14844 {
14845     DumpableObject *preDataBound = boundaryObjs + 0;
14846     DumpableObject *postDataBound = boundaryObjs + 1;
14847     int         i;
14848 
14849     for (i = 0; i < numObjs; i++)
14850     {
14851         DumpableObject *dobj = dobjs[i];
14852 
14853         /*
14854          * The classification of object types here must match the SECTION_xxx
14855          * values assigned during subsequent ArchiveEntry calls!
14856          */
14857         switch (dobj->objType)
14858         {
14859             case DO_NAMESPACE:
14860             case DO_EXTENSION:
14861             case DO_TYPE:
14862             case DO_SHELL_TYPE:
14863             case DO_FUNC:
14864             case DO_AGG:
14865             case DO_OPERATOR:
14866             case DO_OPCLASS:
14867             case DO_OPFAMILY:
14868             case DO_COLLATION:
14869             case DO_CONVERSION:
14870             case DO_TABLE:
14871             case DO_ATTRDEF:
14872             case DO_PROCLANG:
14873             case DO_CAST:
14874             case DO_DUMMY_TYPE:
14875             case DO_TSPARSER:
14876             case DO_TSDICT:
14877             case DO_TSTEMPLATE:
14878             case DO_TSCONFIG:
14879             case DO_FDW:
14880             case DO_FOREIGN_SERVER:
14881             case DO_BLOB:
14882                 /* Pre-data objects: must come before the pre-data boundary */
14883                 addObjectDependency(preDataBound, dobj->dumpId);
14884                 break;
14885             case DO_TABLE_DATA:
14886             case DO_BLOB_DATA:
14887                 /* Data objects: must come between the boundaries */
14888                 addObjectDependency(dobj, preDataBound->dumpId);
14889                 addObjectDependency(postDataBound, dobj->dumpId);
14890                 break;
14891             case DO_INDEX:
14892             case DO_REFRESH_MATVIEW:
14893             case DO_TRIGGER:
14894             case DO_EVENT_TRIGGER:
14895             case DO_DEFAULT_ACL:
14896                 /* Post-data objects: must come after the post-data boundary */
14897                 addObjectDependency(dobj, postDataBound->dumpId);
14898                 break;
14899             case DO_RULE:
14900                 /* Rules are post-data, but only if dumped separately */
14901                 if (((RuleInfo *) dobj)->separate)
14902                     addObjectDependency(dobj, postDataBound->dumpId);
14903                 break;
14904             case DO_CONSTRAINT:
14905             case DO_FK_CONSTRAINT:
14906                 /* Constraints are post-data, but only if dumped separately */
14907                 if (((ConstraintInfo *) dobj)->separate)
14908                     addObjectDependency(dobj, postDataBound->dumpId);
14909                 break;
14910             case DO_PRE_DATA_BOUNDARY:
14911                 /* nothing to do */
14912                 break;
14913             case DO_POST_DATA_BOUNDARY:
14914                 /* must come after the pre-data boundary */
14915                 addObjectDependency(dobj, preDataBound->dumpId);
14916                 break;
14917         }
14918     }
14919 }
14920 
14921 
14922 /*
14923  * BuildArchiveDependencies - create dependency data for archive TOC entries
14924  *
14925  * The raw dependency data obtained by getDependencies() is not terribly
14926  * useful in an archive dump, because in many cases there are dependency
14927  * chains linking through objects that don't appear explicitly in the dump.
14928  * For example, a view will depend on its _RETURN rule while the _RETURN rule
14929  * will depend on other objects --- but the rule will not appear as a separate
14930  * object in the dump.  We need to adjust the view's dependencies to include
14931  * whatever the rule depends on that is included in the dump.
14932  *
14933  * Just to make things more complicated, there are also "special" dependencies
14934  * such as the dependency of a TABLE DATA item on its TABLE, which we must
14935  * not rearrange because pg_restore knows that TABLE DATA only depends on
14936  * its table.  In these cases we must leave the dependencies strictly as-is
14937  * even if they refer to not-to-be-dumped objects.
14938  *
14939  * To handle this, the convention is that "special" dependencies are created
14940  * during ArchiveEntry calls, and an archive TOC item that has any such
14941  * entries will not be touched here.  Otherwise, we recursively search the
14942  * DumpableObject data structures to build the correct dependencies for each
14943  * archive TOC item.
14944  */
14945 static void
14946 BuildArchiveDependencies(Archive *fout)
14947 {
14948     ArchiveHandle *AH = (ArchiveHandle *) fout;
14949     TocEntry   *te;
14950 
14951     /* Scan all TOC entries in the archive */
14952     for (te = AH->toc->next; te != AH->toc; te = te->next)
14953     {
14954         DumpableObject *dobj;
14955         DumpId     *dependencies;
14956         int         nDeps;
14957         int         allocDeps;
14958 
14959         /* No need to process entries that will not be dumped */
14960         if (te->reqs == 0)
14961             continue;
14962         /* Ignore entries that already have "special" dependencies */
14963         if (te->nDeps > 0)
14964             continue;
14965         /* Otherwise, look up the item's original DumpableObject, if any */
14966         dobj = findObjectByDumpId(te->dumpId);
14967         if (dobj == NULL)
14968             continue;
14969         /* No work if it has no dependencies */
14970         if (dobj->nDeps <= 0)
14971             continue;
14972         /* Set up work array */
14973         allocDeps = 64;
14974         dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
14975         nDeps = 0;
14976         /* Recursively find all dumpable dependencies */
14977         findDumpableDependencies(AH, dobj,
14978                                  &dependencies, &nDeps, &allocDeps);
14979         /* And save 'em ... */
14980         if (nDeps > 0)
14981         {
14982             dependencies = (DumpId *) pg_realloc(dependencies,
14983                                                  nDeps * sizeof(DumpId));
14984             te->dependencies = dependencies;
14985             te->nDeps = nDeps;
14986         }
14987         else
14988             free(dependencies);
14989     }
14990 }
14991 
14992 /* Recursive search subroutine for BuildArchiveDependencies */
14993 static void
14994 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
14995                          DumpId **dependencies, int *nDeps, int *allocDeps)
14996 {
14997     int         i;
14998 
14999     /*
15000      * Ignore section boundary objects: if we search through them, we'll
15001      * report lots of bogus dependencies.
15002      */
15003     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
15004         dobj->objType == DO_POST_DATA_BOUNDARY)
15005         return;
15006 
15007     for (i = 0; i < dobj->nDeps; i++)
15008     {
15009         DumpId      depid = dobj->dependencies[i];
15010 
15011         if (TocIDRequired(AH, depid) != 0)
15012         {
15013             /* Object will be dumped, so just reference it as a dependency */
15014             if (*nDeps >= *allocDeps)
15015             {
15016                 *allocDeps *= 2;
15017                 *dependencies = (DumpId *) pg_realloc(*dependencies,
15018                                                 *allocDeps * sizeof(DumpId));
15019             }
15020             (*dependencies)[*nDeps] = depid;
15021             (*nDeps)++;
15022         }
15023         else
15024         {
15025             /*
15026              * Object will not be dumped, so recursively consider its deps. We
15027              * rely on the assumption that sortDumpableObjects already broke
15028              * any dependency loops, else we might recurse infinitely.
15029              */
15030             DumpableObject *otherdobj = findObjectByDumpId(depid);
15031 
15032             if (otherdobj)
15033                 findDumpableDependencies(AH, otherdobj,
15034                                          dependencies, nDeps, allocDeps);
15035         }
15036     }
15037 }
15038 
15039 
15040 /*
15041  * selectSourceSchema - make the specified schema the active search path
15042  * in the source database.
15043  *
15044  * NB: pg_catalog is explicitly searched after the specified schema;
15045  * so user names are only qualified if they are cross-schema references,
15046  * and system names are only qualified if they conflict with a user name
15047  * in the current schema.
15048  *
15049  * Whenever the selected schema is not pg_catalog, be careful to qualify
15050  * references to system catalogs and types in our emitted commands!
15051  *
15052  * This function is called only from selectSourceSchemaOnAH and
15053  * selectSourceSchema.
15054  */
15055 static void
15056 selectSourceSchema(Archive *fout, const char *schemaName)
15057 {
15058     PQExpBuffer query;
15059 
15060     /* This is checked by the callers already */
15061     Assert(schemaName != NULL && *schemaName != '\0');
15062 
15063     /* Not relevant if fetching from pre-7.3 DB */
15064     if (fout->remoteVersion < 70300)
15065         return;
15066 
15067     query = createPQExpBuffer();
15068     appendPQExpBuffer(query, "SET search_path = %s",
15069                       fmtId(schemaName));
15070     if (strcmp(schemaName, "pg_catalog") != 0)
15071         appendPQExpBuffer(query, ", pg_catalog");
15072 
15073     ExecuteSqlStatement(fout, query->data);
15074 
15075     destroyPQExpBuffer(query);
15076 }
15077 
15078 /*
15079  * getFormattedTypeName - retrieve a nicely-formatted type name for the
15080  * given type name.
15081  *
15082  * NB: in 7.3 and up the result may depend on the currently-selected
15083  * schema; this is why we don't try to cache the names.
15084  */
15085 static char *
15086 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
15087 {
15088     char       *result;
15089     PQExpBuffer query;
15090     PGresult   *res;
15091 
15092     if (oid == 0)
15093     {
15094         if ((opts & zeroAsOpaque) != 0)
15095             return pg_strdup(g_opaque_type);
15096         else if ((opts & zeroAsAny) != 0)
15097             return pg_strdup("'any'");
15098         else if ((opts & zeroAsStar) != 0)
15099             return pg_strdup("*");
15100         else if ((opts & zeroAsNone) != 0)
15101             return pg_strdup("NONE");
15102     }
15103 
15104     query = createPQExpBuffer();
15105     if (fout->remoteVersion >= 70300)
15106     {
15107         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
15108                           oid);
15109     }
15110     else if (fout->remoteVersion >= 70100)
15111     {
15112         appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
15113                           oid);
15114     }
15115     else
15116     {
15117         appendPQExpBuffer(query, "SELECT typname "
15118                           "FROM pg_type "
15119                           "WHERE oid = '%u'::oid",
15120                           oid);
15121     }
15122 
15123     res = ExecuteSqlQueryForSingleRow(fout, query->data);
15124 
15125     if (fout->remoteVersion >= 70100)
15126     {
15127         /* already quoted */
15128         result = pg_strdup(PQgetvalue(res, 0, 0));
15129     }
15130     else
15131     {
15132         /* may need to quote it */
15133         result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
15134     }
15135 
15136     PQclear(res);
15137     destroyPQExpBuffer(query);
15138 
15139     return result;
15140 }
15141 
15142 /*
15143  * myFormatType --- local implementation of format_type for use with 7.0.
15144  */
15145 static char *
15146 myFormatType(const char *typname, int32 typmod)
15147 {
15148     char       *result;
15149     bool        isarray = false;
15150     PQExpBuffer buf = createPQExpBuffer();
15151 
15152     /* Handle array types */
15153     if (typname[0] == '_')
15154     {
15155         isarray = true;
15156         typname++;
15157     }
15158 
15159     /* Show lengths on bpchar and varchar */
15160     if (strcmp(typname, "bpchar") == 0)
15161     {
15162         int         len = (typmod - VARHDRSZ);
15163 
15164         appendPQExpBuffer(buf, "character");
15165         if (len > 1)
15166             appendPQExpBuffer(buf, "(%d)",
15167                               typmod - VARHDRSZ);
15168     }
15169     else if (strcmp(typname, "varchar") == 0)
15170     {
15171         appendPQExpBuffer(buf, "character varying");
15172         if (typmod != -1)
15173             appendPQExpBuffer(buf, "(%d)",
15174                               typmod - VARHDRSZ);
15175     }
15176     else if (strcmp(typname, "numeric") == 0)
15177     {
15178         appendPQExpBuffer(buf, "numeric");
15179         if (typmod != -1)
15180         {
15181             int32       tmp_typmod;
15182             int         precision;
15183             int         scale;
15184 
15185             tmp_typmod = typmod - VARHDRSZ;
15186             precision = (tmp_typmod >> 16) & 0xffff;
15187             scale = tmp_typmod & 0xffff;
15188             appendPQExpBuffer(buf, "(%d,%d)",
15189                               precision, scale);
15190         }
15191     }
15192 
15193     /*
15194      * char is an internal single-byte data type; Let's make sure we force it
15195      * through with quotes. - thomas 1998-12-13
15196      */
15197     else if (strcmp(typname, "char") == 0)
15198         appendPQExpBuffer(buf, "\"char\"");
15199     else
15200         appendPQExpBuffer(buf, "%s", fmtId(typname));
15201 
15202     /* Append array qualifier for array types */
15203     if (isarray)
15204         appendPQExpBuffer(buf, "[]");
15205 
15206     result = pg_strdup(buf->data);
15207     destroyPQExpBuffer(buf);
15208 
15209     return result;
15210 }
15211 
15212 /*
15213  * Return a column list clause for the given relation.
15214  *
15215  * Special case: if there are no undropped columns in the relation, return
15216  * "", not an invalid "()" column list.
15217  */
15218 static const char *
15219 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
15220 {
15221     int         numatts = ti->numatts;
15222     char      **attnames = ti->attnames;
15223     bool       *attisdropped = ti->attisdropped;
15224     bool        needComma;
15225     int         i;
15226 
15227     appendPQExpBuffer(buffer, "(");
15228     needComma = false;
15229     for (i = 0; i < numatts; i++)
15230     {
15231         if (attisdropped[i])
15232             continue;
15233         if (needComma)
15234             appendPQExpBuffer(buffer, ", ");
15235         appendPQExpBuffer(buffer, "%s", fmtId(attnames[i]));
15236         needComma = true;
15237     }
15238 
15239     if (!needComma)
15240         return "";              /* no undropped columns */
15241 
15242     appendPQExpBuffer(buffer, ")");
15243     return buffer->data;
15244 }
15245 
15246 /*
15247  * Execute an SQL query and verify that we got exactly one row back.
15248  */
15249 static PGresult *
15250 ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
15251 {
15252     PGresult   *res;
15253     int         ntups;
15254 
15255     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
15256 
15257     /* Expecting a single result only */
15258     ntups = PQntuples(res);
15259     if (ntups != 1)
15260         exit_horribly(NULL,
15261                       ngettext("query returned %d row instead of one: %s\n",
15262                                "query returned %d rows instead of one: %s\n",
15263                                ntups),
15264                       ntups, query);
15265 
15266     return res;
15267 }