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