PageRenderTime 129ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 1ms

/src/bin/pg_dump/pg_dump.c

https://github.com/matheusoliveira/postgres
C | 15699 lines | 11346 code | 1874 blank | 2479 comment | 1611 complexity | bb079b515b6be228674b0fcc00c8e61b MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*-------------------------------------------------------------------------
  2. *
  3. * pg_dump.c
  4. * pg_dump is a utility for dumping out a postgres database
  5. * into a script file.
  6. *
  7. * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
  8. * Portions Copyright (c) 1994, Regents of the University of California
  9. *
  10. * pg_dump will read the system catalogs in a database and dump out a
  11. * script that reproduces the schema in terms of SQL that is understood
  12. * by PostgreSQL
  13. *
  14. * Note that pg_dump runs in a transaction-snapshot mode transaction,
  15. * so it sees a consistent snapshot of the database including system
  16. * catalogs. However, it relies in part on various specialized backend
  17. * functions like pg_get_indexdef(), and those things tend to look at
  18. * the currently committed state. So it is possible to get 'cache
  19. * lookup failed' error if someone performs DDL changes while a dump is
  20. * happening. The window for this sort of thing is from the acquisition
  21. * of the transaction snapshot to getSchemaData() (when pg_dump acquires
  22. * AccessShareLock on every table it intends to dump). It isn't very large,
  23. * but it can happen.
  24. *
  25. * http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
  26. *
  27. * IDENTIFICATION
  28. * src/bin/pg_dump/pg_dump.c
  29. *
  30. *-------------------------------------------------------------------------
  31. */
  32. #include "postgres_fe.h"
  33. #include <unistd.h>
  34. #include <ctype.h>
  35. #ifdef ENABLE_NLS
  36. #include <locale.h>
  37. #endif
  38. #ifdef HAVE_TERMIOS_H
  39. #include <termios.h>
  40. #endif
  41. #include "getopt_long.h"
  42. #include "access/attnum.h"
  43. #include "access/sysattr.h"
  44. #include "access/transam.h"
  45. #include "catalog/pg_cast.h"
  46. #include "catalog/pg_class.h"
  47. #include "catalog/pg_default_acl.h"
  48. #include "catalog/pg_event_trigger.h"
  49. #include "catalog/pg_largeobject.h"
  50. #include "catalog/pg_largeobject_metadata.h"
  51. #include "catalog/pg_proc.h"
  52. #include "catalog/pg_trigger.h"
  53. #include "catalog/pg_type.h"
  54. #include "libpq/libpq-fs.h"
  55. #include "pg_backup_archiver.h"
  56. #include "pg_backup_db.h"
  57. #include "pg_backup_utils.h"
  58. #include "dumputils.h"
  59. #include "parallel.h"
  60. typedef struct
  61. {
  62. const char *descr; /* comment for an object */
  63. Oid classoid; /* object class (catalog OID) */
  64. Oid objoid; /* object OID */
  65. int objsubid; /* subobject (table column #) */
  66. } CommentItem;
  67. typedef struct
  68. {
  69. const char *provider; /* label provider of this security label */
  70. const char *label; /* security label for an object */
  71. Oid classoid; /* object class (catalog OID) */
  72. Oid objoid; /* object OID */
  73. int objsubid; /* subobject (table column #) */
  74. } SecLabelItem;
  75. /* global decls */
  76. bool g_verbose; /* User wants verbose narration of our
  77. * activities. */
  78. /* various user-settable parameters */
  79. static bool schemaOnly;
  80. static bool dataOnly;
  81. static int dumpSections; /* bitmask of chosen sections */
  82. static bool aclsSkip;
  83. static const char *lockWaitTimeout;
  84. /* subquery used to convert user ID (eg, datdba) to user name */
  85. static const char *username_subquery;
  86. /* obsolete as of 7.3: */
  87. static Oid g_last_builtin_oid; /* value of the last builtin oid */
  88. /*
  89. * Object inclusion/exclusion lists
  90. *
  91. * The string lists record the patterns given by command-line switches,
  92. * which we then convert to lists of OIDs of matching objects.
  93. */
  94. static SimpleStringList schema_include_patterns = {NULL, NULL};
  95. static SimpleOidList schema_include_oids = {NULL, NULL};
  96. static SimpleStringList schema_exclude_patterns = {NULL, NULL};
  97. static SimpleOidList schema_exclude_oids = {NULL, NULL};
  98. static SimpleStringList table_include_patterns = {NULL, NULL};
  99. static SimpleOidList table_include_oids = {NULL, NULL};
  100. static SimpleStringList table_exclude_patterns = {NULL, NULL};
  101. static SimpleOidList table_exclude_oids = {NULL, NULL};
  102. static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
  103. static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
  104. /* default, if no "inclusion" switches appear, is to dump everything */
  105. static bool include_everything = true;
  106. char g_opaque_type[10]; /* name for the opaque type */
  107. /* placeholders for the delimiters for comments */
  108. char g_comment_start[10];
  109. char g_comment_end[10];
  110. static const CatalogId nilCatalogId = {0, 0};
  111. /* flags for various command-line long options */
  112. static int binary_upgrade = 0;
  113. static int disable_dollar_quoting = 0;
  114. static int dump_inserts = 0;
  115. static int column_inserts = 0;
  116. static int if_exists = 0;
  117. static int no_security_labels = 0;
  118. static int no_synchronized_snapshots = 0;
  119. static int no_unlogged_table_data = 0;
  120. static int serializable_deferrable = 0;
  121. static void help(const char *progname);
  122. static void setup_connection(Archive *AH, const char *dumpencoding,
  123. char *use_role);
  124. static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
  125. static void expand_schema_name_patterns(Archive *fout,
  126. SimpleStringList *patterns,
  127. SimpleOidList *oids);
  128. static void expand_table_name_patterns(Archive *fout,
  129. SimpleStringList *patterns,
  130. SimpleOidList *oids);
  131. static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
  132. static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
  133. static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
  134. static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
  135. static void dumpComment(Archive *fout, const char *target,
  136. const char *namespace, const char *owner,
  137. CatalogId catalogId, int subid, DumpId dumpId);
  138. static int findComments(Archive *fout, Oid classoid, Oid objoid,
  139. CommentItem **items);
  140. static int collectComments(Archive *fout, CommentItem **items);
  141. static void dumpSecLabel(Archive *fout, const char *target,
  142. const char *namespace, const char *owner,
  143. CatalogId catalogId, int subid, DumpId dumpId);
  144. static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
  145. SecLabelItem **items);
  146. static int collectSecLabels(Archive *fout, SecLabelItem **items);
  147. static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
  148. static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
  149. static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
  150. static void dumpType(Archive *fout, TypeInfo *tyinfo);
  151. static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
  152. static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
  153. static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
  154. static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
  155. static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
  156. static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
  157. static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
  158. static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
  159. static void dumpFunc(Archive *fout, FuncInfo *finfo);
  160. static void dumpCast(Archive *fout, CastInfo *cast);
  161. static void dumpOpr(Archive *fout, OprInfo *oprinfo);
  162. static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
  163. static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
  164. static void dumpCollation(Archive *fout, CollInfo *convinfo);
  165. static void dumpConversion(Archive *fout, ConvInfo *convinfo);
  166. static void dumpRule(Archive *fout, RuleInfo *rinfo);
  167. static void dumpAgg(Archive *fout, AggInfo *agginfo);
  168. static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
  169. static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
  170. static void dumpTable(Archive *fout, TableInfo *tbinfo);
  171. static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
  172. static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
  173. static void dumpSequence(Archive *fout, TableInfo *tbinfo);
  174. static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
  175. static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
  176. static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
  177. static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
  178. static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
  179. static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
  180. static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
  181. static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
  182. static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
  183. static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
  184. static void dumpUserMappings(Archive *fout,
  185. const char *servername, const char *namespace,
  186. const char *owner, CatalogId catalogId, DumpId dumpId);
  187. static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
  188. static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
  189. const char *type, const char *name, const char *subname,
  190. const char *tag, const char *nspname, const char *owner,
  191. const char *acls);
  192. static void getDependencies(Archive *fout);
  193. static void BuildArchiveDependencies(Archive *fout);
  194. static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
  195. DumpId **dependencies, int *nDeps, int *allocDeps);
  196. static DumpableObject *createBoundaryObjects(void);
  197. static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
  198. DumpableObject *boundaryObjs);
  199. static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
  200. static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
  201. static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
  202. static void buildMatViewRefreshDependencies(Archive *fout);
  203. static void getTableDataFKConstraints(void);
  204. static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
  205. bool is_agg);
  206. static char *format_function_arguments_old(Archive *fout,
  207. FuncInfo *finfo, int nallargs,
  208. char **allargtypes,
  209. char **argmodes,
  210. char **argnames);
  211. static char *format_function_signature(Archive *fout,
  212. FuncInfo *finfo, bool honor_quotes);
  213. static char *convertRegProcReference(Archive *fout,
  214. const char *proc);
  215. static char *convertOperatorReference(Archive *fout, const char *opr);
  216. static const char *convertTSFunction(Archive *fout, Oid funcOid);
  217. static Oid findLastBuiltinOid_V71(Archive *fout, const char *);
  218. static Oid findLastBuiltinOid_V70(Archive *fout);
  219. static void selectSourceSchema(Archive *fout, const char *schemaName);
  220. static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
  221. static char *myFormatType(const char *typname, int32 typmod);
  222. static void getBlobs(Archive *fout);
  223. static void dumpBlob(Archive *fout, BlobInfo *binfo);
  224. static int dumpBlobs(Archive *fout, void *arg);
  225. static void dumpDatabase(Archive *AH);
  226. static void dumpEncoding(Archive *AH);
  227. static void dumpStdStrings(Archive *AH);
  228. static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
  229. PQExpBuffer upgrade_buffer, Oid pg_type_oid);
  230. static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
  231. PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
  232. static void binary_upgrade_set_pg_class_oids(Archive *fout,
  233. PQExpBuffer upgrade_buffer,
  234. Oid pg_class_oid, bool is_index);
  235. static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
  236. DumpableObject *dobj,
  237. const char *objlabel);
  238. static const char *getAttrName(int attrnum, TableInfo *tblInfo);
  239. static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
  240. static char *get_synchronized_snapshot(Archive *fout);
  241. static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
  242. static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt);
  243. int
  244. main(int argc, char **argv)
  245. {
  246. int c;
  247. const char *filename = NULL;
  248. const char *format = "p";
  249. const char *dbname = NULL;
  250. const char *pghost = NULL;
  251. const char *pgport = NULL;
  252. const char *username = NULL;
  253. const char *dumpencoding = NULL;
  254. bool oids = false;
  255. TableInfo *tblinfo;
  256. int numTables;
  257. DumpableObject **dobjs;
  258. int numObjs;
  259. DumpableObject *boundaryObjs;
  260. int i;
  261. int numWorkers = 1;
  262. enum trivalue prompt_password = TRI_DEFAULT;
  263. int compressLevel = -1;
  264. int plainText = 0;
  265. int outputClean = 0;
  266. int outputCreateDB = 0;
  267. bool outputBlobs = false;
  268. int outputNoOwner = 0;
  269. char *outputSuperuser = NULL;
  270. char *use_role = NULL;
  271. int optindex;
  272. RestoreOptions *ropt;
  273. ArchiveFormat archiveFormat = archUnknown;
  274. ArchiveMode archiveMode;
  275. Archive *fout; /* the script file */
  276. static int disable_triggers = 0;
  277. static int outputNoTablespaces = 0;
  278. static int use_setsessauth = 0;
  279. static struct option long_options[] = {
  280. {"data-only", no_argument, NULL, 'a'},
  281. {"blobs", no_argument, NULL, 'b'},
  282. {"clean", no_argument, NULL, 'c'},
  283. {"create", no_argument, NULL, 'C'},
  284. {"dbname", required_argument, NULL, 'd'},
  285. {"file", required_argument, NULL, 'f'},
  286. {"format", required_argument, NULL, 'F'},
  287. {"host", required_argument, NULL, 'h'},
  288. {"ignore-version", no_argument, NULL, 'i'},
  289. {"jobs", 1, NULL, 'j'},
  290. {"no-reconnect", no_argument, NULL, 'R'},
  291. {"oids", no_argument, NULL, 'o'},
  292. {"no-owner", no_argument, NULL, 'O'},
  293. {"port", required_argument, NULL, 'p'},
  294. {"schema", required_argument, NULL, 'n'},
  295. {"exclude-schema", required_argument, NULL, 'N'},
  296. {"schema-only", no_argument, NULL, 's'},
  297. {"superuser", required_argument, NULL, 'S'},
  298. {"table", required_argument, NULL, 't'},
  299. {"exclude-table", required_argument, NULL, 'T'},
  300. {"no-password", no_argument, NULL, 'w'},
  301. {"password", no_argument, NULL, 'W'},
  302. {"username", required_argument, NULL, 'U'},
  303. {"verbose", no_argument, NULL, 'v'},
  304. {"no-privileges", no_argument, NULL, 'x'},
  305. {"no-acl", no_argument, NULL, 'x'},
  306. {"compress", required_argument, NULL, 'Z'},
  307. {"encoding", required_argument, NULL, 'E'},
  308. {"help", no_argument, NULL, '?'},
  309. {"version", no_argument, NULL, 'V'},
  310. /*
  311. * the following options don't have an equivalent short option letter
  312. */
  313. {"attribute-inserts", no_argument, &column_inserts, 1},
  314. {"binary-upgrade", no_argument, &binary_upgrade, 1},
  315. {"column-inserts", no_argument, &column_inserts, 1},
  316. {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
  317. {"disable-triggers", no_argument, &disable_triggers, 1},
  318. {"exclude-table-data", required_argument, NULL, 4},
  319. {"if-exists", no_argument, &if_exists, 1},
  320. {"inserts", no_argument, &dump_inserts, 1},
  321. {"lock-wait-timeout", required_argument, NULL, 2},
  322. {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
  323. {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
  324. {"role", required_argument, NULL, 3},
  325. {"section", required_argument, NULL, 5},
  326. {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
  327. {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
  328. {"no-security-labels", no_argument, &no_security_labels, 1},
  329. {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
  330. {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
  331. {NULL, 0, NULL, 0}
  332. };
  333. set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
  334. /*
  335. * Initialize what we need for parallel execution, especially for thread
  336. * support on Windows.
  337. */
  338. init_parallel_dump_utils();
  339. g_verbose = false;
  340. strcpy(g_comment_start, "-- ");
  341. g_comment_end[0] = '\0';
  342. strcpy(g_opaque_type, "opaque");
  343. dataOnly = schemaOnly = false;
  344. dumpSections = DUMP_UNSECTIONED;
  345. lockWaitTimeout = NULL;
  346. progname = get_progname(argv[0]);
  347. /* Set default options based on progname */
  348. if (strcmp(progname, "pg_backup") == 0)
  349. format = "c";
  350. if (argc > 1)
  351. {
  352. if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
  353. {
  354. help(progname);
  355. exit_nicely(0);
  356. }
  357. if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
  358. {
  359. puts("pg_dump (PostgreSQL) " PG_VERSION);
  360. exit_nicely(0);
  361. }
  362. }
  363. while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:n:N:oOp:RsS:t:T:U:vwWxZ:",
  364. long_options, &optindex)) != -1)
  365. {
  366. switch (c)
  367. {
  368. case 'a': /* Dump data only */
  369. dataOnly = true;
  370. break;
  371. case 'b': /* Dump blobs */
  372. outputBlobs = true;
  373. break;
  374. case 'c': /* clean (i.e., drop) schema prior to create */
  375. outputClean = 1;
  376. break;
  377. case 'C': /* Create DB */
  378. outputCreateDB = 1;
  379. break;
  380. case 'd': /* database name */
  381. dbname = pg_strdup(optarg);
  382. break;
  383. case 'E': /* Dump encoding */
  384. dumpencoding = pg_strdup(optarg);
  385. break;
  386. case 'f':
  387. filename = pg_strdup(optarg);
  388. break;
  389. case 'F':
  390. format = pg_strdup(optarg);
  391. break;
  392. case 'h': /* server host */
  393. pghost = pg_strdup(optarg);
  394. break;
  395. case 'i':
  396. /* ignored, deprecated option */
  397. break;
  398. case 'j': /* number of dump jobs */
  399. numWorkers = atoi(optarg);
  400. break;
  401. case 'n': /* include schema(s) */
  402. simple_string_list_append(&schema_include_patterns, optarg);
  403. include_everything = false;
  404. break;
  405. case 'N': /* exclude schema(s) */
  406. simple_string_list_append(&schema_exclude_patterns, optarg);
  407. break;
  408. case 'o': /* Dump oids */
  409. oids = true;
  410. break;
  411. case 'O': /* Don't reconnect to match owner */
  412. outputNoOwner = 1;
  413. break;
  414. case 'p': /* server port */
  415. pgport = pg_strdup(optarg);
  416. break;
  417. case 'R':
  418. /* no-op, still accepted for backwards compatibility */
  419. break;
  420. case 's': /* dump schema only */
  421. schemaOnly = true;
  422. break;
  423. case 'S': /* Username for superuser in plain text output */
  424. outputSuperuser = pg_strdup(optarg);
  425. break;
  426. case 't': /* include table(s) */
  427. simple_string_list_append(&table_include_patterns, optarg);
  428. include_everything = false;
  429. break;
  430. case 'T': /* exclude table(s) */
  431. simple_string_list_append(&table_exclude_patterns, optarg);
  432. break;
  433. case 'U':
  434. username = pg_strdup(optarg);
  435. break;
  436. case 'v': /* verbose */
  437. g_verbose = true;
  438. break;
  439. case 'w':
  440. prompt_password = TRI_NO;
  441. break;
  442. case 'W':
  443. prompt_password = TRI_YES;
  444. break;
  445. case 'x': /* skip ACL dump */
  446. aclsSkip = true;
  447. break;
  448. case 'Z': /* Compression Level */
  449. compressLevel = atoi(optarg);
  450. break;
  451. case 0:
  452. /* This covers the long options. */
  453. break;
  454. case 2: /* lock-wait-timeout */
  455. lockWaitTimeout = pg_strdup(optarg);
  456. break;
  457. case 3: /* SET ROLE */
  458. use_role = pg_strdup(optarg);
  459. break;
  460. case 4: /* exclude table(s) data */
  461. simple_string_list_append(&tabledata_exclude_patterns, optarg);
  462. break;
  463. case 5: /* section */
  464. set_dump_section(optarg, &dumpSections);
  465. break;
  466. default:
  467. fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
  468. exit_nicely(1);
  469. }
  470. }
  471. /*
  472. * Non-option argument specifies database name as long as it wasn't
  473. * already specified with -d / --dbname
  474. */
  475. if (optind < argc && dbname == NULL)
  476. dbname = argv[optind++];
  477. /* Complain if any arguments remain */
  478. if (optind < argc)
  479. {
  480. fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
  481. progname, argv[optind]);
  482. fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
  483. progname);
  484. exit_nicely(1);
  485. }
  486. /* --column-inserts implies --inserts */
  487. if (column_inserts)
  488. dump_inserts = 1;
  489. if (dataOnly && schemaOnly)
  490. {
  491. write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
  492. exit_nicely(1);
  493. }
  494. if (dataOnly && outputClean)
  495. {
  496. write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
  497. exit_nicely(1);
  498. }
  499. if (dump_inserts && oids)
  500. {
  501. write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
  502. write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
  503. exit_nicely(1);
  504. }
  505. if (if_exists && !outputClean)
  506. exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
  507. /* Identify archive format to emit */
  508. archiveFormat = parseArchiveFormat(format, &archiveMode);
  509. /* archiveFormat specific setup */
  510. if (archiveFormat == archNull)
  511. plainText = 1;
  512. /* Custom and directory formats are compressed by default, others not */
  513. if (compressLevel == -1)
  514. {
  515. if (archiveFormat == archCustom || archiveFormat == archDirectory)
  516. compressLevel = Z_DEFAULT_COMPRESSION;
  517. else
  518. compressLevel = 0;
  519. }
  520. /*
  521. * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
  522. * parallel jobs because that's the maximum limit for the
  523. * WaitForMultipleObjects() call.
  524. */
  525. if (numWorkers <= 0
  526. #ifdef WIN32
  527. || numWorkers > MAXIMUM_WAIT_OBJECTS
  528. #endif
  529. )
  530. exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
  531. /* Parallel backup only in the directory archive format so far */
  532. if (archiveFormat != archDirectory && numWorkers > 1)
  533. exit_horribly(NULL, "parallel backup only supported by the directory format\n");
  534. /* Open the output file */
  535. fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
  536. setupDumpWorker);
  537. /* Register the cleanup hook */
  538. on_exit_close_archive(fout);
  539. if (fout == NULL)
  540. exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
  541. /* Let the archiver know how noisy to be */
  542. fout->verbose = g_verbose;
  543. /*
  544. * We allow the server to be back to 7.0, and up to any minor release of
  545. * our own major version. (See also version check in pg_dumpall.c.)
  546. */
  547. fout->minRemoteVersion = 70000;
  548. fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
  549. fout->numWorkers = numWorkers;
  550. /*
  551. * Open the database using the Archiver, so it knows about it. Errors mean
  552. * death.
  553. */
  554. ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
  555. setup_connection(fout, dumpencoding, use_role);
  556. /*
  557. * Disable security label support if server version < v9.1.x (prevents
  558. * access to nonexistent pg_seclabel catalog)
  559. */
  560. if (fout->remoteVersion < 90100)
  561. no_security_labels = 1;
  562. /*
  563. * When running against 9.0 or later, check if we are in recovery mode,
  564. * which means we are on a hot standby.
  565. */
  566. if (fout->remoteVersion >= 90000)
  567. {
  568. PGresult *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
  569. if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
  570. {
  571. /*
  572. * On hot standby slaves, never try to dump unlogged table data,
  573. * since it will just throw an error.
  574. */
  575. no_unlogged_table_data = true;
  576. }
  577. PQclear(res);
  578. }
  579. /* Select the appropriate subquery to convert user IDs to names */
  580. if (fout->remoteVersion >= 80100)
  581. username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
  582. else if (fout->remoteVersion >= 70300)
  583. username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
  584. else
  585. username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
  586. /* check the version for the synchronized snapshots feature */
  587. if (numWorkers > 1 && fout->remoteVersion < 90200
  588. && !no_synchronized_snapshots)
  589. exit_horribly(NULL,
  590. "Synchronized snapshots are not supported by this server version.\n"
  591. "Run with --no-synchronized-snapshots instead if you do not need\n"
  592. "synchronized snapshots.\n");
  593. /* Find the last built-in OID, if needed */
  594. if (fout->remoteVersion < 70300)
  595. {
  596. if (fout->remoteVersion >= 70100)
  597. g_last_builtin_oid = findLastBuiltinOid_V71(fout,
  598. PQdb(GetConnection(fout)));
  599. else
  600. g_last_builtin_oid = findLastBuiltinOid_V70(fout);
  601. if (g_verbose)
  602. write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
  603. }
  604. /* Expand schema selection patterns into OID lists */
  605. if (schema_include_patterns.head != NULL)
  606. {
  607. expand_schema_name_patterns(fout, &schema_include_patterns,
  608. &schema_include_oids);
  609. if (schema_include_oids.head == NULL)
  610. exit_horribly(NULL, "No matching schemas were found\n");
  611. }
  612. expand_schema_name_patterns(fout, &schema_exclude_patterns,
  613. &schema_exclude_oids);
  614. /* non-matching exclusion patterns aren't an error */
  615. /* Expand table selection patterns into OID lists */
  616. if (table_include_patterns.head != NULL)
  617. {
  618. expand_table_name_patterns(fout, &table_include_patterns,
  619. &table_include_oids);
  620. if (table_include_oids.head == NULL)
  621. exit_horribly(NULL, "No matching tables were found\n");
  622. }
  623. expand_table_name_patterns(fout, &table_exclude_patterns,
  624. &table_exclude_oids);
  625. expand_table_name_patterns(fout, &tabledata_exclude_patterns,
  626. &tabledata_exclude_oids);
  627. /* non-matching exclusion patterns aren't an error */
  628. /*
  629. * Dumping blobs is now default unless we saw an inclusion switch or -s
  630. * ... but even if we did see one of these, -b turns it back on.
  631. */
  632. if (include_everything && !schemaOnly)
  633. outputBlobs = true;
  634. /*
  635. * Now scan the database and create DumpableObject structs for all the
  636. * objects we intend to dump.
  637. */
  638. tblinfo = getSchemaData(fout, &numTables);
  639. if (fout->remoteVersion < 80400)
  640. guessConstraintInheritance(tblinfo, numTables);
  641. if (!schemaOnly)
  642. {
  643. getTableData(tblinfo, numTables, oids);
  644. buildMatViewRefreshDependencies(fout);
  645. if (dataOnly)
  646. getTableDataFKConstraints();
  647. }
  648. if (outputBlobs)
  649. getBlobs(fout);
  650. /*
  651. * Collect dependency data to assist in ordering the objects.
  652. */
  653. getDependencies(fout);
  654. /* Lastly, create dummy objects to represent the section boundaries */
  655. boundaryObjs = createBoundaryObjects();
  656. /* Get pointers to all the known DumpableObjects */
  657. getDumpableObjects(&dobjs, &numObjs);
  658. /*
  659. * Add dummy dependencies to enforce the dump section ordering.
  660. */
  661. addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
  662. /*
  663. * Sort the objects into a safe dump order (no forward references).
  664. *
  665. * In 7.3 or later, we can rely on dependency information to help us
  666. * determine a safe order, so the initial sort is mostly for cosmetic
  667. * purposes: we sort by name to ensure that logically identical schemas
  668. * will dump identically. Before 7.3 we don't have dependencies and we
  669. * use OID ordering as an (unreliable) guide to creation order.
  670. */
  671. if (fout->remoteVersion >= 70300)
  672. sortDumpableObjectsByTypeName(dobjs, numObjs);
  673. else
  674. sortDumpableObjectsByTypeOid(dobjs, numObjs);
  675. /* If we do a parallel dump, we want the largest tables to go first */
  676. if (archiveFormat == archDirectory && numWorkers > 1)
  677. sortDataAndIndexObjectsBySize(dobjs, numObjs);
  678. sortDumpableObjects(dobjs, numObjs,
  679. boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
  680. /*
  681. * Create archive TOC entries for all the objects to be dumped, in a safe
  682. * order.
  683. */
  684. /* First the special ENCODING and STDSTRINGS entries. */
  685. dumpEncoding(fout);
  686. dumpStdStrings(fout);
  687. /* The database item is always next, unless we don't want it at all */
  688. if (include_everything && !dataOnly)
  689. dumpDatabase(fout);
  690. /* Now the rearrangeable objects. */
  691. for (i = 0; i < numObjs; i++)
  692. dumpDumpableObject(fout, dobjs[i]);
  693. /*
  694. * Set up options info to ensure we dump what we want.
  695. */
  696. ropt = NewRestoreOptions();
  697. ropt->filename = filename;
  698. ropt->dropSchema = outputClean;
  699. ropt->dataOnly = dataOnly;
  700. ropt->schemaOnly = schemaOnly;
  701. ropt->if_exists = if_exists;
  702. ropt->dumpSections = dumpSections;
  703. ropt->aclsSkip = aclsSkip;
  704. ropt->superuser = outputSuperuser;
  705. ropt->createDB = outputCreateDB;
  706. ropt->noOwner = outputNoOwner;
  707. ropt->noTablespace = outputNoTablespaces;
  708. ropt->disable_triggers = disable_triggers;
  709. ropt->use_setsessauth = use_setsessauth;
  710. if (compressLevel == -1)
  711. ropt->compression = 0;
  712. else
  713. ropt->compression = compressLevel;
  714. ropt->suppressDumpWarnings = true; /* We've already shown them */
  715. SetArchiveRestoreOptions(fout, ropt);
  716. /*
  717. * The archive's TOC entries are now marked as to which ones will actually
  718. * be output, so we can set up their dependency lists properly. This isn't
  719. * necessary for plain-text output, though.
  720. */
  721. if (!plainText)
  722. BuildArchiveDependencies(fout);
  723. /*
  724. * And finally we can do the actual output.
  725. *
  726. * Note: for non-plain-text output formats, the output file is written
  727. * inside CloseArchive(). This is, um, bizarre; but not worth changing
  728. * right now.
  729. */
  730. if (plainText)
  731. RestoreArchive(fout);
  732. CloseArchive(fout);
  733. exit_nicely(0);
  734. }
  735. static void
  736. help(const char *progname)
  737. {
  738. printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
  739. printf(_("Usage:\n"));
  740. printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
  741. printf(_("\nGeneral options:\n"));
  742. printf(_(" -f, --file=FILENAME output file or directory name\n"));
  743. printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
  744. " plain text (default))\n"));
  745. printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
  746. printf(_(" -v, --verbose verbose mode\n"));
  747. printf(_(" -V, --version output version information, then exit\n"));
  748. printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
  749. printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
  750. printf(_(" -?, --help show this help, then exit\n"));
  751. printf(_("\nOptions controlling the output content:\n"));
  752. printf(_(" -a, --data-only dump only the data, not the schema\n"));
  753. printf(_(" -b, --blobs include large objects in dump\n"));
  754. printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
  755. printf(_(" -C, --create include commands to create database in dump\n"));
  756. printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
  757. printf(_(" -n, --schema=SCHEMA dump the named schema(s) only\n"));
  758. printf(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
  759. printf(_(" -o, --oids include OIDs in dump\n"));
  760. printf(_(" -O, --no-owner skip restoration of object ownership in\n"
  761. " plain-text format\n"));
  762. printf(_(" -s, --schema-only dump only the schema, no data\n"));
  763. printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
  764. printf(_(" -t, --table=TABLE dump the named table(s) only\n"));
  765. printf(_(" -T, --exclude-table=TABLE do NOT dump the named table(s)\n"));
  766. printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
  767. printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
  768. printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
  769. printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
  770. printf(_(" --disable-triggers disable triggers during data-only restore\n"));
  771. printf(_(" --exclude-table-data=TABLE do NOT dump data for the named table(s)\n"));
  772. printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
  773. printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
  774. printf(_(" --no-security-labels do not dump security label assignments\n"));
  775. printf(_(" --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs\n"));
  776. printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
  777. printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
  778. printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
  779. printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
  780. printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
  781. printf(_(" --use-set-session-authorization\n"
  782. " use SET SESSION AUTHORIZATION commands instead of\n"
  783. " ALTER OWNER commands to set ownership\n"));
  784. printf(_("\nConnection options:\n"));
  785. printf(_(" -d, --dbname=DBNAME database to dump\n"));
  786. printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
  787. printf(_(" -p, --port=PORT database server port number\n"));
  788. printf(_(" -U, --username=NAME connect as specified database user\n"));
  789. printf(_(" -w, --no-password never prompt for password\n"));
  790. printf(_(" -W, --password force password prompt (should happen automatically)\n"));
  791. printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
  792. printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
  793. "variable value is used.\n\n"));
  794. printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
  795. }
  796. static void
  797. setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
  798. {
  799. PGconn *conn = GetConnection(AH);
  800. const char *std_strings;
  801. /*
  802. * Set the client encoding if requested. If dumpencoding == NULL then
  803. * either it hasn't been requested or we're a cloned connection and then
  804. * this has already been set in CloneArchive according to the original
  805. * connection encoding.
  806. */
  807. if (dumpencoding)
  808. {
  809. if (PQsetClientEncoding(conn, dumpencoding) < 0)
  810. exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
  811. dumpencoding);
  812. }
  813. /*
  814. * Get the active encoding and the standard_conforming_strings setting, so
  815. * we know how to escape strings.
  816. */
  817. AH->encoding = PQclientEncoding(conn);
  818. std_strings = PQparameterStatus(conn, "standard_conforming_strings");
  819. AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
  820. /* Set the role if requested */
  821. if (!use_role && AH->use_role)
  822. use_role = AH->use_role;
  823. /* Set the role if requested */
  824. if (use_role && AH->remoteVersion >= 80100)
  825. {
  826. PQExpBuffer query = createPQExpBuffer();
  827. appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
  828. ExecuteSqlStatement(AH, query->data);
  829. destroyPQExpBuffer(query);
  830. /* save this for later use on parallel connections */
  831. if (!AH->use_role)
  832. AH->use_role = strdup(use_role);
  833. }
  834. /* Set the datestyle to ISO to ensure the dump's portability */
  835. ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
  836. /* Likewise, avoid using sql_standard intervalstyle */
  837. if (AH->remoteVersion >= 80400)
  838. ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
  839. /*
  840. * If supported, set extra_float_digits so that we can dump float data
  841. * exactly (given correctly implemented float I/O code, anyway)
  842. */
  843. if (AH->remoteVersion >= 90000)
  844. ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
  845. else if (AH->remoteVersion >= 70400)
  846. ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
  847. /*
  848. * If synchronized scanning is supported, disable it, to prevent
  849. * unpredictable changes in row ordering across a dump and reload.
  850. */
  851. if (AH->remoteVersion >= 80300)
  852. ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
  853. /*
  854. * Disable timeouts if supported.
  855. */
  856. if (AH->remoteVersion >= 70300)
  857. ExecuteSqlStatement(AH, "SET statement_timeout = 0");
  858. if (AH->remoteVersion >= 90300)
  859. ExecuteSqlStatement(AH, "SET lock_timeout = 0");
  860. /*
  861. * Quote all identifiers, if requested.
  862. */
  863. if (quote_all_identifiers && AH->remoteVersion >= 90100)
  864. ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
  865. /*
  866. * Start transaction-snapshot mode transaction to dump consistent data.
  867. */
  868. ExecuteSqlStatement(AH, "BEGIN");
  869. if (AH->remoteVersion >= 90100)
  870. {
  871. if (serializable_deferrable)
  872. ExecuteSqlStatement(AH,
  873. "SET TRANSACTION ISOLATION LEVEL "
  874. "SERIALIZABLE, READ ONLY, DEFERRABLE");
  875. else
  876. ExecuteSqlStatement(AH,
  877. "SET TRANSACTION ISOLATION LEVEL "
  878. "REPEATABLE READ, READ ONLY");
  879. }
  880. else if (AH->remoteVersion >= 70400)
  881. {
  882. /* note: comma was not accepted in SET TRANSACTION before 8.0 */
  883. ExecuteSqlStatement(AH,
  884. "SET TRANSACTION ISOLATION LEVEL "
  885. "SERIALIZABLE READ ONLY");
  886. }
  887. else
  888. ExecuteSqlStatement(AH,
  889. "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
  890. if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots)
  891. {
  892. if (AH->sync_snapshot_id)
  893. {
  894. PQExpBuffer query = createPQExpBuffer();
  895. appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
  896. appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
  897. ExecuteSqlStatement(AH, query->data);
  898. destroyPQExpBuffer(query);
  899. }
  900. else
  901. AH->sync_snapshot_id = get_synchronized_snapshot(AH);
  902. }
  903. }
  904. static void
  905. setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
  906. {
  907. setup_connection(AHX, NULL, NULL);
  908. }
  909. static char *
  910. get_synchronized_snapshot(Archive *fout)
  911. {
  912. char *query = "SELECT pg_export_snapshot()";
  913. char *result;
  914. PGresult *res;
  915. res = ExecuteSqlQueryForSingleRow(fout, query);
  916. result = strdup(PQgetvalue(res, 0, 0));
  917. PQclear(res);
  918. return result;
  919. }
  920. static ArchiveFormat
  921. parseArchiveFormat(const char *format, ArchiveMode *mode)
  922. {
  923. ArchiveFormat archiveFormat;
  924. *mode = archModeWrite;
  925. if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
  926. {
  927. /* This is used by pg_dumpall, and is not documented */
  928. archiveFormat = archNull;
  929. *mode = archModeAppend;
  930. }
  931. else if (pg_strcasecmp(format, "c") == 0)
  932. archiveFormat = archCustom;
  933. else if (pg_strcasecmp(format, "custom") == 0)
  934. archiveFormat = archCustom;
  935. else if (pg_strcasecmp(format, "d") == 0)
  936. archiveFormat = archDirectory;
  937. else if (pg_strcasecmp(format, "directory") == 0)
  938. archiveFormat = archDirectory;
  939. else if (pg_strcasecmp(format, "p") == 0)
  940. archiveFormat = archNull;
  941. else if (pg_strcasecmp(format, "plain") == 0)
  942. archiveFormat = archNull;
  943. else if (pg_strcasecmp(format, "t") == 0)
  944. archiveFormat = archTar;
  945. else if (pg_strcasecmp(format, "tar") == 0)
  946. archiveFormat = archTar;
  947. else
  948. exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
  949. return archiveFormat;
  950. }
  951. /*
  952. * Find the OIDs of all schemas matching the given list of patterns,
  953. * and append them to the given OID list.
  954. */
  955. static void
  956. expand_schema_name_patterns(Archive *fout,
  957. SimpleStringList *patterns,
  958. SimpleOidList *oids)
  959. {
  960. PQExpBuffer query;
  961. PGresult *res;
  962. SimpleStringListCell *cell;
  963. int i;
  964. if (patterns->head == NULL)
  965. return; /* nothing to do */
  966. if (fout->remoteVersion < 70300)
  967. exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
  968. query = createPQExpBuffer();
  969. /*
  970. * We use UNION ALL rather than UNION; this might sometimes result in
  971. * duplicate entries in the OID list, but we don't care.
  972. */
  973. for (cell = patterns->head; cell; cell = cell->next)
  974. {
  975. if (cell != patterns->head)
  976. appendPQExpBufferStr(query, "UNION ALL\n");
  977. appendPQExpBuffer(query,
  978. "SELECT oid FROM pg_catalog.pg_namespace n\n");
  979. processSQLNamePattern(GetConnection(fout), query, cell->val, false,
  980. false, NULL, "n.nspname", NULL, NULL);
  981. }
  982. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  983. for (i = 0; i < PQntuples(res); i++)
  984. {
  985. simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
  986. }
  987. PQclear(res);
  988. destroyPQExpBuffer(query);
  989. }
  990. /*
  991. * Find the OIDs of all tables matching the given list of patterns,
  992. * and append them to the given OID list.
  993. */
  994. static void
  995. expand_table_name_patterns(Archive *fout,
  996. SimpleStringList *patterns, SimpleOidList *oids)
  997. {
  998. PQExpBuffer query;
  999. PGresult *res;
  1000. SimpleStringListCell *cell;
  1001. int i;
  1002. if (patterns->head == NULL)
  1003. return; /* nothing to do */
  1004. query = createPQExpBuffer();
  1005. /*
  1006. * We use UNION ALL rather than UNION; this might sometimes result in
  1007. * duplicate entries in the OID list, but we don't care.
  1008. */
  1009. for (cell = patterns->head; cell; cell = cell->next)
  1010. {
  1011. if (cell != patterns->head)
  1012. appendPQExpBufferStr(query, "UNION ALL\n");
  1013. appendPQExpBuffer(query,
  1014. "SELECT c.oid"
  1015. "\nFROM pg_catalog.pg_class c"
  1016. "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
  1017. "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
  1018. RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
  1019. RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
  1020. processSQLNamePattern(GetConnection(fout), query, cell->val, true,
  1021. false, "n.nspname", "c.relname", NULL,
  1022. "pg_catalog.pg_table_is_visible(c.oid)");
  1023. }
  1024. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  1025. for (i = 0; i < PQntuples(res); i++)
  1026. {
  1027. simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
  1028. }
  1029. PQclear(res);
  1030. destroyPQExpBuffer(query);
  1031. }
  1032. /*
  1033. * selectDumpableNamespace: policy-setting subroutine
  1034. * Mark a namespace as to be dumped or not
  1035. */
  1036. static void
  1037. selectDumpableNamespace(NamespaceInfo *nsinfo)
  1038. {
  1039. /*
  1040. * If specific tables are being dumped, do not dump any complete
  1041. * namespaces. If specific namespaces are being dumped, dump just those
  1042. * namespaces. Otherwise, dump all non-system namespaces.
  1043. */
  1044. if (table_include_oids.head != NULL)
  1045. nsinfo->dobj.dump = false;
  1046. else if (schema_include_oids.head != NULL)
  1047. nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
  1048. nsinfo->dobj.catId.oid);
  1049. else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
  1050. strcmp(nsinfo->dobj.name, "information_schema") == 0)
  1051. nsinfo->dobj.dump = false;
  1052. else
  1053. nsinfo->dobj.dump = true;
  1054. /*
  1055. * In any case, a namespace can be excluded by an exclusion switch
  1056. */
  1057. if (nsinfo->dobj.dump &&
  1058. simple_oid_list_member(&schema_exclude_oids,
  1059. nsinfo->dobj.catId.oid))
  1060. nsinfo->dobj.dump = false;
  1061. }
  1062. /*
  1063. * selectDumpableTable: policy-setting subroutine
  1064. * Mark a table as to be dumped or not
  1065. */
  1066. static void
  1067. selectDumpableTable(TableInfo *tbinfo)
  1068. {
  1069. /*
  1070. * If specific tables are being dumped, dump just those tables; else, dump
  1071. * according to the parent namespace's dump flag.
  1072. */
  1073. if (table_include_oids.head != NULL)
  1074. tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
  1075. tbinfo->dobj.catId.oid);
  1076. else
  1077. tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
  1078. /*
  1079. * In any case, a table can be excluded by an exclusion switch
  1080. */
  1081. if (tbinfo->dobj.dump &&
  1082. simple_oid_list_member(&table_exclude_oids,
  1083. tbinfo->dobj.catId.oid))
  1084. tbinfo->dobj.dump = false;
  1085. }
  1086. /*
  1087. * selectDumpableType: policy-setting subroutine
  1088. * Mark a type as to be dumped or not
  1089. *
  1090. * If it's a table's rowtype or an autogenerated array type, we also apply a
  1091. * special type code to facilitate sorting into the desired order. (We don't
  1092. * want to consider those to be ordinary types because that would bring tables
  1093. * up into the datatype part of the dump order.) We still set the object's
  1094. * dump flag; that's not going to cause the dummy type to be dumped, but we
  1095. * need it so that casts involving such types will be dumped correctly -- see
  1096. * dumpCast. This means the flag should be set the same as for the underlying
  1097. * object (the table or base type).
  1098. */
  1099. static void
  1100. selectDumpableType(TypeInfo *tyinfo)
  1101. {
  1102. /* skip complex types, except for standalone composite types */
  1103. if (OidIsValid(tyinfo->typrelid) &&
  1104. tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
  1105. {
  1106. TableInfo *tytable = findTableByOid(tyinfo->typrelid);
  1107. tyinfo->dobj.objType = DO_DUMMY_TYPE;
  1108. if (tytable != NULL)
  1109. tyinfo->dobj.dump = tytable->dobj.dump;
  1110. else
  1111. tyinfo->dobj.dump = false;
  1112. return;
  1113. }
  1114. /* skip auto-generated array types */
  1115. if (tyinfo->isArray)
  1116. {
  1117. tyinfo->dobj.objType = DO_DUMMY_TYPE;
  1118. /*
  1119. * Fall through to set the dump flag; we assume that the subsequent
  1120. * rules will do the same thing as they would for the array's base
  1121. * type. (We cannot reliably look up the base type here, since
  1122. * getTypes may not have processed it yet.)
  1123. */
  1124. }
  1125. /* dump only types in dumpable namespaces */
  1126. if (!tyinfo->dobj.namespace->dobj.dump)
  1127. tyinfo->dobj.dump = false;
  1128. /* skip undefined placeholder types */
  1129. else if (!tyinfo->isDefined)
  1130. tyinfo->dobj.dump = false;
  1131. else
  1132. tyinfo->dobj.dump = true;
  1133. }
  1134. /*
  1135. * selectDumpableDefaultACL: policy-setting subroutine
  1136. * Mark a default ACL as to be dumped or not
  1137. *
  1138. * For per-schema default ACLs, dump if the schema is to be dumped.
  1139. * Otherwise dump if we are dumping "everything". Note that dataOnly
  1140. * and aclsSkip are checked separately.
  1141. */
  1142. static void
  1143. selectDumpableDefaultACL(DefaultACLInfo *dinfo)
  1144. {
  1145. if (dinfo->dobj.namespace)
  1146. dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
  1147. else
  1148. dinfo->dobj.dump = include_everything;
  1149. }
  1150. /*
  1151. * selectDumpableExtension: policy-setting subroutine
  1152. * Mark an extension as to be dumped or not
  1153. *
  1154. * Normally, we dump all extensions, or none of them if include_everything
  1155. * is false (i.e., a --schema or --table switch was given). However, in
  1156. * binary-upgrade mode it's necessary to skip built-in extensions, since we
  1157. * assume those will already be installed in the target database. We identify
  1158. * such extensions by their having OIDs in the range reserved for initdb.
  1159. */
  1160. static void
  1161. selectDumpableExtension(ExtensionInfo *extinfo)
  1162. {
  1163. if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
  1164. extinfo->dobj.dump = false;
  1165. else
  1166. extinfo->dobj.dump = include_everything;
  1167. }
  1168. /*
  1169. * selectDumpableObject: policy-setting subroutine
  1170. * Mark a generic dumpable object as to be dumped or not
  1171. *
  1172. * Use this only for object types without a special-case routine above.
  1173. */
  1174. static void
  1175. selectDumpableObject(DumpableObject *dobj)
  1176. {
  1177. /*
  1178. * Default policy is to dump if parent namespace is dumpable, or always
  1179. * for non-namespace-associated items.
  1180. */
  1181. if (dobj->namespace)
  1182. dobj->dump = dobj->namespace->dobj.dump;
  1183. else
  1184. dobj->dump = true;
  1185. }
  1186. /*
  1187. * Dump a table's contents for loading using the COPY command
  1188. * - this routine is called by the Archiver when it wants the table
  1189. * to be dumped.
  1190. */
  1191. static int
  1192. dumpTableData_copy(Archive *fout, void *dcontext)
  1193. {
  1194. TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
  1195. TableInfo *tbinfo = tdinfo->tdtable;
  1196. const char *classname = tbinfo->dobj.name;
  1197. const bool hasoids = tbinfo->hasoids;
  1198. const bool oids = tdinfo->oids;
  1199. PQExpBuffer q = createPQExpBuffer();
  1200. /*
  1201. * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
  1202. * which uses it already.
  1203. */
  1204. PQExpBuffer clistBuf = createPQExpBuffer();
  1205. PGconn *conn = GetConnection(fout);
  1206. PGresult *res;
  1207. int ret;
  1208. char *copybuf;
  1209. const char *column_list;
  1210. if (g_verbose)
  1211. write_msg(NULL, "dumping contents of table %s\n", classname);
  1212. /*
  1213. * Make sure we are in proper schema. We will qualify the table name
  1214. * below anyway (in case its name conflicts with a pg_catalog table); but
  1215. * this ensures reproducible results in case the table contains regproc,
  1216. * regclass, etc columns.
  1217. */
  1218. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  1219. /*
  1220. * If possible, specify the column list explicitly so that we have no
  1221. * possibility of retrieving data in the wrong column order. (The default
  1222. * column ordering of COPY will not be what we want in certain corner
  1223. * cases involving ADD COLUMN and inheritance.)
  1224. */
  1225. if (fout->remoteVersion >= 70300)
  1226. column_list = fmtCopyColumnList(tbinfo, clistBuf);
  1227. else
  1228. column_list = ""; /* can't select columns in COPY */
  1229. if (oids && hasoids)
  1230. {
  1231. appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
  1232. fmtQualifiedId(fout->remoteVersion,
  1233. tbinfo->dobj.namespace->dobj.name,
  1234. classname),
  1235. column_list);
  1236. }
  1237. else if (tdinfo->filtercond)
  1238. {
  1239. /* Note: this syntax is only supported in 8.2 and up */
  1240. appendPQExpBufferStr(q, "COPY (SELECT ");
  1241. /* klugery to get rid of parens in column list */
  1242. if (strlen(column_list) > 2)
  1243. {
  1244. appendPQExpBufferStr(q, column_list + 1);
  1245. q->data[q->len - 1] = ' ';
  1246. }
  1247. else
  1248. appendPQExpBufferStr(q, "* ");
  1249. appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
  1250. fmtQualifiedId(fout->remoteVersion,
  1251. tbinfo->dobj.namespace->dobj.name,
  1252. classname),
  1253. tdinfo->filtercond);
  1254. }
  1255. else
  1256. {
  1257. appendPQExpBuffer(q, "COPY %s %s TO stdout;",
  1258. fmtQualifiedId(fout->remoteVersion,
  1259. tbinfo->dobj.namespace->dobj.name,
  1260. classname),
  1261. column_list);
  1262. }
  1263. res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
  1264. PQclear(res);
  1265. destroyPQExpBuffer(clistBuf);
  1266. for (;;)
  1267. {
  1268. ret = PQgetCopyData(conn, &copybuf, 0);
  1269. if (ret < 0)
  1270. break; /* done or error */
  1271. if (copybuf)
  1272. {
  1273. WriteData(fout, copybuf, ret);
  1274. PQfreemem(copybuf);
  1275. }
  1276. /* ----------
  1277. * THROTTLE:
  1278. *
  1279. * There was considerable discussion in late July, 2000 regarding
  1280. * slowing down pg_dump when backing up large tables. Users with both
  1281. * slow & fast (multi-processor) machines experienced performance
  1282. * degradation when doing a backup.
  1283. *
  1284. * Initial attempts based on sleeping for a number of ms for each ms
  1285. * of work were deemed too complex, then a simple 'sleep in each loop'
  1286. * implementation was suggested. The latter failed because the loop
  1287. * was too tight. Finally, the following was implemented:
  1288. *
  1289. * If throttle is non-zero, then
  1290. * See how long since the last sleep.
  1291. * Work out how long to sleep (based on ratio).
  1292. * If sleep is more than 100ms, then
  1293. * sleep
  1294. * reset timer
  1295. * EndIf
  1296. * EndIf
  1297. *
  1298. * where the throttle value was the number of ms to sleep per ms of
  1299. * work. The calculation was done in each loop.
  1300. *
  1301. * Most of the hard work is done in the backend, and this solution
  1302. * still did not work particularly well: on slow machines, the ratio
  1303. * was 50:1, and on medium paced machines, 1:1, and on fast
  1304. * multi-processor machines, it had little or no effect, for reasons
  1305. * that were unclear.
  1306. *
  1307. * Further discussion ensued, and the proposal was dropped.
  1308. *
  1309. * For those people who want this feature, it can be implemented using
  1310. * gettimeofday in each loop, calculating the time since last sleep,
  1311. * multiplying that by the sleep ratio, then if the result is more
  1312. * than a preset 'minimum sleep time' (say 100ms), call the 'select'
  1313. * function to sleep for a subsecond period ie.
  1314. *
  1315. * select(0, NULL, NULL, NULL, &tvi);
  1316. *
  1317. * This will return after the interval specified in the structure tvi.
  1318. * Finally, call gettimeofday again to save the 'last sleep time'.
  1319. * ----------
  1320. */
  1321. }
  1322. archprintf(fout, "\\.\n\n\n");
  1323. if (ret == -2)
  1324. {
  1325. /* copy data transfer failed */
  1326. write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
  1327. write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
  1328. write_msg(NULL, "The command was: %s\n", q->data);
  1329. exit_nicely(1);
  1330. }
  1331. /* Check command status and return to normal libpq state */
  1332. res = PQgetResult(conn);
  1333. if (PQresultStatus(res) != PGRES_COMMAND_OK)
  1334. {
  1335. write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
  1336. write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
  1337. write_msg(NULL, "The command was: %s\n", q->data);
  1338. exit_nicely(1);
  1339. }
  1340. PQclear(res);
  1341. destroyPQExpBuffer(q);
  1342. return 1;
  1343. }
  1344. /*
  1345. * Dump table data using INSERT commands.
  1346. *
  1347. * Caution: when we restore from an archive file direct to database, the
  1348. * INSERT commands emitted by this function have to be parsed by
  1349. * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
  1350. * E'' strings, or dollar-quoted strings. So don't emit anything like that.
  1351. */
  1352. static int
  1353. dumpTableData_insert(Archive *fout, void *dcontext)
  1354. {
  1355. TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
  1356. TableInfo *tbinfo = tdinfo->tdtable;
  1357. const char *classname = tbinfo->dobj.name;
  1358. PQExpBuffer q = createPQExpBuffer();
  1359. PQExpBuffer insertStmt = NULL;
  1360. PGresult *res;
  1361. int tuple;
  1362. int nfields;
  1363. int field;
  1364. /*
  1365. * Make sure we are in proper schema. We will qualify the table name
  1366. * below anyway (in case its name conflicts with a pg_catalog table); but
  1367. * this ensures reproducible results in case the table contains regproc,
  1368. * regclass, etc columns.
  1369. */
  1370. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  1371. if (fout->remoteVersion >= 70100)
  1372. {
  1373. appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
  1374. "SELECT * FROM ONLY %s",
  1375. fmtQualifiedId(fout->remoteVersion,
  1376. tbinfo->dobj.namespace->dobj.name,
  1377. classname));
  1378. }
  1379. else
  1380. {
  1381. appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
  1382. "SELECT * FROM %s",
  1383. fmtQualifiedId(fout->remoteVersion,
  1384. tbinfo->dobj.namespace->dobj.name,
  1385. classname));
  1386. }
  1387. if (tdinfo->filtercond)
  1388. appendPQExpBuffer(q, " %s", tdinfo->filtercond);
  1389. ExecuteSqlStatement(fout, q->data);
  1390. while (1)
  1391. {
  1392. res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
  1393. PGRES_TUPLES_OK);
  1394. nfields = PQnfields(res);
  1395. for (tuple = 0; tuple < PQntuples(res); tuple++)
  1396. {
  1397. /*
  1398. * First time through, we build as much of the INSERT statement as
  1399. * possible in "insertStmt", which we can then just print for each
  1400. * line. If the table happens to have zero columns then this will
  1401. * be a complete statement, otherwise it will end in "VALUES(" and
  1402. * be ready to have the row's column values appended.
  1403. */
  1404. if (insertStmt == NULL)
  1405. {
  1406. insertStmt = createPQExpBuffer();
  1407. appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
  1408. fmtId(classname));
  1409. /* corner case for zero-column table */
  1410. if (nfields == 0)
  1411. {
  1412. appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
  1413. }
  1414. else
  1415. {
  1416. /* append the list of column names if required */
  1417. if (column_inserts)
  1418. {
  1419. appendPQExpBufferStr(insertStmt, "(");
  1420. for (field = 0; field < nfields; field++)
  1421. {
  1422. if (field > 0)
  1423. appendPQExpBufferStr(insertStmt, ", ");
  1424. appendPQExpBufferStr(insertStmt,
  1425. fmtId(PQfname(res, field)));
  1426. }
  1427. appendPQExpBufferStr(insertStmt, ") ");
  1428. }
  1429. appendPQExpBufferStr(insertStmt, "VALUES (");
  1430. }
  1431. }
  1432. archputs(insertStmt->data, fout);
  1433. /* if it is zero-column table then we're done */
  1434. if (nfields == 0)
  1435. continue;
  1436. for (field = 0; field < nfields; field++)
  1437. {
  1438. if (field > 0)
  1439. archputs(", ", fout);
  1440. if (PQgetisnull(res, tuple, field))
  1441. {
  1442. archputs("NULL", fout);
  1443. continue;
  1444. }
  1445. /* XXX This code is partially duplicated in ruleutils.c */
  1446. switch (PQftype(res, field))
  1447. {
  1448. case INT2OID:
  1449. case INT4OID:
  1450. case INT8OID:
  1451. case OIDOID:
  1452. case FLOAT4OID:
  1453. case FLOAT8OID:
  1454. case NUMERICOID:
  1455. {
  1456. /*
  1457. * These types are printed without quotes unless
  1458. * they contain values that aren't accepted by the
  1459. * scanner unquoted (e.g., 'NaN'). Note that
  1460. * strtod() and friends might accept NaN, so we
  1461. * can't use that to test.
  1462. *
  1463. * In reality we only need to defend against
  1464. * infinity and NaN, so we need not get too crazy
  1465. * about pattern matching here.
  1466. */
  1467. const char *s = PQgetvalue(res, tuple, field);
  1468. if (strspn(s, "0123456789 +-eE.") == strlen(s))
  1469. archputs(s, fout);
  1470. else
  1471. archprintf(fout, "'%s'", s);
  1472. }
  1473. break;
  1474. case BITOID:
  1475. case VARBITOID:
  1476. archprintf(fout, "B'%s'",
  1477. PQgetvalue(res, tuple, field));
  1478. break;
  1479. case BOOLOID:
  1480. if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
  1481. archputs("true", fout);
  1482. else
  1483. archputs("false", fout);
  1484. break;
  1485. default:
  1486. /* All other types are printed as string literals. */
  1487. resetPQExpBuffer(q);
  1488. appendStringLiteralAH(q,
  1489. PQgetvalue(res, tuple, field),
  1490. fout);
  1491. archputs(q->data, fout);
  1492. break;
  1493. }
  1494. }
  1495. archputs(");\n", fout);
  1496. }
  1497. if (PQntuples(res) <= 0)
  1498. {
  1499. PQclear(res);
  1500. break;
  1501. }
  1502. PQclear(res);
  1503. }
  1504. archputs("\n\n", fout);
  1505. ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
  1506. destroyPQExpBuffer(q);
  1507. if (insertStmt != NULL)
  1508. destroyPQExpBuffer(insertStmt);
  1509. return 1;
  1510. }
  1511. /*
  1512. * dumpTableData -
  1513. * dump the contents of a single table
  1514. *
  1515. * Actually, this just makes an ArchiveEntry for the table contents.
  1516. */
  1517. static void
  1518. dumpTableData(Archive *fout, TableDataInfo *tdinfo)
  1519. {
  1520. TableInfo *tbinfo = tdinfo->tdtable;
  1521. PQExpBuffer copyBuf = createPQExpBuffer();
  1522. PQExpBuffer clistBuf = createPQExpBuffer();
  1523. DataDumperPtr dumpFn;
  1524. char *copyStmt;
  1525. if (!dump_inserts)
  1526. {
  1527. /* Dump/restore using COPY */
  1528. dumpFn = dumpTableData_copy;
  1529. /* must use 2 steps here 'cause fmtId is nonreentrant */
  1530. appendPQExpBuffer(copyBuf, "COPY %s ",
  1531. fmtId(tbinfo->dobj.name));
  1532. appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
  1533. fmtCopyColumnList(tbinfo, clistBuf),
  1534. (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
  1535. copyStmt = copyBuf->data;
  1536. }
  1537. else
  1538. {
  1539. /* Restore using INSERT */
  1540. dumpFn = dumpTableData_insert;
  1541. copyStmt = NULL;
  1542. }
  1543. /*
  1544. * Note: although the TableDataInfo is a full DumpableObject, we treat its
  1545. * dependency on its table as "special" and pass it to ArchiveEntry now.
  1546. * See comments for BuildArchiveDependencies.
  1547. */
  1548. ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
  1549. tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
  1550. NULL, tbinfo->rolname,
  1551. false, "TABLE DATA", SECTION_DATA,
  1552. "", "", copyStmt,
  1553. &(tbinfo->dobj.dumpId), 1,
  1554. dumpFn, tdinfo);
  1555. destroyPQExpBuffer(copyBuf);
  1556. destroyPQExpBuffer(clistBuf);
  1557. }
  1558. /*
  1559. * refreshMatViewData -
  1560. * load or refresh the contents of a single materialized view
  1561. *
  1562. * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
  1563. * statement.
  1564. */
  1565. static void
  1566. refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
  1567. {
  1568. TableInfo *tbinfo = tdinfo->tdtable;
  1569. PQExpBuffer q;
  1570. /* If the materialized view is not flagged as populated, skip this. */
  1571. if (!tbinfo->relispopulated)
  1572. return;
  1573. q = createPQExpBuffer();
  1574. appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
  1575. fmtId(tbinfo->dobj.name));
  1576. ArchiveEntry(fout,
  1577. tdinfo->dobj.catId, /* catalog ID */
  1578. tdinfo->dobj.dumpId, /* dump ID */
  1579. tbinfo->dobj.name, /* Name */
  1580. tbinfo->dobj.namespace->dobj.name, /* Namespace */
  1581. NULL, /* Tablespace */
  1582. tbinfo->rolname, /* Owner */
  1583. false, /* with oids */
  1584. "MATERIALIZED VIEW DATA", /* Desc */
  1585. SECTION_POST_DATA, /* Section */
  1586. q->data, /* Create */
  1587. "", /* Del */
  1588. NULL, /* Copy */
  1589. tdinfo->dobj.dependencies, /* Deps */
  1590. tdinfo->dobj.nDeps, /* # Deps */
  1591. NULL, /* Dumper */
  1592. NULL); /* Dumper Arg */
  1593. destroyPQExpBuffer(q);
  1594. }
  1595. /*
  1596. * getTableData -
  1597. * set up dumpable objects representing the contents of tables
  1598. */
  1599. static void
  1600. getTableData(TableInfo *tblinfo, int numTables, bool oids)
  1601. {
  1602. int i;
  1603. for (i = 0; i < numTables; i++)
  1604. {
  1605. if (tblinfo[i].dobj.dump)
  1606. makeTableDataInfo(&(tblinfo[i]), oids);
  1607. }
  1608. }
  1609. /*
  1610. * Make a dumpable object for the data of this specific table
  1611. *
  1612. * Note: we make a TableDataInfo if and only if we are going to dump the
  1613. * table data; the "dump" flag in such objects isn't used.
  1614. */
  1615. static void
  1616. makeTableDataInfo(TableInfo *tbinfo, bool oids)
  1617. {
  1618. TableDataInfo *tdinfo;
  1619. /*
  1620. * Nothing to do if we already decided to dump the table. This will
  1621. * happen for "config" tables.
  1622. */
  1623. if (tbinfo->dataObj != NULL)
  1624. return;
  1625. /* Skip VIEWs (no data to dump) */
  1626. if (tbinfo->relkind == RELKIND_VIEW)
  1627. return;
  1628. /* Skip FOREIGN TABLEs (no data to dump) */
  1629. if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
  1630. return;
  1631. /* Don't dump data in unlogged tables, if so requested */
  1632. if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
  1633. no_unlogged_table_data)
  1634. return;
  1635. /* Check that the data is not explicitly excluded */
  1636. if (simple_oid_list_member(&tabledata_exclude_oids,
  1637. tbinfo->dobj.catId.oid))
  1638. return;
  1639. /* OK, let's dump it */
  1640. tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
  1641. if (tbinfo->relkind == RELKIND_MATVIEW)
  1642. tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
  1643. else
  1644. tdinfo->dobj.objType = DO_TABLE_DATA;
  1645. /*
  1646. * Note: use tableoid 0 so that this object won't be mistaken for
  1647. * something that pg_depend entries apply to.
  1648. */
  1649. tdinfo->dobj.catId.tableoid = 0;
  1650. tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
  1651. AssignDumpId(&tdinfo->dobj);
  1652. tdinfo->dobj.name = tbinfo->dobj.name;
  1653. tdinfo->dobj.namespace = tbinfo->dobj.namespace;
  1654. tdinfo->tdtable = tbinfo;
  1655. tdinfo->oids = oids;
  1656. tdinfo->filtercond = NULL; /* might get set later */
  1657. addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
  1658. tbinfo->dataObj = tdinfo;
  1659. }
  1660. /*
  1661. * The refresh for a materialized view must be dependent on the refresh for
  1662. * any materialized view that this one is dependent on.
  1663. *
  1664. * This must be called after all the objects are created, but before they are
  1665. * sorted.
  1666. */
  1667. static void
  1668. buildMatViewRefreshDependencies(Archive *fout)
  1669. {
  1670. PQExpBuffer query;
  1671. PGresult *res;
  1672. int ntups,
  1673. i;
  1674. int i_classid,
  1675. i_objid,
  1676. i_refobjid;
  1677. /* No Mat Views before 9.3. */
  1678. if (fout->remoteVersion < 90300)
  1679. return;
  1680. /* Make sure we are in proper schema */
  1681. selectSourceSchema(fout, "pg_catalog");
  1682. query = createPQExpBuffer();
  1683. appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
  1684. "( "
  1685. "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
  1686. "FROM pg_depend d1 "
  1687. "JOIN pg_class c1 ON c1.oid = d1.objid "
  1688. "AND c1.relkind = 'm' "
  1689. "JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
  1690. "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
  1691. "AND d2.objid = r1.oid "
  1692. "AND d2.refobjid <> d1.objid "
  1693. "JOIN pg_class c2 ON c2.oid = d2.refobjid "
  1694. "AND c2.relkind IN ('m','v') "
  1695. "WHERE d1.classid = 'pg_class'::regclass "
  1696. "UNION "
  1697. "SELECT w.objid, d3.refobjid, c3.relkind "
  1698. "FROM w "
  1699. "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
  1700. "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
  1701. "AND d3.objid = r3.oid "
  1702. "AND d3.refobjid <> w.refobjid "
  1703. "JOIN pg_class c3 ON c3.oid = d3.refobjid "
  1704. "AND c3.relkind IN ('m','v') "
  1705. ") "
  1706. "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
  1707. "FROM w "
  1708. "WHERE refrelkind = 'm'");
  1709. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  1710. ntups = PQntuples(res);
  1711. i_classid = PQfnumber(res, "classid");
  1712. i_objid = PQfnumber(res, "objid");
  1713. i_refobjid = PQfnumber(res, "refobjid");
  1714. for (i = 0; i < ntups; i++)
  1715. {
  1716. CatalogId objId;
  1717. CatalogId refobjId;
  1718. DumpableObject *dobj;
  1719. DumpableObject *refdobj;
  1720. TableInfo *tbinfo;
  1721. TableInfo *reftbinfo;
  1722. objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
  1723. objId.oid = atooid(PQgetvalue(res, i, i_objid));
  1724. refobjId.tableoid = objId.tableoid;
  1725. refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
  1726. dobj = findObjectByCatalogId(objId);
  1727. if (dobj == NULL)
  1728. continue;
  1729. Assert(dobj->objType == DO_TABLE);
  1730. tbinfo = (TableInfo *) dobj;
  1731. Assert(tbinfo->relkind == RELKIND_MATVIEW);
  1732. dobj = (DumpableObject *) tbinfo->dataObj;
  1733. if (dobj == NULL)
  1734. continue;
  1735. Assert(dobj->objType == DO_REFRESH_MATVIEW);
  1736. refdobj = findObjectByCatalogId(refobjId);
  1737. if (refdobj == NULL)
  1738. continue;
  1739. Assert(refdobj->objType == DO_TABLE);
  1740. reftbinfo = (TableInfo *) refdobj;
  1741. Assert(reftbinfo->relkind == RELKIND_MATVIEW);
  1742. refdobj = (DumpableObject *) reftbinfo->dataObj;
  1743. if (refdobj == NULL)
  1744. continue;
  1745. Assert(refdobj->objType == DO_REFRESH_MATVIEW);
  1746. addObjectDependency(dobj, refdobj->dumpId);
  1747. if (!reftbinfo->relispopulated)
  1748. tbinfo->relispopulated = false;
  1749. }
  1750. PQclear(res);
  1751. destroyPQExpBuffer(query);
  1752. }
  1753. /*
  1754. * getTableDataFKConstraints -
  1755. * add dump-order dependencies reflecting foreign key constraints
  1756. *
  1757. * This code is executed only in a data-only dump --- in schema+data dumps
  1758. * we handle foreign key issues by not creating the FK constraints until
  1759. * after the data is loaded. In a data-only dump, however, we want to
  1760. * order the table data objects in such a way that a table's referenced
  1761. * tables are restored first. (In the presence of circular references or
  1762. * self-references this may be impossible; we'll detect and complain about
  1763. * that during the dependency sorting step.)
  1764. */
  1765. static void
  1766. getTableDataFKConstraints(void)
  1767. {
  1768. DumpableObject **dobjs;
  1769. int numObjs;
  1770. int i;
  1771. /* Search through all the dumpable objects for FK constraints */
  1772. getDumpableObjects(&dobjs, &numObjs);
  1773. for (i = 0; i < numObjs; i++)
  1774. {
  1775. if (dobjs[i]->objType == DO_FK_CONSTRAINT)
  1776. {
  1777. ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
  1778. TableInfo *ftable;
  1779. /* Not interesting unless both tables are to be dumped */
  1780. if (cinfo->contable == NULL ||
  1781. cinfo->contable->dataObj == NULL)
  1782. continue;
  1783. ftable = findTableByOid(cinfo->confrelid);
  1784. if (ftable == NULL ||
  1785. ftable->dataObj == NULL)
  1786. continue;
  1787. /*
  1788. * Okay, make referencing table's TABLE_DATA object depend on the
  1789. * referenced table's TABLE_DATA object.
  1790. */
  1791. addObjectDependency(&cinfo->contable->dataObj->dobj,
  1792. ftable->dataObj->dobj.dumpId);
  1793. }
  1794. }
  1795. free(dobjs);
  1796. }
  1797. /*
  1798. * guessConstraintInheritance:
  1799. * In pre-8.4 databases, we can't tell for certain which constraints
  1800. * are inherited. We assume a CHECK constraint is inherited if its name
  1801. * matches the name of any constraint in the parent. Originally this code
  1802. * tried to compare the expression texts, but that can fail for various
  1803. * reasons --- for example, if the parent and child tables are in different
  1804. * schemas, reverse-listing of function calls may produce different text
  1805. * (schema-qualified or not) depending on search path.
  1806. *
  1807. * In 8.4 and up we can rely on the conislocal field to decide which
  1808. * constraints must be dumped; much safer.
  1809. *
  1810. * This function assumes all conislocal flags were initialized to TRUE.
  1811. * It clears the flag on anything that seems to be inherited.
  1812. */
  1813. static void
  1814. guessConstraintInheritance(TableInfo *tblinfo, int numTables)
  1815. {
  1816. int i,
  1817. j,
  1818. k;
  1819. for (i = 0; i < numTables; i++)
  1820. {
  1821. TableInfo *tbinfo = &(tblinfo[i]);
  1822. int numParents;
  1823. TableInfo **parents;
  1824. TableInfo *parent;
  1825. /* Sequences and views never have parents */
  1826. if (tbinfo->relkind == RELKIND_SEQUENCE ||
  1827. tbinfo->relkind == RELKIND_VIEW)
  1828. continue;
  1829. /* Don't bother computing anything for non-target tables, either */
  1830. if (!tbinfo->dobj.dump)
  1831. continue;
  1832. numParents = tbinfo->numParents;
  1833. parents = tbinfo->parents;
  1834. if (numParents == 0)
  1835. continue; /* nothing to see here, move along */
  1836. /* scan for inherited CHECK constraints */
  1837. for (j = 0; j < tbinfo->ncheck; j++)
  1838. {
  1839. ConstraintInfo *constr;
  1840. constr = &(tbinfo->checkexprs[j]);
  1841. for (k = 0; k < numParents; k++)
  1842. {
  1843. int l;
  1844. parent = parents[k];
  1845. for (l = 0; l < parent->ncheck; l++)
  1846. {
  1847. ConstraintInfo *pconstr = &(parent->checkexprs[l]);
  1848. if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
  1849. {
  1850. constr->conislocal = false;
  1851. break;
  1852. }
  1853. }
  1854. if (!constr->conislocal)
  1855. break;
  1856. }
  1857. }
  1858. }
  1859. }
  1860. /*
  1861. * dumpDatabase:
  1862. * dump the database definition
  1863. */
  1864. static void
  1865. dumpDatabase(Archive *fout)
  1866. {
  1867. PQExpBuffer dbQry = createPQExpBuffer();
  1868. PQExpBuffer delQry = createPQExpBuffer();
  1869. PQExpBuffer creaQry = createPQExpBuffer();
  1870. PGconn *conn = GetConnection(fout);
  1871. PGresult *res;
  1872. int i_tableoid,
  1873. i_oid,
  1874. i_dba,
  1875. i_encoding,
  1876. i_collate,
  1877. i_ctype,
  1878. i_frozenxid,
  1879. i_minmxid,
  1880. i_tablespace;
  1881. CatalogId dbCatId;
  1882. DumpId dbDumpId;
  1883. const char *datname,
  1884. *dba,
  1885. *encoding,
  1886. *collate,
  1887. *ctype,
  1888. *tablespace;
  1889. uint32 frozenxid, minmxid;
  1890. datname = PQdb(conn);
  1891. if (g_verbose)
  1892. write_msg(NULL, "saving database definition\n");
  1893. /* Make sure we are in proper schema */
  1894. selectSourceSchema(fout, "pg_catalog");
  1895. /* Get the database owner and parameters from pg_database */
  1896. if (fout->remoteVersion >= 90300)
  1897. {
  1898. appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
  1899. "(%s datdba) AS dba, "
  1900. "pg_encoding_to_char(encoding) AS encoding, "
  1901. "datcollate, datctype, datfrozenxid, datminmxid, "
  1902. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
  1903. "shobj_description(oid, 'pg_database') AS description "
  1904. "FROM pg_database "
  1905. "WHERE datname = ",
  1906. username_subquery);
  1907. appendStringLiteralAH(dbQry, datname, fout);
  1908. }
  1909. else if (fout->remoteVersion >= 80400)
  1910. {
  1911. appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
  1912. "(%s datdba) AS dba, "
  1913. "pg_encoding_to_char(encoding) AS encoding, "
  1914. "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
  1915. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
  1916. "shobj_description(oid, 'pg_database') AS description "
  1917. "FROM pg_database "
  1918. "WHERE datname = ",
  1919. username_subquery);
  1920. appendStringLiteralAH(dbQry, datname, fout);
  1921. }
  1922. else if (fout->remoteVersion >= 80200)
  1923. {
  1924. appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
  1925. "(%s datdba) AS dba, "
  1926. "pg_encoding_to_char(encoding) AS encoding, "
  1927. "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
  1928. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
  1929. "shobj_description(oid, 'pg_database') AS description "
  1930. "FROM pg_database "
  1931. "WHERE datname = ",
  1932. username_subquery);
  1933. appendStringLiteralAH(dbQry, datname, fout);
  1934. }
  1935. else if (fout->remoteVersion >= 80000)
  1936. {
  1937. appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
  1938. "(%s datdba) AS dba, "
  1939. "pg_encoding_to_char(encoding) AS encoding, "
  1940. "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
  1941. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
  1942. "FROM pg_database "
  1943. "WHERE datname = ",
  1944. username_subquery);
  1945. appendStringLiteralAH(dbQry, datname, fout);
  1946. }
  1947. else if (fout->remoteVersion >= 70100)
  1948. {
  1949. appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
  1950. "(%s datdba) AS dba, "
  1951. "pg_encoding_to_char(encoding) AS encoding, "
  1952. "NULL AS datcollate, NULL AS datctype, "
  1953. "0 AS datfrozenxid, 0 AS datminmxid, "
  1954. "NULL AS tablespace "
  1955. "FROM pg_database "
  1956. "WHERE datname = ",
  1957. username_subquery);
  1958. appendStringLiteralAH(dbQry, datname, fout);
  1959. }
  1960. else
  1961. {
  1962. appendPQExpBuffer(dbQry, "SELECT "
  1963. "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
  1964. "oid, "
  1965. "(%s datdba) AS dba, "
  1966. "pg_encoding_to_char(encoding) AS encoding, "
  1967. "NULL AS datcollate, NULL AS datctype, "
  1968. "0 AS datfrozenxid, 0 AS datminmxid, "
  1969. "NULL AS tablespace "
  1970. "FROM pg_database "
  1971. "WHERE datname = ",
  1972. username_subquery);
  1973. appendStringLiteralAH(dbQry, datname, fout);
  1974. }
  1975. res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
  1976. i_tableoid = PQfnumber(res, "tableoid");
  1977. i_oid = PQfnumber(res, "oid");
  1978. i_dba = PQfnumber(res, "dba");
  1979. i_encoding = PQfnumber(res, "encoding");
  1980. i_collate = PQfnumber(res, "datcollate");
  1981. i_ctype = PQfnumber(res, "datctype");
  1982. i_frozenxid = PQfnumber(res, "datfrozenxid");
  1983. i_minmxid = PQfnumber(res, "datminmxid");
  1984. i_tablespace = PQfnumber(res, "tablespace");
  1985. dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
  1986. dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
  1987. dba = PQgetvalue(res, 0, i_dba);
  1988. encoding = PQgetvalue(res, 0, i_encoding);
  1989. collate = PQgetvalue(res, 0, i_collate);
  1990. ctype = PQgetvalue(res, 0, i_ctype);
  1991. frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
  1992. minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
  1993. tablespace = PQgetvalue(res, 0, i_tablespace);
  1994. appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
  1995. fmtId(datname));
  1996. if (strlen(encoding) > 0)
  1997. {
  1998. appendPQExpBufferStr(creaQry, " ENCODING = ");
  1999. appendStringLiteralAH(creaQry, encoding, fout);
  2000. }
  2001. if (strlen(collate) > 0)
  2002. {
  2003. appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
  2004. appendStringLiteralAH(creaQry, collate, fout);
  2005. }
  2006. if (strlen(ctype) > 0)
  2007. {
  2008. appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
  2009. appendStringLiteralAH(creaQry, ctype, fout);
  2010. }
  2011. if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
  2012. appendPQExpBuffer(creaQry, " TABLESPACE = %s",
  2013. fmtId(tablespace));
  2014. appendPQExpBufferStr(creaQry, ";\n");
  2015. if (binary_upgrade)
  2016. {
  2017. appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
  2018. appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
  2019. "SET datfrozenxid = '%u', datminmxid = '%u'\n"
  2020. "WHERE datname = ",
  2021. frozenxid, minmxid);
  2022. appendStringLiteralAH(creaQry, datname, fout);
  2023. appendPQExpBufferStr(creaQry, ";\n");
  2024. }
  2025. appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
  2026. fmtId(datname));
  2027. dbDumpId = createDumpId();
  2028. ArchiveEntry(fout,
  2029. dbCatId, /* catalog ID */
  2030. dbDumpId, /* dump ID */
  2031. datname, /* Name */
  2032. NULL, /* Namespace */
  2033. NULL, /* Tablespace */
  2034. dba, /* Owner */
  2035. false, /* with oids */
  2036. "DATABASE", /* Desc */
  2037. SECTION_PRE_DATA, /* Section */
  2038. creaQry->data, /* Create */
  2039. delQry->data, /* Del */
  2040. NULL, /* Copy */
  2041. NULL, /* Deps */
  2042. 0, /* # Deps */
  2043. NULL, /* Dumper */
  2044. NULL); /* Dumper Arg */
  2045. /*
  2046. * pg_largeobject and pg_largeobject_metadata come from the old system
  2047. * intact, so set their relfrozenxids and relminmxids.
  2048. */
  2049. if (binary_upgrade)
  2050. {
  2051. PGresult *lo_res;
  2052. PQExpBuffer loFrozenQry = createPQExpBuffer();
  2053. PQExpBuffer loOutQry = createPQExpBuffer();
  2054. int i_relfrozenxid, i_relminmxid;
  2055. /*
  2056. * pg_largeobject
  2057. */
  2058. if (fout->remoteVersion >= 90300)
  2059. appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
  2060. "FROM pg_catalog.pg_class\n"
  2061. "WHERE oid = %u;\n",
  2062. LargeObjectRelationId);
  2063. else
  2064. appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
  2065. "FROM pg_catalog.pg_class\n"
  2066. "WHERE oid = %u;\n",
  2067. LargeObjectRelationId);
  2068. lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
  2069. i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
  2070. i_relminmxid = PQfnumber(lo_res, "relminmxid");
  2071. appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
  2072. appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
  2073. "SET relfrozenxid = '%u', relminmxid = '%u'\n"
  2074. "WHERE oid = %u;\n",
  2075. atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
  2076. atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
  2077. LargeObjectRelationId);
  2078. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  2079. "pg_largeobject", NULL, NULL, "",
  2080. false, "pg_largeobject", SECTION_PRE_DATA,
  2081. loOutQry->data, "", NULL,
  2082. NULL, 0,
  2083. NULL, NULL);
  2084. PQclear(lo_res);
  2085. /*
  2086. * pg_largeobject_metadata
  2087. */
  2088. if (fout->remoteVersion >= 90000)
  2089. {
  2090. resetPQExpBuffer(loFrozenQry);
  2091. resetPQExpBuffer(loOutQry);
  2092. if (fout->remoteVersion >= 90300)
  2093. appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
  2094. "FROM pg_catalog.pg_class\n"
  2095. "WHERE oid = %u;\n",
  2096. LargeObjectMetadataRelationId);
  2097. else
  2098. appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
  2099. "FROM pg_catalog.pg_class\n"
  2100. "WHERE oid = %u;\n",
  2101. LargeObjectMetadataRelationId);
  2102. lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
  2103. i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
  2104. i_relminmxid = PQfnumber(lo_res, "relminmxid");
  2105. appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
  2106. appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
  2107. "SET relfrozenxid = '%u', relminmxid = '%u'\n"
  2108. "WHERE oid = %u;\n",
  2109. atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
  2110. atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
  2111. LargeObjectMetadataRelationId);
  2112. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  2113. "pg_largeobject_metadata", NULL, NULL, "",
  2114. false, "pg_largeobject_metadata", SECTION_PRE_DATA,
  2115. loOutQry->data, "", NULL,
  2116. NULL, 0,
  2117. NULL, NULL);
  2118. PQclear(lo_res);
  2119. }
  2120. destroyPQExpBuffer(loFrozenQry);
  2121. destroyPQExpBuffer(loOutQry);
  2122. }
  2123. /* Dump DB comment if any */
  2124. if (fout->remoteVersion >= 80200)
  2125. {
  2126. /*
  2127. * 8.2 keeps comments on shared objects in a shared table, so we
  2128. * cannot use the dumpComment used for other database objects.
  2129. */
  2130. char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
  2131. if (comment && strlen(comment))
  2132. {
  2133. resetPQExpBuffer(dbQry);
  2134. /*
  2135. * Generates warning when loaded into a differently-named
  2136. * database.
  2137. */
  2138. appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
  2139. appendStringLiteralAH(dbQry, comment, fout);
  2140. appendPQExpBufferStr(dbQry, ";\n");
  2141. ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
  2142. dba, false, "COMMENT", SECTION_NONE,
  2143. dbQry->data, "", NULL,
  2144. &dbDumpId, 1, NULL, NULL);
  2145. }
  2146. }
  2147. else
  2148. {
  2149. resetPQExpBuffer(dbQry);
  2150. appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
  2151. dumpComment(fout, dbQry->data, NULL, "",
  2152. dbCatId, 0, dbDumpId);
  2153. }
  2154. PQclear(res);
  2155. /* Dump shared security label. */
  2156. if (!no_security_labels && fout->remoteVersion >= 90200)
  2157. {
  2158. PQExpBuffer seclabelQry = createPQExpBuffer();
  2159. buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
  2160. res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
  2161. resetPQExpBuffer(seclabelQry);
  2162. emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
  2163. if (strlen(seclabelQry->data))
  2164. ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
  2165. dba, false, "SECURITY LABEL", SECTION_NONE,
  2166. seclabelQry->data, "", NULL,
  2167. &dbDumpId, 1, NULL, NULL);
  2168. destroyPQExpBuffer(seclabelQry);
  2169. }
  2170. destroyPQExpBuffer(dbQry);
  2171. destroyPQExpBuffer(delQry);
  2172. destroyPQExpBuffer(creaQry);
  2173. }
  2174. /*
  2175. * dumpEncoding: put the correct encoding into the archive
  2176. */
  2177. static void
  2178. dumpEncoding(Archive *AH)
  2179. {
  2180. const char *encname = pg_encoding_to_char(AH->encoding);
  2181. PQExpBuffer qry = createPQExpBuffer();
  2182. if (g_verbose)
  2183. write_msg(NULL, "saving encoding = %s\n", encname);
  2184. appendPQExpBufferStr(qry, "SET client_encoding = ");
  2185. appendStringLiteralAH(qry, encname, AH);
  2186. appendPQExpBufferStr(qry, ";\n");
  2187. ArchiveEntry(AH, nilCatalogId, createDumpId(),
  2188. "ENCODING", NULL, NULL, "",
  2189. false, "ENCODING", SECTION_PRE_DATA,
  2190. qry->data, "", NULL,
  2191. NULL, 0,
  2192. NULL, NULL);
  2193. destroyPQExpBuffer(qry);
  2194. }
  2195. /*
  2196. * dumpStdStrings: put the correct escape string behavior into the archive
  2197. */
  2198. static void
  2199. dumpStdStrings(Archive *AH)
  2200. {
  2201. const char *stdstrings = AH->std_strings ? "on" : "off";
  2202. PQExpBuffer qry = createPQExpBuffer();
  2203. if (g_verbose)
  2204. write_msg(NULL, "saving standard_conforming_strings = %s\n",
  2205. stdstrings);
  2206. appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
  2207. stdstrings);
  2208. ArchiveEntry(AH, nilCatalogId, createDumpId(),
  2209. "STDSTRINGS", NULL, NULL, "",
  2210. false, "STDSTRINGS", SECTION_PRE_DATA,
  2211. qry->data, "", NULL,
  2212. NULL, 0,
  2213. NULL, NULL);
  2214. destroyPQExpBuffer(qry);
  2215. }
  2216. /*
  2217. * getBlobs:
  2218. * Collect schema-level data about large objects
  2219. */
  2220. static void
  2221. getBlobs(Archive *fout)
  2222. {
  2223. PQExpBuffer blobQry = createPQExpBuffer();
  2224. BlobInfo *binfo;
  2225. DumpableObject *bdata;
  2226. PGresult *res;
  2227. int ntups;
  2228. int i;
  2229. /* Verbose message */
  2230. if (g_verbose)
  2231. write_msg(NULL, "reading large objects\n");
  2232. /* Make sure we are in proper schema */
  2233. selectSourceSchema(fout, "pg_catalog");
  2234. /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
  2235. if (fout->remoteVersion >= 90000)
  2236. appendPQExpBuffer(blobQry,
  2237. "SELECT oid, (%s lomowner) AS rolname, lomacl"
  2238. " FROM pg_largeobject_metadata",
  2239. username_subquery);
  2240. else if (fout->remoteVersion >= 70100)
  2241. appendPQExpBufferStr(blobQry,
  2242. "SELECT DISTINCT loid, NULL::oid, NULL::oid"
  2243. " FROM pg_largeobject");
  2244. else
  2245. appendPQExpBufferStr(blobQry,
  2246. "SELECT oid, NULL::oid, NULL::oid"
  2247. " FROM pg_class WHERE relkind = 'l'");
  2248. res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
  2249. ntups = PQntuples(res);
  2250. if (ntups > 0)
  2251. {
  2252. /*
  2253. * Each large object has its own BLOB archive entry.
  2254. */
  2255. binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
  2256. for (i = 0; i < ntups; i++)
  2257. {
  2258. binfo[i].dobj.objType = DO_BLOB;
  2259. binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
  2260. binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
  2261. AssignDumpId(&binfo[i].dobj);
  2262. binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
  2263. if (!PQgetisnull(res, i, 1))
  2264. binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
  2265. else
  2266. binfo[i].rolname = "";
  2267. if (!PQgetisnull(res, i, 2))
  2268. binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
  2269. else
  2270. binfo[i].blobacl = NULL;
  2271. }
  2272. /*
  2273. * If we have any large objects, a "BLOBS" archive entry is needed.
  2274. * This is just a placeholder for sorting; it carries no data now.
  2275. */
  2276. bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
  2277. bdata->objType = DO_BLOB_DATA;
  2278. bdata->catId = nilCatalogId;
  2279. AssignDumpId(bdata);
  2280. bdata->name = pg_strdup("BLOBS");
  2281. }
  2282. PQclear(res);
  2283. destroyPQExpBuffer(blobQry);
  2284. }
  2285. /*
  2286. * dumpBlob
  2287. *
  2288. * dump the definition (metadata) of the given large object
  2289. */
  2290. static void
  2291. dumpBlob(Archive *fout, BlobInfo *binfo)
  2292. {
  2293. PQExpBuffer cquery = createPQExpBuffer();
  2294. PQExpBuffer dquery = createPQExpBuffer();
  2295. appendPQExpBuffer(cquery,
  2296. "SELECT pg_catalog.lo_create('%s');\n",
  2297. binfo->dobj.name);
  2298. appendPQExpBuffer(dquery,
  2299. "SELECT pg_catalog.lo_unlink('%s');\n",
  2300. binfo->dobj.name);
  2301. ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
  2302. binfo->dobj.name,
  2303. NULL, NULL,
  2304. binfo->rolname, false,
  2305. "BLOB", SECTION_PRE_DATA,
  2306. cquery->data, dquery->data, NULL,
  2307. NULL, 0,
  2308. NULL, NULL);
  2309. /* set up tag for comment and/or ACL */
  2310. resetPQExpBuffer(cquery);
  2311. appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
  2312. /* Dump comment if any */
  2313. dumpComment(fout, cquery->data,
  2314. NULL, binfo->rolname,
  2315. binfo->dobj.catId, 0, binfo->dobj.dumpId);
  2316. /* Dump security label if any */
  2317. dumpSecLabel(fout, cquery->data,
  2318. NULL, binfo->rolname,
  2319. binfo->dobj.catId, 0, binfo->dobj.dumpId);
  2320. /* Dump ACL if any */
  2321. if (binfo->blobacl)
  2322. dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
  2323. binfo->dobj.name, NULL, cquery->data,
  2324. NULL, binfo->rolname, binfo->blobacl);
  2325. destroyPQExpBuffer(cquery);
  2326. destroyPQExpBuffer(dquery);
  2327. }
  2328. /*
  2329. * dumpBlobs:
  2330. * dump the data contents of all large objects
  2331. */
  2332. static int
  2333. dumpBlobs(Archive *fout, void *arg)
  2334. {
  2335. const char *blobQry;
  2336. const char *blobFetchQry;
  2337. PGconn *conn = GetConnection(fout);
  2338. PGresult *res;
  2339. char buf[LOBBUFSIZE];
  2340. int ntups;
  2341. int i;
  2342. int cnt;
  2343. if (g_verbose)
  2344. write_msg(NULL, "saving large objects\n");
  2345. /* Make sure we are in proper schema */
  2346. selectSourceSchema(fout, "pg_catalog");
  2347. /*
  2348. * Currently, we re-fetch all BLOB OIDs using a cursor. Consider scanning
  2349. * the already-in-memory dumpable objects instead...
  2350. */
  2351. if (fout->remoteVersion >= 90000)
  2352. blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
  2353. else if (fout->remoteVersion >= 70100)
  2354. blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
  2355. else
  2356. blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
  2357. ExecuteSqlStatement(fout, blobQry);
  2358. /* Command to fetch from cursor */
  2359. blobFetchQry = "FETCH 1000 IN bloboid";
  2360. do
  2361. {
  2362. /* Do a fetch */
  2363. res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
  2364. /* Process the tuples, if any */
  2365. ntups = PQntuples(res);
  2366. for (i = 0; i < ntups; i++)
  2367. {
  2368. Oid blobOid;
  2369. int loFd;
  2370. blobOid = atooid(PQgetvalue(res, i, 0));
  2371. /* Open the BLOB */
  2372. loFd = lo_open(conn, blobOid, INV_READ);
  2373. if (loFd == -1)
  2374. exit_horribly(NULL, "could not open large object %u: %s",
  2375. blobOid, PQerrorMessage(conn));
  2376. StartBlob(fout, blobOid);
  2377. /* Now read it in chunks, sending data to archive */
  2378. do
  2379. {
  2380. cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
  2381. if (cnt < 0)
  2382. exit_horribly(NULL, "error reading large object %u: %s",
  2383. blobOid, PQerrorMessage(conn));
  2384. WriteData(fout, buf, cnt);
  2385. } while (cnt > 0);
  2386. lo_close(conn, loFd);
  2387. EndBlob(fout, blobOid);
  2388. }
  2389. PQclear(res);
  2390. } while (ntups > 0);
  2391. return 1;
  2392. }
  2393. static void
  2394. binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
  2395. PQExpBuffer upgrade_buffer,
  2396. Oid pg_type_oid)
  2397. {
  2398. PQExpBuffer upgrade_query = createPQExpBuffer();
  2399. PGresult *upgrade_res;
  2400. Oid pg_type_array_oid;
  2401. appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
  2402. appendPQExpBuffer(upgrade_buffer,
  2403. "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
  2404. pg_type_oid);
  2405. /* we only support old >= 8.3 for binary upgrades */
  2406. appendPQExpBuffer(upgrade_query,
  2407. "SELECT typarray "
  2408. "FROM pg_catalog.pg_type "
  2409. "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
  2410. pg_type_oid);
  2411. upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
  2412. pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
  2413. if (OidIsValid(pg_type_array_oid))
  2414. {
  2415. appendPQExpBufferStr(upgrade_buffer,
  2416. "\n-- For binary upgrade, must preserve pg_type array oid\n");
  2417. appendPQExpBuffer(upgrade_buffer,
  2418. "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
  2419. pg_type_array_oid);
  2420. }
  2421. PQclear(upgrade_res);
  2422. destroyPQExpBuffer(upgrade_query);
  2423. }
  2424. static bool
  2425. binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
  2426. PQExpBuffer upgrade_buffer,
  2427. Oid pg_rel_oid)
  2428. {
  2429. PQExpBuffer upgrade_query = createPQExpBuffer();
  2430. PGresult *upgrade_res;
  2431. Oid pg_type_oid;
  2432. bool toast_set = false;
  2433. /* we only support old >= 8.3 for binary upgrades */
  2434. appendPQExpBuffer(upgrade_query,
  2435. "SELECT c.reltype AS crel, t.reltype AS trel "
  2436. "FROM pg_catalog.pg_class c "
  2437. "LEFT JOIN pg_catalog.pg_class t ON "
  2438. " (c.reltoastrelid = t.oid) "
  2439. "WHERE c.oid = '%u'::pg_catalog.oid;",
  2440. pg_rel_oid);
  2441. upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
  2442. pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
  2443. binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
  2444. pg_type_oid);
  2445. if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
  2446. {
  2447. /* Toast tables do not have pg_type array rows */
  2448. Oid pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
  2449. PQfnumber(upgrade_res, "trel")));
  2450. appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
  2451. appendPQExpBuffer(upgrade_buffer,
  2452. "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
  2453. pg_type_toast_oid);
  2454. toast_set = true;
  2455. }
  2456. PQclear(upgrade_res);
  2457. destroyPQExpBuffer(upgrade_query);
  2458. return toast_set;
  2459. }
  2460. static void
  2461. binary_upgrade_set_pg_class_oids(Archive *fout,
  2462. PQExpBuffer upgrade_buffer, Oid pg_class_oid,
  2463. bool is_index)
  2464. {
  2465. PQExpBuffer upgrade_query = createPQExpBuffer();
  2466. PGresult *upgrade_res;
  2467. Oid pg_class_reltoastrelid;
  2468. Oid pg_index_indexrelid;
  2469. appendPQExpBuffer(upgrade_query,
  2470. "SELECT c.reltoastrelid, i.indexrelid "
  2471. "FROM pg_catalog.pg_class c LEFT JOIN "
  2472. "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
  2473. "WHERE c.oid = '%u'::pg_catalog.oid;",
  2474. pg_class_oid);
  2475. upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
  2476. pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
  2477. pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
  2478. appendPQExpBufferStr(upgrade_buffer,
  2479. "\n-- For binary upgrade, must preserve pg_class oids\n");
  2480. if (!is_index)
  2481. {
  2482. appendPQExpBuffer(upgrade_buffer,
  2483. "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
  2484. pg_class_oid);
  2485. /* only tables have toast tables, not indexes */
  2486. if (OidIsValid(pg_class_reltoastrelid))
  2487. {
  2488. /*
  2489. * One complexity is that the table definition might not require
  2490. * the creation of a TOAST table, and the TOAST table might have
  2491. * been created long after table creation, when the table was
  2492. * loaded with wide data. By setting the TOAST oid we force
  2493. * creation of the TOAST heap and TOAST index by the backend so we
  2494. * can cleanly copy the files during binary upgrade.
  2495. */
  2496. appendPQExpBuffer(upgrade_buffer,
  2497. "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
  2498. pg_class_reltoastrelid);
  2499. /* every toast table has an index */
  2500. appendPQExpBuffer(upgrade_buffer,
  2501. "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
  2502. pg_index_indexrelid);
  2503. }
  2504. }
  2505. else
  2506. appendPQExpBuffer(upgrade_buffer,
  2507. "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
  2508. pg_class_oid);
  2509. appendPQExpBufferChar(upgrade_buffer, '\n');
  2510. PQclear(upgrade_res);
  2511. destroyPQExpBuffer(upgrade_query);
  2512. }
  2513. /*
  2514. * If the DumpableObject is a member of an extension, add a suitable
  2515. * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
  2516. */
  2517. static void
  2518. binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
  2519. DumpableObject *dobj,
  2520. const char *objlabel)
  2521. {
  2522. DumpableObject *extobj = NULL;
  2523. int i;
  2524. if (!dobj->ext_member)
  2525. return;
  2526. /*
  2527. * Find the parent extension. We could avoid this search if we wanted to
  2528. * add a link field to DumpableObject, but the space costs of that would
  2529. * be considerable. We assume that member objects could only have a
  2530. * direct dependency on their own extension, not any others.
  2531. */
  2532. for (i = 0; i < dobj->nDeps; i++)
  2533. {
  2534. extobj = findObjectByDumpId(dobj->dependencies[i]);
  2535. if (extobj && extobj->objType == DO_EXTENSION)
  2536. break;
  2537. extobj = NULL;
  2538. }
  2539. if (extobj == NULL)
  2540. exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
  2541. appendPQExpBufferStr(upgrade_buffer,
  2542. "\n-- For binary upgrade, handle extension membership the hard way\n");
  2543. appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
  2544. fmtId(extobj->name),
  2545. objlabel);
  2546. }
  2547. /*
  2548. * getNamespaces:
  2549. * read all namespaces in the system catalogs and return them in the
  2550. * NamespaceInfo* structure
  2551. *
  2552. * numNamespaces is set to the number of namespaces read in
  2553. */
  2554. NamespaceInfo *
  2555. getNamespaces(Archive *fout, int *numNamespaces)
  2556. {
  2557. PGresult *res;
  2558. int ntups;
  2559. int i;
  2560. PQExpBuffer query;
  2561. NamespaceInfo *nsinfo;
  2562. int i_tableoid;
  2563. int i_oid;
  2564. int i_nspname;
  2565. int i_rolname;
  2566. int i_nspacl;
  2567. /*
  2568. * Before 7.3, there are no real namespaces; create two dummy entries, one
  2569. * for user stuff and one for system stuff.
  2570. */
  2571. if (fout->remoteVersion < 70300)
  2572. {
  2573. nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
  2574. nsinfo[0].dobj.objType = DO_NAMESPACE;
  2575. nsinfo[0].dobj.catId.tableoid = 0;
  2576. nsinfo[0].dobj.catId.oid = 0;
  2577. AssignDumpId(&nsinfo[0].dobj);
  2578. nsinfo[0].dobj.name = pg_strdup("public");
  2579. nsinfo[0].rolname = pg_strdup("");
  2580. nsinfo[0].nspacl = pg_strdup("");
  2581. selectDumpableNamespace(&nsinfo[0]);
  2582. nsinfo[1].dobj.objType = DO_NAMESPACE;
  2583. nsinfo[1].dobj.catId.tableoid = 0;
  2584. nsinfo[1].dobj.catId.oid = 1;
  2585. AssignDumpId(&nsinfo[1].dobj);
  2586. nsinfo[1].dobj.name = pg_strdup("pg_catalog");
  2587. nsinfo[1].rolname = pg_strdup("");
  2588. nsinfo[1].nspacl = pg_strdup("");
  2589. selectDumpableNamespace(&nsinfo[1]);
  2590. *numNamespaces = 2;
  2591. return nsinfo;
  2592. }
  2593. query = createPQExpBuffer();
  2594. /* Make sure we are in proper schema */
  2595. selectSourceSchema(fout, "pg_catalog");
  2596. /*
  2597. * we fetch all namespaces including system ones, so that every object we
  2598. * read in can be linked to a containing namespace.
  2599. */
  2600. appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
  2601. "(%s nspowner) AS rolname, "
  2602. "nspacl FROM pg_namespace",
  2603. username_subquery);
  2604. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  2605. ntups = PQntuples(res);
  2606. nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
  2607. i_tableoid = PQfnumber(res, "tableoid");
  2608. i_oid = PQfnumber(res, "oid");
  2609. i_nspname = PQfnumber(res, "nspname");
  2610. i_rolname = PQfnumber(res, "rolname");
  2611. i_nspacl = PQfnumber(res, "nspacl");
  2612. for (i = 0; i < ntups; i++)
  2613. {
  2614. nsinfo[i].dobj.objType = DO_NAMESPACE;
  2615. nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  2616. nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  2617. AssignDumpId(&nsinfo[i].dobj);
  2618. nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
  2619. nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  2620. nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
  2621. /* Decide whether to dump this namespace */
  2622. selectDumpableNamespace(&nsinfo[i]);
  2623. if (strlen(nsinfo[i].rolname) == 0)
  2624. write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
  2625. nsinfo[i].dobj.name);
  2626. }
  2627. PQclear(res);
  2628. destroyPQExpBuffer(query);
  2629. *numNamespaces = ntups;
  2630. return nsinfo;
  2631. }
  2632. /*
  2633. * findNamespace:
  2634. * given a namespace OID and an object OID, look up the info read by
  2635. * getNamespaces
  2636. *
  2637. * NB: for pre-7.3 source database, we use object OID to guess whether it's
  2638. * a system object or not. In 7.3 and later there is no guessing, and we
  2639. * don't use objoid at all.
  2640. */
  2641. static NamespaceInfo *
  2642. findNamespace(Archive *fout, Oid nsoid, Oid objoid)
  2643. {
  2644. NamespaceInfo *nsinfo;
  2645. if (fout->remoteVersion >= 70300)
  2646. {
  2647. nsinfo = findNamespaceByOid(nsoid);
  2648. }
  2649. else
  2650. {
  2651. /* This code depends on the dummy objects set up by getNamespaces. */
  2652. Oid i;
  2653. if (objoid > g_last_builtin_oid)
  2654. i = 0; /* user object */
  2655. else
  2656. i = 1; /* system object */
  2657. nsinfo = findNamespaceByOid(i);
  2658. }
  2659. if (nsinfo == NULL)
  2660. exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
  2661. return nsinfo;
  2662. }
  2663. /*
  2664. * getExtensions:
  2665. * read all extensions in the system catalogs and return them in the
  2666. * ExtensionInfo* structure
  2667. *
  2668. * numExtensions is set to the number of extensions read in
  2669. */
  2670. ExtensionInfo *
  2671. getExtensions(Archive *fout, int *numExtensions)
  2672. {
  2673. PGresult *res;
  2674. int ntups;
  2675. int i;
  2676. PQExpBuffer query;
  2677. ExtensionInfo *extinfo;
  2678. int i_tableoid;
  2679. int i_oid;
  2680. int i_extname;
  2681. int i_nspname;
  2682. int i_extrelocatable;
  2683. int i_extversion;
  2684. int i_extconfig;
  2685. int i_extcondition;
  2686. /*
  2687. * Before 9.1, there are no extensions.
  2688. */
  2689. if (fout->remoteVersion < 90100)
  2690. {
  2691. *numExtensions = 0;
  2692. return NULL;
  2693. }
  2694. query = createPQExpBuffer();
  2695. /* Make sure we are in proper schema */
  2696. selectSourceSchema(fout, "pg_catalog");
  2697. appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
  2698. "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
  2699. "FROM pg_extension x "
  2700. "JOIN pg_namespace n ON n.oid = x.extnamespace");
  2701. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  2702. ntups = PQntuples(res);
  2703. extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
  2704. i_tableoid = PQfnumber(res, "tableoid");
  2705. i_oid = PQfnumber(res, "oid");
  2706. i_extname = PQfnumber(res, "extname");
  2707. i_nspname = PQfnumber(res, "nspname");
  2708. i_extrelocatable = PQfnumber(res, "extrelocatable");
  2709. i_extversion = PQfnumber(res, "extversion");
  2710. i_extconfig = PQfnumber(res, "extconfig");
  2711. i_extcondition = PQfnumber(res, "extcondition");
  2712. for (i = 0; i < ntups; i++)
  2713. {
  2714. extinfo[i].dobj.objType = DO_EXTENSION;
  2715. extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  2716. extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  2717. AssignDumpId(&extinfo[i].dobj);
  2718. extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
  2719. extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
  2720. extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
  2721. extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
  2722. extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
  2723. extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
  2724. /* Decide whether we want to dump it */
  2725. selectDumpableExtension(&(extinfo[i]));
  2726. }
  2727. PQclear(res);
  2728. destroyPQExpBuffer(query);
  2729. *numExtensions = ntups;
  2730. return extinfo;
  2731. }
  2732. /*
  2733. * getTypes:
  2734. * read all types in the system catalogs and return them in the
  2735. * TypeInfo* structure
  2736. *
  2737. * numTypes is set to the number of types read in
  2738. *
  2739. * NB: this must run after getFuncs() because we assume we can do
  2740. * findFuncByOid().
  2741. */
  2742. TypeInfo *
  2743. getTypes(Archive *fout, int *numTypes)
  2744. {
  2745. PGresult *res;
  2746. int ntups;
  2747. int i;
  2748. PQExpBuffer query = createPQExpBuffer();
  2749. TypeInfo *tyinfo;
  2750. ShellTypeInfo *stinfo;
  2751. int i_tableoid;
  2752. int i_oid;
  2753. int i_typname;
  2754. int i_typnamespace;
  2755. int i_typacl;
  2756. int i_rolname;
  2757. int i_typinput;
  2758. int i_typoutput;
  2759. int i_typelem;
  2760. int i_typrelid;
  2761. int i_typrelkind;
  2762. int i_typtype;
  2763. int i_typisdefined;
  2764. int i_isarray;
  2765. /*
  2766. * we include even the built-in types because those may be used as array
  2767. * elements by user-defined types
  2768. *
  2769. * we filter out the built-in types when we dump out the types
  2770. *
  2771. * same approach for undefined (shell) types and array types
  2772. *
  2773. * Note: as of 8.3 we can reliably detect whether a type is an
  2774. * auto-generated array type by checking the element type's typarray.
  2775. * (Before that the test is capable of generating false positives.) We
  2776. * still check for name beginning with '_', though, so as to avoid the
  2777. * cost of the subselect probe for all standard types. This would have to
  2778. * be revisited if the backend ever allows renaming of array types.
  2779. */
  2780. /* Make sure we are in proper schema */
  2781. selectSourceSchema(fout, "pg_catalog");
  2782. if (fout->remoteVersion >= 90200)
  2783. {
  2784. appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
  2785. "typnamespace, typacl, "
  2786. "(%s typowner) AS rolname, "
  2787. "typinput::oid AS typinput, "
  2788. "typoutput::oid AS typoutput, typelem, typrelid, "
  2789. "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
  2790. "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
  2791. "typtype, typisdefined, "
  2792. "typname[0] = '_' AND typelem != 0 AND "
  2793. "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
  2794. "FROM pg_type",
  2795. username_subquery);
  2796. }
  2797. else if (fout->remoteVersion >= 80300)
  2798. {
  2799. appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
  2800. "typnamespace, '{=U}' AS typacl, "
  2801. "(%s typowner) AS rolname, "
  2802. "typinput::oid AS typinput, "
  2803. "typoutput::oid AS typoutput, typelem, typrelid, "
  2804. "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
  2805. "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
  2806. "typtype, typisdefined, "
  2807. "typname[0] = '_' AND typelem != 0 AND "
  2808. "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
  2809. "FROM pg_type",
  2810. username_subquery);
  2811. }
  2812. else if (fout->remoteVersion >= 70300)
  2813. {
  2814. appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
  2815. "typnamespace, '{=U}' AS typacl, "
  2816. "(%s typowner) AS rolname, "
  2817. "typinput::oid AS typinput, "
  2818. "typoutput::oid AS typoutput, typelem, typrelid, "
  2819. "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
  2820. "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
  2821. "typtype, typisdefined, "
  2822. "typname[0] = '_' AND typelem != 0 AS isarray "
  2823. "FROM pg_type",
  2824. username_subquery);
  2825. }
  2826. else if (fout->remoteVersion >= 70100)
  2827. {
  2828. appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
  2829. "0::oid AS typnamespace, '{=U}' AS typacl, "
  2830. "(%s typowner) AS rolname, "
  2831. "typinput::oid AS typinput, "
  2832. "typoutput::oid AS typoutput, typelem, typrelid, "
  2833. "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
  2834. "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
  2835. "typtype, typisdefined, "
  2836. "typname[0] = '_' AND typelem != 0 AS isarray "
  2837. "FROM pg_type",
  2838. username_subquery);
  2839. }
  2840. else
  2841. {
  2842. appendPQExpBuffer(query, "SELECT "
  2843. "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
  2844. "oid, typname, "
  2845. "0::oid AS typnamespace, '{=U}' AS typacl, "
  2846. "(%s typowner) AS rolname, "
  2847. "typinput::oid AS typinput, "
  2848. "typoutput::oid AS typoutput, typelem, typrelid, "
  2849. "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
  2850. "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
  2851. "typtype, typisdefined, "
  2852. "typname[0] = '_' AND typelem != 0 AS isarray "
  2853. "FROM pg_type",
  2854. username_subquery);
  2855. }
  2856. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  2857. ntups = PQntuples(res);
  2858. tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
  2859. i_tableoid = PQfnumber(res, "tableoid");
  2860. i_oid = PQfnumber(res, "oid");
  2861. i_typname = PQfnumber(res, "typname");
  2862. i_typnamespace = PQfnumber(res, "typnamespace");
  2863. i_typacl = PQfnumber(res, "typacl");
  2864. i_rolname = PQfnumber(res, "rolname");
  2865. i_typinput = PQfnumber(res, "typinput");
  2866. i_typoutput = PQfnumber(res, "typoutput");
  2867. i_typelem = PQfnumber(res, "typelem");
  2868. i_typrelid = PQfnumber(res, "typrelid");
  2869. i_typrelkind = PQfnumber(res, "typrelkind");
  2870. i_typtype = PQfnumber(res, "typtype");
  2871. i_typisdefined = PQfnumber(res, "typisdefined");
  2872. i_isarray = PQfnumber(res, "isarray");
  2873. for (i = 0; i < ntups; i++)
  2874. {
  2875. tyinfo[i].dobj.objType = DO_TYPE;
  2876. tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  2877. tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  2878. AssignDumpId(&tyinfo[i].dobj);
  2879. tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
  2880. tyinfo[i].dobj.namespace =
  2881. findNamespace(fout,
  2882. atooid(PQgetvalue(res, i, i_typnamespace)),
  2883. tyinfo[i].dobj.catId.oid);
  2884. tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  2885. tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
  2886. tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
  2887. tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
  2888. tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
  2889. tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
  2890. tyinfo[i].shellType = NULL;
  2891. if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
  2892. tyinfo[i].isDefined = true;
  2893. else
  2894. tyinfo[i].isDefined = false;
  2895. if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
  2896. tyinfo[i].isArray = true;
  2897. else
  2898. tyinfo[i].isArray = false;
  2899. /* Decide whether we want to dump it */
  2900. selectDumpableType(&tyinfo[i]);
  2901. /*
  2902. * If it's a domain, fetch info about its constraints, if any
  2903. */
  2904. tyinfo[i].nDomChecks = 0;
  2905. tyinfo[i].domChecks = NULL;
  2906. if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
  2907. getDomainConstraints(fout, &(tyinfo[i]));
  2908. /*
  2909. * If it's a base type, make a DumpableObject representing a shell
  2910. * definition of the type. We will need to dump that ahead of the I/O
  2911. * functions for the type. Similarly, range types need a shell
  2912. * definition in case they have a canonicalize function.
  2913. *
  2914. * Note: the shell type doesn't have a catId. You might think it
  2915. * should copy the base type's catId, but then it might capture the
  2916. * pg_depend entries for the type, which we don't want.
  2917. */
  2918. if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
  2919. tyinfo[i].typtype == TYPTYPE_RANGE))
  2920. {
  2921. stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
  2922. stinfo->dobj.objType = DO_SHELL_TYPE;
  2923. stinfo->dobj.catId = nilCatalogId;
  2924. AssignDumpId(&stinfo->dobj);
  2925. stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
  2926. stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
  2927. stinfo->baseType = &(tyinfo[i]);
  2928. tyinfo[i].shellType = stinfo;
  2929. /*
  2930. * Initially mark the shell type as not to be dumped. We'll only
  2931. * dump it if the I/O or canonicalize functions need to be dumped;
  2932. * this is taken care of while sorting dependencies.
  2933. */
  2934. stinfo->dobj.dump = false;
  2935. /*
  2936. * However, if dumping from pre-7.3, there will be no dependency
  2937. * info so we have to fake it here. We only need to worry about
  2938. * typinput and typoutput since the other functions only exist
  2939. * post-7.3.
  2940. */
  2941. if (fout->remoteVersion < 70300)
  2942. {
  2943. Oid typinput;
  2944. Oid typoutput;
  2945. FuncInfo *funcInfo;
  2946. typinput = atooid(PQgetvalue(res, i, i_typinput));
  2947. typoutput = atooid(PQgetvalue(res, i, i_typoutput));
  2948. funcInfo = findFuncByOid(typinput);
  2949. if (funcInfo && funcInfo->dobj.dump)
  2950. {
  2951. /* base type depends on function */
  2952. addObjectDependency(&tyinfo[i].dobj,
  2953. funcInfo->dobj.dumpId);
  2954. /* function depends on shell type */
  2955. addObjectDependency(&funcInfo->dobj,
  2956. stinfo->dobj.dumpId);
  2957. /* mark shell type as to be dumped */
  2958. stinfo->dobj.dump = true;
  2959. }
  2960. funcInfo = findFuncByOid(typoutput);
  2961. if (funcInfo && funcInfo->dobj.dump)
  2962. {
  2963. /* base type depends on function */
  2964. addObjectDependency(&tyinfo[i].dobj,
  2965. funcInfo->dobj.dumpId);
  2966. /* function depends on shell type */
  2967. addObjectDependency(&funcInfo->dobj,
  2968. stinfo->dobj.dumpId);
  2969. /* mark shell type as to be dumped */
  2970. stinfo->dobj.dump = true;
  2971. }
  2972. }
  2973. }
  2974. if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
  2975. write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
  2976. tyinfo[i].dobj.name);
  2977. }
  2978. *numTypes = ntups;
  2979. PQclear(res);
  2980. destroyPQExpBuffer(query);
  2981. return tyinfo;
  2982. }
  2983. /*
  2984. * getOperators:
  2985. * read all operators in the system catalogs and return them in the
  2986. * OprInfo* structure
  2987. *
  2988. * numOprs is set to the number of operators read in
  2989. */
  2990. OprInfo *
  2991. getOperators(Archive *fout, int *numOprs)
  2992. {
  2993. PGresult *res;
  2994. int ntups;
  2995. int i;
  2996. PQExpBuffer query = createPQExpBuffer();
  2997. OprInfo *oprinfo;
  2998. int i_tableoid;
  2999. int i_oid;
  3000. int i_oprname;
  3001. int i_oprnamespace;
  3002. int i_rolname;
  3003. int i_oprkind;
  3004. int i_oprcode;
  3005. /*
  3006. * find all operators, including builtin operators; we filter out
  3007. * system-defined operators at dump-out time.
  3008. */
  3009. /* Make sure we are in proper schema */
  3010. selectSourceSchema(fout, "pg_catalog");
  3011. if (fout->remoteVersion >= 70300)
  3012. {
  3013. appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
  3014. "oprnamespace, "
  3015. "(%s oprowner) AS rolname, "
  3016. "oprkind, "
  3017. "oprcode::oid AS oprcode "
  3018. "FROM pg_operator",
  3019. username_subquery);
  3020. }
  3021. else if (fout->remoteVersion >= 70100)
  3022. {
  3023. appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
  3024. "0::oid AS oprnamespace, "
  3025. "(%s oprowner) AS rolname, "
  3026. "oprkind, "
  3027. "oprcode::oid AS oprcode "
  3028. "FROM pg_operator",
  3029. username_subquery);
  3030. }
  3031. else
  3032. {
  3033. appendPQExpBuffer(query, "SELECT "
  3034. "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
  3035. "oid, oprname, "
  3036. "0::oid AS oprnamespace, "
  3037. "(%s oprowner) AS rolname, "
  3038. "oprkind, "
  3039. "oprcode::oid AS oprcode "
  3040. "FROM pg_operator",
  3041. username_subquery);
  3042. }
  3043. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  3044. ntups = PQntuples(res);
  3045. *numOprs = ntups;
  3046. oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
  3047. i_tableoid = PQfnumber(res, "tableoid");
  3048. i_oid = PQfnumber(res, "oid");
  3049. i_oprname = PQfnumber(res, "oprname");
  3050. i_oprnamespace = PQfnumber(res, "oprnamespace");
  3051. i_rolname = PQfnumber(res, "rolname");
  3052. i_oprkind = PQfnumber(res, "oprkind");
  3053. i_oprcode = PQfnumber(res, "oprcode");
  3054. for (i = 0; i < ntups; i++)
  3055. {
  3056. oprinfo[i].dobj.objType = DO_OPERATOR;
  3057. oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  3058. oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  3059. AssignDumpId(&oprinfo[i].dobj);
  3060. oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
  3061. oprinfo[i].dobj.namespace =
  3062. findNamespace(fout,
  3063. atooid(PQgetvalue(res, i, i_oprnamespace)),
  3064. oprinfo[i].dobj.catId.oid);
  3065. oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  3066. oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
  3067. oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
  3068. /* Decide whether we want to dump it */
  3069. selectDumpableObject(&(oprinfo[i].dobj));
  3070. if (strlen(oprinfo[i].rolname) == 0)
  3071. write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
  3072. oprinfo[i].dobj.name);
  3073. }
  3074. PQclear(res);
  3075. destroyPQExpBuffer(query);
  3076. return oprinfo;
  3077. }
  3078. /*
  3079. * getCollations:
  3080. * read all collations in the system catalogs and return them in the
  3081. * CollInfo* structure
  3082. *
  3083. * numCollations is set to the number of collations read in
  3084. */
  3085. CollInfo *
  3086. getCollations(Archive *fout, int *numCollations)
  3087. {
  3088. PGresult *res;
  3089. int ntups;
  3090. int i;
  3091. PQExpBuffer query;
  3092. CollInfo *collinfo;
  3093. int i_tableoid;
  3094. int i_oid;
  3095. int i_collname;
  3096. int i_collnamespace;
  3097. int i_rolname;
  3098. /* Collations didn't exist pre-9.1 */
  3099. if (fout->remoteVersion < 90100)
  3100. {
  3101. *numCollations = 0;
  3102. return NULL;
  3103. }
  3104. query = createPQExpBuffer();
  3105. /*
  3106. * find all collations, including builtin collations; we filter out
  3107. * system-defined collations at dump-out time.
  3108. */
  3109. /* Make sure we are in proper schema */
  3110. selectSourceSchema(fout, "pg_catalog");
  3111. appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
  3112. "collnamespace, "
  3113. "(%s collowner) AS rolname "
  3114. "FROM pg_collation",
  3115. username_subquery);
  3116. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  3117. ntups = PQntuples(res);
  3118. *numCollations = ntups;
  3119. collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
  3120. i_tableoid = PQfnumber(res, "tableoid");
  3121. i_oid = PQfnumber(res, "oid");
  3122. i_collname = PQfnumber(res, "collname");
  3123. i_collnamespace = PQfnumber(res, "collnamespace");
  3124. i_rolname = PQfnumber(res, "rolname");
  3125. for (i = 0; i < ntups; i++)
  3126. {
  3127. collinfo[i].dobj.objType = DO_COLLATION;
  3128. collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  3129. collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  3130. AssignDumpId(&collinfo[i].dobj);
  3131. collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
  3132. collinfo[i].dobj.namespace =
  3133. findNamespace(fout,
  3134. atooid(PQgetvalue(res, i, i_collnamespace)),
  3135. collinfo[i].dobj.catId.oid);
  3136. collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  3137. /* Decide whether we want to dump it */
  3138. selectDumpableObject(&(collinfo[i].dobj));
  3139. }
  3140. PQclear(res);
  3141. destroyPQExpBuffer(query);
  3142. return collinfo;
  3143. }
  3144. /*
  3145. * getConversions:
  3146. * read all conversions in the system catalogs and return them in the
  3147. * ConvInfo* structure
  3148. *
  3149. * numConversions is set to the number of conversions read in
  3150. */
  3151. ConvInfo *
  3152. getConversions(Archive *fout, int *numConversions)
  3153. {
  3154. PGresult *res;
  3155. int ntups;
  3156. int i;
  3157. PQExpBuffer query;
  3158. ConvInfo *convinfo;
  3159. int i_tableoid;
  3160. int i_oid;
  3161. int i_conname;
  3162. int i_connamespace;
  3163. int i_rolname;
  3164. /* Conversions didn't exist pre-7.3 */
  3165. if (fout->remoteVersion < 70300)
  3166. {
  3167. *numConversions = 0;
  3168. return NULL;
  3169. }
  3170. query = createPQExpBuffer();
  3171. /*
  3172. * find all conversions, including builtin conversions; we filter out
  3173. * system-defined conversions at dump-out time.
  3174. */
  3175. /* Make sure we are in proper schema */
  3176. selectSourceSchema(fout, "pg_catalog");
  3177. appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
  3178. "connamespace, "
  3179. "(%s conowner) AS rolname "
  3180. "FROM pg_conversion",
  3181. username_subquery);
  3182. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  3183. ntups = PQntuples(res);
  3184. *numConversions = ntups;
  3185. convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
  3186. i_tableoid = PQfnumber(res, "tableoid");
  3187. i_oid = PQfnumber(res, "oid");
  3188. i_conname = PQfnumber(res, "conname");
  3189. i_connamespace = PQfnumber(res, "connamespace");
  3190. i_rolname = PQfnumber(res, "rolname");
  3191. for (i = 0; i < ntups; i++)
  3192. {
  3193. convinfo[i].dobj.objType = DO_CONVERSION;
  3194. convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  3195. convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  3196. AssignDumpId(&convinfo[i].dobj);
  3197. convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
  3198. convinfo[i].dobj.namespace =
  3199. findNamespace(fout,
  3200. atooid(PQgetvalue(res, i, i_connamespace)),
  3201. convinfo[i].dobj.catId.oid);
  3202. convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  3203. /* Decide whether we want to dump it */
  3204. selectDumpableObject(&(convinfo[i].dobj));
  3205. }
  3206. PQclear(res);
  3207. destroyPQExpBuffer(query);
  3208. return convinfo;
  3209. }
  3210. /*
  3211. * getOpclasses:
  3212. * read all opclasses in the system catalogs and return them in the
  3213. * OpclassInfo* structure
  3214. *
  3215. * numOpclasses is set to the number of opclasses read in
  3216. */
  3217. OpclassInfo *
  3218. getOpclasses(Archive *fout, int *numOpclasses)
  3219. {
  3220. PGresult *res;
  3221. int ntups;
  3222. int i;
  3223. PQExpBuffer query = createPQExpBuffer();
  3224. OpclassInfo *opcinfo;
  3225. int i_tableoid;
  3226. int i_oid;
  3227. int i_opcname;
  3228. int i_opcnamespace;
  3229. int i_rolname;
  3230. /*
  3231. * find all opclasses, including builtin opclasses; we filter out
  3232. * system-defined opclasses at dump-out time.
  3233. */
  3234. /* Make sure we are in proper schema */
  3235. selectSourceSchema(fout, "pg_catalog");
  3236. if (fout->remoteVersion >= 70300)
  3237. {
  3238. appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
  3239. "opcnamespace, "
  3240. "(%s opcowner) AS rolname "
  3241. "FROM pg_opclass",
  3242. username_subquery);
  3243. }
  3244. else if (fout->remoteVersion >= 70100)
  3245. {
  3246. appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
  3247. "0::oid AS opcnamespace, "
  3248. "''::name AS rolname "
  3249. "FROM pg_opclass");
  3250. }
  3251. else
  3252. {
  3253. appendPQExpBufferStr(query, "SELECT "
  3254. "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
  3255. "oid, opcname, "
  3256. "0::oid AS opcnamespace, "
  3257. "''::name AS rolname "
  3258. "FROM pg_opclass");
  3259. }
  3260. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  3261. ntups = PQntuples(res);
  3262. *numOpclasses = ntups;
  3263. opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
  3264. i_tableoid = PQfnumber(res, "tableoid");
  3265. i_oid = PQfnumber(res, "oid");
  3266. i_opcname = PQfnumber(res, "opcname");
  3267. i_opcnamespace = PQfnumber(res, "opcnamespace");
  3268. i_rolname = PQfnumber(res, "rolname");
  3269. for (i = 0; i < ntups; i++)
  3270. {
  3271. opcinfo[i].dobj.objType = DO_OPCLASS;
  3272. opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  3273. opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  3274. AssignDumpId(&opcinfo[i].dobj);
  3275. opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
  3276. opcinfo[i].dobj.namespace =
  3277. findNamespace(fout,
  3278. atooid(PQgetvalue(res, i, i_opcnamespace)),
  3279. opcinfo[i].dobj.catId.oid);
  3280. opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  3281. /* Decide whether we want to dump it */
  3282. selectDumpableObject(&(opcinfo[i].dobj));
  3283. if (fout->remoteVersion >= 70300)
  3284. {
  3285. if (strlen(opcinfo[i].rolname) == 0)
  3286. write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
  3287. opcinfo[i].dobj.name);
  3288. }
  3289. }
  3290. PQclear(res);
  3291. destroyPQExpBuffer(query);
  3292. return opcinfo;
  3293. }
  3294. /*
  3295. * getOpfamilies:
  3296. * read all opfamilies in the system catalogs and return them in the
  3297. * OpfamilyInfo* structure
  3298. *
  3299. * numOpfamilies is set to the number of opfamilies read in
  3300. */
  3301. OpfamilyInfo *
  3302. getOpfamilies(Archive *fout, int *numOpfamilies)
  3303. {
  3304. PGresult *res;
  3305. int ntups;
  3306. int i;
  3307. PQExpBuffer query;
  3308. OpfamilyInfo *opfinfo;
  3309. int i_tableoid;
  3310. int i_oid;
  3311. int i_opfname;
  3312. int i_opfnamespace;
  3313. int i_rolname;
  3314. /* Before 8.3, there is no separate concept of opfamilies */
  3315. if (fout->remoteVersion < 80300)
  3316. {
  3317. *numOpfamilies = 0;
  3318. return NULL;
  3319. }
  3320. query = createPQExpBuffer();
  3321. /*
  3322. * find all opfamilies, including builtin opfamilies; we filter out
  3323. * system-defined opfamilies at dump-out time.
  3324. */
  3325. /* Make sure we are in proper schema */
  3326. selectSourceSchema(fout, "pg_catalog");
  3327. appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
  3328. "opfnamespace, "
  3329. "(%s opfowner) AS rolname "
  3330. "FROM pg_opfamily",
  3331. username_subquery);
  3332. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  3333. ntups = PQntuples(res);
  3334. *numOpfamilies = ntups;
  3335. opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
  3336. i_tableoid = PQfnumber(res, "tableoid");
  3337. i_oid = PQfnumber(res, "oid");
  3338. i_opfname = PQfnumber(res, "opfname");
  3339. i_opfnamespace = PQfnumber(res, "opfnamespace");
  3340. i_rolname = PQfnumber(res, "rolname");
  3341. for (i = 0; i < ntups; i++)
  3342. {
  3343. opfinfo[i].dobj.objType = DO_OPFAMILY;
  3344. opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  3345. opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  3346. AssignDumpId(&opfinfo[i].dobj);
  3347. opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
  3348. opfinfo[i].dobj.namespace =
  3349. findNamespace(fout,
  3350. atooid(PQgetvalue(res, i, i_opfnamespace)),
  3351. opfinfo[i].dobj.catId.oid);
  3352. opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  3353. /* Decide whether we want to dump it */
  3354. selectDumpableObject(&(opfinfo[i].dobj));
  3355. if (fout->remoteVersion >= 70300)
  3356. {
  3357. if (strlen(opfinfo[i].rolname) == 0)
  3358. write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
  3359. opfinfo[i].dobj.name);
  3360. }
  3361. }
  3362. PQclear(res);
  3363. destroyPQExpBuffer(query);
  3364. return opfinfo;
  3365. }
  3366. /*
  3367. * getAggregates:
  3368. * read all the user-defined aggregates in the system catalogs and
  3369. * return them in the AggInfo* structure
  3370. *
  3371. * numAggs is set to the number of aggregates read in
  3372. */
  3373. AggInfo *
  3374. getAggregates(Archive *fout, int *numAggs)
  3375. {
  3376. PGresult *res;
  3377. int ntups;
  3378. int i;
  3379. PQExpBuffer query = createPQExpBuffer();
  3380. AggInfo *agginfo;
  3381. int i_tableoid;
  3382. int i_oid;
  3383. int i_aggname;
  3384. int i_aggnamespace;
  3385. int i_pronargs;
  3386. int i_proargtypes;
  3387. int i_rolname;
  3388. int i_aggacl;
  3389. int i_proiargs;
  3390. /* Make sure we are in proper schema */
  3391. selectSourceSchema(fout, "pg_catalog");
  3392. /*
  3393. * Find all user-defined aggregates. See comment in getFuncs() for the
  3394. * rationale behind the filtering logic.
  3395. */
  3396. if (fout->remoteVersion >= 80400)
  3397. {
  3398. appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
  3399. "pronamespace AS aggnamespace, "
  3400. "pronargs, proargtypes, "
  3401. "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
  3402. "(%s proowner) AS rolname, "
  3403. "proacl AS aggacl "
  3404. "FROM pg_proc p "
  3405. "WHERE proisagg AND ("
  3406. "pronamespace != "
  3407. "(SELECT oid FROM pg_namespace "
  3408. "WHERE nspname = 'pg_catalog')",
  3409. username_subquery);
  3410. if (binary_upgrade && fout->remoteVersion >= 90100)
  3411. appendPQExpBufferStr(query,
  3412. " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
  3413. "classid = 'pg_proc'::regclass AND "
  3414. "objid = p.oid AND "
  3415. "refclassid = 'pg_extension'::regclass AND "
  3416. "deptype = 'e')");
  3417. appendPQExpBufferChar(query, ')');
  3418. }
  3419. else if (fout->remoteVersion >= 80200)
  3420. {
  3421. appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
  3422. "pronamespace AS aggnamespace, "
  3423. "pronargs, proargtypes, "
  3424. "NULL::text AS proiargs,"
  3425. "(%s proowner) AS rolname, "
  3426. "proacl AS aggacl "
  3427. "FROM pg_proc p "
  3428. "WHERE proisagg AND ("
  3429. "pronamespace != "
  3430. "(SELECT oid FROM pg_namespace "
  3431. "WHERE nspname = 'pg_catalog'))",
  3432. username_subquery);
  3433. }
  3434. else if (fout->remoteVersion >= 70300)
  3435. {
  3436. appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
  3437. "pronamespace AS aggnamespace, "
  3438. "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
  3439. "proargtypes, "
  3440. "NULL::text AS proiargs, "
  3441. "(%s proowner) AS rolname, "
  3442. "proacl AS aggacl "
  3443. "FROM pg_proc "
  3444. "WHERE proisagg "
  3445. "AND pronamespace != "
  3446. "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
  3447. username_subquery);
  3448. }
  3449. else if (fout->remoteVersion >= 70100)
  3450. {
  3451. appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
  3452. "0::oid AS aggnamespace, "
  3453. "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
  3454. "aggbasetype AS proargtypes, "
  3455. "NULL::text AS proiargs, "
  3456. "(%s aggowner) AS rolname, "
  3457. "'{=X}' AS aggacl "
  3458. "FROM pg_aggregate "
  3459. "where oid > '%u'::oid",
  3460. username_subquery,
  3461. g_last_builtin_oid);
  3462. }
  3463. else
  3464. {
  3465. appendPQExpBuffer(query, "SELECT "
  3466. "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
  3467. "oid, aggname, "
  3468. "0::oid AS aggnamespace, "
  3469. "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
  3470. "aggbasetype AS proargtypes, "
  3471. "NULL::text AS proiargs, "
  3472. "(%s aggowner) AS rolname, "
  3473. "'{=X}' AS aggacl "
  3474. "FROM pg_aggregate "
  3475. "where oid > '%u'::oid",
  3476. username_subquery,
  3477. g_last_builtin_oid);
  3478. }
  3479. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  3480. ntups = PQntuples(res);
  3481. *numAggs = ntups;
  3482. agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
  3483. i_tableoid = PQfnumber(res, "tableoid");
  3484. i_oid = PQfnumber(res, "oid");
  3485. i_aggname = PQfnumber(res, "aggname");
  3486. i_aggnamespace = PQfnumber(res, "aggnamespace");
  3487. i_pronargs = PQfnumber(res, "pronargs");
  3488. i_proargtypes = PQfnumber(res, "proargtypes");
  3489. i_rolname = PQfnumber(res, "rolname");
  3490. i_aggacl = PQfnumber(res, "aggacl");
  3491. i_proiargs = PQfnumber(res, "proiargs");
  3492. for (i = 0; i < ntups; i++)
  3493. {
  3494. agginfo[i].aggfn.dobj.objType = DO_AGG;
  3495. agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  3496. agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  3497. AssignDumpId(&agginfo[i].aggfn.dobj);
  3498. agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
  3499. agginfo[i].aggfn.dobj.namespace =
  3500. findNamespace(fout,
  3501. atooid(PQgetvalue(res, i, i_aggnamespace)),
  3502. agginfo[i].aggfn.dobj.catId.oid);
  3503. agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  3504. if (strlen(agginfo[i].aggfn.rolname) == 0)
  3505. write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
  3506. agginfo[i].aggfn.dobj.name);
  3507. agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
  3508. agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
  3509. agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
  3510. agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
  3511. agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
  3512. if (agginfo[i].aggfn.nargs == 0)
  3513. agginfo[i].aggfn.argtypes = NULL;
  3514. else
  3515. {
  3516. agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
  3517. if (fout->remoteVersion >= 70300)
  3518. parseOidArray(PQgetvalue(res, i, i_proargtypes),
  3519. agginfo[i].aggfn.argtypes,
  3520. agginfo[i].aggfn.nargs);
  3521. else
  3522. /* it's just aggbasetype */
  3523. agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
  3524. }
  3525. /* Decide whether we want to dump it */
  3526. selectDumpableObject(&(agginfo[i].aggfn.dobj));
  3527. }
  3528. PQclear(res);
  3529. destroyPQExpBuffer(query);
  3530. return agginfo;
  3531. }
  3532. /*
  3533. * getFuncs:
  3534. * read all the user-defined functions in the system catalogs and
  3535. * return them in the FuncInfo* structure
  3536. *
  3537. * numFuncs is set to the number of functions read in
  3538. */
  3539. FuncInfo *
  3540. getFuncs(Archive *fout, int *numFuncs)
  3541. {
  3542. PGresult *res;
  3543. int ntups;
  3544. int i;
  3545. PQExpBuffer query = createPQExpBuffer();
  3546. FuncInfo *finfo;
  3547. int i_tableoid;
  3548. int i_oid;
  3549. int i_proname;
  3550. int i_pronamespace;
  3551. int i_rolname;
  3552. int i_prolang;
  3553. int i_pronargs;
  3554. int i_proargtypes;
  3555. int i_prorettype;
  3556. int i_proacl;
  3557. int i_proiargs;
  3558. /* Make sure we are in proper schema */
  3559. selectSourceSchema(fout, "pg_catalog");
  3560. /*
  3561. * Find all user-defined functions. Normally we can exclude functions in
  3562. * pg_catalog, which is worth doing since there are several thousand of
  3563. * 'em. However, there are some extensions that create functions in
  3564. * pg_catalog. In normal dumps we can still ignore those --- but in
  3565. * binary-upgrade mode, we must dump the member objects of the extension,
  3566. * so be sure to fetch any such functions.
  3567. *
  3568. * Also, in 9.2 and up, exclude functions that are internally dependent on
  3569. * something else, since presumably those will be created as a result of
  3570. * creating the something else. This currently only acts to suppress
  3571. * constructor functions for range types. Note that this is OK only
  3572. * because the constructors don't have any dependencies the range type
  3573. * doesn't have; otherwise we might not get creation ordering correct.
  3574. */
  3575. if (fout->remoteVersion >= 80400)
  3576. {
  3577. appendPQExpBuffer(query,
  3578. "SELECT tableoid, oid, proname, prolang, "
  3579. "pronargs, proargtypes, prorettype, proacl, "
  3580. "pronamespace, "
  3581. "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
  3582. "(%s proowner) AS rolname "
  3583. "FROM pg_proc p "
  3584. "WHERE NOT proisagg AND ("
  3585. "pronamespace != "
  3586. "(SELECT oid FROM pg_namespace "
  3587. "WHERE nspname = 'pg_catalog')",
  3588. username_subquery);
  3589. if (fout->remoteVersion >= 90200)
  3590. appendPQExpBufferStr(query,
  3591. "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
  3592. "WHERE classid = 'pg_proc'::regclass AND "
  3593. "objid = p.oid AND deptype = 'i')");
  3594. if (binary_upgrade && fout->remoteVersion >= 90100)
  3595. appendPQExpBufferStr(query,
  3596. "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
  3597. "classid = 'pg_proc'::regclass AND "
  3598. "objid = p.oid AND "
  3599. "refclassid = 'pg_extension'::regclass AND "
  3600. "deptype = 'e')");
  3601. appendPQExpBufferChar(query, ')');
  3602. }
  3603. else if (fout->remoteVersion >= 70300)
  3604. {
  3605. appendPQExpBuffer(query,
  3606. "SELECT tableoid, oid, proname, prolang, "
  3607. "pronargs, proargtypes, prorettype, proacl, "
  3608. "pronamespace, "
  3609. "NULL::text AS proiargs,"
  3610. "(%s proowner) AS rolname "
  3611. "FROM pg_proc p "
  3612. "WHERE NOT proisagg AND ("
  3613. "pronamespace != "
  3614. "(SELECT oid FROM pg_namespace "
  3615. "WHERE nspname = 'pg_catalog'))",
  3616. username_subquery);
  3617. }
  3618. else if (fout->remoteVersion >= 70100)
  3619. {
  3620. appendPQExpBuffer(query,
  3621. "SELECT tableoid, oid, proname, prolang, "
  3622. "pronargs, proargtypes, prorettype, "
  3623. "'{=X}' AS proacl, "
  3624. "0::oid AS pronamespace, "
  3625. "NULL::text AS proiargs,"
  3626. "(%s proowner) AS rolname "
  3627. "FROM pg_proc "
  3628. "WHERE pg_proc.oid > '%u'::oid",
  3629. username_subquery,
  3630. g_last_builtin_oid);
  3631. }
  3632. else
  3633. {
  3634. appendPQExpBuffer(query,
  3635. "SELECT "
  3636. "(SELECT oid FROM pg_class "
  3637. " WHERE relname = 'pg_proc') AS tableoid, "
  3638. "oid, proname, prolang, "
  3639. "pronargs, proargtypes, prorettype, "
  3640. "'{=X}' AS proacl, "
  3641. "0::oid AS pronamespace, "
  3642. "NULL::text AS proiargs,"
  3643. "(%s proowner) AS rolname "
  3644. "FROM pg_proc "
  3645. "where pg_proc.oid > '%u'::oid",
  3646. username_subquery,
  3647. g_last_builtin_oid);
  3648. }
  3649. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  3650. ntups = PQntuples(res);
  3651. *numFuncs = ntups;
  3652. finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
  3653. i_tableoid = PQfnumber(res, "tableoid");
  3654. i_oid = PQfnumber(res, "oid");
  3655. i_proname = PQfnumber(res, "proname");
  3656. i_pronamespace = PQfnumber(res, "pronamespace");
  3657. i_rolname = PQfnumber(res, "rolname");
  3658. i_prolang = PQfnumber(res, "prolang");
  3659. i_pronargs = PQfnumber(res, "pronargs");
  3660. i_proargtypes = PQfnumber(res, "proargtypes");
  3661. i_prorettype = PQfnumber(res, "prorettype");
  3662. i_proacl = PQfnumber(res, "proacl");
  3663. i_proiargs = PQfnumber(res, "proiargs");
  3664. for (i = 0; i < ntups; i++)
  3665. {
  3666. finfo[i].dobj.objType = DO_FUNC;
  3667. finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  3668. finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  3669. AssignDumpId(&finfo[i].dobj);
  3670. finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
  3671. finfo[i].dobj.namespace =
  3672. findNamespace(fout,
  3673. atooid(PQgetvalue(res, i, i_pronamespace)),
  3674. finfo[i].dobj.catId.oid);
  3675. finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  3676. finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
  3677. finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
  3678. finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
  3679. finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
  3680. finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
  3681. if (finfo[i].nargs == 0)
  3682. finfo[i].argtypes = NULL;
  3683. else
  3684. {
  3685. finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
  3686. parseOidArray(PQgetvalue(res, i, i_proargtypes),
  3687. finfo[i].argtypes, finfo[i].nargs);
  3688. }
  3689. /* Decide whether we want to dump it */
  3690. selectDumpableObject(&(finfo[i].dobj));
  3691. if (strlen(finfo[i].rolname) == 0)
  3692. write_msg(NULL,
  3693. "WARNING: owner of function \"%s\" appears to be invalid\n",
  3694. finfo[i].dobj.name);
  3695. }
  3696. PQclear(res);
  3697. destroyPQExpBuffer(query);
  3698. return finfo;
  3699. }
  3700. /*
  3701. * getTables
  3702. * read all the user-defined tables (no indexes, no catalogs)
  3703. * in the system catalogs return them in the TableInfo* structure
  3704. *
  3705. * numTables is set to the number of tables read in
  3706. */
  3707. TableInfo *
  3708. getTables(Archive *fout, int *numTables)
  3709. {
  3710. PGresult *res;
  3711. int ntups;
  3712. int i;
  3713. PQExpBuffer query = createPQExpBuffer();
  3714. TableInfo *tblinfo;
  3715. int i_reltableoid;
  3716. int i_reloid;
  3717. int i_relname;
  3718. int i_relnamespace;
  3719. int i_relkind;
  3720. int i_relacl;
  3721. int i_rolname;
  3722. int i_relchecks;
  3723. int i_relhastriggers;
  3724. int i_relhasindex;
  3725. int i_relhasrules;
  3726. int i_relhasoids;
  3727. int i_relfrozenxid;
  3728. int i_relminmxid;
  3729. int i_toastoid;
  3730. int i_toastfrozenxid;
  3731. int i_toastminmxid;
  3732. int i_relpersistence;
  3733. int i_relispopulated;
  3734. int i_relreplident;
  3735. int i_owning_tab;
  3736. int i_owning_col;
  3737. int i_reltablespace;
  3738. int i_reloptions;
  3739. int i_checkoption;
  3740. int i_toastreloptions;
  3741. int i_reloftype;
  3742. int i_relpages;
  3743. /* Make sure we are in proper schema */
  3744. selectSourceSchema(fout, "pg_catalog");
  3745. /*
  3746. * Find all the tables and table-like objects.
  3747. *
  3748. * We include system catalogs, so that we can work if a user table is
  3749. * defined to inherit from a system catalog (pretty weird, but...)
  3750. *
  3751. * We ignore relations that are not ordinary tables, sequences, views,
  3752. * materialized views, composite types, or foreign tables.
  3753. *
  3754. * Composite-type table entries won't be dumped as such, but we have to
  3755. * make a DumpableObject for them so that we can track dependencies of the
  3756. * composite type (pg_depend entries for columns of the composite type
  3757. * link to the pg_class entry not the pg_type entry).
  3758. *
  3759. * Note: in this phase we should collect only a minimal amount of
  3760. * information about each table, basically just enough to decide if it is
  3761. * interesting. We must fetch all tables in this phase because otherwise
  3762. * we cannot correctly identify inherited columns, owned sequences, etc.
  3763. */
  3764. if (fout->remoteVersion >= 90400)
  3765. {
  3766. /*
  3767. * Left join to pick up dependency info linking sequences to their
  3768. * owning column, if any (note this dependency is AUTO as of 8.2)
  3769. */
  3770. appendPQExpBuffer(query,
  3771. "SELECT c.tableoid, c.oid, c.relname, "
  3772. "c.relacl, c.relkind, c.relnamespace, "
  3773. "(%s c.relowner) AS rolname, "
  3774. "c.relchecks, c.relhastriggers, "
  3775. "c.relhasindex, c.relhasrules, c.relhasoids, "
  3776. "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
  3777. "tc.relfrozenxid AS tfrozenxid, "
  3778. "tc.relminmxid AS tminmxid, "
  3779. "c.relpersistence, c.relispopulated, "
  3780. "c.relreplident, c.relpages, "
  3781. "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
  3782. "d.refobjid AS owning_tab, "
  3783. "d.refobjsubid AS owning_col, "
  3784. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
  3785. "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
  3786. "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
  3787. "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
  3788. "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
  3789. "FROM pg_class c "
  3790. "LEFT JOIN pg_depend d ON "
  3791. "(c.relkind = '%c' AND "
  3792. "d.classid = c.tableoid AND d.objid = c.oid AND "
  3793. "d.objsubid = 0 AND "
  3794. "d.refclassid = c.tableoid AND d.deptype = 'a') "
  3795. "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
  3796. "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
  3797. "ORDER BY c.oid",
  3798. username_subquery,
  3799. RELKIND_SEQUENCE,
  3800. RELKIND_RELATION, RELKIND_SEQUENCE,
  3801. RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
  3802. RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
  3803. }
  3804. else if (fout->remoteVersion >= 90300)
  3805. {
  3806. /*
  3807. * Left join to pick up dependency info linking sequences to their
  3808. * owning column, if any (note this dependency is AUTO as of 8.2)
  3809. */
  3810. appendPQExpBuffer(query,
  3811. "SELECT c.tableoid, c.oid, c.relname, "
  3812. "c.relacl, c.relkind, c.relnamespace, "
  3813. "(%s c.relowner) AS rolname, "
  3814. "c.relchecks, c.relhastriggers, "
  3815. "c.relhasindex, c.relhasrules, c.relhasoids, "
  3816. "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
  3817. "tc.relfrozenxid AS tfrozenxid, "
  3818. "tc.relminmxid AS tminmxid, "
  3819. "c.relpersistence, c.relispopulated, "
  3820. "'d' AS relreplident, c.relpages, "
  3821. "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
  3822. "d.refobjid AS owning_tab, "
  3823. "d.refobjsubid AS owning_col, "
  3824. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
  3825. "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
  3826. "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
  3827. "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
  3828. "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
  3829. "FROM pg_class c "
  3830. "LEFT JOIN pg_depend d ON "
  3831. "(c.relkind = '%c' AND "
  3832. "d.classid = c.tableoid AND d.objid = c.oid AND "
  3833. "d.objsubid = 0 AND "
  3834. "d.refclassid = c.tableoid AND d.deptype = 'a') "
  3835. "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
  3836. "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
  3837. "ORDER BY c.oid",
  3838. username_subquery,
  3839. RELKIND_SEQUENCE,
  3840. RELKIND_RELATION, RELKIND_SEQUENCE,
  3841. RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
  3842. RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
  3843. }
  3844. else if (fout->remoteVersion >= 90100)
  3845. {
  3846. /*
  3847. * Left join to pick up dependency info linking sequences to their
  3848. * owning column, if any (note this dependency is AUTO as of 8.2)
  3849. */
  3850. appendPQExpBuffer(query,
  3851. "SELECT c.tableoid, c.oid, c.relname, "
  3852. "c.relacl, c.relkind, c.relnamespace, "
  3853. "(%s c.relowner) AS rolname, "
  3854. "c.relchecks, c.relhastriggers, "
  3855. "c.relhasindex, c.relhasrules, c.relhasoids, "
  3856. "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
  3857. "tc.relfrozenxid AS tfrozenxid, "
  3858. "0 AS tminmxid, "
  3859. "c.relpersistence, 't' as relispopulated, "
  3860. "'d' AS relreplident, c.relpages, "
  3861. "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
  3862. "d.refobjid AS owning_tab, "
  3863. "d.refobjsubid AS owning_col, "
  3864. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
  3865. "array_to_string(c.reloptions, ', ') AS reloptions, "
  3866. "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
  3867. "FROM pg_class c "
  3868. "LEFT JOIN pg_depend d ON "
  3869. "(c.relkind = '%c' AND "
  3870. "d.classid = c.tableoid AND d.objid = c.oid AND "
  3871. "d.objsubid = 0 AND "
  3872. "d.refclassid = c.tableoid AND d.deptype = 'a') "
  3873. "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
  3874. "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
  3875. "ORDER BY c.oid",
  3876. username_subquery,
  3877. RELKIND_SEQUENCE,
  3878. RELKIND_RELATION, RELKIND_SEQUENCE,
  3879. RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
  3880. RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
  3881. }
  3882. else if (fout->remoteVersion >= 90000)
  3883. {
  3884. /*
  3885. * Left join to pick up dependency info linking sequences to their
  3886. * owning column, if any (note this dependency is AUTO as of 8.2)
  3887. */
  3888. appendPQExpBuffer(query,
  3889. "SELECT c.tableoid, c.oid, c.relname, "
  3890. "c.relacl, c.relkind, c.relnamespace, "
  3891. "(%s c.relowner) AS rolname, "
  3892. "c.relchecks, c.relhastriggers, "
  3893. "c.relhasindex, c.relhasrules, c.relhasoids, "
  3894. "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
  3895. "tc.relfrozenxid AS tfrozenxid, "
  3896. "0 AS tminmxid, "
  3897. "'p' AS relpersistence, 't' as relispopulated, "
  3898. "'d' AS relreplident, c.relpages, "
  3899. "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
  3900. "d.refobjid AS owning_tab, "
  3901. "d.refobjsubid AS owning_col, "
  3902. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
  3903. "array_to_string(c.reloptions, ', ') AS reloptions, "
  3904. "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
  3905. "FROM pg_class c "
  3906. "LEFT JOIN pg_depend d ON "
  3907. "(c.relkind = '%c' AND "
  3908. "d.classid = c.tableoid AND d.objid = c.oid AND "
  3909. "d.objsubid = 0 AND "
  3910. "d.refclassid = c.tableoid AND d.deptype = 'a') "
  3911. "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
  3912. "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
  3913. "ORDER BY c.oid",
  3914. username_subquery,
  3915. RELKIND_SEQUENCE,
  3916. RELKIND_RELATION, RELKIND_SEQUENCE,
  3917. RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
  3918. }
  3919. else if (fout->remoteVersion >= 80400)
  3920. {
  3921. /*
  3922. * Left join to pick up dependency info linking sequences to their
  3923. * owning column, if any (note this dependency is AUTO as of 8.2)
  3924. */
  3925. appendPQExpBuffer(query,
  3926. "SELECT c.tableoid, c.oid, c.relname, "
  3927. "c.relacl, c.relkind, c.relnamespace, "
  3928. "(%s c.relowner) AS rolname, "
  3929. "c.relchecks, c.relhastriggers, "
  3930. "c.relhasindex, c.relhasrules, c.relhasoids, "
  3931. "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
  3932. "tc.relfrozenxid AS tfrozenxid, "
  3933. "0 AS tminmxid, "
  3934. "'p' AS relpersistence, 't' as relispopulated, "
  3935. "'d' AS relreplident, c.relpages, "
  3936. "NULL AS reloftype, "
  3937. "d.refobjid AS owning_tab, "
  3938. "d.refobjsubid AS owning_col, "
  3939. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
  3940. "array_to_string(c.reloptions, ', ') AS reloptions, "
  3941. "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
  3942. "FROM pg_class c "
  3943. "LEFT JOIN pg_depend d ON "
  3944. "(c.relkind = '%c' AND "
  3945. "d.classid = c.tableoid AND d.objid = c.oid AND "
  3946. "d.objsubid = 0 AND "
  3947. "d.refclassid = c.tableoid AND d.deptype = 'a') "
  3948. "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
  3949. "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
  3950. "ORDER BY c.oid",
  3951. username_subquery,
  3952. RELKIND_SEQUENCE,
  3953. RELKIND_RELATION, RELKIND_SEQUENCE,
  3954. RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
  3955. }
  3956. else if (fout->remoteVersion >= 80200)
  3957. {
  3958. /*
  3959. * Left join to pick up dependency info linking sequences to their
  3960. * owning column, if any (note this dependency is AUTO as of 8.2)
  3961. */
  3962. appendPQExpBuffer(query,
  3963. "SELECT c.tableoid, c.oid, c.relname, "
  3964. "c.relacl, c.relkind, c.relnamespace, "
  3965. "(%s c.relowner) AS rolname, "
  3966. "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
  3967. "c.relhasindex, c.relhasrules, c.relhasoids, "
  3968. "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
  3969. "tc.relfrozenxid AS tfrozenxid, "
  3970. "0 AS tminmxid, "
  3971. "'p' AS relpersistence, 't' as relispopulated, "
  3972. "'d' AS relreplident, c.relpages, "
  3973. "NULL AS reloftype, "
  3974. "d.refobjid AS owning_tab, "
  3975. "d.refobjsubid AS owning_col, "
  3976. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
  3977. "array_to_string(c.reloptions, ', ') AS reloptions, "
  3978. "NULL AS toast_reloptions "
  3979. "FROM pg_class c "
  3980. "LEFT JOIN pg_depend d ON "
  3981. "(c.relkind = '%c' AND "
  3982. "d.classid = c.tableoid AND d.objid = c.oid AND "
  3983. "d.objsubid = 0 AND "
  3984. "d.refclassid = c.tableoid AND d.deptype = 'a') "
  3985. "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
  3986. "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
  3987. "ORDER BY c.oid",
  3988. username_subquery,
  3989. RELKIND_SEQUENCE,
  3990. RELKIND_RELATION, RELKIND_SEQUENCE,
  3991. RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
  3992. }
  3993. else if (fout->remoteVersion >= 80000)
  3994. {
  3995. /*
  3996. * Left join to pick up dependency info linking sequences to their
  3997. * owning column, if any
  3998. */
  3999. appendPQExpBuffer(query,
  4000. "SELECT c.tableoid, c.oid, relname, "
  4001. "relacl, relkind, relnamespace, "
  4002. "(%s relowner) AS rolname, "
  4003. "relchecks, (reltriggers <> 0) AS relhastriggers, "
  4004. "relhasindex, relhasrules, relhasoids, "
  4005. "0 AS relfrozenxid, 0 AS relminmxid,"
  4006. "0 AS toid, "
  4007. "0 AS tfrozenxid, 0 AS tminmxid,"
  4008. "'p' AS relpersistence, 't' as relispopulated, "
  4009. "'d' AS relreplident, relpages, "
  4010. "NULL AS reloftype, "
  4011. "d.refobjid AS owning_tab, "
  4012. "d.refobjsubid AS owning_col, "
  4013. "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
  4014. "NULL AS reloptions, "
  4015. "NULL AS toast_reloptions "
  4016. "FROM pg_class c "
  4017. "LEFT JOIN pg_depend d ON "
  4018. "(c.relkind = '%c' AND "
  4019. "d.classid = c.tableoid AND d.objid = c.oid AND "
  4020. "d.objsubid = 0 AND "
  4021. "d.refclassid = c.tableoid AND d.deptype = 'i') "
  4022. "WHERE relkind in ('%c', '%c', '%c', '%c') "
  4023. "ORDER BY c.oid",
  4024. username_subquery,
  4025. RELKIND_SEQUENCE,
  4026. RELKIND_RELATION, RELKIND_SEQUENCE,
  4027. RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
  4028. }
  4029. else if (fout->remoteVersion >= 70300)
  4030. {
  4031. /*
  4032. * Left join to pick up dependency info linking sequences to their
  4033. * owning column, if any
  4034. */
  4035. appendPQExpBuffer(query,
  4036. "SELECT c.tableoid, c.oid, relname, "
  4037. "relacl, relkind, relnamespace, "
  4038. "(%s relowner) AS rolname, "
  4039. "relchecks, (reltriggers <> 0) AS relhastriggers, "
  4040. "relhasindex, relhasrules, relhasoids, "
  4041. "0 AS relfrozenxid, 0 AS relminmxid,"
  4042. "0 AS toid, "
  4043. "0 AS tfrozenxid, 0 AS tminmxid,"
  4044. "'p' AS relpersistence, 't' as relispopulated, "
  4045. "'d' AS relreplident, relpages, "
  4046. "NULL AS reloftype, "
  4047. "d.refobjid AS owning_tab, "
  4048. "d.refobjsubid AS owning_col, "
  4049. "NULL AS reltablespace, "
  4050. "NULL AS reloptions, "
  4051. "NULL AS toast_reloptions "
  4052. "FROM pg_class c "
  4053. "LEFT JOIN pg_depend d ON "
  4054. "(c.relkind = '%c' AND "
  4055. "d.classid = c.tableoid AND d.objid = c.oid AND "
  4056. "d.objsubid = 0 AND "
  4057. "d.refclassid = c.tableoid AND d.deptype = 'i') "
  4058. "WHERE relkind IN ('%c', '%c', '%c', '%c') "
  4059. "ORDER BY c.oid",
  4060. username_subquery,
  4061. RELKIND_SEQUENCE,
  4062. RELKIND_RELATION, RELKIND_SEQUENCE,
  4063. RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
  4064. }
  4065. else if (fout->remoteVersion >= 70200)
  4066. {
  4067. appendPQExpBuffer(query,
  4068. "SELECT tableoid, oid, relname, relacl, relkind, "
  4069. "0::oid AS relnamespace, "
  4070. "(%s relowner) AS rolname, "
  4071. "relchecks, (reltriggers <> 0) AS relhastriggers, "
  4072. "relhasindex, relhasrules, relhasoids, "
  4073. "0 AS relfrozenxid, 0 AS relminmxid,"
  4074. "0 AS toid, "
  4075. "0 AS tfrozenxid, 0 AS tminmxid,"
  4076. "'p' AS relpersistence, 't' as relispopulated, "
  4077. "'d' AS relreplident, relpages, "
  4078. "NULL AS reloftype, "
  4079. "NULL::oid AS owning_tab, "
  4080. "NULL::int4 AS owning_col, "
  4081. "NULL AS reltablespace, "
  4082. "NULL AS reloptions, "
  4083. "NULL AS toast_reloptions "
  4084. "FROM pg_class "
  4085. "WHERE relkind IN ('%c', '%c', '%c') "
  4086. "ORDER BY oid",
  4087. username_subquery,
  4088. RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
  4089. }
  4090. else if (fout->remoteVersion >= 70100)
  4091. {
  4092. /* all tables have oids in 7.1 */
  4093. appendPQExpBuffer(query,
  4094. "SELECT tableoid, oid, relname, relacl, relkind, "
  4095. "0::oid AS relnamespace, "
  4096. "(%s relowner) AS rolname, "
  4097. "relchecks, (reltriggers <> 0) AS relhastriggers, "
  4098. "relhasindex, relhasrules, "
  4099. "'t'::bool AS relhasoids, "
  4100. "0 AS relfrozenxid, 0 AS relminmxid,"
  4101. "0 AS toid, "
  4102. "0 AS tfrozenxid, 0 AS tminmxid,"
  4103. "'p' AS relpersistence, 't' as relispopulated, "
  4104. "'d' AS relreplident, relpages, "
  4105. "NULL AS reloftype, "
  4106. "NULL::oid AS owning_tab, "
  4107. "NULL::int4 AS owning_col, "
  4108. "NULL AS reltablespace, "
  4109. "NULL AS reloptions, "
  4110. "NULL AS toast_reloptions "
  4111. "FROM pg_class "
  4112. "WHERE relkind IN ('%c', '%c', '%c') "
  4113. "ORDER BY oid",
  4114. username_subquery,
  4115. RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
  4116. }
  4117. else
  4118. {
  4119. /*
  4120. * Before 7.1, view relkind was not set to 'v', so we must check if we
  4121. * have a view by looking for a rule in pg_rewrite.
  4122. */
  4123. appendPQExpBuffer(query,
  4124. "SELECT "
  4125. "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
  4126. "oid, relname, relacl, "
  4127. "CASE WHEN relhasrules and relkind = 'r' "
  4128. " and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
  4129. " r.ev_class = c.oid AND r.ev_type = '1') "
  4130. "THEN '%c'::\"char\" "
  4131. "ELSE relkind END AS relkind,"
  4132. "0::oid AS relnamespace, "
  4133. "(%s relowner) AS rolname, "
  4134. "relchecks, (reltriggers <> 0) AS relhastriggers, "
  4135. "relhasindex, relhasrules, "
  4136. "'t'::bool AS relhasoids, "
  4137. "0 AS relfrozenxid, 0 AS relminmxid,"
  4138. "0 AS toid, "
  4139. "0 AS tfrozenxid, 0 AS tminmxid,"
  4140. "'p' AS relpersistence, 't' as relispopulated, "
  4141. "'d' AS relreplident, 0 AS relpages, "
  4142. "NULL AS reloftype, "
  4143. "NULL::oid AS owning_tab, "
  4144. "NULL::int4 AS owning_col, "
  4145. "NULL AS reltablespace, "
  4146. "NULL AS reloptions, "
  4147. "NULL AS toast_reloptions "
  4148. "FROM pg_class c "
  4149. "WHERE relkind IN ('%c', '%c') "
  4150. "ORDER BY oid",
  4151. RELKIND_VIEW,
  4152. username_subquery,
  4153. RELKIND_RELATION, RELKIND_SEQUENCE);
  4154. }
  4155. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  4156. ntups = PQntuples(res);
  4157. *numTables = ntups;
  4158. /*
  4159. * Extract data from result and lock dumpable tables. We do the locking
  4160. * before anything else, to minimize the window wherein a table could
  4161. * disappear under us.
  4162. *
  4163. * Note that we have to save info about all tables here, even when dumping
  4164. * only one, because we don't yet know which tables might be inheritance
  4165. * ancestors of the target table.
  4166. */
  4167. tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
  4168. i_reltableoid = PQfnumber(res, "tableoid");
  4169. i_reloid = PQfnumber(res, "oid");
  4170. i_relname = PQfnumber(res, "relname");
  4171. i_relnamespace = PQfnumber(res, "relnamespace");
  4172. i_relacl = PQfnumber(res, "relacl");
  4173. i_relkind = PQfnumber(res, "relkind");
  4174. i_rolname = PQfnumber(res, "rolname");
  4175. i_relchecks = PQfnumber(res, "relchecks");
  4176. i_relhastriggers = PQfnumber(res, "relhastriggers");
  4177. i_relhasindex = PQfnumber(res, "relhasindex");
  4178. i_relhasrules = PQfnumber(res, "relhasrules");
  4179. i_relhasoids = PQfnumber(res, "relhasoids");
  4180. i_relfrozenxid = PQfnumber(res, "relfrozenxid");
  4181. i_relminmxid = PQfnumber(res, "relminmxid");
  4182. i_toastoid = PQfnumber(res, "toid");
  4183. i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
  4184. i_toastminmxid = PQfnumber(res, "tminmxid");
  4185. i_relpersistence = PQfnumber(res, "relpersistence");
  4186. i_relispopulated = PQfnumber(res, "relispopulated");
  4187. i_relreplident = PQfnumber(res, "relreplident");
  4188. i_relpages = PQfnumber(res, "relpages");
  4189. i_owning_tab = PQfnumber(res, "owning_tab");
  4190. i_owning_col = PQfnumber(res, "owning_col");
  4191. i_reltablespace = PQfnumber(res, "reltablespace");
  4192. i_reloptions = PQfnumber(res, "reloptions");
  4193. i_checkoption = PQfnumber(res, "checkoption");
  4194. i_toastreloptions = PQfnumber(res, "toast_reloptions");
  4195. i_reloftype = PQfnumber(res, "reloftype");
  4196. if (lockWaitTimeout && fout->remoteVersion >= 70300)
  4197. {
  4198. /*
  4199. * Arrange to fail instead of waiting forever for a table lock.
  4200. *
  4201. * NB: this coding assumes that the only queries issued within the
  4202. * following loop are LOCK TABLEs; else the timeout may be undesirably
  4203. * applied to other things too.
  4204. */
  4205. resetPQExpBuffer(query);
  4206. appendPQExpBufferStr(query, "SET statement_timeout = ");
  4207. appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
  4208. ExecuteSqlStatement(fout, query->data);
  4209. }
  4210. for (i = 0; i < ntups; i++)
  4211. {
  4212. tblinfo[i].dobj.objType = DO_TABLE;
  4213. tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
  4214. tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
  4215. AssignDumpId(&tblinfo[i].dobj);
  4216. tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
  4217. tblinfo[i].dobj.namespace =
  4218. findNamespace(fout,
  4219. atooid(PQgetvalue(res, i, i_relnamespace)),
  4220. tblinfo[i].dobj.catId.oid);
  4221. tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  4222. tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
  4223. tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
  4224. tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
  4225. tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
  4226. tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
  4227. tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
  4228. tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
  4229. tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
  4230. tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
  4231. tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
  4232. tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
  4233. tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
  4234. tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
  4235. tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
  4236. tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
  4237. if (PQgetisnull(res, i, i_reloftype))
  4238. tblinfo[i].reloftype = NULL;
  4239. else
  4240. tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
  4241. tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
  4242. if (PQgetisnull(res, i, i_owning_tab))
  4243. {
  4244. tblinfo[i].owning_tab = InvalidOid;
  4245. tblinfo[i].owning_col = 0;
  4246. }
  4247. else
  4248. {
  4249. tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
  4250. tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
  4251. }
  4252. tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
  4253. tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
  4254. if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
  4255. tblinfo[i].checkoption = NULL;
  4256. else
  4257. tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
  4258. tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
  4259. /* other fields were zeroed above */
  4260. /*
  4261. * Decide whether we want to dump this table.
  4262. */
  4263. if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
  4264. tblinfo[i].dobj.dump = false;
  4265. else
  4266. selectDumpableTable(&tblinfo[i]);
  4267. tblinfo[i].interesting = tblinfo[i].dobj.dump;
  4268. tblinfo[i].postponed_def = false; /* might get set during sort */
  4269. /*
  4270. * Read-lock target tables to make sure they aren't DROPPED or altered
  4271. * in schema before we get around to dumping them.
  4272. *
  4273. * Note that we don't explicitly lock parents of the target tables; we
  4274. * assume our lock on the child is enough to prevent schema
  4275. * alterations to parent tables.
  4276. *
  4277. * NOTE: it'd be kinda nice to lock other relations too, not only
  4278. * plain tables, but the backend doesn't presently allow that.
  4279. */
  4280. if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
  4281. {
  4282. resetPQExpBuffer(query);
  4283. appendPQExpBuffer(query,
  4284. "LOCK TABLE %s IN ACCESS SHARE MODE",
  4285. fmtQualifiedId(fout->remoteVersion,
  4286. tblinfo[i].dobj.namespace->dobj.name,
  4287. tblinfo[i].dobj.name));
  4288. ExecuteSqlStatement(fout, query->data);
  4289. }
  4290. /* Emit notice if join for owner failed */
  4291. if (strlen(tblinfo[i].rolname) == 0)
  4292. write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
  4293. tblinfo[i].dobj.name);
  4294. }
  4295. if (lockWaitTimeout && fout->remoteVersion >= 70300)
  4296. {
  4297. ExecuteSqlStatement(fout, "SET statement_timeout = 0");
  4298. }
  4299. PQclear(res);
  4300. destroyPQExpBuffer(query);
  4301. return tblinfo;
  4302. }
  4303. /*
  4304. * getOwnedSeqs
  4305. * identify owned sequences and mark them as dumpable if owning table is
  4306. *
  4307. * We used to do this in getTables(), but it's better to do it after the
  4308. * index used by findTableByOid() has been set up.
  4309. */
  4310. void
  4311. getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
  4312. {
  4313. int i;
  4314. /*
  4315. * Force sequences that are "owned" by table columns to be dumped whenever
  4316. * their owning table is being dumped.
  4317. */
  4318. for (i = 0; i < numTables; i++)
  4319. {
  4320. TableInfo *seqinfo = &tblinfo[i];
  4321. TableInfo *owning_tab;
  4322. if (!OidIsValid(seqinfo->owning_tab))
  4323. continue; /* not an owned sequence */
  4324. if (seqinfo->dobj.dump)
  4325. continue; /* no need to search */
  4326. owning_tab = findTableByOid(seqinfo->owning_tab);
  4327. if (owning_tab && owning_tab->dobj.dump)
  4328. {
  4329. seqinfo->interesting = true;
  4330. seqinfo->dobj.dump = true;
  4331. }
  4332. }
  4333. }
  4334. /*
  4335. * getInherits
  4336. * read all the inheritance information
  4337. * from the system catalogs return them in the InhInfo* structure
  4338. *
  4339. * numInherits is set to the number of pairs read in
  4340. */
  4341. InhInfo *
  4342. getInherits(Archive *fout, int *numInherits)
  4343. {
  4344. PGresult *res;
  4345. int ntups;
  4346. int i;
  4347. PQExpBuffer query = createPQExpBuffer();
  4348. InhInfo *inhinfo;
  4349. int i_inhrelid;
  4350. int i_inhparent;
  4351. /* Make sure we are in proper schema */
  4352. selectSourceSchema(fout, "pg_catalog");
  4353. /* find all the inheritance information */
  4354. appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
  4355. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  4356. ntups = PQntuples(res);
  4357. *numInherits = ntups;
  4358. inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
  4359. i_inhrelid = PQfnumber(res, "inhrelid");
  4360. i_inhparent = PQfnumber(res, "inhparent");
  4361. for (i = 0; i < ntups; i++)
  4362. {
  4363. inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
  4364. inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
  4365. }
  4366. PQclear(res);
  4367. destroyPQExpBuffer(query);
  4368. return inhinfo;
  4369. }
  4370. /*
  4371. * getIndexes
  4372. * get information about every index on a dumpable table
  4373. *
  4374. * Note: index data is not returned directly to the caller, but it
  4375. * does get entered into the DumpableObject tables.
  4376. */
  4377. void
  4378. getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
  4379. {
  4380. int i,
  4381. j;
  4382. PQExpBuffer query = createPQExpBuffer();
  4383. PGresult *res;
  4384. IndxInfo *indxinfo;
  4385. ConstraintInfo *constrinfo;
  4386. int i_tableoid,
  4387. i_oid,
  4388. i_indexname,
  4389. i_indexdef,
  4390. i_indnkeys,
  4391. i_indkey,
  4392. i_indisclustered,
  4393. i_indisreplident,
  4394. i_contype,
  4395. i_conname,
  4396. i_condeferrable,
  4397. i_condeferred,
  4398. i_contableoid,
  4399. i_conoid,
  4400. i_condef,
  4401. i_tablespace,
  4402. i_options,
  4403. i_relpages;
  4404. int ntups;
  4405. for (i = 0; i < numTables; i++)
  4406. {
  4407. TableInfo *tbinfo = &tblinfo[i];
  4408. /* Only plain tables and materialized views have indexes. */
  4409. if (tbinfo->relkind != RELKIND_RELATION &&
  4410. tbinfo->relkind != RELKIND_MATVIEW)
  4411. continue;
  4412. if (!tbinfo->hasindex)
  4413. continue;
  4414. /* Ignore indexes of tables not to be dumped */
  4415. if (!tbinfo->dobj.dump)
  4416. continue;
  4417. if (g_verbose)
  4418. write_msg(NULL, "reading indexes for table \"%s\"\n",
  4419. tbinfo->dobj.name);
  4420. /* Make sure we are in proper schema so indexdef is right */
  4421. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  4422. /*
  4423. * The point of the messy-looking outer join is to find a constraint
  4424. * that is related by an internal dependency link to the index. If we
  4425. * find one, create a CONSTRAINT entry linked to the INDEX entry. We
  4426. * assume an index won't have more than one internal dependency.
  4427. *
  4428. * As of 9.0 we don't need to look at pg_depend but can check for a
  4429. * match to pg_constraint.conindid. The check on conrelid is
  4430. * redundant but useful because that column is indexed while conindid
  4431. * is not.
  4432. */
  4433. resetPQExpBuffer(query);
  4434. if (fout->remoteVersion >= 90400)
  4435. {
  4436. /*
  4437. * the test on indisready is necessary in 9.2, and harmless in
  4438. * earlier/later versions
  4439. */
  4440. appendPQExpBuffer(query,
  4441. "SELECT t.tableoid, t.oid, "
  4442. "t.relname AS indexname, "
  4443. "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
  4444. "t.relnatts AS indnkeys, "
  4445. "i.indkey, i.indisclustered, "
  4446. "i.indisreplident, t.relpages, "
  4447. "c.contype, c.conname, "
  4448. "c.condeferrable, c.condeferred, "
  4449. "c.tableoid AS contableoid, "
  4450. "c.oid AS conoid, "
  4451. "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
  4452. "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
  4453. "array_to_string(t.reloptions, ', ') AS options "
  4454. "FROM pg_catalog.pg_index i "
  4455. "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
  4456. "LEFT JOIN pg_catalog.pg_constraint c "
  4457. "ON (i.indrelid = c.conrelid AND "
  4458. "i.indexrelid = c.conindid AND "
  4459. "c.contype IN ('p','u','x')) "
  4460. "WHERE i.indrelid = '%u'::pg_catalog.oid "
  4461. "AND i.indisvalid AND i.indisready "
  4462. "ORDER BY indexname",
  4463. tbinfo->dobj.catId.oid);
  4464. }
  4465. else if (fout->remoteVersion >= 90000)
  4466. {
  4467. /*
  4468. * the test on indisready is necessary in 9.2, and harmless in
  4469. * earlier/later versions
  4470. */
  4471. appendPQExpBuffer(query,
  4472. "SELECT t.tableoid, t.oid, "
  4473. "t.relname AS indexname, "
  4474. "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
  4475. "t.relnatts AS indnkeys, "
  4476. "i.indkey, i.indisclustered, "
  4477. "false AS indisreplident, t.relpages, "
  4478. "c.contype, c.conname, "
  4479. "c.condeferrable, c.condeferred, "
  4480. "c.tableoid AS contableoid, "
  4481. "c.oid AS conoid, "
  4482. "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
  4483. "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
  4484. "array_to_string(t.reloptions, ', ') AS options "
  4485. "FROM pg_catalog.pg_index i "
  4486. "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
  4487. "LEFT JOIN pg_catalog.pg_constraint c "
  4488. "ON (i.indrelid = c.conrelid AND "
  4489. "i.indexrelid = c.conindid AND "
  4490. "c.contype IN ('p','u','x')) "
  4491. "WHERE i.indrelid = '%u'::pg_catalog.oid "
  4492. "AND i.indisvalid AND i.indisready "
  4493. "ORDER BY indexname",
  4494. tbinfo->dobj.catId.oid);
  4495. }
  4496. else if (fout->remoteVersion >= 80200)
  4497. {
  4498. appendPQExpBuffer(query,
  4499. "SELECT t.tableoid, t.oid, "
  4500. "t.relname AS indexname, "
  4501. "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
  4502. "t.relnatts AS indnkeys, "
  4503. "i.indkey, i.indisclustered, "
  4504. "false AS indisreplident, t.relpages, "
  4505. "c.contype, c.conname, "
  4506. "c.condeferrable, c.condeferred, "
  4507. "c.tableoid AS contableoid, "
  4508. "c.oid AS conoid, "
  4509. "null AS condef, "
  4510. "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
  4511. "array_to_string(t.reloptions, ', ') AS options "
  4512. "FROM pg_catalog.pg_index i "
  4513. "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
  4514. "LEFT JOIN pg_catalog.pg_depend d "
  4515. "ON (d.classid = t.tableoid "
  4516. "AND d.objid = t.oid "
  4517. "AND d.deptype = 'i') "
  4518. "LEFT JOIN pg_catalog.pg_constraint c "
  4519. "ON (d.refclassid = c.tableoid "
  4520. "AND d.refobjid = c.oid) "
  4521. "WHERE i.indrelid = '%u'::pg_catalog.oid "
  4522. "AND i.indisvalid "
  4523. "ORDER BY indexname",
  4524. tbinfo->dobj.catId.oid);
  4525. }
  4526. else if (fout->remoteVersion >= 80000)
  4527. {
  4528. appendPQExpBuffer(query,
  4529. "SELECT t.tableoid, t.oid, "
  4530. "t.relname AS indexname, "
  4531. "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
  4532. "t.relnatts AS indnkeys, "
  4533. "i.indkey, i.indisclustered, "
  4534. "false AS indisreplident, t.relpages, "
  4535. "c.contype, c.conname, "
  4536. "c.condeferrable, c.condeferred, "
  4537. "c.tableoid AS contableoid, "
  4538. "c.oid AS conoid, "
  4539. "null AS condef, "
  4540. "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
  4541. "null AS options "
  4542. "FROM pg_catalog.pg_index i "
  4543. "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
  4544. "LEFT JOIN pg_catalog.pg_depend d "
  4545. "ON (d.classid = t.tableoid "
  4546. "AND d.objid = t.oid "
  4547. "AND d.deptype = 'i') "
  4548. "LEFT JOIN pg_catalog.pg_constraint c "
  4549. "ON (d.refclassid = c.tableoid "
  4550. "AND d.refobjid = c.oid) "
  4551. "WHERE i.indrelid = '%u'::pg_catalog.oid "
  4552. "ORDER BY indexname",
  4553. tbinfo->dobj.catId.oid);
  4554. }
  4555. else if (fout->remoteVersion >= 70300)
  4556. {
  4557. appendPQExpBuffer(query,
  4558. "SELECT t.tableoid, t.oid, "
  4559. "t.relname AS indexname, "
  4560. "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
  4561. "t.relnatts AS indnkeys, "
  4562. "i.indkey, i.indisclustered, "
  4563. "false AS indisreplident, t.relpages, "
  4564. "c.contype, c.conname, "
  4565. "c.condeferrable, c.condeferred, "
  4566. "c.tableoid AS contableoid, "
  4567. "c.oid AS conoid, "
  4568. "null AS condef, "
  4569. "NULL AS tablespace, "
  4570. "null AS options "
  4571. "FROM pg_catalog.pg_index i "
  4572. "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
  4573. "LEFT JOIN pg_catalog.pg_depend d "
  4574. "ON (d.classid = t.tableoid "
  4575. "AND d.objid = t.oid "
  4576. "AND d.deptype = 'i') "
  4577. "LEFT JOIN pg_catalog.pg_constraint c "
  4578. "ON (d.refclassid = c.tableoid "
  4579. "AND d.refobjid = c.oid) "
  4580. "WHERE i.indrelid = '%u'::pg_catalog.oid "
  4581. "ORDER BY indexname",
  4582. tbinfo->dobj.catId.oid);
  4583. }
  4584. else if (fout->remoteVersion >= 70100)
  4585. {
  4586. appendPQExpBuffer(query,
  4587. "SELECT t.tableoid, t.oid, "
  4588. "t.relname AS indexname, "
  4589. "pg_get_indexdef(i.indexrelid) AS indexdef, "
  4590. "t.relnatts AS indnkeys, "
  4591. "i.indkey, false AS indisclustered, "
  4592. "false AS indisreplident, t.relpages, "
  4593. "CASE WHEN i.indisprimary THEN 'p'::char "
  4594. "ELSE '0'::char END AS contype, "
  4595. "t.relname AS conname, "
  4596. "false AS condeferrable, "
  4597. "false AS condeferred, "
  4598. "0::oid AS contableoid, "
  4599. "t.oid AS conoid, "
  4600. "null AS condef, "
  4601. "NULL AS tablespace, "
  4602. "null AS options "
  4603. "FROM pg_index i, pg_class t "
  4604. "WHERE t.oid = i.indexrelid "
  4605. "AND i.indrelid = '%u'::oid "
  4606. "ORDER BY indexname",
  4607. tbinfo->dobj.catId.oid);
  4608. }
  4609. else
  4610. {
  4611. appendPQExpBuffer(query,
  4612. "SELECT "
  4613. "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
  4614. "t.oid, "
  4615. "t.relname AS indexname, "
  4616. "pg_get_indexdef(i.indexrelid) AS indexdef, "
  4617. "t.relnatts AS indnkeys, "
  4618. "i.indkey, false AS indisclustered, "
  4619. "false AS indisreplident, t.relpages, "
  4620. "CASE WHEN i.indisprimary THEN 'p'::char "
  4621. "ELSE '0'::char END AS contype, "
  4622. "t.relname AS conname, "
  4623. "false AS condeferrable, "
  4624. "false AS condeferred, "
  4625. "0::oid AS contableoid, "
  4626. "t.oid AS conoid, "
  4627. "null AS condef, "
  4628. "NULL AS tablespace, "
  4629. "null AS options "
  4630. "FROM pg_index i, pg_class t "
  4631. "WHERE t.oid = i.indexrelid "
  4632. "AND i.indrelid = '%u'::oid "
  4633. "ORDER BY indexname",
  4634. tbinfo->dobj.catId.oid);
  4635. }
  4636. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  4637. ntups = PQntuples(res);
  4638. i_tableoid = PQfnumber(res, "tableoid");
  4639. i_oid = PQfnumber(res, "oid");
  4640. i_indexname = PQfnumber(res, "indexname");
  4641. i_indexdef = PQfnumber(res, "indexdef");
  4642. i_indnkeys = PQfnumber(res, "indnkeys");
  4643. i_indkey = PQfnumber(res, "indkey");
  4644. i_indisclustered = PQfnumber(res, "indisclustered");
  4645. i_indisreplident = PQfnumber(res, "indisreplident");
  4646. i_relpages = PQfnumber(res, "relpages");
  4647. i_contype = PQfnumber(res, "contype");
  4648. i_conname = PQfnumber(res, "conname");
  4649. i_condeferrable = PQfnumber(res, "condeferrable");
  4650. i_condeferred = PQfnumber(res, "condeferred");
  4651. i_contableoid = PQfnumber(res, "contableoid");
  4652. i_conoid = PQfnumber(res, "conoid");
  4653. i_condef = PQfnumber(res, "condef");
  4654. i_tablespace = PQfnumber(res, "tablespace");
  4655. i_options = PQfnumber(res, "options");
  4656. indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
  4657. constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
  4658. for (j = 0; j < ntups; j++)
  4659. {
  4660. char contype;
  4661. indxinfo[j].dobj.objType = DO_INDEX;
  4662. indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
  4663. indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
  4664. AssignDumpId(&indxinfo[j].dobj);
  4665. indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
  4666. indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
  4667. indxinfo[j].indextable = tbinfo;
  4668. indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
  4669. indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
  4670. indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
  4671. indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
  4672. /*
  4673. * In pre-7.4 releases, indkeys may contain more entries than
  4674. * indnkeys says (since indnkeys will be 1 for a functional
  4675. * index). We don't actually care about this case since we don't
  4676. * examine indkeys except for indexes associated with PRIMARY and
  4677. * UNIQUE constraints, which are never functional indexes. But we
  4678. * have to allocate enough space to keep parseOidArray from
  4679. * complaining.
  4680. */
  4681. indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
  4682. parseOidArray(PQgetvalue(res, j, i_indkey),
  4683. indxinfo[j].indkeys, INDEX_MAX_KEYS);
  4684. indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
  4685. indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
  4686. indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
  4687. contype = *(PQgetvalue(res, j, i_contype));
  4688. if (contype == 'p' || contype == 'u' || contype == 'x')
  4689. {
  4690. /*
  4691. * If we found a constraint matching the index, create an
  4692. * entry for it.
  4693. *
  4694. * In a pre-7.3 database, we take this path iff the index was
  4695. * marked indisprimary.
  4696. */
  4697. constrinfo[j].dobj.objType = DO_CONSTRAINT;
  4698. constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
  4699. constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
  4700. AssignDumpId(&constrinfo[j].dobj);
  4701. constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
  4702. constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
  4703. constrinfo[j].contable = tbinfo;
  4704. constrinfo[j].condomain = NULL;
  4705. constrinfo[j].contype = contype;
  4706. if (contype == 'x')
  4707. constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
  4708. else
  4709. constrinfo[j].condef = NULL;
  4710. constrinfo[j].confrelid = InvalidOid;
  4711. constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
  4712. constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
  4713. constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
  4714. constrinfo[j].conislocal = true;
  4715. constrinfo[j].separate = true;
  4716. indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
  4717. /* If pre-7.3 DB, better make sure table comes first */
  4718. addObjectDependency(&constrinfo[j].dobj,
  4719. tbinfo->dobj.dumpId);
  4720. }
  4721. else
  4722. {
  4723. /* Plain secondary index */
  4724. indxinfo[j].indexconstraint = 0;
  4725. }
  4726. }
  4727. PQclear(res);
  4728. }
  4729. destroyPQExpBuffer(query);
  4730. }
  4731. /*
  4732. * getConstraints
  4733. *
  4734. * Get info about constraints on dumpable tables.
  4735. *
  4736. * Currently handles foreign keys only.
  4737. * Unique and primary key constraints are handled with indexes,
  4738. * while check constraints are processed in getTableAttrs().
  4739. */
  4740. void
  4741. getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
  4742. {
  4743. int i,
  4744. j;
  4745. ConstraintInfo *constrinfo;
  4746. PQExpBuffer query;
  4747. PGresult *res;
  4748. int i_contableoid,
  4749. i_conoid,
  4750. i_conname,
  4751. i_confrelid,
  4752. i_condef;
  4753. int ntups;
  4754. /* pg_constraint was created in 7.3, so nothing to do if older */
  4755. if (fout->remoteVersion < 70300)
  4756. return;
  4757. query = createPQExpBuffer();
  4758. for (i = 0; i < numTables; i++)
  4759. {
  4760. TableInfo *tbinfo = &tblinfo[i];
  4761. if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
  4762. continue;
  4763. if (g_verbose)
  4764. write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
  4765. tbinfo->dobj.name);
  4766. /*
  4767. * select table schema to ensure constraint expr is qualified if
  4768. * needed
  4769. */
  4770. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  4771. resetPQExpBuffer(query);
  4772. appendPQExpBuffer(query,
  4773. "SELECT tableoid, oid, conname, confrelid, "
  4774. "pg_catalog.pg_get_constraintdef(oid) AS condef "
  4775. "FROM pg_catalog.pg_constraint "
  4776. "WHERE conrelid = '%u'::pg_catalog.oid "
  4777. "AND contype = 'f'",
  4778. tbinfo->dobj.catId.oid);
  4779. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  4780. ntups = PQntuples(res);
  4781. i_contableoid = PQfnumber(res, "tableoid");
  4782. i_conoid = PQfnumber(res, "oid");
  4783. i_conname = PQfnumber(res, "conname");
  4784. i_confrelid = PQfnumber(res, "confrelid");
  4785. i_condef = PQfnumber(res, "condef");
  4786. constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
  4787. for (j = 0; j < ntups; j++)
  4788. {
  4789. constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
  4790. constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
  4791. constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
  4792. AssignDumpId(&constrinfo[j].dobj);
  4793. constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
  4794. constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
  4795. constrinfo[j].contable = tbinfo;
  4796. constrinfo[j].condomain = NULL;
  4797. constrinfo[j].contype = 'f';
  4798. constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
  4799. constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
  4800. constrinfo[j].conindex = 0;
  4801. constrinfo[j].condeferrable = false;
  4802. constrinfo[j].condeferred = false;
  4803. constrinfo[j].conislocal = true;
  4804. constrinfo[j].separate = true;
  4805. }
  4806. PQclear(res);
  4807. }
  4808. destroyPQExpBuffer(query);
  4809. }
  4810. /*
  4811. * getDomainConstraints
  4812. *
  4813. * Get info about constraints on a domain.
  4814. */
  4815. static void
  4816. getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
  4817. {
  4818. int i;
  4819. ConstraintInfo *constrinfo;
  4820. PQExpBuffer query;
  4821. PGresult *res;
  4822. int i_tableoid,
  4823. i_oid,
  4824. i_conname,
  4825. i_consrc;
  4826. int ntups;
  4827. /* pg_constraint was created in 7.3, so nothing to do if older */
  4828. if (fout->remoteVersion < 70300)
  4829. return;
  4830. /*
  4831. * select appropriate schema to ensure names in constraint are properly
  4832. * qualified
  4833. */
  4834. selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
  4835. query = createPQExpBuffer();
  4836. if (fout->remoteVersion >= 90100)
  4837. appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
  4838. "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
  4839. "convalidated "
  4840. "FROM pg_catalog.pg_constraint "
  4841. "WHERE contypid = '%u'::pg_catalog.oid "
  4842. "ORDER BY conname",
  4843. tyinfo->dobj.catId.oid);
  4844. else if (fout->remoteVersion >= 70400)
  4845. appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
  4846. "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
  4847. "true as convalidated "
  4848. "FROM pg_catalog.pg_constraint "
  4849. "WHERE contypid = '%u'::pg_catalog.oid "
  4850. "ORDER BY conname",
  4851. tyinfo->dobj.catId.oid);
  4852. else
  4853. appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
  4854. "'CHECK (' || consrc || ')' AS consrc, "
  4855. "true as convalidated "
  4856. "FROM pg_catalog.pg_constraint "
  4857. "WHERE contypid = '%u'::pg_catalog.oid "
  4858. "ORDER BY conname",
  4859. tyinfo->dobj.catId.oid);
  4860. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  4861. ntups = PQntuples(res);
  4862. i_tableoid = PQfnumber(res, "tableoid");
  4863. i_oid = PQfnumber(res, "oid");
  4864. i_conname = PQfnumber(res, "conname");
  4865. i_consrc = PQfnumber(res, "consrc");
  4866. constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
  4867. tyinfo->nDomChecks = ntups;
  4868. tyinfo->domChecks = constrinfo;
  4869. for (i = 0; i < ntups; i++)
  4870. {
  4871. bool validated = PQgetvalue(res, i, 4)[0] == 't';
  4872. constrinfo[i].dobj.objType = DO_CONSTRAINT;
  4873. constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  4874. constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  4875. AssignDumpId(&constrinfo[i].dobj);
  4876. constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
  4877. constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
  4878. constrinfo[i].contable = NULL;
  4879. constrinfo[i].condomain = tyinfo;
  4880. constrinfo[i].contype = 'c';
  4881. constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
  4882. constrinfo[i].confrelid = InvalidOid;
  4883. constrinfo[i].conindex = 0;
  4884. constrinfo[i].condeferrable = false;
  4885. constrinfo[i].condeferred = false;
  4886. constrinfo[i].conislocal = true;
  4887. constrinfo[i].separate = !validated;
  4888. /*
  4889. * Make the domain depend on the constraint, ensuring it won't be
  4890. * output till any constraint dependencies are OK. If the constraint
  4891. * has not been validated, it's going to be dumped after the domain
  4892. * anyway, so this doesn't matter.
  4893. */
  4894. if (validated)
  4895. addObjectDependency(&tyinfo->dobj,
  4896. constrinfo[i].dobj.dumpId);
  4897. }
  4898. PQclear(res);
  4899. destroyPQExpBuffer(query);
  4900. }
  4901. /*
  4902. * getRules
  4903. * get basic information about every rule in the system
  4904. *
  4905. * numRules is set to the number of rules read in
  4906. */
  4907. RuleInfo *
  4908. getRules(Archive *fout, int *numRules)
  4909. {
  4910. PGresult *res;
  4911. int ntups;
  4912. int i;
  4913. PQExpBuffer query = createPQExpBuffer();
  4914. RuleInfo *ruleinfo;
  4915. int i_tableoid;
  4916. int i_oid;
  4917. int i_rulename;
  4918. int i_ruletable;
  4919. int i_ev_type;
  4920. int i_is_instead;
  4921. int i_ev_enabled;
  4922. /* Make sure we are in proper schema */
  4923. selectSourceSchema(fout, "pg_catalog");
  4924. if (fout->remoteVersion >= 80300)
  4925. {
  4926. appendPQExpBufferStr(query, "SELECT "
  4927. "tableoid, oid, rulename, "
  4928. "ev_class AS ruletable, ev_type, is_instead, "
  4929. "ev_enabled "
  4930. "FROM pg_rewrite "
  4931. "ORDER BY oid");
  4932. }
  4933. else if (fout->remoteVersion >= 70100)
  4934. {
  4935. appendPQExpBufferStr(query, "SELECT "
  4936. "tableoid, oid, rulename, "
  4937. "ev_class AS ruletable, ev_type, is_instead, "
  4938. "'O'::char AS ev_enabled "
  4939. "FROM pg_rewrite "
  4940. "ORDER BY oid");
  4941. }
  4942. else
  4943. {
  4944. appendPQExpBufferStr(query, "SELECT "
  4945. "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
  4946. "oid, rulename, "
  4947. "ev_class AS ruletable, ev_type, is_instead, "
  4948. "'O'::char AS ev_enabled "
  4949. "FROM pg_rewrite "
  4950. "ORDER BY oid");
  4951. }
  4952. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  4953. ntups = PQntuples(res);
  4954. *numRules = ntups;
  4955. ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
  4956. i_tableoid = PQfnumber(res, "tableoid");
  4957. i_oid = PQfnumber(res, "oid");
  4958. i_rulename = PQfnumber(res, "rulename");
  4959. i_ruletable = PQfnumber(res, "ruletable");
  4960. i_ev_type = PQfnumber(res, "ev_type");
  4961. i_is_instead = PQfnumber(res, "is_instead");
  4962. i_ev_enabled = PQfnumber(res, "ev_enabled");
  4963. for (i = 0; i < ntups; i++)
  4964. {
  4965. Oid ruletableoid;
  4966. ruleinfo[i].dobj.objType = DO_RULE;
  4967. ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  4968. ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  4969. AssignDumpId(&ruleinfo[i].dobj);
  4970. ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
  4971. ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
  4972. ruleinfo[i].ruletable = findTableByOid(ruletableoid);
  4973. if (ruleinfo[i].ruletable == NULL)
  4974. exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
  4975. ruletableoid, ruleinfo[i].dobj.catId.oid);
  4976. ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
  4977. ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
  4978. ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
  4979. ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
  4980. ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
  4981. if (ruleinfo[i].ruletable)
  4982. {
  4983. /*
  4984. * If the table is a view or materialized view, force its ON
  4985. * SELECT rule to be sorted before the view itself --- this
  4986. * ensures that any dependencies for the rule affect the table's
  4987. * positioning. Other rules are forced to appear after their
  4988. * table.
  4989. */
  4990. if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
  4991. ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
  4992. ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
  4993. {
  4994. addObjectDependency(&ruleinfo[i].ruletable->dobj,
  4995. ruleinfo[i].dobj.dumpId);
  4996. /* We'll merge the rule into CREATE VIEW, if possible */
  4997. ruleinfo[i].separate = false;
  4998. }
  4999. else
  5000. {
  5001. addObjectDependency(&ruleinfo[i].dobj,
  5002. ruleinfo[i].ruletable->dobj.dumpId);
  5003. ruleinfo[i].separate = true;
  5004. }
  5005. }
  5006. else
  5007. ruleinfo[i].separate = true;
  5008. /*
  5009. * If we're forced to break a dependency loop by dumping a view as a
  5010. * table and separate _RETURN rule, we'll move the view's reloptions
  5011. * to the rule. (This is necessary because tables and views have
  5012. * different valid reloptions, so we can't apply the options until the
  5013. * backend knows it's a view.) Otherwise the rule's reloptions stay
  5014. * NULL.
  5015. */
  5016. ruleinfo[i].reloptions = NULL;
  5017. }
  5018. PQclear(res);
  5019. destroyPQExpBuffer(query);
  5020. return ruleinfo;
  5021. }
  5022. /*
  5023. * getTriggers
  5024. * get information about every trigger on a dumpable table
  5025. *
  5026. * Note: trigger data is not returned directly to the caller, but it
  5027. * does get entered into the DumpableObject tables.
  5028. */
  5029. void
  5030. getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
  5031. {
  5032. int i,
  5033. j;
  5034. PQExpBuffer query = createPQExpBuffer();
  5035. PGresult *res;
  5036. TriggerInfo *tginfo;
  5037. int i_tableoid,
  5038. i_oid,
  5039. i_tgname,
  5040. i_tgfname,
  5041. i_tgtype,
  5042. i_tgnargs,
  5043. i_tgargs,
  5044. i_tgisconstraint,
  5045. i_tgconstrname,
  5046. i_tgconstrrelid,
  5047. i_tgconstrrelname,
  5048. i_tgenabled,
  5049. i_tgdeferrable,
  5050. i_tginitdeferred,
  5051. i_tgdef;
  5052. int ntups;
  5053. for (i = 0; i < numTables; i++)
  5054. {
  5055. TableInfo *tbinfo = &tblinfo[i];
  5056. if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
  5057. continue;
  5058. if (g_verbose)
  5059. write_msg(NULL, "reading triggers for table \"%s\"\n",
  5060. tbinfo->dobj.name);
  5061. /*
  5062. * select table schema to ensure regproc name is qualified if needed
  5063. */
  5064. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  5065. resetPQExpBuffer(query);
  5066. if (fout->remoteVersion >= 90000)
  5067. {
  5068. /*
  5069. * NB: think not to use pretty=true in pg_get_triggerdef. It
  5070. * could result in non-forward-compatible dumps of WHEN clauses
  5071. * due to under-parenthesization.
  5072. */
  5073. appendPQExpBuffer(query,
  5074. "SELECT tgname, "
  5075. "tgfoid::pg_catalog.regproc AS tgfname, "
  5076. "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
  5077. "tgenabled, tableoid, oid "
  5078. "FROM pg_catalog.pg_trigger t "
  5079. "WHERE tgrelid = '%u'::pg_catalog.oid "
  5080. "AND NOT tgisinternal",
  5081. tbinfo->dobj.catId.oid);
  5082. }
  5083. else if (fout->remoteVersion >= 80300)
  5084. {
  5085. /*
  5086. * We ignore triggers that are tied to a foreign-key constraint
  5087. */
  5088. appendPQExpBuffer(query,
  5089. "SELECT tgname, "
  5090. "tgfoid::pg_catalog.regproc AS tgfname, "
  5091. "tgtype, tgnargs, tgargs, tgenabled, "
  5092. "tgisconstraint, tgconstrname, tgdeferrable, "
  5093. "tgconstrrelid, tginitdeferred, tableoid, oid, "
  5094. "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
  5095. "FROM pg_catalog.pg_trigger t "
  5096. "WHERE tgrelid = '%u'::pg_catalog.oid "
  5097. "AND tgconstraint = 0",
  5098. tbinfo->dobj.catId.oid);
  5099. }
  5100. else if (fout->remoteVersion >= 70300)
  5101. {
  5102. /*
  5103. * We ignore triggers that are tied to a foreign-key constraint,
  5104. * but in these versions we have to grovel through pg_constraint
  5105. * to find out
  5106. */
  5107. appendPQExpBuffer(query,
  5108. "SELECT tgname, "
  5109. "tgfoid::pg_catalog.regproc AS tgfname, "
  5110. "tgtype, tgnargs, tgargs, tgenabled, "
  5111. "tgisconstraint, tgconstrname, tgdeferrable, "
  5112. "tgconstrrelid, tginitdeferred, tableoid, oid, "
  5113. "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
  5114. "FROM pg_catalog.pg_trigger t "
  5115. "WHERE tgrelid = '%u'::pg_catalog.oid "
  5116. "AND (NOT tgisconstraint "
  5117. " OR NOT EXISTS"
  5118. " (SELECT 1 FROM pg_catalog.pg_depend d "
  5119. " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
  5120. " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
  5121. tbinfo->dobj.catId.oid);
  5122. }
  5123. else if (fout->remoteVersion >= 70100)
  5124. {
  5125. appendPQExpBuffer(query,
  5126. "SELECT tgname, tgfoid::regproc AS tgfname, "
  5127. "tgtype, tgnargs, tgargs, tgenabled, "
  5128. "tgisconstraint, tgconstrname, tgdeferrable, "
  5129. "tgconstrrelid, tginitdeferred, tableoid, oid, "
  5130. "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
  5131. " AS tgconstrrelname "
  5132. "FROM pg_trigger "
  5133. "WHERE tgrelid = '%u'::oid",
  5134. tbinfo->dobj.catId.oid);
  5135. }
  5136. else
  5137. {
  5138. appendPQExpBuffer(query,
  5139. "SELECT tgname, tgfoid::regproc AS tgfname, "
  5140. "tgtype, tgnargs, tgargs, tgenabled, "
  5141. "tgisconstraint, tgconstrname, tgdeferrable, "
  5142. "tgconstrrelid, tginitdeferred, "
  5143. "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
  5144. "oid, "
  5145. "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
  5146. " AS tgconstrrelname "
  5147. "FROM pg_trigger "
  5148. "WHERE tgrelid = '%u'::oid",
  5149. tbinfo->dobj.catId.oid);
  5150. }
  5151. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  5152. ntups = PQntuples(res);
  5153. i_tableoid = PQfnumber(res, "tableoid");
  5154. i_oid = PQfnumber(res, "oid");
  5155. i_tgname = PQfnumber(res, "tgname");
  5156. i_tgfname = PQfnumber(res, "tgfname");
  5157. i_tgtype = PQfnumber(res, "tgtype");
  5158. i_tgnargs = PQfnumber(res, "tgnargs");
  5159. i_tgargs = PQfnumber(res, "tgargs");
  5160. i_tgisconstraint = PQfnumber(res, "tgisconstraint");
  5161. i_tgconstrname = PQfnumber(res, "tgconstrname");
  5162. i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
  5163. i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
  5164. i_tgenabled = PQfnumber(res, "tgenabled");
  5165. i_tgdeferrable = PQfnumber(res, "tgdeferrable");
  5166. i_tginitdeferred = PQfnumber(res, "tginitdeferred");
  5167. i_tgdef = PQfnumber(res, "tgdef");
  5168. tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
  5169. for (j = 0; j < ntups; j++)
  5170. {
  5171. tginfo[j].dobj.objType = DO_TRIGGER;
  5172. tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
  5173. tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
  5174. AssignDumpId(&tginfo[j].dobj);
  5175. tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
  5176. tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
  5177. tginfo[j].tgtable = tbinfo;
  5178. tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
  5179. if (i_tgdef >= 0)
  5180. {
  5181. tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
  5182. /* remaining fields are not valid if we have tgdef */
  5183. tginfo[j].tgfname = NULL;
  5184. tginfo[j].tgtype = 0;
  5185. tginfo[j].tgnargs = 0;
  5186. tginfo[j].tgargs = NULL;
  5187. tginfo[j].tgisconstraint = false;
  5188. tginfo[j].tgdeferrable = false;
  5189. tginfo[j].tginitdeferred = false;
  5190. tginfo[j].tgconstrname = NULL;
  5191. tginfo[j].tgconstrrelid = InvalidOid;
  5192. tginfo[j].tgconstrrelname = NULL;
  5193. }
  5194. else
  5195. {
  5196. tginfo[j].tgdef = NULL;
  5197. tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
  5198. tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
  5199. tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
  5200. tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
  5201. tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
  5202. tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
  5203. tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
  5204. if (tginfo[j].tgisconstraint)
  5205. {
  5206. tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
  5207. tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
  5208. if (OidIsValid(tginfo[j].tgconstrrelid))
  5209. {
  5210. if (PQgetisnull(res, j, i_tgconstrrelname))
  5211. exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
  5212. tginfo[j].dobj.name,
  5213. tbinfo->dobj.name,
  5214. tginfo[j].tgconstrrelid);
  5215. tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
  5216. }
  5217. else
  5218. tginfo[j].tgconstrrelname = NULL;
  5219. }
  5220. else
  5221. {
  5222. tginfo[j].tgconstrname = NULL;
  5223. tginfo[j].tgconstrrelid = InvalidOid;
  5224. tginfo[j].tgconstrrelname = NULL;
  5225. }
  5226. }
  5227. }
  5228. PQclear(res);
  5229. }
  5230. destroyPQExpBuffer(query);
  5231. }
  5232. /*
  5233. * getEventTriggers
  5234. * get information about event triggers
  5235. */
  5236. EventTriggerInfo *
  5237. getEventTriggers(Archive *fout, int *numEventTriggers)
  5238. {
  5239. int i;
  5240. PQExpBuffer query;
  5241. PGresult *res;
  5242. EventTriggerInfo *evtinfo;
  5243. int i_tableoid,
  5244. i_oid,
  5245. i_evtname,
  5246. i_evtevent,
  5247. i_evtowner,
  5248. i_evttags,
  5249. i_evtfname,
  5250. i_evtenabled;
  5251. int ntups;
  5252. /* Before 9.3, there are no event triggers */
  5253. if (fout->remoteVersion < 90300)
  5254. {
  5255. *numEventTriggers = 0;
  5256. return NULL;
  5257. }
  5258. query = createPQExpBuffer();
  5259. /* Make sure we are in proper schema */
  5260. selectSourceSchema(fout, "pg_catalog");
  5261. appendPQExpBuffer(query,
  5262. "SELECT e.tableoid, e.oid, evtname, evtenabled, "
  5263. "evtevent, (%s evtowner) AS evtowner, "
  5264. "array_to_string(array("
  5265. "select quote_literal(x) "
  5266. " from unnest(evttags) as t(x)), ', ') as evttags, "
  5267. "e.evtfoid::regproc as evtfname "
  5268. "FROM pg_event_trigger e "
  5269. "ORDER BY e.oid",
  5270. username_subquery);
  5271. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  5272. ntups = PQntuples(res);
  5273. *numEventTriggers = ntups;
  5274. evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
  5275. i_tableoid = PQfnumber(res, "tableoid");
  5276. i_oid = PQfnumber(res, "oid");
  5277. i_evtname = PQfnumber(res, "evtname");
  5278. i_evtevent = PQfnumber(res, "evtevent");
  5279. i_evtowner = PQfnumber(res, "evtowner");
  5280. i_evttags = PQfnumber(res, "evttags");
  5281. i_evtfname = PQfnumber(res, "evtfname");
  5282. i_evtenabled = PQfnumber(res, "evtenabled");
  5283. for (i = 0; i < ntups; i++)
  5284. {
  5285. evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
  5286. evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  5287. evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  5288. AssignDumpId(&evtinfo[i].dobj);
  5289. evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
  5290. evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
  5291. evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
  5292. evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
  5293. evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
  5294. evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
  5295. evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
  5296. }
  5297. PQclear(res);
  5298. destroyPQExpBuffer(query);
  5299. return evtinfo;
  5300. }
  5301. /*
  5302. * getProcLangs
  5303. * get basic information about every procedural language in the system
  5304. *
  5305. * numProcLangs is set to the number of langs read in
  5306. *
  5307. * NB: this must run after getFuncs() because we assume we can do
  5308. * findFuncByOid().
  5309. */
  5310. ProcLangInfo *
  5311. getProcLangs(Archive *fout, int *numProcLangs)
  5312. {
  5313. PGresult *res;
  5314. int ntups;
  5315. int i;
  5316. PQExpBuffer query = createPQExpBuffer();
  5317. ProcLangInfo *planginfo;
  5318. int i_tableoid;
  5319. int i_oid;
  5320. int i_lanname;
  5321. int i_lanpltrusted;
  5322. int i_lanplcallfoid;
  5323. int i_laninline;
  5324. int i_lanvalidator;
  5325. int i_lanacl;
  5326. int i_lanowner;
  5327. /* Make sure we are in proper schema */
  5328. selectSourceSchema(fout, "pg_catalog");
  5329. if (fout->remoteVersion >= 90000)
  5330. {
  5331. /* pg_language has a laninline column */
  5332. appendPQExpBuffer(query, "SELECT tableoid, oid, "
  5333. "lanname, lanpltrusted, lanplcallfoid, "
  5334. "laninline, lanvalidator, lanacl, "
  5335. "(%s lanowner) AS lanowner "
  5336. "FROM pg_language "
  5337. "WHERE lanispl "
  5338. "ORDER BY oid",
  5339. username_subquery);
  5340. }
  5341. else if (fout->remoteVersion >= 80300)
  5342. {
  5343. /* pg_language has a lanowner column */
  5344. appendPQExpBuffer(query, "SELECT tableoid, oid, "
  5345. "lanname, lanpltrusted, lanplcallfoid, "
  5346. "lanvalidator, lanacl, "
  5347. "(%s lanowner) AS lanowner "
  5348. "FROM pg_language "
  5349. "WHERE lanispl "
  5350. "ORDER BY oid",
  5351. username_subquery);
  5352. }
  5353. else if (fout->remoteVersion >= 80100)
  5354. {
  5355. /* Languages are owned by the bootstrap superuser, OID 10 */
  5356. appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
  5357. "(%s '10') AS lanowner "
  5358. "FROM pg_language "
  5359. "WHERE lanispl "
  5360. "ORDER BY oid",
  5361. username_subquery);
  5362. }
  5363. else if (fout->remoteVersion >= 70400)
  5364. {
  5365. /* Languages are owned by the bootstrap superuser, sysid 1 */
  5366. appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
  5367. "(%s '1') AS lanowner "
  5368. "FROM pg_language "
  5369. "WHERE lanispl "
  5370. "ORDER BY oid",
  5371. username_subquery);
  5372. }
  5373. else if (fout->remoteVersion >= 70100)
  5374. {
  5375. /* No clear notion of an owner at all before 7.4 ... */
  5376. appendPQExpBufferStr(query, "SELECT tableoid, oid, * FROM pg_language "
  5377. "WHERE lanispl "
  5378. "ORDER BY oid");
  5379. }
  5380. else
  5381. {
  5382. appendPQExpBufferStr(query, "SELECT "
  5383. "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
  5384. "oid, * FROM pg_language "
  5385. "WHERE lanispl "
  5386. "ORDER BY oid");
  5387. }
  5388. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  5389. ntups = PQntuples(res);
  5390. *numProcLangs = ntups;
  5391. planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
  5392. i_tableoid = PQfnumber(res, "tableoid");
  5393. i_oid = PQfnumber(res, "oid");
  5394. i_lanname = PQfnumber(res, "lanname");
  5395. i_lanpltrusted = PQfnumber(res, "lanpltrusted");
  5396. i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
  5397. /* these may fail and return -1: */
  5398. i_laninline = PQfnumber(res, "laninline");
  5399. i_lanvalidator = PQfnumber(res, "lanvalidator");
  5400. i_lanacl = PQfnumber(res, "lanacl");
  5401. i_lanowner = PQfnumber(res, "lanowner");
  5402. for (i = 0; i < ntups; i++)
  5403. {
  5404. planginfo[i].dobj.objType = DO_PROCLANG;
  5405. planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  5406. planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  5407. AssignDumpId(&planginfo[i].dobj);
  5408. planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
  5409. planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
  5410. planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
  5411. if (i_laninline >= 0)
  5412. planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
  5413. else
  5414. planginfo[i].laninline = InvalidOid;
  5415. if (i_lanvalidator >= 0)
  5416. planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
  5417. else
  5418. planginfo[i].lanvalidator = InvalidOid;
  5419. if (i_lanacl >= 0)
  5420. planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
  5421. else
  5422. planginfo[i].lanacl = pg_strdup("{=U}");
  5423. if (i_lanowner >= 0)
  5424. planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
  5425. else
  5426. planginfo[i].lanowner = pg_strdup("");
  5427. if (fout->remoteVersion < 70300)
  5428. {
  5429. /*
  5430. * We need to make a dependency to ensure the function will be
  5431. * dumped first. (In 7.3 and later the regular dependency
  5432. * mechanism will handle this for us.)
  5433. */
  5434. FuncInfo *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
  5435. if (funcInfo)
  5436. addObjectDependency(&planginfo[i].dobj,
  5437. funcInfo->dobj.dumpId);
  5438. }
  5439. }
  5440. PQclear(res);
  5441. destroyPQExpBuffer(query);
  5442. return planginfo;
  5443. }
  5444. /*
  5445. * getCasts
  5446. * get basic information about every cast in the system
  5447. *
  5448. * numCasts is set to the number of casts read in
  5449. */
  5450. CastInfo *
  5451. getCasts(Archive *fout, int *numCasts)
  5452. {
  5453. PGresult *res;
  5454. int ntups;
  5455. int i;
  5456. PQExpBuffer query = createPQExpBuffer();
  5457. CastInfo *castinfo;
  5458. int i_tableoid;
  5459. int i_oid;
  5460. int i_castsource;
  5461. int i_casttarget;
  5462. int i_castfunc;
  5463. int i_castcontext;
  5464. int i_castmethod;
  5465. /* Make sure we are in proper schema */
  5466. selectSourceSchema(fout, "pg_catalog");
  5467. if (fout->remoteVersion >= 80400)
  5468. {
  5469. appendPQExpBufferStr(query, "SELECT tableoid, oid, "
  5470. "castsource, casttarget, castfunc, castcontext, "
  5471. "castmethod "
  5472. "FROM pg_cast ORDER BY 3,4");
  5473. }
  5474. else if (fout->remoteVersion >= 70300)
  5475. {
  5476. appendPQExpBufferStr(query, "SELECT tableoid, oid, "
  5477. "castsource, casttarget, castfunc, castcontext, "
  5478. "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
  5479. "FROM pg_cast ORDER BY 3,4");
  5480. }
  5481. else
  5482. {
  5483. appendPQExpBufferStr(query, "SELECT 0 AS tableoid, p.oid, "
  5484. "t1.oid AS castsource, t2.oid AS casttarget, "
  5485. "p.oid AS castfunc, 'e' AS castcontext, "
  5486. "'f' AS castmethod "
  5487. "FROM pg_type t1, pg_type t2, pg_proc p "
  5488. "WHERE p.pronargs = 1 AND "
  5489. "p.proargtypes[0] = t1.oid AND "
  5490. "p.prorettype = t2.oid AND p.proname = t2.typname "
  5491. "ORDER BY 3,4");
  5492. }
  5493. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  5494. ntups = PQntuples(res);
  5495. *numCasts = ntups;
  5496. castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
  5497. i_tableoid = PQfnumber(res, "tableoid");
  5498. i_oid = PQfnumber(res, "oid");
  5499. i_castsource = PQfnumber(res, "castsource");
  5500. i_casttarget = PQfnumber(res, "casttarget");
  5501. i_castfunc = PQfnumber(res, "castfunc");
  5502. i_castcontext = PQfnumber(res, "castcontext");
  5503. i_castmethod = PQfnumber(res, "castmethod");
  5504. for (i = 0; i < ntups; i++)
  5505. {
  5506. PQExpBufferData namebuf;
  5507. TypeInfo *sTypeInfo;
  5508. TypeInfo *tTypeInfo;
  5509. castinfo[i].dobj.objType = DO_CAST;
  5510. castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  5511. castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  5512. AssignDumpId(&castinfo[i].dobj);
  5513. castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
  5514. castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
  5515. castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
  5516. castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
  5517. castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
  5518. /*
  5519. * Try to name cast as concatenation of typnames. This is only used
  5520. * for purposes of sorting. If we fail to find either type, the name
  5521. * will be an empty string.
  5522. */
  5523. initPQExpBuffer(&namebuf);
  5524. sTypeInfo = findTypeByOid(castinfo[i].castsource);
  5525. tTypeInfo = findTypeByOid(castinfo[i].casttarget);
  5526. if (sTypeInfo && tTypeInfo)
  5527. appendPQExpBuffer(&namebuf, "%s %s",
  5528. sTypeInfo->dobj.name, tTypeInfo->dobj.name);
  5529. castinfo[i].dobj.name = namebuf.data;
  5530. if (OidIsValid(castinfo[i].castfunc))
  5531. {
  5532. /*
  5533. * We need to make a dependency to ensure the function will be
  5534. * dumped first. (In 7.3 and later the regular dependency
  5535. * mechanism will handle this for us.)
  5536. */
  5537. FuncInfo *funcInfo;
  5538. funcInfo = findFuncByOid(castinfo[i].castfunc);
  5539. if (funcInfo)
  5540. addObjectDependency(&castinfo[i].dobj,
  5541. funcInfo->dobj.dumpId);
  5542. }
  5543. }
  5544. PQclear(res);
  5545. destroyPQExpBuffer(query);
  5546. return castinfo;
  5547. }
  5548. /*
  5549. * getTableAttrs -
  5550. * for each interesting table, read info about its attributes
  5551. * (names, types, default values, CHECK constraints, etc)
  5552. *
  5553. * This is implemented in a very inefficient way right now, looping
  5554. * through the tblinfo and doing a join per table to find the attrs and their
  5555. * types. However, because we want type names and so forth to be named
  5556. * relative to the schema of each table, we couldn't do it in just one
  5557. * query. (Maybe one query per schema?)
  5558. *
  5559. * modifies tblinfo
  5560. */
  5561. void
  5562. getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
  5563. {
  5564. int i,
  5565. j;
  5566. PQExpBuffer q = createPQExpBuffer();
  5567. int i_attnum;
  5568. int i_attname;
  5569. int i_atttypname;
  5570. int i_atttypmod;
  5571. int i_attstattarget;
  5572. int i_attstorage;
  5573. int i_typstorage;
  5574. int i_attnotnull;
  5575. int i_atthasdef;
  5576. int i_attisdropped;
  5577. int i_attlen;
  5578. int i_attalign;
  5579. int i_attislocal;
  5580. int i_attoptions;
  5581. int i_attcollation;
  5582. int i_attfdwoptions;
  5583. PGresult *res;
  5584. int ntups;
  5585. bool hasdefaults;
  5586. for (i = 0; i < numTables; i++)
  5587. {
  5588. TableInfo *tbinfo = &tblinfo[i];
  5589. /* Don't bother to collect info for sequences */
  5590. if (tbinfo->relkind == RELKIND_SEQUENCE)
  5591. continue;
  5592. /* Don't bother with uninteresting tables, either */
  5593. if (!tbinfo->interesting)
  5594. continue;
  5595. /*
  5596. * Make sure we are in proper schema for this table; this allows
  5597. * correct retrieval of formatted type names and default exprs
  5598. */
  5599. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  5600. /* find all the user attributes and their types */
  5601. /*
  5602. * we must read the attribute names in attribute number order! because
  5603. * we will use the attnum to index into the attnames array later. We
  5604. * actually ask to order by "attrelid, attnum" because (at least up to
  5605. * 7.3) the planner is not smart enough to realize it needn't re-sort
  5606. * the output of an indexscan on pg_attribute_relid_attnum_index.
  5607. */
  5608. if (g_verbose)
  5609. write_msg(NULL, "finding the columns and types of table \"%s\"\n",
  5610. tbinfo->dobj.name);
  5611. resetPQExpBuffer(q);
  5612. if (fout->remoteVersion >= 90200)
  5613. {
  5614. /*
  5615. * attfdwoptions is new in 9.2.
  5616. */
  5617. appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
  5618. "a.attstattarget, a.attstorage, t.typstorage, "
  5619. "a.attnotnull, a.atthasdef, a.attisdropped, "
  5620. "a.attlen, a.attalign, a.attislocal, "
  5621. "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
  5622. "array_to_string(a.attoptions, ', ') AS attoptions, "
  5623. "CASE WHEN a.attcollation <> t.typcollation "
  5624. "THEN a.attcollation ELSE 0 END AS attcollation, "
  5625. "pg_catalog.array_to_string(ARRAY("
  5626. "SELECT pg_catalog.quote_ident(option_name) || "
  5627. "' ' || pg_catalog.quote_literal(option_value) "
  5628. "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
  5629. "ORDER BY option_name"
  5630. "), E',\n ') AS attfdwoptions "
  5631. "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
  5632. "ON a.atttypid = t.oid "
  5633. "WHERE a.attrelid = '%u'::pg_catalog.oid "
  5634. "AND a.attnum > 0::pg_catalog.int2 "
  5635. "ORDER BY a.attrelid, a.attnum",
  5636. tbinfo->dobj.catId.oid);
  5637. }
  5638. else if (fout->remoteVersion >= 90100)
  5639. {
  5640. /*
  5641. * attcollation is new in 9.1. Since we only want to dump COLLATE
  5642. * clauses for attributes whose collation is different from their
  5643. * type's default, we use a CASE here to suppress uninteresting
  5644. * attcollations cheaply.
  5645. */
  5646. appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
  5647. "a.attstattarget, a.attstorage, t.typstorage, "
  5648. "a.attnotnull, a.atthasdef, a.attisdropped, "
  5649. "a.attlen, a.attalign, a.attislocal, "
  5650. "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
  5651. "array_to_string(a.attoptions, ', ') AS attoptions, "
  5652. "CASE WHEN a.attcollation <> t.typcollation "
  5653. "THEN a.attcollation ELSE 0 END AS attcollation, "
  5654. "NULL AS attfdwoptions "
  5655. "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
  5656. "ON a.atttypid = t.oid "
  5657. "WHERE a.attrelid = '%u'::pg_catalog.oid "
  5658. "AND a.attnum > 0::pg_catalog.int2 "
  5659. "ORDER BY a.attrelid, a.attnum",
  5660. tbinfo->dobj.catId.oid);
  5661. }
  5662. else if (fout->remoteVersion >= 90000)
  5663. {
  5664. /* attoptions is new in 9.0 */
  5665. appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
  5666. "a.attstattarget, a.attstorage, t.typstorage, "
  5667. "a.attnotnull, a.atthasdef, a.attisdropped, "
  5668. "a.attlen, a.attalign, a.attislocal, "
  5669. "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
  5670. "array_to_string(a.attoptions, ', ') AS attoptions, "
  5671. "0 AS attcollation, "
  5672. "NULL AS attfdwoptions "
  5673. "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
  5674. "ON a.atttypid = t.oid "
  5675. "WHERE a.attrelid = '%u'::pg_catalog.oid "
  5676. "AND a.attnum > 0::pg_catalog.int2 "
  5677. "ORDER BY a.attrelid, a.attnum",
  5678. tbinfo->dobj.catId.oid);
  5679. }
  5680. else if (fout->remoteVersion >= 70300)
  5681. {
  5682. /* need left join here to not fail on dropped columns ... */
  5683. appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
  5684. "a.attstattarget, a.attstorage, t.typstorage, "
  5685. "a.attnotnull, a.atthasdef, a.attisdropped, "
  5686. "a.attlen, a.attalign, a.attislocal, "
  5687. "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
  5688. "'' AS attoptions, 0 AS attcollation, "
  5689. "NULL AS attfdwoptions "
  5690. "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
  5691. "ON a.atttypid = t.oid "
  5692. "WHERE a.attrelid = '%u'::pg_catalog.oid "
  5693. "AND a.attnum > 0::pg_catalog.int2 "
  5694. "ORDER BY a.attrelid, a.attnum",
  5695. tbinfo->dobj.catId.oid);
  5696. }
  5697. else if (fout->remoteVersion >= 70100)
  5698. {
  5699. /*
  5700. * attstattarget doesn't exist in 7.1. It does exist in 7.2, but
  5701. * we don't dump it because we can't tell whether it's been
  5702. * explicitly set or was just a default.
  5703. *
  5704. * attislocal doesn't exist before 7.3, either; in older databases
  5705. * we assume it's TRUE, else we'd fail to dump non-inherited atts.
  5706. */
  5707. appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
  5708. "-1 AS attstattarget, a.attstorage, "
  5709. "t.typstorage, a.attnotnull, a.atthasdef, "
  5710. "false AS attisdropped, a.attlen, "
  5711. "a.attalign, true AS attislocal, "
  5712. "format_type(t.oid,a.atttypmod) AS atttypname, "
  5713. "'' AS attoptions, 0 AS attcollation, "
  5714. "NULL AS attfdwoptions "
  5715. "FROM pg_attribute a LEFT JOIN pg_type t "
  5716. "ON a.atttypid = t.oid "
  5717. "WHERE a.attrelid = '%u'::oid "
  5718. "AND a.attnum > 0::int2 "
  5719. "ORDER BY a.attrelid, a.attnum",
  5720. tbinfo->dobj.catId.oid);
  5721. }
  5722. else
  5723. {
  5724. /* format_type not available before 7.1 */
  5725. appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
  5726. "-1 AS attstattarget, "
  5727. "attstorage, attstorage AS typstorage, "
  5728. "attnotnull, atthasdef, false AS attisdropped, "
  5729. "attlen, attalign, "
  5730. "true AS attislocal, "
  5731. "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
  5732. "'' AS attoptions, 0 AS attcollation, "
  5733. "NULL AS attfdwoptions "
  5734. "FROM pg_attribute a "
  5735. "WHERE attrelid = '%u'::oid "
  5736. "AND attnum > 0::int2 "
  5737. "ORDER BY attrelid, attnum",
  5738. tbinfo->dobj.catId.oid);
  5739. }
  5740. res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
  5741. ntups = PQntuples(res);
  5742. i_attnum = PQfnumber(res, "attnum");
  5743. i_attname = PQfnumber(res, "attname");
  5744. i_atttypname = PQfnumber(res, "atttypname");
  5745. i_atttypmod = PQfnumber(res, "atttypmod");
  5746. i_attstattarget = PQfnumber(res, "attstattarget");
  5747. i_attstorage = PQfnumber(res, "attstorage");
  5748. i_typstorage = PQfnumber(res, "typstorage");
  5749. i_attnotnull = PQfnumber(res, "attnotnull");
  5750. i_atthasdef = PQfnumber(res, "atthasdef");
  5751. i_attisdropped = PQfnumber(res, "attisdropped");
  5752. i_attlen = PQfnumber(res, "attlen");
  5753. i_attalign = PQfnumber(res, "attalign");
  5754. i_attislocal = PQfnumber(res, "attislocal");
  5755. i_attoptions = PQfnumber(res, "attoptions");
  5756. i_attcollation = PQfnumber(res, "attcollation");
  5757. i_attfdwoptions = PQfnumber(res, "attfdwoptions");
  5758. tbinfo->numatts = ntups;
  5759. tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
  5760. tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
  5761. tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
  5762. tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
  5763. tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
  5764. tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
  5765. tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
  5766. tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
  5767. tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
  5768. tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
  5769. tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
  5770. tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
  5771. tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
  5772. tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
  5773. tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
  5774. tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
  5775. hasdefaults = false;
  5776. for (j = 0; j < ntups; j++)
  5777. {
  5778. if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
  5779. exit_horribly(NULL,
  5780. "invalid column numbering in table \"%s\"\n",
  5781. tbinfo->dobj.name);
  5782. tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
  5783. tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
  5784. tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
  5785. tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
  5786. tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
  5787. tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
  5788. tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
  5789. tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
  5790. tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
  5791. tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
  5792. tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
  5793. tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
  5794. tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
  5795. tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
  5796. tbinfo->attrdefs[j] = NULL; /* fix below */
  5797. if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
  5798. hasdefaults = true;
  5799. /* these flags will be set in flagInhAttrs() */
  5800. tbinfo->inhNotNull[j] = false;
  5801. }
  5802. PQclear(res);
  5803. /*
  5804. * Get info about column defaults
  5805. */
  5806. if (hasdefaults)
  5807. {
  5808. AttrDefInfo *attrdefs;
  5809. int numDefaults;
  5810. if (g_verbose)
  5811. write_msg(NULL, "finding default expressions of table \"%s\"\n",
  5812. tbinfo->dobj.name);
  5813. resetPQExpBuffer(q);
  5814. if (fout->remoteVersion >= 70300)
  5815. {
  5816. appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
  5817. "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
  5818. "FROM pg_catalog.pg_attrdef "
  5819. "WHERE adrelid = '%u'::pg_catalog.oid",
  5820. tbinfo->dobj.catId.oid);
  5821. }
  5822. else if (fout->remoteVersion >= 70200)
  5823. {
  5824. /* 7.2 did not have OIDs in pg_attrdef */
  5825. appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
  5826. "pg_get_expr(adbin, adrelid) AS adsrc "
  5827. "FROM pg_attrdef "
  5828. "WHERE adrelid = '%u'::oid",
  5829. tbinfo->dobj.catId.oid);
  5830. }
  5831. else if (fout->remoteVersion >= 70100)
  5832. {
  5833. /* no pg_get_expr, so must rely on adsrc */
  5834. appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
  5835. "FROM pg_attrdef "
  5836. "WHERE adrelid = '%u'::oid",
  5837. tbinfo->dobj.catId.oid);
  5838. }
  5839. else
  5840. {
  5841. /* no pg_get_expr, no tableoid either */
  5842. appendPQExpBuffer(q, "SELECT "
  5843. "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
  5844. "oid, adnum, adsrc "
  5845. "FROM pg_attrdef "
  5846. "WHERE adrelid = '%u'::oid",
  5847. tbinfo->dobj.catId.oid);
  5848. }
  5849. res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
  5850. numDefaults = PQntuples(res);
  5851. attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
  5852. for (j = 0; j < numDefaults; j++)
  5853. {
  5854. int adnum;
  5855. adnum = atoi(PQgetvalue(res, j, 2));
  5856. if (adnum <= 0 || adnum > ntups)
  5857. exit_horribly(NULL,
  5858. "invalid adnum value %d for table \"%s\"\n",
  5859. adnum, tbinfo->dobj.name);
  5860. /*
  5861. * dropped columns shouldn't have defaults, but just in case,
  5862. * ignore 'em
  5863. */
  5864. if (tbinfo->attisdropped[adnum - 1])
  5865. continue;
  5866. attrdefs[j].dobj.objType = DO_ATTRDEF;
  5867. attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
  5868. attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
  5869. AssignDumpId(&attrdefs[j].dobj);
  5870. attrdefs[j].adtable = tbinfo;
  5871. attrdefs[j].adnum = adnum;
  5872. attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
  5873. attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
  5874. attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
  5875. attrdefs[j].dobj.dump = tbinfo->dobj.dump;
  5876. /*
  5877. * Defaults on a VIEW must always be dumped as separate ALTER
  5878. * TABLE commands. Defaults on regular tables are dumped as
  5879. * part of the CREATE TABLE if possible, which it won't be if
  5880. * the column is not going to be emitted explicitly.
  5881. */
  5882. if (tbinfo->relkind == RELKIND_VIEW)
  5883. {
  5884. attrdefs[j].separate = true;
  5885. /* needed in case pre-7.3 DB: */
  5886. addObjectDependency(&attrdefs[j].dobj,
  5887. tbinfo->dobj.dumpId);
  5888. }
  5889. else if (!shouldPrintColumn(tbinfo, adnum - 1))
  5890. {
  5891. /* column will be suppressed, print default separately */
  5892. attrdefs[j].separate = true;
  5893. /* needed in case pre-7.3 DB: */
  5894. addObjectDependency(&attrdefs[j].dobj,
  5895. tbinfo->dobj.dumpId);
  5896. }
  5897. else
  5898. {
  5899. attrdefs[j].separate = false;
  5900. /*
  5901. * Mark the default as needing to appear before the table,
  5902. * so that any dependencies it has must be emitted before
  5903. * the CREATE TABLE. If this is not possible, we'll
  5904. * change to "separate" mode while sorting dependencies.
  5905. */
  5906. addObjectDependency(&tbinfo->dobj,
  5907. attrdefs[j].dobj.dumpId);
  5908. }
  5909. tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
  5910. }
  5911. PQclear(res);
  5912. }
  5913. /*
  5914. * Get info about table CHECK constraints
  5915. */
  5916. if (tbinfo->ncheck > 0)
  5917. {
  5918. ConstraintInfo *constrs;
  5919. int numConstrs;
  5920. if (g_verbose)
  5921. write_msg(NULL, "finding check constraints for table \"%s\"\n",
  5922. tbinfo->dobj.name);
  5923. resetPQExpBuffer(q);
  5924. if (fout->remoteVersion >= 90200)
  5925. {
  5926. /*
  5927. * convalidated is new in 9.2 (actually, it is there in 9.1,
  5928. * but it wasn't ever false for check constraints until 9.2).
  5929. */
  5930. appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
  5931. "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
  5932. "conislocal, convalidated "
  5933. "FROM pg_catalog.pg_constraint "
  5934. "WHERE conrelid = '%u'::pg_catalog.oid "
  5935. " AND contype = 'c' "
  5936. "ORDER BY conname",
  5937. tbinfo->dobj.catId.oid);
  5938. }
  5939. else if (fout->remoteVersion >= 80400)
  5940. {
  5941. /* conislocal is new in 8.4 */
  5942. appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
  5943. "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
  5944. "conislocal, true AS convalidated "
  5945. "FROM pg_catalog.pg_constraint "
  5946. "WHERE conrelid = '%u'::pg_catalog.oid "
  5947. " AND contype = 'c' "
  5948. "ORDER BY conname",
  5949. tbinfo->dobj.catId.oid);
  5950. }
  5951. else if (fout->remoteVersion >= 70400)
  5952. {
  5953. appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
  5954. "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
  5955. "true AS conislocal, true AS convalidated "
  5956. "FROM pg_catalog.pg_constraint "
  5957. "WHERE conrelid = '%u'::pg_catalog.oid "
  5958. " AND contype = 'c' "
  5959. "ORDER BY conname",
  5960. tbinfo->dobj.catId.oid);
  5961. }
  5962. else if (fout->remoteVersion >= 70300)
  5963. {
  5964. /* no pg_get_constraintdef, must use consrc */
  5965. appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
  5966. "'CHECK (' || consrc || ')' AS consrc, "
  5967. "true AS conislocal, true AS convalidated "
  5968. "FROM pg_catalog.pg_constraint "
  5969. "WHERE conrelid = '%u'::pg_catalog.oid "
  5970. " AND contype = 'c' "
  5971. "ORDER BY conname",
  5972. tbinfo->dobj.catId.oid);
  5973. }
  5974. else if (fout->remoteVersion >= 70200)
  5975. {
  5976. /* 7.2 did not have OIDs in pg_relcheck */
  5977. appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
  5978. "rcname AS conname, "
  5979. "'CHECK (' || rcsrc || ')' AS consrc, "
  5980. "true AS conislocal, true AS convalidated "
  5981. "FROM pg_relcheck "
  5982. "WHERE rcrelid = '%u'::oid "
  5983. "ORDER BY rcname",
  5984. tbinfo->dobj.catId.oid);
  5985. }
  5986. else if (fout->remoteVersion >= 70100)
  5987. {
  5988. appendPQExpBuffer(q, "SELECT tableoid, oid, "
  5989. "rcname AS conname, "
  5990. "'CHECK (' || rcsrc || ')' AS consrc, "
  5991. "true AS conislocal, true AS convalidated "
  5992. "FROM pg_relcheck "
  5993. "WHERE rcrelid = '%u'::oid "
  5994. "ORDER BY rcname",
  5995. tbinfo->dobj.catId.oid);
  5996. }
  5997. else
  5998. {
  5999. /* no tableoid in 7.0 */
  6000. appendPQExpBuffer(q, "SELECT "
  6001. "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
  6002. "oid, rcname AS conname, "
  6003. "'CHECK (' || rcsrc || ')' AS consrc, "
  6004. "true AS conislocal, true AS convalidated "
  6005. "FROM pg_relcheck "
  6006. "WHERE rcrelid = '%u'::oid "
  6007. "ORDER BY rcname",
  6008. tbinfo->dobj.catId.oid);
  6009. }
  6010. res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
  6011. numConstrs = PQntuples(res);
  6012. if (numConstrs != tbinfo->ncheck)
  6013. {
  6014. write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
  6015. "expected %d check constraints on table \"%s\" but found %d\n",
  6016. tbinfo->ncheck),
  6017. tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
  6018. write_msg(NULL, "(The system catalogs might be corrupted.)\n");
  6019. exit_nicely(1);
  6020. }
  6021. constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
  6022. tbinfo->checkexprs = constrs;
  6023. for (j = 0; j < numConstrs; j++)
  6024. {
  6025. bool validated = PQgetvalue(res, j, 5)[0] == 't';
  6026. constrs[j].dobj.objType = DO_CONSTRAINT;
  6027. constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
  6028. constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
  6029. AssignDumpId(&constrs[j].dobj);
  6030. constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
  6031. constrs[j].dobj.namespace = tbinfo->dobj.namespace;
  6032. constrs[j].contable = tbinfo;
  6033. constrs[j].condomain = NULL;
  6034. constrs[j].contype = 'c';
  6035. constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
  6036. constrs[j].confrelid = InvalidOid;
  6037. constrs[j].conindex = 0;
  6038. constrs[j].condeferrable = false;
  6039. constrs[j].condeferred = false;
  6040. constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
  6041. /*
  6042. * An unvalidated constraint needs to be dumped separately, so
  6043. * that potentially-violating existing data is loaded before
  6044. * the constraint.
  6045. */
  6046. constrs[j].separate = !validated;
  6047. constrs[j].dobj.dump = tbinfo->dobj.dump;
  6048. /*
  6049. * Mark the constraint as needing to appear before the table
  6050. * --- this is so that any other dependencies of the
  6051. * constraint will be emitted before we try to create the
  6052. * table. If the constraint is to be dumped separately, it
  6053. * will be dumped after data is loaded anyway, so don't do it.
  6054. * (There's an automatic dependency in the opposite direction
  6055. * anyway, so don't need to add one manually here.)
  6056. */
  6057. if (!constrs[j].separate)
  6058. addObjectDependency(&tbinfo->dobj,
  6059. constrs[j].dobj.dumpId);
  6060. /*
  6061. * If the constraint is inherited, this will be detected later
  6062. * (in pre-8.4 databases). We also detect later if the
  6063. * constraint must be split out from the table definition.
  6064. */
  6065. }
  6066. PQclear(res);
  6067. }
  6068. }
  6069. destroyPQExpBuffer(q);
  6070. }
  6071. /*
  6072. * Test whether a column should be printed as part of table's CREATE TABLE.
  6073. * Column number is zero-based.
  6074. *
  6075. * Normally this is always true, but it's false for dropped columns, as well
  6076. * as those that were inherited without any local definition. (If we print
  6077. * such a column it will mistakenly get pg_attribute.attislocal set to true.)
  6078. * However, in binary_upgrade mode, we must print all such columns anyway and
  6079. * fix the attislocal/attisdropped state later, so as to keep control of the
  6080. * physical column order.
  6081. *
  6082. * This function exists because there are scattered nonobvious places that
  6083. * must be kept in sync with this decision.
  6084. */
  6085. bool
  6086. shouldPrintColumn(TableInfo *tbinfo, int colno)
  6087. {
  6088. if (binary_upgrade)
  6089. return true;
  6090. return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
  6091. }
  6092. /*
  6093. * getTSParsers:
  6094. * read all text search parsers in the system catalogs and return them
  6095. * in the TSParserInfo* structure
  6096. *
  6097. * numTSParsers is set to the number of parsers read in
  6098. */
  6099. TSParserInfo *
  6100. getTSParsers(Archive *fout, int *numTSParsers)
  6101. {
  6102. PGresult *res;
  6103. int ntups;
  6104. int i;
  6105. PQExpBuffer query;
  6106. TSParserInfo *prsinfo;
  6107. int i_tableoid;
  6108. int i_oid;
  6109. int i_prsname;
  6110. int i_prsnamespace;
  6111. int i_prsstart;
  6112. int i_prstoken;
  6113. int i_prsend;
  6114. int i_prsheadline;
  6115. int i_prslextype;
  6116. /* Before 8.3, there is no built-in text search support */
  6117. if (fout->remoteVersion < 80300)
  6118. {
  6119. *numTSParsers = 0;
  6120. return NULL;
  6121. }
  6122. query = createPQExpBuffer();
  6123. /*
  6124. * find all text search objects, including builtin ones; we filter out
  6125. * system-defined objects at dump-out time.
  6126. */
  6127. /* Make sure we are in proper schema */
  6128. selectSourceSchema(fout, "pg_catalog");
  6129. appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
  6130. "prsstart::oid, prstoken::oid, "
  6131. "prsend::oid, prsheadline::oid, prslextype::oid "
  6132. "FROM pg_ts_parser");
  6133. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  6134. ntups = PQntuples(res);
  6135. *numTSParsers = ntups;
  6136. prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
  6137. i_tableoid = PQfnumber(res, "tableoid");
  6138. i_oid = PQfnumber(res, "oid");
  6139. i_prsname = PQfnumber(res, "prsname");
  6140. i_prsnamespace = PQfnumber(res, "prsnamespace");
  6141. i_prsstart = PQfnumber(res, "prsstart");
  6142. i_prstoken = PQfnumber(res, "prstoken");
  6143. i_prsend = PQfnumber(res, "prsend");
  6144. i_prsheadline = PQfnumber(res, "prsheadline");
  6145. i_prslextype = PQfnumber(res, "prslextype");
  6146. for (i = 0; i < ntups; i++)
  6147. {
  6148. prsinfo[i].dobj.objType = DO_TSPARSER;
  6149. prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  6150. prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  6151. AssignDumpId(&prsinfo[i].dobj);
  6152. prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
  6153. prsinfo[i].dobj.namespace =
  6154. findNamespace(fout,
  6155. atooid(PQgetvalue(res, i, i_prsnamespace)),
  6156. prsinfo[i].dobj.catId.oid);
  6157. prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
  6158. prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
  6159. prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
  6160. prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
  6161. prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
  6162. /* Decide whether we want to dump it */
  6163. selectDumpableObject(&(prsinfo[i].dobj));
  6164. }
  6165. PQclear(res);
  6166. destroyPQExpBuffer(query);
  6167. return prsinfo;
  6168. }
  6169. /*
  6170. * getTSDictionaries:
  6171. * read all text search dictionaries in the system catalogs and return them
  6172. * in the TSDictInfo* structure
  6173. *
  6174. * numTSDicts is set to the number of dictionaries read in
  6175. */
  6176. TSDictInfo *
  6177. getTSDictionaries(Archive *fout, int *numTSDicts)
  6178. {
  6179. PGresult *res;
  6180. int ntups;
  6181. int i;
  6182. PQExpBuffer query;
  6183. TSDictInfo *dictinfo;
  6184. int i_tableoid;
  6185. int i_oid;
  6186. int i_dictname;
  6187. int i_dictnamespace;
  6188. int i_rolname;
  6189. int i_dicttemplate;
  6190. int i_dictinitoption;
  6191. /* Before 8.3, there is no built-in text search support */
  6192. if (fout->remoteVersion < 80300)
  6193. {
  6194. *numTSDicts = 0;
  6195. return NULL;
  6196. }
  6197. query = createPQExpBuffer();
  6198. /* Make sure we are in proper schema */
  6199. selectSourceSchema(fout, "pg_catalog");
  6200. appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
  6201. "dictnamespace, (%s dictowner) AS rolname, "
  6202. "dicttemplate, dictinitoption "
  6203. "FROM pg_ts_dict",
  6204. username_subquery);
  6205. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  6206. ntups = PQntuples(res);
  6207. *numTSDicts = ntups;
  6208. dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
  6209. i_tableoid = PQfnumber(res, "tableoid");
  6210. i_oid = PQfnumber(res, "oid");
  6211. i_dictname = PQfnumber(res, "dictname");
  6212. i_dictnamespace = PQfnumber(res, "dictnamespace");
  6213. i_rolname = PQfnumber(res, "rolname");
  6214. i_dictinitoption = PQfnumber(res, "dictinitoption");
  6215. i_dicttemplate = PQfnumber(res, "dicttemplate");
  6216. for (i = 0; i < ntups; i++)
  6217. {
  6218. dictinfo[i].dobj.objType = DO_TSDICT;
  6219. dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  6220. dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  6221. AssignDumpId(&dictinfo[i].dobj);
  6222. dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
  6223. dictinfo[i].dobj.namespace =
  6224. findNamespace(fout,
  6225. atooid(PQgetvalue(res, i, i_dictnamespace)),
  6226. dictinfo[i].dobj.catId.oid);
  6227. dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  6228. dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
  6229. if (PQgetisnull(res, i, i_dictinitoption))
  6230. dictinfo[i].dictinitoption = NULL;
  6231. else
  6232. dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
  6233. /* Decide whether we want to dump it */
  6234. selectDumpableObject(&(dictinfo[i].dobj));
  6235. }
  6236. PQclear(res);
  6237. destroyPQExpBuffer(query);
  6238. return dictinfo;
  6239. }
  6240. /*
  6241. * getTSTemplates:
  6242. * read all text search templates in the system catalogs and return them
  6243. * in the TSTemplateInfo* structure
  6244. *
  6245. * numTSTemplates is set to the number of templates read in
  6246. */
  6247. TSTemplateInfo *
  6248. getTSTemplates(Archive *fout, int *numTSTemplates)
  6249. {
  6250. PGresult *res;
  6251. int ntups;
  6252. int i;
  6253. PQExpBuffer query;
  6254. TSTemplateInfo *tmplinfo;
  6255. int i_tableoid;
  6256. int i_oid;
  6257. int i_tmplname;
  6258. int i_tmplnamespace;
  6259. int i_tmplinit;
  6260. int i_tmpllexize;
  6261. /* Before 8.3, there is no built-in text search support */
  6262. if (fout->remoteVersion < 80300)
  6263. {
  6264. *numTSTemplates = 0;
  6265. return NULL;
  6266. }
  6267. query = createPQExpBuffer();
  6268. /* Make sure we are in proper schema */
  6269. selectSourceSchema(fout, "pg_catalog");
  6270. appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
  6271. "tmplnamespace, tmplinit::oid, tmpllexize::oid "
  6272. "FROM pg_ts_template");
  6273. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  6274. ntups = PQntuples(res);
  6275. *numTSTemplates = ntups;
  6276. tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
  6277. i_tableoid = PQfnumber(res, "tableoid");
  6278. i_oid = PQfnumber(res, "oid");
  6279. i_tmplname = PQfnumber(res, "tmplname");
  6280. i_tmplnamespace = PQfnumber(res, "tmplnamespace");
  6281. i_tmplinit = PQfnumber(res, "tmplinit");
  6282. i_tmpllexize = PQfnumber(res, "tmpllexize");
  6283. for (i = 0; i < ntups; i++)
  6284. {
  6285. tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
  6286. tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  6287. tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  6288. AssignDumpId(&tmplinfo[i].dobj);
  6289. tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
  6290. tmplinfo[i].dobj.namespace =
  6291. findNamespace(fout,
  6292. atooid(PQgetvalue(res, i, i_tmplnamespace)),
  6293. tmplinfo[i].dobj.catId.oid);
  6294. tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
  6295. tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
  6296. /* Decide whether we want to dump it */
  6297. selectDumpableObject(&(tmplinfo[i].dobj));
  6298. }
  6299. PQclear(res);
  6300. destroyPQExpBuffer(query);
  6301. return tmplinfo;
  6302. }
  6303. /*
  6304. * getTSConfigurations:
  6305. * read all text search configurations in the system catalogs and return
  6306. * them in the TSConfigInfo* structure
  6307. *
  6308. * numTSConfigs is set to the number of configurations read in
  6309. */
  6310. TSConfigInfo *
  6311. getTSConfigurations(Archive *fout, int *numTSConfigs)
  6312. {
  6313. PGresult *res;
  6314. int ntups;
  6315. int i;
  6316. PQExpBuffer query;
  6317. TSConfigInfo *cfginfo;
  6318. int i_tableoid;
  6319. int i_oid;
  6320. int i_cfgname;
  6321. int i_cfgnamespace;
  6322. int i_rolname;
  6323. int i_cfgparser;
  6324. /* Before 8.3, there is no built-in text search support */
  6325. if (fout->remoteVersion < 80300)
  6326. {
  6327. *numTSConfigs = 0;
  6328. return NULL;
  6329. }
  6330. query = createPQExpBuffer();
  6331. /* Make sure we are in proper schema */
  6332. selectSourceSchema(fout, "pg_catalog");
  6333. appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
  6334. "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
  6335. "FROM pg_ts_config",
  6336. username_subquery);
  6337. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  6338. ntups = PQntuples(res);
  6339. *numTSConfigs = ntups;
  6340. cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
  6341. i_tableoid = PQfnumber(res, "tableoid");
  6342. i_oid = PQfnumber(res, "oid");
  6343. i_cfgname = PQfnumber(res, "cfgname");
  6344. i_cfgnamespace = PQfnumber(res, "cfgnamespace");
  6345. i_rolname = PQfnumber(res, "rolname");
  6346. i_cfgparser = PQfnumber(res, "cfgparser");
  6347. for (i = 0; i < ntups; i++)
  6348. {
  6349. cfginfo[i].dobj.objType = DO_TSCONFIG;
  6350. cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  6351. cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  6352. AssignDumpId(&cfginfo[i].dobj);
  6353. cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
  6354. cfginfo[i].dobj.namespace =
  6355. findNamespace(fout,
  6356. atooid(PQgetvalue(res, i, i_cfgnamespace)),
  6357. cfginfo[i].dobj.catId.oid);
  6358. cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  6359. cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
  6360. /* Decide whether we want to dump it */
  6361. selectDumpableObject(&(cfginfo[i].dobj));
  6362. }
  6363. PQclear(res);
  6364. destroyPQExpBuffer(query);
  6365. return cfginfo;
  6366. }
  6367. /*
  6368. * getForeignDataWrappers:
  6369. * read all foreign-data wrappers in the system catalogs and return
  6370. * them in the FdwInfo* structure
  6371. *
  6372. * numForeignDataWrappers is set to the number of fdws read in
  6373. */
  6374. FdwInfo *
  6375. getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
  6376. {
  6377. PGresult *res;
  6378. int ntups;
  6379. int i;
  6380. PQExpBuffer query;
  6381. FdwInfo *fdwinfo;
  6382. int i_tableoid;
  6383. int i_oid;
  6384. int i_fdwname;
  6385. int i_rolname;
  6386. int i_fdwhandler;
  6387. int i_fdwvalidator;
  6388. int i_fdwacl;
  6389. int i_fdwoptions;
  6390. /* Before 8.4, there are no foreign-data wrappers */
  6391. if (fout->remoteVersion < 80400)
  6392. {
  6393. *numForeignDataWrappers = 0;
  6394. return NULL;
  6395. }
  6396. query = createPQExpBuffer();
  6397. /* Make sure we are in proper schema */
  6398. selectSourceSchema(fout, "pg_catalog");
  6399. if (fout->remoteVersion >= 90100)
  6400. {
  6401. appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
  6402. "(%s fdwowner) AS rolname, "
  6403. "fdwhandler::pg_catalog.regproc, "
  6404. "fdwvalidator::pg_catalog.regproc, fdwacl, "
  6405. "array_to_string(ARRAY("
  6406. "SELECT quote_ident(option_name) || ' ' || "
  6407. "quote_literal(option_value) "
  6408. "FROM pg_options_to_table(fdwoptions) "
  6409. "ORDER BY option_name"
  6410. "), E',\n ') AS fdwoptions "
  6411. "FROM pg_foreign_data_wrapper",
  6412. username_subquery);
  6413. }
  6414. else
  6415. {
  6416. appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
  6417. "(%s fdwowner) AS rolname, "
  6418. "'-' AS fdwhandler, "
  6419. "fdwvalidator::pg_catalog.regproc, fdwacl, "
  6420. "array_to_string(ARRAY("
  6421. "SELECT quote_ident(option_name) || ' ' || "
  6422. "quote_literal(option_value) "
  6423. "FROM pg_options_to_table(fdwoptions) "
  6424. "ORDER BY option_name"
  6425. "), E',\n ') AS fdwoptions "
  6426. "FROM pg_foreign_data_wrapper",
  6427. username_subquery);
  6428. }
  6429. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  6430. ntups = PQntuples(res);
  6431. *numForeignDataWrappers = ntups;
  6432. fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
  6433. i_tableoid = PQfnumber(res, "tableoid");
  6434. i_oid = PQfnumber(res, "oid");
  6435. i_fdwname = PQfnumber(res, "fdwname");
  6436. i_rolname = PQfnumber(res, "rolname");
  6437. i_fdwhandler = PQfnumber(res, "fdwhandler");
  6438. i_fdwvalidator = PQfnumber(res, "fdwvalidator");
  6439. i_fdwacl = PQfnumber(res, "fdwacl");
  6440. i_fdwoptions = PQfnumber(res, "fdwoptions");
  6441. for (i = 0; i < ntups; i++)
  6442. {
  6443. fdwinfo[i].dobj.objType = DO_FDW;
  6444. fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  6445. fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  6446. AssignDumpId(&fdwinfo[i].dobj);
  6447. fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
  6448. fdwinfo[i].dobj.namespace = NULL;
  6449. fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  6450. fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
  6451. fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
  6452. fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
  6453. fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
  6454. /* Decide whether we want to dump it */
  6455. selectDumpableObject(&(fdwinfo[i].dobj));
  6456. }
  6457. PQclear(res);
  6458. destroyPQExpBuffer(query);
  6459. return fdwinfo;
  6460. }
  6461. /*
  6462. * getForeignServers:
  6463. * read all foreign servers in the system catalogs and return
  6464. * them in the ForeignServerInfo * structure
  6465. *
  6466. * numForeignServers is set to the number of servers read in
  6467. */
  6468. ForeignServerInfo *
  6469. getForeignServers(Archive *fout, int *numForeignServers)
  6470. {
  6471. PGresult *res;
  6472. int ntups;
  6473. int i;
  6474. PQExpBuffer query;
  6475. ForeignServerInfo *srvinfo;
  6476. int i_tableoid;
  6477. int i_oid;
  6478. int i_srvname;
  6479. int i_rolname;
  6480. int i_srvfdw;
  6481. int i_srvtype;
  6482. int i_srvversion;
  6483. int i_srvacl;
  6484. int i_srvoptions;
  6485. /* Before 8.4, there are no foreign servers */
  6486. if (fout->remoteVersion < 80400)
  6487. {
  6488. *numForeignServers = 0;
  6489. return NULL;
  6490. }
  6491. query = createPQExpBuffer();
  6492. /* Make sure we are in proper schema */
  6493. selectSourceSchema(fout, "pg_catalog");
  6494. appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
  6495. "(%s srvowner) AS rolname, "
  6496. "srvfdw, srvtype, srvversion, srvacl,"
  6497. "array_to_string(ARRAY("
  6498. "SELECT quote_ident(option_name) || ' ' || "
  6499. "quote_literal(option_value) "
  6500. "FROM pg_options_to_table(srvoptions) "
  6501. "ORDER BY option_name"
  6502. "), E',\n ') AS srvoptions "
  6503. "FROM pg_foreign_server",
  6504. username_subquery);
  6505. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  6506. ntups = PQntuples(res);
  6507. *numForeignServers = ntups;
  6508. srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
  6509. i_tableoid = PQfnumber(res, "tableoid");
  6510. i_oid = PQfnumber(res, "oid");
  6511. i_srvname = PQfnumber(res, "srvname");
  6512. i_rolname = PQfnumber(res, "rolname");
  6513. i_srvfdw = PQfnumber(res, "srvfdw");
  6514. i_srvtype = PQfnumber(res, "srvtype");
  6515. i_srvversion = PQfnumber(res, "srvversion");
  6516. i_srvacl = PQfnumber(res, "srvacl");
  6517. i_srvoptions = PQfnumber(res, "srvoptions");
  6518. for (i = 0; i < ntups; i++)
  6519. {
  6520. srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
  6521. srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  6522. srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  6523. AssignDumpId(&srvinfo[i].dobj);
  6524. srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
  6525. srvinfo[i].dobj.namespace = NULL;
  6526. srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
  6527. srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
  6528. srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
  6529. srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
  6530. srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
  6531. srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
  6532. /* Decide whether we want to dump it */
  6533. selectDumpableObject(&(srvinfo[i].dobj));
  6534. }
  6535. PQclear(res);
  6536. destroyPQExpBuffer(query);
  6537. return srvinfo;
  6538. }
  6539. /*
  6540. * getDefaultACLs:
  6541. * read all default ACL information in the system catalogs and return
  6542. * them in the DefaultACLInfo structure
  6543. *
  6544. * numDefaultACLs is set to the number of ACLs read in
  6545. */
  6546. DefaultACLInfo *
  6547. getDefaultACLs(Archive *fout, int *numDefaultACLs)
  6548. {
  6549. DefaultACLInfo *daclinfo;
  6550. PQExpBuffer query;
  6551. PGresult *res;
  6552. int i_oid;
  6553. int i_tableoid;
  6554. int i_defaclrole;
  6555. int i_defaclnamespace;
  6556. int i_defaclobjtype;
  6557. int i_defaclacl;
  6558. int i,
  6559. ntups;
  6560. if (fout->remoteVersion < 90000)
  6561. {
  6562. *numDefaultACLs = 0;
  6563. return NULL;
  6564. }
  6565. query = createPQExpBuffer();
  6566. /* Make sure we are in proper schema */
  6567. selectSourceSchema(fout, "pg_catalog");
  6568. appendPQExpBuffer(query, "SELECT oid, tableoid, "
  6569. "(%s defaclrole) AS defaclrole, "
  6570. "defaclnamespace, "
  6571. "defaclobjtype, "
  6572. "defaclacl "
  6573. "FROM pg_default_acl",
  6574. username_subquery);
  6575. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  6576. ntups = PQntuples(res);
  6577. *numDefaultACLs = ntups;
  6578. daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
  6579. i_oid = PQfnumber(res, "oid");
  6580. i_tableoid = PQfnumber(res, "tableoid");
  6581. i_defaclrole = PQfnumber(res, "defaclrole");
  6582. i_defaclnamespace = PQfnumber(res, "defaclnamespace");
  6583. i_defaclobjtype = PQfnumber(res, "defaclobjtype");
  6584. i_defaclacl = PQfnumber(res, "defaclacl");
  6585. for (i = 0; i < ntups; i++)
  6586. {
  6587. Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
  6588. daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
  6589. daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
  6590. daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
  6591. AssignDumpId(&daclinfo[i].dobj);
  6592. /* cheesy ... is it worth coming up with a better object name? */
  6593. daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
  6594. if (nspid != InvalidOid)
  6595. daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
  6596. daclinfo[i].dobj.catId.oid);
  6597. else
  6598. daclinfo[i].dobj.namespace = NULL;
  6599. daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
  6600. daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
  6601. daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
  6602. /* Decide whether we want to dump it */
  6603. selectDumpableDefaultACL(&(daclinfo[i]));
  6604. }
  6605. PQclear(res);
  6606. destroyPQExpBuffer(query);
  6607. return daclinfo;
  6608. }
  6609. /*
  6610. * dumpComment --
  6611. *
  6612. * This routine is used to dump any comments associated with the
  6613. * object handed to this routine. The routine takes a constant character
  6614. * string for the target part of the comment-creation command, plus
  6615. * the namespace and owner of the object (for labeling the ArchiveEntry),
  6616. * plus catalog ID and subid which are the lookup key for pg_description,
  6617. * plus the dump ID for the object (for setting a dependency).
  6618. * If a matching pg_description entry is found, it is dumped.
  6619. *
  6620. * Note: although this routine takes a dumpId for dependency purposes,
  6621. * that purpose is just to mark the dependency in the emitted dump file
  6622. * for possible future use by pg_restore. We do NOT use it for determining
  6623. * ordering of the comment in the dump file, because this routine is called
  6624. * after dependency sorting occurs. This routine should be called just after
  6625. * calling ArchiveEntry() for the specified object.
  6626. */
  6627. static void
  6628. dumpComment(Archive *fout, const char *target,
  6629. const char *namespace, const char *owner,
  6630. CatalogId catalogId, int subid, DumpId dumpId)
  6631. {
  6632. CommentItem *comments;
  6633. int ncomments;
  6634. /* Comments are schema not data ... except blob comments are data */
  6635. if (strncmp(target, "LARGE OBJECT ", 13) != 0)
  6636. {
  6637. if (dataOnly)
  6638. return;
  6639. }
  6640. else
  6641. {
  6642. if (schemaOnly)
  6643. return;
  6644. }
  6645. /* Search for comments associated with catalogId, using table */
  6646. ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
  6647. &comments);
  6648. /* Is there one matching the subid? */
  6649. while (ncomments > 0)
  6650. {
  6651. if (comments->objsubid == subid)
  6652. break;
  6653. comments++;
  6654. ncomments--;
  6655. }
  6656. /* If a comment exists, build COMMENT ON statement */
  6657. if (ncomments > 0)
  6658. {
  6659. PQExpBuffer query = createPQExpBuffer();
  6660. appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
  6661. appendStringLiteralAH(query, comments->descr, fout);
  6662. appendPQExpBufferStr(query, ";\n");
  6663. /*
  6664. * We mark comments as SECTION_NONE because they really belong in the
  6665. * same section as their parent, whether that is pre-data or
  6666. * post-data.
  6667. */
  6668. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  6669. target, namespace, NULL, owner,
  6670. false, "COMMENT", SECTION_NONE,
  6671. query->data, "", NULL,
  6672. &(dumpId), 1,
  6673. NULL, NULL);
  6674. destroyPQExpBuffer(query);
  6675. }
  6676. }
  6677. /*
  6678. * dumpTableComment --
  6679. *
  6680. * As above, but dump comments for both the specified table (or view)
  6681. * and its columns.
  6682. */
  6683. static void
  6684. dumpTableComment(Archive *fout, TableInfo *tbinfo,
  6685. const char *reltypename)
  6686. {
  6687. CommentItem *comments;
  6688. int ncomments;
  6689. PQExpBuffer query;
  6690. PQExpBuffer target;
  6691. /* Comments are SCHEMA not data */
  6692. if (dataOnly)
  6693. return;
  6694. /* Search for comments associated with relation, using table */
  6695. ncomments = findComments(fout,
  6696. tbinfo->dobj.catId.tableoid,
  6697. tbinfo->dobj.catId.oid,
  6698. &comments);
  6699. /* If comments exist, build COMMENT ON statements */
  6700. if (ncomments <= 0)
  6701. return;
  6702. query = createPQExpBuffer();
  6703. target = createPQExpBuffer();
  6704. while (ncomments > 0)
  6705. {
  6706. const char *descr = comments->descr;
  6707. int objsubid = comments->objsubid;
  6708. if (objsubid == 0)
  6709. {
  6710. resetPQExpBuffer(target);
  6711. appendPQExpBuffer(target, "%s %s", reltypename,
  6712. fmtId(tbinfo->dobj.name));
  6713. resetPQExpBuffer(query);
  6714. appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
  6715. appendStringLiteralAH(query, descr, fout);
  6716. appendPQExpBufferStr(query, ";\n");
  6717. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  6718. target->data,
  6719. tbinfo->dobj.namespace->dobj.name,
  6720. NULL, tbinfo->rolname,
  6721. false, "COMMENT", SECTION_NONE,
  6722. query->data, "", NULL,
  6723. &(tbinfo->dobj.dumpId), 1,
  6724. NULL, NULL);
  6725. }
  6726. else if (objsubid > 0 && objsubid <= tbinfo->numatts)
  6727. {
  6728. resetPQExpBuffer(target);
  6729. appendPQExpBuffer(target, "COLUMN %s.",
  6730. fmtId(tbinfo->dobj.name));
  6731. appendPQExpBufferStr(target, fmtId(tbinfo->attnames[objsubid - 1]));
  6732. resetPQExpBuffer(query);
  6733. appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
  6734. appendStringLiteralAH(query, descr, fout);
  6735. appendPQExpBufferStr(query, ";\n");
  6736. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  6737. target->data,
  6738. tbinfo->dobj.namespace->dobj.name,
  6739. NULL, tbinfo->rolname,
  6740. false, "COMMENT", SECTION_NONE,
  6741. query->data, "", NULL,
  6742. &(tbinfo->dobj.dumpId), 1,
  6743. NULL, NULL);
  6744. }
  6745. comments++;
  6746. ncomments--;
  6747. }
  6748. destroyPQExpBuffer(query);
  6749. destroyPQExpBuffer(target);
  6750. }
  6751. /*
  6752. * findComments --
  6753. *
  6754. * Find the comment(s), if any, associated with the given object. All the
  6755. * objsubid values associated with the given classoid/objoid are found with
  6756. * one search.
  6757. */
  6758. static int
  6759. findComments(Archive *fout, Oid classoid, Oid objoid,
  6760. CommentItem **items)
  6761. {
  6762. /* static storage for table of comments */
  6763. static CommentItem *comments = NULL;
  6764. static int ncomments = -1;
  6765. CommentItem *middle = NULL;
  6766. CommentItem *low;
  6767. CommentItem *high;
  6768. int nmatch;
  6769. /* Get comments if we didn't already */
  6770. if (ncomments < 0)
  6771. ncomments = collectComments(fout, &comments);
  6772. /*
  6773. * Pre-7.2, pg_description does not contain classoid, so collectComments
  6774. * just stores a zero. If there's a collision on object OID, well, you
  6775. * get duplicate comments.
  6776. */
  6777. if (fout->remoteVersion < 70200)
  6778. classoid = 0;
  6779. /*
  6780. * Do binary search to find some item matching the object.
  6781. */
  6782. low = &comments[0];
  6783. high = &comments[ncomments - 1];
  6784. while (low <= high)
  6785. {
  6786. middle = low + (high - low) / 2;
  6787. if (classoid < middle->classoid)
  6788. high = middle - 1;
  6789. else if (classoid > middle->classoid)
  6790. low = middle + 1;
  6791. else if (objoid < middle->objoid)
  6792. high = middle - 1;
  6793. else if (objoid > middle->objoid)
  6794. low = middle + 1;
  6795. else
  6796. break; /* found a match */
  6797. }
  6798. if (low > high) /* no matches */
  6799. {
  6800. *items = NULL;
  6801. return 0;
  6802. }
  6803. /*
  6804. * Now determine how many items match the object. The search loop
  6805. * invariant still holds: only items between low and high inclusive could
  6806. * match.
  6807. */
  6808. nmatch = 1;
  6809. while (middle > low)
  6810. {
  6811. if (classoid != middle[-1].classoid ||
  6812. objoid != middle[-1].objoid)
  6813. break;
  6814. middle--;
  6815. nmatch++;
  6816. }
  6817. *items = middle;
  6818. middle += nmatch;
  6819. while (middle <= high)
  6820. {
  6821. if (classoid != middle->classoid ||
  6822. objoid != middle->objoid)
  6823. break;
  6824. middle++;
  6825. nmatch++;
  6826. }
  6827. return nmatch;
  6828. }
  6829. /*
  6830. * collectComments --
  6831. *
  6832. * Construct a table of all comments available for database objects.
  6833. * We used to do per-object queries for the comments, but it's much faster
  6834. * to pull them all over at once, and on most databases the memory cost
  6835. * isn't high.
  6836. *
  6837. * The table is sorted by classoid/objid/objsubid for speed in lookup.
  6838. */
  6839. static int
  6840. collectComments(Archive *fout, CommentItem **items)
  6841. {
  6842. PGresult *res;
  6843. PQExpBuffer query;
  6844. int i_description;
  6845. int i_classoid;
  6846. int i_objoid;
  6847. int i_objsubid;
  6848. int ntups;
  6849. int i;
  6850. CommentItem *comments;
  6851. /*
  6852. * Note we do NOT change source schema here; preserve the caller's
  6853. * setting, instead.
  6854. */
  6855. query = createPQExpBuffer();
  6856. if (fout->remoteVersion >= 70300)
  6857. {
  6858. appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
  6859. "FROM pg_catalog.pg_description "
  6860. "ORDER BY classoid, objoid, objsubid");
  6861. }
  6862. else if (fout->remoteVersion >= 70200)
  6863. {
  6864. appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
  6865. "FROM pg_description "
  6866. "ORDER BY classoid, objoid, objsubid");
  6867. }
  6868. else
  6869. {
  6870. /* Note: this will fail to find attribute comments in pre-7.2... */
  6871. appendPQExpBufferStr(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
  6872. "FROM pg_description "
  6873. "ORDER BY objoid");
  6874. }
  6875. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  6876. /* Construct lookup table containing OIDs in numeric form */
  6877. i_description = PQfnumber(res, "description");
  6878. i_classoid = PQfnumber(res, "classoid");
  6879. i_objoid = PQfnumber(res, "objoid");
  6880. i_objsubid = PQfnumber(res, "objsubid");
  6881. ntups = PQntuples(res);
  6882. comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
  6883. for (i = 0; i < ntups; i++)
  6884. {
  6885. comments[i].descr = PQgetvalue(res, i, i_description);
  6886. comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
  6887. comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
  6888. comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
  6889. }
  6890. /* Do NOT free the PGresult since we are keeping pointers into it */
  6891. destroyPQExpBuffer(query);
  6892. *items = comments;
  6893. return ntups;
  6894. }
  6895. /*
  6896. * dumpDumpableObject
  6897. *
  6898. * This routine and its subsidiaries are responsible for creating
  6899. * ArchiveEntries (TOC objects) for each object to be dumped.
  6900. */
  6901. static void
  6902. dumpDumpableObject(Archive *fout, DumpableObject *dobj)
  6903. {
  6904. switch (dobj->objType)
  6905. {
  6906. case DO_NAMESPACE:
  6907. dumpNamespace(fout, (NamespaceInfo *) dobj);
  6908. break;
  6909. case DO_EXTENSION:
  6910. dumpExtension(fout, (ExtensionInfo *) dobj);
  6911. break;
  6912. case DO_TYPE:
  6913. dumpType(fout, (TypeInfo *) dobj);
  6914. break;
  6915. case DO_SHELL_TYPE:
  6916. dumpShellType(fout, (ShellTypeInfo *) dobj);
  6917. break;
  6918. case DO_FUNC:
  6919. dumpFunc(fout, (FuncInfo *) dobj);
  6920. break;
  6921. case DO_AGG:
  6922. dumpAgg(fout, (AggInfo *) dobj);
  6923. break;
  6924. case DO_OPERATOR:
  6925. dumpOpr(fout, (OprInfo *) dobj);
  6926. break;
  6927. case DO_OPCLASS:
  6928. dumpOpclass(fout, (OpclassInfo *) dobj);
  6929. break;
  6930. case DO_OPFAMILY:
  6931. dumpOpfamily(fout, (OpfamilyInfo *) dobj);
  6932. break;
  6933. case DO_COLLATION:
  6934. dumpCollation(fout, (CollInfo *) dobj);
  6935. break;
  6936. case DO_CONVERSION:
  6937. dumpConversion(fout, (ConvInfo *) dobj);
  6938. break;
  6939. case DO_TABLE:
  6940. dumpTable(fout, (TableInfo *) dobj);
  6941. break;
  6942. case DO_ATTRDEF:
  6943. dumpAttrDef(fout, (AttrDefInfo *) dobj);
  6944. break;
  6945. case DO_INDEX:
  6946. dumpIndex(fout, (IndxInfo *) dobj);
  6947. break;
  6948. case DO_REFRESH_MATVIEW:
  6949. refreshMatViewData(fout, (TableDataInfo *) dobj);
  6950. break;
  6951. case DO_RULE:
  6952. dumpRule(fout, (RuleInfo *) dobj);
  6953. break;
  6954. case DO_TRIGGER:
  6955. dumpTrigger(fout, (TriggerInfo *) dobj);
  6956. break;
  6957. case DO_EVENT_TRIGGER:
  6958. dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
  6959. break;
  6960. case DO_CONSTRAINT:
  6961. dumpConstraint(fout, (ConstraintInfo *) dobj);
  6962. break;
  6963. case DO_FK_CONSTRAINT:
  6964. dumpConstraint(fout, (ConstraintInfo *) dobj);
  6965. break;
  6966. case DO_PROCLANG:
  6967. dumpProcLang(fout, (ProcLangInfo *) dobj);
  6968. break;
  6969. case DO_CAST:
  6970. dumpCast(fout, (CastInfo *) dobj);
  6971. break;
  6972. case DO_TABLE_DATA:
  6973. if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
  6974. dumpSequenceData(fout, (TableDataInfo *) dobj);
  6975. else
  6976. dumpTableData(fout, (TableDataInfo *) dobj);
  6977. break;
  6978. case DO_DUMMY_TYPE:
  6979. /* table rowtypes and array types are never dumped separately */
  6980. break;
  6981. case DO_TSPARSER:
  6982. dumpTSParser(fout, (TSParserInfo *) dobj);
  6983. break;
  6984. case DO_TSDICT:
  6985. dumpTSDictionary(fout, (TSDictInfo *) dobj);
  6986. break;
  6987. case DO_TSTEMPLATE:
  6988. dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
  6989. break;
  6990. case DO_TSCONFIG:
  6991. dumpTSConfig(fout, (TSConfigInfo *) dobj);
  6992. break;
  6993. case DO_FDW:
  6994. dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
  6995. break;
  6996. case DO_FOREIGN_SERVER:
  6997. dumpForeignServer(fout, (ForeignServerInfo *) dobj);
  6998. break;
  6999. case DO_DEFAULT_ACL:
  7000. dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
  7001. break;
  7002. case DO_BLOB:
  7003. dumpBlob(fout, (BlobInfo *) dobj);
  7004. break;
  7005. case DO_BLOB_DATA:
  7006. ArchiveEntry(fout, dobj->catId, dobj->dumpId,
  7007. dobj->name, NULL, NULL, "",
  7008. false, "BLOBS", SECTION_DATA,
  7009. "", "", NULL,
  7010. NULL, 0,
  7011. dumpBlobs, NULL);
  7012. break;
  7013. case DO_PRE_DATA_BOUNDARY:
  7014. case DO_POST_DATA_BOUNDARY:
  7015. /* never dumped, nothing to do */
  7016. break;
  7017. }
  7018. }
  7019. /*
  7020. * dumpNamespace
  7021. * writes out to fout the queries to recreate a user-defined namespace
  7022. */
  7023. static void
  7024. dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
  7025. {
  7026. PQExpBuffer q;
  7027. PQExpBuffer delq;
  7028. PQExpBuffer labelq;
  7029. char *qnspname;
  7030. /* Skip if not to be dumped */
  7031. if (!nspinfo->dobj.dump || dataOnly)
  7032. return;
  7033. /* don't dump dummy namespace from pre-7.3 source */
  7034. if (strlen(nspinfo->dobj.name) == 0)
  7035. return;
  7036. q = createPQExpBuffer();
  7037. delq = createPQExpBuffer();
  7038. labelq = createPQExpBuffer();
  7039. qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
  7040. appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
  7041. appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
  7042. appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
  7043. if (binary_upgrade)
  7044. binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
  7045. ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
  7046. nspinfo->dobj.name,
  7047. NULL, NULL,
  7048. nspinfo->rolname,
  7049. false, "SCHEMA", SECTION_PRE_DATA,
  7050. q->data, delq->data, NULL,
  7051. NULL, 0,
  7052. NULL, NULL);
  7053. /* Dump Schema Comments and Security Labels */
  7054. dumpComment(fout, labelq->data,
  7055. NULL, nspinfo->rolname,
  7056. nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
  7057. dumpSecLabel(fout, labelq->data,
  7058. NULL, nspinfo->rolname,
  7059. nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
  7060. dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
  7061. qnspname, NULL, nspinfo->dobj.name, NULL,
  7062. nspinfo->rolname, nspinfo->nspacl);
  7063. free(qnspname);
  7064. destroyPQExpBuffer(q);
  7065. destroyPQExpBuffer(delq);
  7066. destroyPQExpBuffer(labelq);
  7067. }
  7068. /*
  7069. * dumpExtension
  7070. * writes out to fout the queries to recreate an extension
  7071. */
  7072. static void
  7073. dumpExtension(Archive *fout, ExtensionInfo *extinfo)
  7074. {
  7075. PQExpBuffer q;
  7076. PQExpBuffer delq;
  7077. PQExpBuffer labelq;
  7078. char *qextname;
  7079. /* Skip if not to be dumped */
  7080. if (!extinfo->dobj.dump || dataOnly)
  7081. return;
  7082. q = createPQExpBuffer();
  7083. delq = createPQExpBuffer();
  7084. labelq = createPQExpBuffer();
  7085. qextname = pg_strdup(fmtId(extinfo->dobj.name));
  7086. appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
  7087. if (!binary_upgrade)
  7088. {
  7089. /*
  7090. * In a regular dump, we use IF NOT EXISTS so that there isn't a
  7091. * problem if the extension already exists in the target database;
  7092. * this is essential for installed-by-default extensions such as
  7093. * plpgsql.
  7094. *
  7095. * In binary-upgrade mode, that doesn't work well, so instead we skip
  7096. * built-in extensions based on their OIDs; see
  7097. * selectDumpableExtension.
  7098. */
  7099. appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
  7100. qextname, fmtId(extinfo->namespace));
  7101. }
  7102. else
  7103. {
  7104. int i;
  7105. int n;
  7106. appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
  7107. /*
  7108. * We unconditionally create the extension, so we must drop it if it
  7109. * exists. This could happen if the user deleted 'plpgsql' and then
  7110. * readded it, causing its oid to be greater than FirstNormalObjectId.
  7111. * The FirstNormalObjectId test was kept to avoid repeatedly dropping
  7112. * and recreating extensions like 'plpgsql'.
  7113. */
  7114. appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
  7115. appendPQExpBufferStr(q,
  7116. "SELECT binary_upgrade.create_empty_extension(");
  7117. appendStringLiteralAH(q, extinfo->dobj.name, fout);
  7118. appendPQExpBufferStr(q, ", ");
  7119. appendStringLiteralAH(q, extinfo->namespace, fout);
  7120. appendPQExpBufferStr(q, ", ");
  7121. appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
  7122. appendStringLiteralAH(q, extinfo->extversion, fout);
  7123. appendPQExpBufferStr(q, ", ");
  7124. /*
  7125. * Note that we're pushing extconfig (an OID array) back into
  7126. * pg_extension exactly as-is. This is OK because pg_class OIDs are
  7127. * preserved in binary upgrade.
  7128. */
  7129. if (strlen(extinfo->extconfig) > 2)
  7130. appendStringLiteralAH(q, extinfo->extconfig, fout);
  7131. else
  7132. appendPQExpBufferStr(q, "NULL");
  7133. appendPQExpBufferStr(q, ", ");
  7134. if (strlen(extinfo->extcondition) > 2)
  7135. appendStringLiteralAH(q, extinfo->extcondition, fout);
  7136. else
  7137. appendPQExpBufferStr(q, "NULL");
  7138. appendPQExpBufferStr(q, ", ");
  7139. appendPQExpBufferStr(q, "ARRAY[");
  7140. n = 0;
  7141. for (i = 0; i < extinfo->dobj.nDeps; i++)
  7142. {
  7143. DumpableObject *extobj;
  7144. extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
  7145. if (extobj && extobj->objType == DO_EXTENSION)
  7146. {
  7147. if (n++ > 0)
  7148. appendPQExpBufferChar(q, ',');
  7149. appendStringLiteralAH(q, extobj->name, fout);
  7150. }
  7151. }
  7152. appendPQExpBufferStr(q, "]::pg_catalog.text[]");
  7153. appendPQExpBufferStr(q, ");\n");
  7154. }
  7155. appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
  7156. ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
  7157. extinfo->dobj.name,
  7158. NULL, NULL,
  7159. "",
  7160. false, "EXTENSION", SECTION_PRE_DATA,
  7161. q->data, delq->data, NULL,
  7162. NULL, 0,
  7163. NULL, NULL);
  7164. /* Dump Extension Comments and Security Labels */
  7165. dumpComment(fout, labelq->data,
  7166. NULL, "",
  7167. extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
  7168. dumpSecLabel(fout, labelq->data,
  7169. NULL, "",
  7170. extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
  7171. free(qextname);
  7172. destroyPQExpBuffer(q);
  7173. destroyPQExpBuffer(delq);
  7174. destroyPQExpBuffer(labelq);
  7175. }
  7176. /*
  7177. * dumpType
  7178. * writes out to fout the queries to recreate a user-defined type
  7179. */
  7180. static void
  7181. dumpType(Archive *fout, TypeInfo *tyinfo)
  7182. {
  7183. /* Skip if not to be dumped */
  7184. if (!tyinfo->dobj.dump || dataOnly)
  7185. return;
  7186. /* Dump out in proper style */
  7187. if (tyinfo->typtype == TYPTYPE_BASE)
  7188. dumpBaseType(fout, tyinfo);
  7189. else if (tyinfo->typtype == TYPTYPE_DOMAIN)
  7190. dumpDomain(fout, tyinfo);
  7191. else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
  7192. dumpCompositeType(fout, tyinfo);
  7193. else if (tyinfo->typtype == TYPTYPE_ENUM)
  7194. dumpEnumType(fout, tyinfo);
  7195. else if (tyinfo->typtype == TYPTYPE_RANGE)
  7196. dumpRangeType(fout, tyinfo);
  7197. else
  7198. write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
  7199. tyinfo->dobj.name);
  7200. }
  7201. /*
  7202. * dumpEnumType
  7203. * writes out to fout the queries to recreate a user-defined enum type
  7204. */
  7205. static void
  7206. dumpEnumType(Archive *fout, TypeInfo *tyinfo)
  7207. {
  7208. PQExpBuffer q = createPQExpBuffer();
  7209. PQExpBuffer delq = createPQExpBuffer();
  7210. PQExpBuffer labelq = createPQExpBuffer();
  7211. PQExpBuffer query = createPQExpBuffer();
  7212. PGresult *res;
  7213. int num,
  7214. i;
  7215. Oid enum_oid;
  7216. char *qtypname;
  7217. char *label;
  7218. /* Set proper schema search path */
  7219. selectSourceSchema(fout, "pg_catalog");
  7220. if (fout->remoteVersion >= 90100)
  7221. appendPQExpBuffer(query, "SELECT oid, enumlabel "
  7222. "FROM pg_catalog.pg_enum "
  7223. "WHERE enumtypid = '%u'"
  7224. "ORDER BY enumsortorder",
  7225. tyinfo->dobj.catId.oid);
  7226. else
  7227. appendPQExpBuffer(query, "SELECT oid, enumlabel "
  7228. "FROM pg_catalog.pg_enum "
  7229. "WHERE enumtypid = '%u'"
  7230. "ORDER BY oid",
  7231. tyinfo->dobj.catId.oid);
  7232. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  7233. num = PQntuples(res);
  7234. qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
  7235. /*
  7236. * DROP must be fully qualified in case same name appears in pg_catalog.
  7237. * CASCADE shouldn't be required here as for normal types since the I/O
  7238. * functions are generic and do not get dropped.
  7239. */
  7240. appendPQExpBuffer(delq, "DROP TYPE %s.",
  7241. fmtId(tyinfo->dobj.namespace->dobj.name));
  7242. appendPQExpBuffer(delq, "%s;\n",
  7243. qtypname);
  7244. if (binary_upgrade)
  7245. binary_upgrade_set_type_oids_by_type_oid(fout, q,
  7246. tyinfo->dobj.catId.oid);
  7247. appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
  7248. qtypname);
  7249. if (!binary_upgrade)
  7250. {
  7251. /* Labels with server-assigned oids */
  7252. for (i = 0; i < num; i++)
  7253. {
  7254. label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
  7255. if (i > 0)
  7256. appendPQExpBufferChar(q, ',');
  7257. appendPQExpBufferStr(q, "\n ");
  7258. appendStringLiteralAH(q, label, fout);
  7259. }
  7260. }
  7261. appendPQExpBufferStr(q, "\n);\n");
  7262. if (binary_upgrade)
  7263. {
  7264. /* Labels with dump-assigned (preserved) oids */
  7265. for (i = 0; i < num; i++)
  7266. {
  7267. enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
  7268. label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
  7269. if (i == 0)
  7270. appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
  7271. appendPQExpBuffer(q,
  7272. "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
  7273. enum_oid);
  7274. appendPQExpBuffer(q, "ALTER TYPE %s.",
  7275. fmtId(tyinfo->dobj.namespace->dobj.name));
  7276. appendPQExpBuffer(q, "%s ADD VALUE ",
  7277. qtypname);
  7278. appendStringLiteralAH(q, label, fout);
  7279. appendPQExpBufferStr(q, ";\n\n");
  7280. }
  7281. }
  7282. appendPQExpBuffer(labelq, "TYPE %s", qtypname);
  7283. if (binary_upgrade)
  7284. binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
  7285. ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
  7286. tyinfo->dobj.name,
  7287. tyinfo->dobj.namespace->dobj.name,
  7288. NULL,
  7289. tyinfo->rolname, false,
  7290. "TYPE", SECTION_PRE_DATA,
  7291. q->data, delq->data, NULL,
  7292. NULL, 0,
  7293. NULL, NULL);
  7294. /* Dump Type Comments and Security Labels */
  7295. dumpComment(fout, labelq->data,
  7296. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  7297. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  7298. dumpSecLabel(fout, labelq->data,
  7299. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  7300. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  7301. dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
  7302. qtypname, NULL, tyinfo->dobj.name,
  7303. tyinfo->dobj.namespace->dobj.name,
  7304. tyinfo->rolname, tyinfo->typacl);
  7305. PQclear(res);
  7306. destroyPQExpBuffer(q);
  7307. destroyPQExpBuffer(delq);
  7308. destroyPQExpBuffer(labelq);
  7309. destroyPQExpBuffer(query);
  7310. }
  7311. /*
  7312. * dumpRangeType
  7313. * writes out to fout the queries to recreate a user-defined range type
  7314. */
  7315. static void
  7316. dumpRangeType(Archive *fout, TypeInfo *tyinfo)
  7317. {
  7318. PQExpBuffer q = createPQExpBuffer();
  7319. PQExpBuffer delq = createPQExpBuffer();
  7320. PQExpBuffer labelq = createPQExpBuffer();
  7321. PQExpBuffer query = createPQExpBuffer();
  7322. PGresult *res;
  7323. Oid collationOid;
  7324. char *qtypname;
  7325. char *procname;
  7326. /*
  7327. * select appropriate schema to ensure names in CREATE are properly
  7328. * qualified
  7329. */
  7330. selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
  7331. appendPQExpBuffer(query,
  7332. "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
  7333. "opc.opcname AS opcname, "
  7334. "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
  7335. " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
  7336. "opc.opcdefault, "
  7337. "CASE WHEN rngcollation = st.typcollation THEN 0 "
  7338. " ELSE rngcollation END AS collation, "
  7339. "rngcanonical, rngsubdiff "
  7340. "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
  7341. " pg_catalog.pg_opclass opc "
  7342. "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
  7343. "rngtypid = '%u'",
  7344. tyinfo->dobj.catId.oid);
  7345. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  7346. qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
  7347. /*
  7348. * DROP must be fully qualified in case same name appears in pg_catalog.
  7349. * CASCADE shouldn't be required here as for normal types since the I/O
  7350. * functions are generic and do not get dropped.
  7351. */
  7352. appendPQExpBuffer(delq, "DROP TYPE %s.",
  7353. fmtId(tyinfo->dobj.namespace->dobj.name));
  7354. appendPQExpBuffer(delq, "%s;\n",
  7355. qtypname);
  7356. if (binary_upgrade)
  7357. binary_upgrade_set_type_oids_by_type_oid(fout,
  7358. q, tyinfo->dobj.catId.oid);
  7359. appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
  7360. qtypname);
  7361. appendPQExpBuffer(q, "\n subtype = %s",
  7362. PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
  7363. /* print subtype_opclass only if not default for subtype */
  7364. if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
  7365. {
  7366. char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
  7367. char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
  7368. /* always schema-qualify, don't try to be smart */
  7369. appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
  7370. fmtId(nspname));
  7371. appendPQExpBufferStr(q, fmtId(opcname));
  7372. }
  7373. collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
  7374. if (OidIsValid(collationOid))
  7375. {
  7376. CollInfo *coll = findCollationByOid(collationOid);
  7377. if (coll)
  7378. {
  7379. /* always schema-qualify, don't try to be smart */
  7380. appendPQExpBuffer(q, ",\n collation = %s.",
  7381. fmtId(coll->dobj.namespace->dobj.name));
  7382. appendPQExpBufferStr(q, fmtId(coll->dobj.name));
  7383. }
  7384. }
  7385. procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
  7386. if (strcmp(procname, "-") != 0)
  7387. appendPQExpBuffer(q, ",\n canonical = %s", procname);
  7388. procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
  7389. if (strcmp(procname, "-") != 0)
  7390. appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
  7391. appendPQExpBufferStr(q, "\n);\n");
  7392. appendPQExpBuffer(labelq, "TYPE %s", qtypname);
  7393. if (binary_upgrade)
  7394. binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
  7395. ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
  7396. tyinfo->dobj.name,
  7397. tyinfo->dobj.namespace->dobj.name,
  7398. NULL,
  7399. tyinfo->rolname, false,
  7400. "TYPE", SECTION_PRE_DATA,
  7401. q->data, delq->data, NULL,
  7402. NULL, 0,
  7403. NULL, NULL);
  7404. /* Dump Type Comments and Security Labels */
  7405. dumpComment(fout, labelq->data,
  7406. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  7407. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  7408. dumpSecLabel(fout, labelq->data,
  7409. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  7410. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  7411. dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
  7412. qtypname, NULL, tyinfo->dobj.name,
  7413. tyinfo->dobj.namespace->dobj.name,
  7414. tyinfo->rolname, tyinfo->typacl);
  7415. PQclear(res);
  7416. destroyPQExpBuffer(q);
  7417. destroyPQExpBuffer(delq);
  7418. destroyPQExpBuffer(labelq);
  7419. destroyPQExpBuffer(query);
  7420. }
  7421. /*
  7422. * dumpBaseType
  7423. * writes out to fout the queries to recreate a user-defined base type
  7424. */
  7425. static void
  7426. dumpBaseType(Archive *fout, TypeInfo *tyinfo)
  7427. {
  7428. PQExpBuffer q = createPQExpBuffer();
  7429. PQExpBuffer delq = createPQExpBuffer();
  7430. PQExpBuffer labelq = createPQExpBuffer();
  7431. PQExpBuffer query = createPQExpBuffer();
  7432. PGresult *res;
  7433. char *qtypname;
  7434. char *typlen;
  7435. char *typinput;
  7436. char *typoutput;
  7437. char *typreceive;
  7438. char *typsend;
  7439. char *typmodin;
  7440. char *typmodout;
  7441. char *typanalyze;
  7442. Oid typreceiveoid;
  7443. Oid typsendoid;
  7444. Oid typmodinoid;
  7445. Oid typmodoutoid;
  7446. Oid typanalyzeoid;
  7447. char *typcategory;
  7448. char *typispreferred;
  7449. char *typdelim;
  7450. char *typbyval;
  7451. char *typalign;
  7452. char *typstorage;
  7453. char *typcollatable;
  7454. char *typdefault;
  7455. bool typdefault_is_literal = false;
  7456. /* Set proper schema search path so regproc references list correctly */
  7457. selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
  7458. /* Fetch type-specific details */
  7459. if (fout->remoteVersion >= 90100)
  7460. {
  7461. appendPQExpBuffer(query, "SELECT typlen, "
  7462. "typinput, typoutput, typreceive, typsend, "
  7463. "typmodin, typmodout, typanalyze, "
  7464. "typreceive::pg_catalog.oid AS typreceiveoid, "
  7465. "typsend::pg_catalog.oid AS typsendoid, "
  7466. "typmodin::pg_catalog.oid AS typmodinoid, "
  7467. "typmodout::pg_catalog.oid AS typmodoutoid, "
  7468. "typanalyze::pg_catalog.oid AS typanalyzeoid, "
  7469. "typcategory, typispreferred, "
  7470. "typdelim, typbyval, typalign, typstorage, "
  7471. "(typcollation <> 0) AS typcollatable, "
  7472. "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
  7473. "FROM pg_catalog.pg_type "
  7474. "WHERE oid = '%u'::pg_catalog.oid",
  7475. tyinfo->dobj.catId.oid);
  7476. }
  7477. else if (fout->remoteVersion >= 80400)
  7478. {
  7479. appendPQExpBuffer(query, "SELECT typlen, "
  7480. "typinput, typoutput, typreceive, typsend, "
  7481. "typmodin, typmodout, typanalyze, "
  7482. "typreceive::pg_catalog.oid AS typreceiveoid, "
  7483. "typsend::pg_catalog.oid AS typsendoid, "
  7484. "typmodin::pg_catalog.oid AS typmodinoid, "
  7485. "typmodout::pg_catalog.oid AS typmodoutoid, "
  7486. "typanalyze::pg_catalog.oid AS typanalyzeoid, "
  7487. "typcategory, typispreferred, "
  7488. "typdelim, typbyval, typalign, typstorage, "
  7489. "false AS typcollatable, "
  7490. "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
  7491. "FROM pg_catalog.pg_type "
  7492. "WHERE oid = '%u'::pg_catalog.oid",
  7493. tyinfo->dobj.catId.oid);
  7494. }
  7495. else if (fout->remoteVersion >= 80300)
  7496. {
  7497. /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
  7498. appendPQExpBuffer(query, "SELECT typlen, "
  7499. "typinput, typoutput, typreceive, typsend, "
  7500. "typmodin, typmodout, typanalyze, "
  7501. "typreceive::pg_catalog.oid AS typreceiveoid, "
  7502. "typsend::pg_catalog.oid AS typsendoid, "
  7503. "typmodin::pg_catalog.oid AS typmodinoid, "
  7504. "typmodout::pg_catalog.oid AS typmodoutoid, "
  7505. "typanalyze::pg_catalog.oid AS typanalyzeoid, "
  7506. "'U' AS typcategory, false AS typispreferred, "
  7507. "typdelim, typbyval, typalign, typstorage, "
  7508. "false AS typcollatable, "
  7509. "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
  7510. "FROM pg_catalog.pg_type "
  7511. "WHERE oid = '%u'::pg_catalog.oid",
  7512. tyinfo->dobj.catId.oid);
  7513. }
  7514. else if (fout->remoteVersion >= 80000)
  7515. {
  7516. appendPQExpBuffer(query, "SELECT typlen, "
  7517. "typinput, typoutput, typreceive, typsend, "
  7518. "'-' AS typmodin, '-' AS typmodout, "
  7519. "typanalyze, "
  7520. "typreceive::pg_catalog.oid AS typreceiveoid, "
  7521. "typsend::pg_catalog.oid AS typsendoid, "
  7522. "0 AS typmodinoid, 0 AS typmodoutoid, "
  7523. "typanalyze::pg_catalog.oid AS typanalyzeoid, "
  7524. "'U' AS typcategory, false AS typispreferred, "
  7525. "typdelim, typbyval, typalign, typstorage, "
  7526. "false AS typcollatable, "
  7527. "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
  7528. "FROM pg_catalog.pg_type "
  7529. "WHERE oid = '%u'::pg_catalog.oid",
  7530. tyinfo->dobj.catId.oid);
  7531. }
  7532. else if (fout->remoteVersion >= 70400)
  7533. {
  7534. appendPQExpBuffer(query, "SELECT typlen, "
  7535. "typinput, typoutput, typreceive, typsend, "
  7536. "'-' AS typmodin, '-' AS typmodout, "
  7537. "'-' AS typanalyze, "
  7538. "typreceive::pg_catalog.oid AS typreceiveoid, "
  7539. "typsend::pg_catalog.oid AS typsendoid, "
  7540. "0 AS typmodinoid, 0 AS typmodoutoid, "
  7541. "0 AS typanalyzeoid, "
  7542. "'U' AS typcategory, false AS typispreferred, "
  7543. "typdelim, typbyval, typalign, typstorage, "
  7544. "false AS typcollatable, "
  7545. "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
  7546. "FROM pg_catalog.pg_type "
  7547. "WHERE oid = '%u'::pg_catalog.oid",
  7548. tyinfo->dobj.catId.oid);
  7549. }
  7550. else if (fout->remoteVersion >= 70300)
  7551. {
  7552. appendPQExpBuffer(query, "SELECT typlen, "
  7553. "typinput, typoutput, "
  7554. "'-' AS typreceive, '-' AS typsend, "
  7555. "'-' AS typmodin, '-' AS typmodout, "
  7556. "'-' AS typanalyze, "
  7557. "0 AS typreceiveoid, 0 AS typsendoid, "
  7558. "0 AS typmodinoid, 0 AS typmodoutoid, "
  7559. "0 AS typanalyzeoid, "
  7560. "'U' AS typcategory, false AS typispreferred, "
  7561. "typdelim, typbyval, typalign, typstorage, "
  7562. "false AS typcollatable, "
  7563. "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
  7564. "FROM pg_catalog.pg_type "
  7565. "WHERE oid = '%u'::pg_catalog.oid",
  7566. tyinfo->dobj.catId.oid);
  7567. }
  7568. else if (fout->remoteVersion >= 70200)
  7569. {
  7570. /*
  7571. * Note: although pre-7.3 catalogs contain typreceive and typsend,
  7572. * ignore them because they are not right.
  7573. */
  7574. appendPQExpBuffer(query, "SELECT typlen, "
  7575. "typinput, typoutput, "
  7576. "'-' AS typreceive, '-' AS typsend, "
  7577. "'-' AS typmodin, '-' AS typmodout, "
  7578. "'-' AS typanalyze, "
  7579. "0 AS typreceiveoid, 0 AS typsendoid, "
  7580. "0 AS typmodinoid, 0 AS typmodoutoid, "
  7581. "0 AS typanalyzeoid, "
  7582. "'U' AS typcategory, false AS typispreferred, "
  7583. "typdelim, typbyval, typalign, typstorage, "
  7584. "false AS typcollatable, "
  7585. "NULL AS typdefaultbin, typdefault "
  7586. "FROM pg_type "
  7587. "WHERE oid = '%u'::oid",
  7588. tyinfo->dobj.catId.oid);
  7589. }
  7590. else if (fout->remoteVersion >= 70100)
  7591. {
  7592. /*
  7593. * Ignore pre-7.2 typdefault; the field exists but has an unusable
  7594. * representation.
  7595. */
  7596. appendPQExpBuffer(query, "SELECT typlen, "
  7597. "typinput, typoutput, "
  7598. "'-' AS typreceive, '-' AS typsend, "
  7599. "'-' AS typmodin, '-' AS typmodout, "
  7600. "'-' AS typanalyze, "
  7601. "0 AS typreceiveoid, 0 AS typsendoid, "
  7602. "0 AS typmodinoid, 0 AS typmodoutoid, "
  7603. "0 AS typanalyzeoid, "
  7604. "'U' AS typcategory, false AS typispreferred, "
  7605. "typdelim, typbyval, typalign, typstorage, "
  7606. "false AS typcollatable, "
  7607. "NULL AS typdefaultbin, NULL AS typdefault "
  7608. "FROM pg_type "
  7609. "WHERE oid = '%u'::oid",
  7610. tyinfo->dobj.catId.oid);
  7611. }
  7612. else
  7613. {
  7614. appendPQExpBuffer(query, "SELECT typlen, "
  7615. "typinput, typoutput, "
  7616. "'-' AS typreceive, '-' AS typsend, "
  7617. "'-' AS typmodin, '-' AS typmodout, "
  7618. "'-' AS typanalyze, "
  7619. "0 AS typreceiveoid, 0 AS typsendoid, "
  7620. "0 AS typmodinoid, 0 AS typmodoutoid, "
  7621. "0 AS typanalyzeoid, "
  7622. "'U' AS typcategory, false AS typispreferred, "
  7623. "typdelim, typbyval, typalign, "
  7624. "'p'::char AS typstorage, "
  7625. "false AS typcollatable, "
  7626. "NULL AS typdefaultbin, NULL AS typdefault "
  7627. "FROM pg_type "
  7628. "WHERE oid = '%u'::oid",
  7629. tyinfo->dobj.catId.oid);
  7630. }
  7631. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  7632. typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
  7633. typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
  7634. typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
  7635. typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
  7636. typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
  7637. typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
  7638. typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
  7639. typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
  7640. typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
  7641. typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
  7642. typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
  7643. typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
  7644. typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
  7645. typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
  7646. typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
  7647. typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
  7648. typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
  7649. typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
  7650. typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
  7651. typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
  7652. if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
  7653. typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
  7654. else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
  7655. {
  7656. typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
  7657. typdefault_is_literal = true; /* it needs quotes */
  7658. }
  7659. else
  7660. typdefault = NULL;
  7661. qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
  7662. /*
  7663. * DROP must be fully qualified in case same name appears in pg_catalog.
  7664. * The reason we include CASCADE is that the circular dependency between
  7665. * the type and its I/O functions makes it impossible to drop the type any
  7666. * other way.
  7667. */
  7668. appendPQExpBuffer(delq, "DROP TYPE %s.",
  7669. fmtId(tyinfo->dobj.namespace->dobj.name));
  7670. appendPQExpBuffer(delq, "%s CASCADE;\n",
  7671. qtypname);
  7672. /* We might already have a shell type, but setting pg_type_oid is harmless */
  7673. if (binary_upgrade)
  7674. binary_upgrade_set_type_oids_by_type_oid(fout, q,
  7675. tyinfo->dobj.catId.oid);
  7676. appendPQExpBuffer(q,
  7677. "CREATE TYPE %s (\n"
  7678. " INTERNALLENGTH = %s",
  7679. qtypname,
  7680. (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
  7681. if (fout->remoteVersion >= 70300)
  7682. {
  7683. /* regproc result is correctly quoted as of 7.3 */
  7684. appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
  7685. appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
  7686. if (OidIsValid(typreceiveoid))
  7687. appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
  7688. if (OidIsValid(typsendoid))
  7689. appendPQExpBuffer(q, ",\n SEND = %s", typsend);
  7690. if (OidIsValid(typmodinoid))
  7691. appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
  7692. if (OidIsValid(typmodoutoid))
  7693. appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
  7694. if (OidIsValid(typanalyzeoid))
  7695. appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
  7696. }
  7697. else
  7698. {
  7699. /* regproc delivers an unquoted name before 7.3 */
  7700. /* cannot combine these because fmtId uses static result area */
  7701. appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput));
  7702. appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput));
  7703. /* receive/send/typmodin/typmodout/analyze need not be printed */
  7704. }
  7705. if (strcmp(typcollatable, "t") == 0)
  7706. appendPQExpBufferStr(q, ",\n COLLATABLE = true");
  7707. if (typdefault != NULL)
  7708. {
  7709. appendPQExpBufferStr(q, ",\n DEFAULT = ");
  7710. if (typdefault_is_literal)
  7711. appendStringLiteralAH(q, typdefault, fout);
  7712. else
  7713. appendPQExpBufferStr(q, typdefault);
  7714. }
  7715. if (OidIsValid(tyinfo->typelem))
  7716. {
  7717. char *elemType;
  7718. /* reselect schema in case changed by function dump */
  7719. selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
  7720. elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
  7721. appendPQExpBuffer(q, ",\n ELEMENT = %s", elemType);
  7722. free(elemType);
  7723. }
  7724. if (strcmp(typcategory, "U") != 0)
  7725. {
  7726. appendPQExpBufferStr(q, ",\n CATEGORY = ");
  7727. appendStringLiteralAH(q, typcategory, fout);
  7728. }
  7729. if (strcmp(typispreferred, "t") == 0)
  7730. appendPQExpBufferStr(q, ",\n PREFERRED = true");
  7731. if (typdelim && strcmp(typdelim, ",") != 0)
  7732. {
  7733. appendPQExpBufferStr(q, ",\n DELIMITER = ");
  7734. appendStringLiteralAH(q, typdelim, fout);
  7735. }
  7736. if (strcmp(typalign, "c") == 0)
  7737. appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
  7738. else if (strcmp(typalign, "s") == 0)
  7739. appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
  7740. else if (strcmp(typalign, "i") == 0)
  7741. appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
  7742. else if (strcmp(typalign, "d") == 0)
  7743. appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
  7744. if (strcmp(typstorage, "p") == 0)
  7745. appendPQExpBufferStr(q, ",\n STORAGE = plain");
  7746. else if (strcmp(typstorage, "e") == 0)
  7747. appendPQExpBufferStr(q, ",\n STORAGE = external");
  7748. else if (strcmp(typstorage, "x") == 0)
  7749. appendPQExpBufferStr(q, ",\n STORAGE = extended");
  7750. else if (strcmp(typstorage, "m") == 0)
  7751. appendPQExpBufferStr(q, ",\n STORAGE = main");
  7752. if (strcmp(typbyval, "t") == 0)
  7753. appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
  7754. appendPQExpBufferStr(q, "\n);\n");
  7755. appendPQExpBuffer(labelq, "TYPE %s", qtypname);
  7756. if (binary_upgrade)
  7757. binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
  7758. ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
  7759. tyinfo->dobj.name,
  7760. tyinfo->dobj.namespace->dobj.name,
  7761. NULL,
  7762. tyinfo->rolname, false,
  7763. "TYPE", SECTION_PRE_DATA,
  7764. q->data, delq->data, NULL,
  7765. NULL, 0,
  7766. NULL, NULL);
  7767. /* Dump Type Comments and Security Labels */
  7768. dumpComment(fout, labelq->data,
  7769. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  7770. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  7771. dumpSecLabel(fout, labelq->data,
  7772. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  7773. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  7774. dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
  7775. qtypname, NULL, tyinfo->dobj.name,
  7776. tyinfo->dobj.namespace->dobj.name,
  7777. tyinfo->rolname, tyinfo->typacl);
  7778. PQclear(res);
  7779. destroyPQExpBuffer(q);
  7780. destroyPQExpBuffer(delq);
  7781. destroyPQExpBuffer(labelq);
  7782. destroyPQExpBuffer(query);
  7783. }
  7784. /*
  7785. * dumpDomain
  7786. * writes out to fout the queries to recreate a user-defined domain
  7787. */
  7788. static void
  7789. dumpDomain(Archive *fout, TypeInfo *tyinfo)
  7790. {
  7791. PQExpBuffer q = createPQExpBuffer();
  7792. PQExpBuffer delq = createPQExpBuffer();
  7793. PQExpBuffer labelq = createPQExpBuffer();
  7794. PQExpBuffer query = createPQExpBuffer();
  7795. PGresult *res;
  7796. int i;
  7797. char *qtypname;
  7798. char *typnotnull;
  7799. char *typdefn;
  7800. char *typdefault;
  7801. Oid typcollation;
  7802. bool typdefault_is_literal = false;
  7803. /* Set proper schema search path so type references list correctly */
  7804. selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
  7805. /* Fetch domain specific details */
  7806. if (fout->remoteVersion >= 90100)
  7807. {
  7808. /* typcollation is new in 9.1 */
  7809. appendPQExpBuffer(query, "SELECT t.typnotnull, "
  7810. "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
  7811. "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
  7812. "t.typdefault, "
  7813. "CASE WHEN t.typcollation <> u.typcollation "
  7814. "THEN t.typcollation ELSE 0 END AS typcollation "
  7815. "FROM pg_catalog.pg_type t "
  7816. "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
  7817. "WHERE t.oid = '%u'::pg_catalog.oid",
  7818. tyinfo->dobj.catId.oid);
  7819. }
  7820. else
  7821. {
  7822. /* We assume here that remoteVersion must be at least 70300 */
  7823. appendPQExpBuffer(query, "SELECT typnotnull, "
  7824. "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
  7825. "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
  7826. "typdefault, 0 AS typcollation "
  7827. "FROM pg_catalog.pg_type "
  7828. "WHERE oid = '%u'::pg_catalog.oid",
  7829. tyinfo->dobj.catId.oid);
  7830. }
  7831. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  7832. typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
  7833. typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
  7834. if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
  7835. typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
  7836. else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
  7837. {
  7838. typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
  7839. typdefault_is_literal = true; /* it needs quotes */
  7840. }
  7841. else
  7842. typdefault = NULL;
  7843. typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
  7844. if (binary_upgrade)
  7845. binary_upgrade_set_type_oids_by_type_oid(fout, q,
  7846. tyinfo->dobj.catId.oid);
  7847. qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
  7848. appendPQExpBuffer(q,
  7849. "CREATE DOMAIN %s AS %s",
  7850. qtypname,
  7851. typdefn);
  7852. /* Print collation only if different from base type's collation */
  7853. if (OidIsValid(typcollation))
  7854. {
  7855. CollInfo *coll;
  7856. coll = findCollationByOid(typcollation);
  7857. if (coll)
  7858. {
  7859. /* always schema-qualify, don't try to be smart */
  7860. appendPQExpBuffer(q, " COLLATE %s.",
  7861. fmtId(coll->dobj.namespace->dobj.name));
  7862. appendPQExpBufferStr(q, fmtId(coll->dobj.name));
  7863. }
  7864. }
  7865. if (typnotnull[0] == 't')
  7866. appendPQExpBufferStr(q, " NOT NULL");
  7867. if (typdefault != NULL)
  7868. {
  7869. appendPQExpBufferStr(q, " DEFAULT ");
  7870. if (typdefault_is_literal)
  7871. appendStringLiteralAH(q, typdefault, fout);
  7872. else
  7873. appendPQExpBufferStr(q, typdefault);
  7874. }
  7875. PQclear(res);
  7876. /*
  7877. * Add any CHECK constraints for the domain
  7878. */
  7879. for (i = 0; i < tyinfo->nDomChecks; i++)
  7880. {
  7881. ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
  7882. if (!domcheck->separate)
  7883. appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
  7884. fmtId(domcheck->dobj.name), domcheck->condef);
  7885. }
  7886. appendPQExpBufferStr(q, ";\n");
  7887. /*
  7888. * DROP must be fully qualified in case same name appears in pg_catalog
  7889. */
  7890. appendPQExpBuffer(delq, "DROP DOMAIN %s.",
  7891. fmtId(tyinfo->dobj.namespace->dobj.name));
  7892. appendPQExpBuffer(delq, "%s;\n",
  7893. qtypname);
  7894. appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
  7895. if (binary_upgrade)
  7896. binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
  7897. ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
  7898. tyinfo->dobj.name,
  7899. tyinfo->dobj.namespace->dobj.name,
  7900. NULL,
  7901. tyinfo->rolname, false,
  7902. "DOMAIN", SECTION_PRE_DATA,
  7903. q->data, delq->data, NULL,
  7904. NULL, 0,
  7905. NULL, NULL);
  7906. /* Dump Domain Comments and Security Labels */
  7907. dumpComment(fout, labelq->data,
  7908. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  7909. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  7910. dumpSecLabel(fout, labelq->data,
  7911. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  7912. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  7913. dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
  7914. qtypname, NULL, tyinfo->dobj.name,
  7915. tyinfo->dobj.namespace->dobj.name,
  7916. tyinfo->rolname, tyinfo->typacl);
  7917. destroyPQExpBuffer(q);
  7918. destroyPQExpBuffer(delq);
  7919. destroyPQExpBuffer(labelq);
  7920. destroyPQExpBuffer(query);
  7921. }
  7922. /*
  7923. * dumpCompositeType
  7924. * writes out to fout the queries to recreate a user-defined stand-alone
  7925. * composite type
  7926. */
  7927. static void
  7928. dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
  7929. {
  7930. PQExpBuffer q = createPQExpBuffer();
  7931. PQExpBuffer dropped = createPQExpBuffer();
  7932. PQExpBuffer delq = createPQExpBuffer();
  7933. PQExpBuffer labelq = createPQExpBuffer();
  7934. PQExpBuffer query = createPQExpBuffer();
  7935. PGresult *res;
  7936. char *qtypname;
  7937. int ntups;
  7938. int i_attname;
  7939. int i_atttypdefn;
  7940. int i_attlen;
  7941. int i_attalign;
  7942. int i_attisdropped;
  7943. int i_attcollation;
  7944. int i_typrelid;
  7945. int i;
  7946. int actual_atts;
  7947. /* Set proper schema search path so type references list correctly */
  7948. selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
  7949. /* Fetch type specific details */
  7950. if (fout->remoteVersion >= 90100)
  7951. {
  7952. /*
  7953. * attcollation is new in 9.1. Since we only want to dump COLLATE
  7954. * clauses for attributes whose collation is different from their
  7955. * type's default, we use a CASE here to suppress uninteresting
  7956. * attcollations cheaply. atttypid will be 0 for dropped columns;
  7957. * collation does not matter for those.
  7958. */
  7959. appendPQExpBuffer(query, "SELECT a.attname, "
  7960. "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
  7961. "a.attlen, a.attalign, a.attisdropped, "
  7962. "CASE WHEN a.attcollation <> at.typcollation "
  7963. "THEN a.attcollation ELSE 0 END AS attcollation, "
  7964. "ct.typrelid "
  7965. "FROM pg_catalog.pg_type ct "
  7966. "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
  7967. "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
  7968. "WHERE ct.oid = '%u'::pg_catalog.oid "
  7969. "ORDER BY a.attnum ",
  7970. tyinfo->dobj.catId.oid);
  7971. }
  7972. else
  7973. {
  7974. /*
  7975. * We assume here that remoteVersion must be at least 70300. Since
  7976. * ALTER TYPE could not drop columns until 9.1, attisdropped should
  7977. * always be false.
  7978. */
  7979. appendPQExpBuffer(query, "SELECT a.attname, "
  7980. "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
  7981. "a.attlen, a.attalign, a.attisdropped, "
  7982. "0 AS attcollation, "
  7983. "ct.typrelid "
  7984. "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
  7985. "WHERE ct.oid = '%u'::pg_catalog.oid "
  7986. "AND a.attrelid = ct.typrelid "
  7987. "ORDER BY a.attnum ",
  7988. tyinfo->dobj.catId.oid);
  7989. }
  7990. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  7991. ntups = PQntuples(res);
  7992. i_attname = PQfnumber(res, "attname");
  7993. i_atttypdefn = PQfnumber(res, "atttypdefn");
  7994. i_attlen = PQfnumber(res, "attlen");
  7995. i_attalign = PQfnumber(res, "attalign");
  7996. i_attisdropped = PQfnumber(res, "attisdropped");
  7997. i_attcollation = PQfnumber(res, "attcollation");
  7998. i_typrelid = PQfnumber(res, "typrelid");
  7999. if (binary_upgrade)
  8000. {
  8001. Oid typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
  8002. binary_upgrade_set_type_oids_by_type_oid(fout, q,
  8003. tyinfo->dobj.catId.oid);
  8004. binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
  8005. }
  8006. qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
  8007. appendPQExpBuffer(q, "CREATE TYPE %s AS (",
  8008. qtypname);
  8009. actual_atts = 0;
  8010. for (i = 0; i < ntups; i++)
  8011. {
  8012. char *attname;
  8013. char *atttypdefn;
  8014. char *attlen;
  8015. char *attalign;
  8016. bool attisdropped;
  8017. Oid attcollation;
  8018. attname = PQgetvalue(res, i, i_attname);
  8019. atttypdefn = PQgetvalue(res, i, i_atttypdefn);
  8020. attlen = PQgetvalue(res, i, i_attlen);
  8021. attalign = PQgetvalue(res, i, i_attalign);
  8022. attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
  8023. attcollation = atooid(PQgetvalue(res, i, i_attcollation));
  8024. if (attisdropped && !binary_upgrade)
  8025. continue;
  8026. /* Format properly if not first attr */
  8027. if (actual_atts++ > 0)
  8028. appendPQExpBufferChar(q, ',');
  8029. appendPQExpBufferStr(q, "\n\t");
  8030. if (!attisdropped)
  8031. {
  8032. appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
  8033. /* Add collation if not default for the column type */
  8034. if (OidIsValid(attcollation))
  8035. {
  8036. CollInfo *coll;
  8037. coll = findCollationByOid(attcollation);
  8038. if (coll)
  8039. {
  8040. /* always schema-qualify, don't try to be smart */
  8041. appendPQExpBuffer(q, " COLLATE %s.",
  8042. fmtId(coll->dobj.namespace->dobj.name));
  8043. appendPQExpBufferStr(q, fmtId(coll->dobj.name));
  8044. }
  8045. }
  8046. }
  8047. else
  8048. {
  8049. /*
  8050. * This is a dropped attribute and we're in binary_upgrade mode.
  8051. * Insert a placeholder for it in the CREATE TYPE command, and set
  8052. * length and alignment with direct UPDATE to the catalogs
  8053. * afterwards. See similar code in dumpTableSchema().
  8054. */
  8055. appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
  8056. /* stash separately for insertion after the CREATE TYPE */
  8057. appendPQExpBufferStr(dropped,
  8058. "\n-- For binary upgrade, recreate dropped column.\n");
  8059. appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
  8060. "SET attlen = %s, "
  8061. "attalign = '%s', attbyval = false\n"
  8062. "WHERE attname = ", attlen, attalign);
  8063. appendStringLiteralAH(dropped, attname, fout);
  8064. appendPQExpBufferStr(dropped, "\n AND attrelid = ");
  8065. appendStringLiteralAH(dropped, qtypname, fout);
  8066. appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
  8067. appendPQExpBuffer(dropped, "ALTER TYPE %s ",
  8068. qtypname);
  8069. appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
  8070. fmtId(attname));
  8071. }
  8072. }
  8073. appendPQExpBufferStr(q, "\n);\n");
  8074. appendPQExpBufferStr(q, dropped->data);
  8075. /*
  8076. * DROP must be fully qualified in case same name appears in pg_catalog
  8077. */
  8078. appendPQExpBuffer(delq, "DROP TYPE %s.",
  8079. fmtId(tyinfo->dobj.namespace->dobj.name));
  8080. appendPQExpBuffer(delq, "%s;\n",
  8081. qtypname);
  8082. appendPQExpBuffer(labelq, "TYPE %s", qtypname);
  8083. if (binary_upgrade)
  8084. binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
  8085. ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
  8086. tyinfo->dobj.name,
  8087. tyinfo->dobj.namespace->dobj.name,
  8088. NULL,
  8089. tyinfo->rolname, false,
  8090. "TYPE", SECTION_PRE_DATA,
  8091. q->data, delq->data, NULL,
  8092. NULL, 0,
  8093. NULL, NULL);
  8094. /* Dump Type Comments and Security Labels */
  8095. dumpComment(fout, labelq->data,
  8096. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  8097. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  8098. dumpSecLabel(fout, labelq->data,
  8099. tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  8100. tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  8101. dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
  8102. qtypname, NULL, tyinfo->dobj.name,
  8103. tyinfo->dobj.namespace->dobj.name,
  8104. tyinfo->rolname, tyinfo->typacl);
  8105. PQclear(res);
  8106. destroyPQExpBuffer(q);
  8107. destroyPQExpBuffer(dropped);
  8108. destroyPQExpBuffer(delq);
  8109. destroyPQExpBuffer(labelq);
  8110. destroyPQExpBuffer(query);
  8111. /* Dump any per-column comments */
  8112. dumpCompositeTypeColComments(fout, tyinfo);
  8113. }
  8114. /*
  8115. * dumpCompositeTypeColComments
  8116. * writes out to fout the queries to recreate comments on the columns of
  8117. * a user-defined stand-alone composite type
  8118. */
  8119. static void
  8120. dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
  8121. {
  8122. CommentItem *comments;
  8123. int ncomments;
  8124. PGresult *res;
  8125. PQExpBuffer query;
  8126. PQExpBuffer target;
  8127. Oid pgClassOid;
  8128. int i;
  8129. int ntups;
  8130. int i_attname;
  8131. int i_attnum;
  8132. query = createPQExpBuffer();
  8133. /* We assume here that remoteVersion must be at least 70300 */
  8134. appendPQExpBuffer(query,
  8135. "SELECT c.tableoid, a.attname, a.attnum "
  8136. "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
  8137. "WHERE c.oid = '%u' AND c.oid = a.attrelid "
  8138. " AND NOT a.attisdropped "
  8139. "ORDER BY a.attnum ",
  8140. tyinfo->typrelid);
  8141. /* Fetch column attnames */
  8142. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  8143. ntups = PQntuples(res);
  8144. if (ntups < 1)
  8145. {
  8146. PQclear(res);
  8147. destroyPQExpBuffer(query);
  8148. return;
  8149. }
  8150. pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
  8151. /* Search for comments associated with type's pg_class OID */
  8152. ncomments = findComments(fout,
  8153. pgClassOid,
  8154. tyinfo->typrelid,
  8155. &comments);
  8156. /* If no comments exist, we're done */
  8157. if (ncomments <= 0)
  8158. {
  8159. PQclear(res);
  8160. destroyPQExpBuffer(query);
  8161. return;
  8162. }
  8163. /* Build COMMENT ON statements */
  8164. target = createPQExpBuffer();
  8165. i_attnum = PQfnumber(res, "attnum");
  8166. i_attname = PQfnumber(res, "attname");
  8167. while (ncomments > 0)
  8168. {
  8169. const char *attname;
  8170. attname = NULL;
  8171. for (i = 0; i < ntups; i++)
  8172. {
  8173. if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
  8174. {
  8175. attname = PQgetvalue(res, i, i_attname);
  8176. break;
  8177. }
  8178. }
  8179. if (attname) /* just in case we don't find it */
  8180. {
  8181. const char *descr = comments->descr;
  8182. resetPQExpBuffer(target);
  8183. appendPQExpBuffer(target, "COLUMN %s.",
  8184. fmtId(tyinfo->dobj.name));
  8185. appendPQExpBufferStr(target, fmtId(attname));
  8186. resetPQExpBuffer(query);
  8187. appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
  8188. appendStringLiteralAH(query, descr, fout);
  8189. appendPQExpBufferStr(query, ";\n");
  8190. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  8191. target->data,
  8192. tyinfo->dobj.namespace->dobj.name,
  8193. NULL, tyinfo->rolname,
  8194. false, "COMMENT", SECTION_NONE,
  8195. query->data, "", NULL,
  8196. &(tyinfo->dobj.dumpId), 1,
  8197. NULL, NULL);
  8198. }
  8199. comments++;
  8200. ncomments--;
  8201. }
  8202. PQclear(res);
  8203. destroyPQExpBuffer(query);
  8204. destroyPQExpBuffer(target);
  8205. }
  8206. /*
  8207. * dumpShellType
  8208. * writes out to fout the queries to create a shell type
  8209. *
  8210. * We dump a shell definition in advance of the I/O functions for the type.
  8211. */
  8212. static void
  8213. dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
  8214. {
  8215. PQExpBuffer q;
  8216. /* Skip if not to be dumped */
  8217. if (!stinfo->dobj.dump || dataOnly)
  8218. return;
  8219. q = createPQExpBuffer();
  8220. /*
  8221. * Note the lack of a DROP command for the shell type; any required DROP
  8222. * is driven off the base type entry, instead. This interacts with
  8223. * _printTocEntry()'s use of the presence of a DROP command to decide
  8224. * whether an entry needs an ALTER OWNER command. We don't want to alter
  8225. * the shell type's owner immediately on creation; that should happen only
  8226. * after it's filled in, otherwise the backend complains.
  8227. */
  8228. if (binary_upgrade)
  8229. binary_upgrade_set_type_oids_by_type_oid(fout, q,
  8230. stinfo->baseType->dobj.catId.oid);
  8231. appendPQExpBuffer(q, "CREATE TYPE %s;\n",
  8232. fmtId(stinfo->dobj.name));
  8233. ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
  8234. stinfo->dobj.name,
  8235. stinfo->dobj.namespace->dobj.name,
  8236. NULL,
  8237. stinfo->baseType->rolname, false,
  8238. "SHELL TYPE", SECTION_PRE_DATA,
  8239. q->data, "", NULL,
  8240. NULL, 0,
  8241. NULL, NULL);
  8242. destroyPQExpBuffer(q);
  8243. }
  8244. /*
  8245. * Determine whether we want to dump definitions for procedural languages.
  8246. * Since the languages themselves don't have schemas, we can't rely on
  8247. * the normal schema-based selection mechanism. We choose to dump them
  8248. * whenever neither --schema nor --table was given. (Before 8.1, we used
  8249. * the dump flag of the PL's call handler function, but in 8.1 this will
  8250. * probably always be false since call handlers are created in pg_catalog.)
  8251. *
  8252. * For some backwards compatibility with the older behavior, we forcibly
  8253. * dump a PL if its handler function (and validator if any) are in a
  8254. * dumpable namespace. That case is not checked here.
  8255. *
  8256. * Also, if the PL belongs to an extension, we do not use this heuristic.
  8257. * That case isn't checked here either.
  8258. */
  8259. static bool
  8260. shouldDumpProcLangs(void)
  8261. {
  8262. if (!include_everything)
  8263. return false;
  8264. /* And they're schema not data */
  8265. if (dataOnly)
  8266. return false;
  8267. return true;
  8268. }
  8269. /*
  8270. * dumpProcLang
  8271. * writes out to fout the queries to recreate a user-defined
  8272. * procedural language
  8273. */
  8274. static void
  8275. dumpProcLang(Archive *fout, ProcLangInfo *plang)
  8276. {
  8277. PQExpBuffer defqry;
  8278. PQExpBuffer delqry;
  8279. PQExpBuffer labelq;
  8280. bool useParams;
  8281. char *qlanname;
  8282. char *lanschema;
  8283. FuncInfo *funcInfo;
  8284. FuncInfo *inlineInfo = NULL;
  8285. FuncInfo *validatorInfo = NULL;
  8286. /* Skip if not to be dumped */
  8287. if (!plang->dobj.dump || dataOnly)
  8288. return;
  8289. /*
  8290. * Try to find the support function(s). It is not an error if we don't
  8291. * find them --- if the functions are in the pg_catalog schema, as is
  8292. * standard in 8.1 and up, then we won't have loaded them. (In this case
  8293. * we will emit a parameterless CREATE LANGUAGE command, which will
  8294. * require PL template knowledge in the backend to reload.)
  8295. */
  8296. funcInfo = findFuncByOid(plang->lanplcallfoid);
  8297. if (funcInfo != NULL && !funcInfo->dobj.dump)
  8298. funcInfo = NULL; /* treat not-dumped same as not-found */
  8299. if (OidIsValid(plang->laninline))
  8300. {
  8301. inlineInfo = findFuncByOid(plang->laninline);
  8302. if (inlineInfo != NULL && !inlineInfo->dobj.dump)
  8303. inlineInfo = NULL;
  8304. }
  8305. if (OidIsValid(plang->lanvalidator))
  8306. {
  8307. validatorInfo = findFuncByOid(plang->lanvalidator);
  8308. if (validatorInfo != NULL && !validatorInfo->dobj.dump)
  8309. validatorInfo = NULL;
  8310. }
  8311. /*
  8312. * If the functions are dumpable then emit a traditional CREATE LANGUAGE
  8313. * with parameters. Otherwise, dump only if shouldDumpProcLangs() says to
  8314. * dump it.
  8315. *
  8316. * However, for a language that belongs to an extension, we must not use
  8317. * the shouldDumpProcLangs heuristic, but just dump the language iff we're
  8318. * told to (via dobj.dump). Generally the support functions will belong
  8319. * to the same extension and so have the same dump flags ... if they
  8320. * don't, this might not work terribly nicely.
  8321. */
  8322. useParams = (funcInfo != NULL &&
  8323. (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
  8324. (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
  8325. if (!plang->dobj.ext_member)
  8326. {
  8327. if (!useParams && !shouldDumpProcLangs())
  8328. return;
  8329. }
  8330. defqry = createPQExpBuffer();
  8331. delqry = createPQExpBuffer();
  8332. labelq = createPQExpBuffer();
  8333. qlanname = pg_strdup(fmtId(plang->dobj.name));
  8334. /*
  8335. * If dumping a HANDLER clause, treat the language as being in the handler
  8336. * function's schema; this avoids cluttering the HANDLER clause. Otherwise
  8337. * it doesn't really have a schema.
  8338. */
  8339. if (useParams)
  8340. lanschema = funcInfo->dobj.namespace->dobj.name;
  8341. else
  8342. lanschema = NULL;
  8343. appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
  8344. qlanname);
  8345. if (useParams)
  8346. {
  8347. appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
  8348. plang->lanpltrusted ? "TRUSTED " : "",
  8349. qlanname);
  8350. appendPQExpBuffer(defqry, " HANDLER %s",
  8351. fmtId(funcInfo->dobj.name));
  8352. if (OidIsValid(plang->laninline))
  8353. {
  8354. appendPQExpBufferStr(defqry, " INLINE ");
  8355. /* Cope with possibility that inline is in different schema */
  8356. if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
  8357. appendPQExpBuffer(defqry, "%s.",
  8358. fmtId(inlineInfo->dobj.namespace->dobj.name));
  8359. appendPQExpBufferStr(defqry, fmtId(inlineInfo->dobj.name));
  8360. }
  8361. if (OidIsValid(plang->lanvalidator))
  8362. {
  8363. appendPQExpBufferStr(defqry, " VALIDATOR ");
  8364. /* Cope with possibility that validator is in different schema */
  8365. if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
  8366. appendPQExpBuffer(defqry, "%s.",
  8367. fmtId(validatorInfo->dobj.namespace->dobj.name));
  8368. appendPQExpBufferStr(defqry, fmtId(validatorInfo->dobj.name));
  8369. }
  8370. }
  8371. else
  8372. {
  8373. /*
  8374. * If not dumping parameters, then use CREATE OR REPLACE so that the
  8375. * command will not fail if the language is preinstalled in the target
  8376. * database. We restrict the use of REPLACE to this case so as to
  8377. * eliminate the risk of replacing a language with incompatible
  8378. * parameter settings: this command will only succeed at all if there
  8379. * is a pg_pltemplate entry, and if there is one, the existing entry
  8380. * must match it too.
  8381. */
  8382. appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
  8383. qlanname);
  8384. }
  8385. appendPQExpBufferStr(defqry, ";\n");
  8386. appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
  8387. if (binary_upgrade)
  8388. binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
  8389. ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
  8390. plang->dobj.name,
  8391. lanschema, NULL, plang->lanowner,
  8392. false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
  8393. defqry->data, delqry->data, NULL,
  8394. NULL, 0,
  8395. NULL, NULL);
  8396. /* Dump Proc Lang Comments and Security Labels */
  8397. dumpComment(fout, labelq->data,
  8398. NULL, "",
  8399. plang->dobj.catId, 0, plang->dobj.dumpId);
  8400. dumpSecLabel(fout, labelq->data,
  8401. NULL, "",
  8402. plang->dobj.catId, 0, plang->dobj.dumpId);
  8403. if (plang->lanpltrusted)
  8404. dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
  8405. qlanname, NULL, plang->dobj.name,
  8406. lanschema,
  8407. plang->lanowner, plang->lanacl);
  8408. free(qlanname);
  8409. destroyPQExpBuffer(defqry);
  8410. destroyPQExpBuffer(delqry);
  8411. destroyPQExpBuffer(labelq);
  8412. }
  8413. /*
  8414. * format_function_arguments: generate function name and argument list
  8415. *
  8416. * This is used when we can rely on pg_get_function_arguments to format
  8417. * the argument list. Note, however, that pg_get_function_arguments
  8418. * does not special-case zero-argument aggregates.
  8419. */
  8420. static char *
  8421. format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
  8422. {
  8423. PQExpBufferData fn;
  8424. initPQExpBuffer(&fn);
  8425. appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
  8426. if (is_agg && finfo->nargs == 0)
  8427. appendPQExpBufferStr(&fn, "(*)");
  8428. else
  8429. appendPQExpBuffer(&fn, "(%s)", funcargs);
  8430. return fn.data;
  8431. }
  8432. /*
  8433. * format_function_arguments_old: generate function name and argument list
  8434. *
  8435. * The argument type names are qualified if needed. The function name
  8436. * is never qualified.
  8437. *
  8438. * This is used only with pre-8.4 servers, so we aren't expecting to see
  8439. * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
  8440. *
  8441. * Any or all of allargtypes, argmodes, argnames may be NULL.
  8442. */
  8443. static char *
  8444. format_function_arguments_old(Archive *fout,
  8445. FuncInfo *finfo, int nallargs,
  8446. char **allargtypes,
  8447. char **argmodes,
  8448. char **argnames)
  8449. {
  8450. PQExpBufferData fn;
  8451. int j;
  8452. initPQExpBuffer(&fn);
  8453. appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
  8454. for (j = 0; j < nallargs; j++)
  8455. {
  8456. Oid typid;
  8457. char *typname;
  8458. const char *argmode;
  8459. const char *argname;
  8460. typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
  8461. typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
  8462. if (argmodes)
  8463. {
  8464. switch (argmodes[j][0])
  8465. {
  8466. case PROARGMODE_IN:
  8467. argmode = "";
  8468. break;
  8469. case PROARGMODE_OUT:
  8470. argmode = "OUT ";
  8471. break;
  8472. case PROARGMODE_INOUT:
  8473. argmode = "INOUT ";
  8474. break;
  8475. default:
  8476. write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
  8477. argmode = "";
  8478. break;
  8479. }
  8480. }
  8481. else
  8482. argmode = "";
  8483. argname = argnames ? argnames[j] : (char *) NULL;
  8484. if (argname && argname[0] == '\0')
  8485. argname = NULL;
  8486. appendPQExpBuffer(&fn, "%s%s%s%s%s",
  8487. (j > 0) ? ", " : "",
  8488. argmode,
  8489. argname ? fmtId(argname) : "",
  8490. argname ? " " : "",
  8491. typname);
  8492. free(typname);
  8493. }
  8494. appendPQExpBufferChar(&fn, ')');
  8495. return fn.data;
  8496. }
  8497. /*
  8498. * format_function_signature: generate function name and argument list
  8499. *
  8500. * This is like format_function_arguments_old except that only a minimal
  8501. * list of input argument types is generated; this is sufficient to
  8502. * reference the function, but not to define it.
  8503. *
  8504. * If honor_quotes is false then the function name is never quoted.
  8505. * This is appropriate for use in TOC tags, but not in SQL commands.
  8506. */
  8507. static char *
  8508. format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
  8509. {
  8510. PQExpBufferData fn;
  8511. int j;
  8512. initPQExpBuffer(&fn);
  8513. if (honor_quotes)
  8514. appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
  8515. else
  8516. appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
  8517. for (j = 0; j < finfo->nargs; j++)
  8518. {
  8519. char *typname;
  8520. if (j > 0)
  8521. appendPQExpBufferStr(&fn, ", ");
  8522. typname = getFormattedTypeName(fout, finfo->argtypes[j],
  8523. zeroAsOpaque);
  8524. appendPQExpBufferStr(&fn, typname);
  8525. free(typname);
  8526. }
  8527. appendPQExpBufferChar(&fn, ')');
  8528. return fn.data;
  8529. }
  8530. /*
  8531. * dumpFunc:
  8532. * dump out one function
  8533. */
  8534. static void
  8535. dumpFunc(Archive *fout, FuncInfo *finfo)
  8536. {
  8537. PQExpBuffer query;
  8538. PQExpBuffer q;
  8539. PQExpBuffer delqry;
  8540. PQExpBuffer labelq;
  8541. PQExpBuffer asPart;
  8542. PGresult *res;
  8543. char *funcsig; /* identity signature */
  8544. char *funcfullsig = NULL; /* full signature */
  8545. char *funcsig_tag;
  8546. char *proretset;
  8547. char *prosrc;
  8548. char *probin;
  8549. char *funcargs;
  8550. char *funciargs;
  8551. char *funcresult;
  8552. char *proallargtypes;
  8553. char *proargmodes;
  8554. char *proargnames;
  8555. char *proiswindow;
  8556. char *provolatile;
  8557. char *proisstrict;
  8558. char *prosecdef;
  8559. char *proleakproof;
  8560. char *proconfig;
  8561. char *procost;
  8562. char *prorows;
  8563. char *lanname;
  8564. char *rettypename;
  8565. int nallargs;
  8566. char **allargtypes = NULL;
  8567. char **argmodes = NULL;
  8568. char **argnames = NULL;
  8569. char **configitems = NULL;
  8570. int nconfigitems = 0;
  8571. int i;
  8572. /* Skip if not to be dumped */
  8573. if (!finfo->dobj.dump || dataOnly)
  8574. return;
  8575. query = createPQExpBuffer();
  8576. q = createPQExpBuffer();
  8577. delqry = createPQExpBuffer();
  8578. labelq = createPQExpBuffer();
  8579. asPart = createPQExpBuffer();
  8580. /* Set proper schema search path so type references list correctly */
  8581. selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
  8582. /* Fetch function-specific details */
  8583. if (fout->remoteVersion >= 90200)
  8584. {
  8585. /*
  8586. * proleakproof was added at v9.2
  8587. */
  8588. appendPQExpBuffer(query,
  8589. "SELECT proretset, prosrc, probin, "
  8590. "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
  8591. "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
  8592. "pg_catalog.pg_get_function_result(oid) AS funcresult, "
  8593. "proiswindow, provolatile, proisstrict, prosecdef, "
  8594. "proleakproof, proconfig, procost, prorows, "
  8595. "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  8596. "FROM pg_catalog.pg_proc "
  8597. "WHERE oid = '%u'::pg_catalog.oid",
  8598. finfo->dobj.catId.oid);
  8599. }
  8600. else if (fout->remoteVersion >= 80400)
  8601. {
  8602. /*
  8603. * In 8.4 and up we rely on pg_get_function_arguments and
  8604. * pg_get_function_result instead of examining proallargtypes etc.
  8605. */
  8606. appendPQExpBuffer(query,
  8607. "SELECT proretset, prosrc, probin, "
  8608. "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
  8609. "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
  8610. "pg_catalog.pg_get_function_result(oid) AS funcresult, "
  8611. "proiswindow, provolatile, proisstrict, prosecdef, "
  8612. "false AS proleakproof, "
  8613. " proconfig, procost, prorows, "
  8614. "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  8615. "FROM pg_catalog.pg_proc "
  8616. "WHERE oid = '%u'::pg_catalog.oid",
  8617. finfo->dobj.catId.oid);
  8618. }
  8619. else if (fout->remoteVersion >= 80300)
  8620. {
  8621. appendPQExpBuffer(query,
  8622. "SELECT proretset, prosrc, probin, "
  8623. "proallargtypes, proargmodes, proargnames, "
  8624. "false AS proiswindow, "
  8625. "provolatile, proisstrict, prosecdef, "
  8626. "false AS proleakproof, "
  8627. "proconfig, procost, prorows, "
  8628. "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  8629. "FROM pg_catalog.pg_proc "
  8630. "WHERE oid = '%u'::pg_catalog.oid",
  8631. finfo->dobj.catId.oid);
  8632. }
  8633. else if (fout->remoteVersion >= 80100)
  8634. {
  8635. appendPQExpBuffer(query,
  8636. "SELECT proretset, prosrc, probin, "
  8637. "proallargtypes, proargmodes, proargnames, "
  8638. "false AS proiswindow, "
  8639. "provolatile, proisstrict, prosecdef, "
  8640. "false AS proleakproof, "
  8641. "null AS proconfig, 0 AS procost, 0 AS prorows, "
  8642. "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  8643. "FROM pg_catalog.pg_proc "
  8644. "WHERE oid = '%u'::pg_catalog.oid",
  8645. finfo->dobj.catId.oid);
  8646. }
  8647. else if (fout->remoteVersion >= 80000)
  8648. {
  8649. appendPQExpBuffer(query,
  8650. "SELECT proretset, prosrc, probin, "
  8651. "null AS proallargtypes, "
  8652. "null AS proargmodes, "
  8653. "proargnames, "
  8654. "false AS proiswindow, "
  8655. "provolatile, proisstrict, prosecdef, "
  8656. "false AS proleakproof, "
  8657. "null AS proconfig, 0 AS procost, 0 AS prorows, "
  8658. "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  8659. "FROM pg_catalog.pg_proc "
  8660. "WHERE oid = '%u'::pg_catalog.oid",
  8661. finfo->dobj.catId.oid);
  8662. }
  8663. else if (fout->remoteVersion >= 70300)
  8664. {
  8665. appendPQExpBuffer(query,
  8666. "SELECT proretset, prosrc, probin, "
  8667. "null AS proallargtypes, "
  8668. "null AS proargmodes, "
  8669. "null AS proargnames, "
  8670. "false AS proiswindow, "
  8671. "provolatile, proisstrict, prosecdef, "
  8672. "false AS proleakproof, "
  8673. "null AS proconfig, 0 AS procost, 0 AS prorows, "
  8674. "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  8675. "FROM pg_catalog.pg_proc "
  8676. "WHERE oid = '%u'::pg_catalog.oid",
  8677. finfo->dobj.catId.oid);
  8678. }
  8679. else if (fout->remoteVersion >= 70100)
  8680. {
  8681. appendPQExpBuffer(query,
  8682. "SELECT proretset, prosrc, probin, "
  8683. "null AS proallargtypes, "
  8684. "null AS proargmodes, "
  8685. "null AS proargnames, "
  8686. "false AS proiswindow, "
  8687. "case when proiscachable then 'i' else 'v' end AS provolatile, "
  8688. "proisstrict, "
  8689. "false AS prosecdef, "
  8690. "false AS proleakproof, "
  8691. "null AS proconfig, 0 AS procost, 0 AS prorows, "
  8692. "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
  8693. "FROM pg_proc "
  8694. "WHERE oid = '%u'::oid",
  8695. finfo->dobj.catId.oid);
  8696. }
  8697. else
  8698. {
  8699. appendPQExpBuffer(query,
  8700. "SELECT proretset, prosrc, probin, "
  8701. "null AS proallargtypes, "
  8702. "null AS proargmodes, "
  8703. "null AS proargnames, "
  8704. "false AS proiswindow, "
  8705. "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
  8706. "false AS proisstrict, "
  8707. "false AS prosecdef, "
  8708. "false AS proleakproof, "
  8709. "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
  8710. "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
  8711. "FROM pg_proc "
  8712. "WHERE oid = '%u'::oid",
  8713. finfo->dobj.catId.oid);
  8714. }
  8715. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  8716. proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
  8717. prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
  8718. probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
  8719. if (fout->remoteVersion >= 80400)
  8720. {
  8721. funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
  8722. funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
  8723. funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
  8724. proallargtypes = proargmodes = proargnames = NULL;
  8725. }
  8726. else
  8727. {
  8728. proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
  8729. proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
  8730. proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
  8731. funcargs = funciargs = funcresult = NULL;
  8732. }
  8733. proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
  8734. provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
  8735. proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
  8736. prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
  8737. proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
  8738. proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
  8739. procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
  8740. prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
  8741. lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
  8742. /*
  8743. * See backend/commands/functioncmds.c for details of how the 'AS' clause
  8744. * is used. In 8.4 and up, an unused probin is NULL (here ""); previous
  8745. * versions would set it to "-". There are no known cases in which prosrc
  8746. * is unused, so the tests below for "-" are probably useless.
  8747. */
  8748. if (probin[0] != '\0' && strcmp(probin, "-") != 0)
  8749. {
  8750. appendPQExpBufferStr(asPart, "AS ");
  8751. appendStringLiteralAH(asPart, probin, fout);
  8752. if (strcmp(prosrc, "-") != 0)
  8753. {
  8754. appendPQExpBufferStr(asPart, ", ");
  8755. /*
  8756. * where we have bin, use dollar quoting if allowed and src
  8757. * contains quote or backslash; else use regular quoting.
  8758. */
  8759. if (disable_dollar_quoting ||
  8760. (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
  8761. appendStringLiteralAH(asPart, prosrc, fout);
  8762. else
  8763. appendStringLiteralDQ(asPart, prosrc, NULL);
  8764. }
  8765. }
  8766. else
  8767. {
  8768. if (strcmp(prosrc, "-") != 0)
  8769. {
  8770. appendPQExpBufferStr(asPart, "AS ");
  8771. /* with no bin, dollar quote src unconditionally if allowed */
  8772. if (disable_dollar_quoting)
  8773. appendStringLiteralAH(asPart, prosrc, fout);
  8774. else
  8775. appendStringLiteralDQ(asPart, prosrc, NULL);
  8776. }
  8777. }
  8778. nallargs = finfo->nargs; /* unless we learn different from allargs */
  8779. if (proallargtypes && *proallargtypes)
  8780. {
  8781. int nitems = 0;
  8782. if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
  8783. nitems < finfo->nargs)
  8784. {
  8785. write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
  8786. if (allargtypes)
  8787. free(allargtypes);
  8788. allargtypes = NULL;
  8789. }
  8790. else
  8791. nallargs = nitems;
  8792. }
  8793. if (proargmodes && *proargmodes)
  8794. {
  8795. int nitems = 0;
  8796. if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
  8797. nitems != nallargs)
  8798. {
  8799. write_msg(NULL, "WARNING: could not parse proargmodes array\n");
  8800. if (argmodes)
  8801. free(argmodes);
  8802. argmodes = NULL;
  8803. }
  8804. }
  8805. if (proargnames && *proargnames)
  8806. {
  8807. int nitems = 0;
  8808. if (!parsePGArray(proargnames, &argnames, &nitems) ||
  8809. nitems != nallargs)
  8810. {
  8811. write_msg(NULL, "WARNING: could not parse proargnames array\n");
  8812. if (argnames)
  8813. free(argnames);
  8814. argnames = NULL;
  8815. }
  8816. }
  8817. if (proconfig && *proconfig)
  8818. {
  8819. if (!parsePGArray(proconfig, &configitems, &nconfigitems))
  8820. {
  8821. write_msg(NULL, "WARNING: could not parse proconfig array\n");
  8822. if (configitems)
  8823. free(configitems);
  8824. configitems = NULL;
  8825. nconfigitems = 0;
  8826. }
  8827. }
  8828. if (funcargs)
  8829. {
  8830. /* 8.4 or later; we rely on server-side code for most of the work */
  8831. funcfullsig = format_function_arguments(finfo, funcargs, false);
  8832. funcsig = format_function_arguments(finfo, funciargs, false);
  8833. }
  8834. else
  8835. /* pre-8.4, do it ourselves */
  8836. funcsig = format_function_arguments_old(fout,
  8837. finfo, nallargs, allargtypes,
  8838. argmodes, argnames);
  8839. funcsig_tag = format_function_signature(fout, finfo, false);
  8840. /*
  8841. * DROP must be fully qualified in case same name appears in pg_catalog
  8842. */
  8843. appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
  8844. fmtId(finfo->dobj.namespace->dobj.name),
  8845. funcsig);
  8846. appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig ? funcfullsig :
  8847. funcsig);
  8848. if (funcresult)
  8849. appendPQExpBuffer(q, "RETURNS %s", funcresult);
  8850. else
  8851. {
  8852. rettypename = getFormattedTypeName(fout, finfo->prorettype,
  8853. zeroAsOpaque);
  8854. appendPQExpBuffer(q, "RETURNS %s%s",
  8855. (proretset[0] == 't') ? "SETOF " : "",
  8856. rettypename);
  8857. free(rettypename);
  8858. }
  8859. appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
  8860. if (proiswindow[0] == 't')
  8861. appendPQExpBufferStr(q, " WINDOW");
  8862. if (provolatile[0] != PROVOLATILE_VOLATILE)
  8863. {
  8864. if (provolatile[0] == PROVOLATILE_IMMUTABLE)
  8865. appendPQExpBufferStr(q, " IMMUTABLE");
  8866. else if (provolatile[0] == PROVOLATILE_STABLE)
  8867. appendPQExpBufferStr(q, " STABLE");
  8868. else if (provolatile[0] != PROVOLATILE_VOLATILE)
  8869. exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
  8870. finfo->dobj.name);
  8871. }
  8872. if (proisstrict[0] == 't')
  8873. appendPQExpBufferStr(q, " STRICT");
  8874. if (prosecdef[0] == 't')
  8875. appendPQExpBufferStr(q, " SECURITY DEFINER");
  8876. if (proleakproof[0] == 't')
  8877. appendPQExpBufferStr(q, " LEAKPROOF");
  8878. /*
  8879. * COST and ROWS are emitted only if present and not default, so as not to
  8880. * break backwards-compatibility of the dump without need. Keep this code
  8881. * in sync with the defaults in functioncmds.c.
  8882. */
  8883. if (strcmp(procost, "0") != 0)
  8884. {
  8885. if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
  8886. {
  8887. /* default cost is 1 */
  8888. if (strcmp(procost, "1") != 0)
  8889. appendPQExpBuffer(q, " COST %s", procost);
  8890. }
  8891. else
  8892. {
  8893. /* default cost is 100 */
  8894. if (strcmp(procost, "100") != 0)
  8895. appendPQExpBuffer(q, " COST %s", procost);
  8896. }
  8897. }
  8898. if (proretset[0] == 't' &&
  8899. strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
  8900. appendPQExpBuffer(q, " ROWS %s", prorows);
  8901. for (i = 0; i < nconfigitems; i++)
  8902. {
  8903. /* we feel free to scribble on configitems[] here */
  8904. char *configitem = configitems[i];
  8905. char *pos;
  8906. pos = strchr(configitem, '=');
  8907. if (pos == NULL)
  8908. continue;
  8909. *pos++ = '\0';
  8910. appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
  8911. /*
  8912. * Some GUC variable names are 'LIST' type and hence must not be
  8913. * quoted.
  8914. */
  8915. if (pg_strcasecmp(configitem, "DateStyle") == 0
  8916. || pg_strcasecmp(configitem, "search_path") == 0)
  8917. appendPQExpBufferStr(q, pos);
  8918. else
  8919. appendStringLiteralAH(q, pos, fout);
  8920. }
  8921. appendPQExpBuffer(q, "\n %s;\n", asPart->data);
  8922. appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
  8923. if (binary_upgrade)
  8924. binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
  8925. ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
  8926. funcsig_tag,
  8927. finfo->dobj.namespace->dobj.name,
  8928. NULL,
  8929. finfo->rolname, false,
  8930. "FUNCTION", SECTION_PRE_DATA,
  8931. q->data, delqry->data, NULL,
  8932. NULL, 0,
  8933. NULL, NULL);
  8934. /* Dump Function Comments and Security Labels */
  8935. dumpComment(fout, labelq->data,
  8936. finfo->dobj.namespace->dobj.name, finfo->rolname,
  8937. finfo->dobj.catId, 0, finfo->dobj.dumpId);
  8938. dumpSecLabel(fout, labelq->data,
  8939. finfo->dobj.namespace->dobj.name, finfo->rolname,
  8940. finfo->dobj.catId, 0, finfo->dobj.dumpId);
  8941. dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
  8942. funcsig, NULL, funcsig_tag,
  8943. finfo->dobj.namespace->dobj.name,
  8944. finfo->rolname, finfo->proacl);
  8945. PQclear(res);
  8946. destroyPQExpBuffer(query);
  8947. destroyPQExpBuffer(q);
  8948. destroyPQExpBuffer(delqry);
  8949. destroyPQExpBuffer(labelq);
  8950. destroyPQExpBuffer(asPart);
  8951. free(funcsig);
  8952. if (funcfullsig)
  8953. free(funcfullsig);
  8954. free(funcsig_tag);
  8955. if (allargtypes)
  8956. free(allargtypes);
  8957. if (argmodes)
  8958. free(argmodes);
  8959. if (argnames)
  8960. free(argnames);
  8961. if (configitems)
  8962. free(configitems);
  8963. }
  8964. /*
  8965. * Dump a user-defined cast
  8966. */
  8967. static void
  8968. dumpCast(Archive *fout, CastInfo *cast)
  8969. {
  8970. PQExpBuffer defqry;
  8971. PQExpBuffer delqry;
  8972. PQExpBuffer labelq;
  8973. FuncInfo *funcInfo = NULL;
  8974. /* Skip if not to be dumped */
  8975. if (!cast->dobj.dump || dataOnly)
  8976. return;
  8977. /* Cannot dump if we don't have the cast function's info */
  8978. if (OidIsValid(cast->castfunc))
  8979. {
  8980. funcInfo = findFuncByOid(cast->castfunc);
  8981. if (funcInfo == NULL)
  8982. return;
  8983. }
  8984. /*
  8985. * As per discussion we dump casts if one or more of the underlying
  8986. * objects (the conversion function and the two data types) are not
  8987. * builtin AND if all of the non-builtin objects are included in the dump.
  8988. * Builtin meaning, the namespace name does not start with "pg_".
  8989. *
  8990. * However, for a cast that belongs to an extension, we must not use this
  8991. * heuristic, but just dump the cast iff we're told to (via dobj.dump).
  8992. */
  8993. if (!cast->dobj.ext_member)
  8994. {
  8995. TypeInfo *sourceInfo = findTypeByOid(cast->castsource);
  8996. TypeInfo *targetInfo = findTypeByOid(cast->casttarget);
  8997. if (sourceInfo == NULL || targetInfo == NULL)
  8998. return;
  8999. /*
  9000. * Skip this cast if all objects are from pg_
  9001. */
  9002. if ((funcInfo == NULL ||
  9003. strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
  9004. strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
  9005. strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
  9006. return;
  9007. /*
  9008. * Skip cast if function isn't from pg_ and is not to be dumped.
  9009. */
  9010. if (funcInfo &&
  9011. strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
  9012. !funcInfo->dobj.dump)
  9013. return;
  9014. /*
  9015. * Same for the source type
  9016. */
  9017. if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
  9018. !sourceInfo->dobj.dump)
  9019. return;
  9020. /*
  9021. * and the target type.
  9022. */
  9023. if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
  9024. !targetInfo->dobj.dump)
  9025. return;
  9026. }
  9027. /* Make sure we are in proper schema (needed for getFormattedTypeName) */
  9028. selectSourceSchema(fout, "pg_catalog");
  9029. defqry = createPQExpBuffer();
  9030. delqry = createPQExpBuffer();
  9031. labelq = createPQExpBuffer();
  9032. appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
  9033. getFormattedTypeName(fout, cast->castsource, zeroAsNone),
  9034. getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
  9035. appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
  9036. getFormattedTypeName(fout, cast->castsource, zeroAsNone),
  9037. getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
  9038. switch (cast->castmethod)
  9039. {
  9040. case COERCION_METHOD_BINARY:
  9041. appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
  9042. break;
  9043. case COERCION_METHOD_INOUT:
  9044. appendPQExpBufferStr(defqry, "WITH INOUT");
  9045. break;
  9046. case COERCION_METHOD_FUNCTION:
  9047. if (funcInfo)
  9048. {
  9049. char *fsig = format_function_signature(fout, funcInfo, true);
  9050. /*
  9051. * Always qualify the function name, in case it is not in
  9052. * pg_catalog schema (format_function_signature won't qualify
  9053. * it).
  9054. */
  9055. appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
  9056. fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
  9057. free(fsig);
  9058. }
  9059. else
  9060. write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
  9061. break;
  9062. default:
  9063. write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
  9064. }
  9065. if (cast->castcontext == 'a')
  9066. appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
  9067. else if (cast->castcontext == 'i')
  9068. appendPQExpBufferStr(defqry, " AS IMPLICIT");
  9069. appendPQExpBufferStr(defqry, ";\n");
  9070. appendPQExpBuffer(labelq, "CAST (%s AS %s)",
  9071. getFormattedTypeName(fout, cast->castsource, zeroAsNone),
  9072. getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
  9073. if (binary_upgrade)
  9074. binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
  9075. ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
  9076. labelq->data,
  9077. "pg_catalog", NULL, "",
  9078. false, "CAST", SECTION_PRE_DATA,
  9079. defqry->data, delqry->data, NULL,
  9080. NULL, 0,
  9081. NULL, NULL);
  9082. /* Dump Cast Comments */
  9083. dumpComment(fout, labelq->data,
  9084. NULL, "",
  9085. cast->dobj.catId, 0, cast->dobj.dumpId);
  9086. destroyPQExpBuffer(defqry);
  9087. destroyPQExpBuffer(delqry);
  9088. destroyPQExpBuffer(labelq);
  9089. }
  9090. /*
  9091. * dumpOpr
  9092. * write out a single operator definition
  9093. */
  9094. static void
  9095. dumpOpr(Archive *fout, OprInfo *oprinfo)
  9096. {
  9097. PQExpBuffer query;
  9098. PQExpBuffer q;
  9099. PQExpBuffer delq;
  9100. PQExpBuffer labelq;
  9101. PQExpBuffer oprid;
  9102. PQExpBuffer details;
  9103. const char *name;
  9104. PGresult *res;
  9105. int i_oprkind;
  9106. int i_oprcode;
  9107. int i_oprleft;
  9108. int i_oprright;
  9109. int i_oprcom;
  9110. int i_oprnegate;
  9111. int i_oprrest;
  9112. int i_oprjoin;
  9113. int i_oprcanmerge;
  9114. int i_oprcanhash;
  9115. char *oprkind;
  9116. char *oprcode;
  9117. char *oprleft;
  9118. char *oprright;
  9119. char *oprcom;
  9120. char *oprnegate;
  9121. char *oprrest;
  9122. char *oprjoin;
  9123. char *oprcanmerge;
  9124. char *oprcanhash;
  9125. char *oprregproc;
  9126. char *oprref;
  9127. /* Skip if not to be dumped */
  9128. if (!oprinfo->dobj.dump || dataOnly)
  9129. return;
  9130. /*
  9131. * some operators are invalid because they were the result of user
  9132. * defining operators before commutators exist
  9133. */
  9134. if (!OidIsValid(oprinfo->oprcode))
  9135. return;
  9136. query = createPQExpBuffer();
  9137. q = createPQExpBuffer();
  9138. delq = createPQExpBuffer();
  9139. labelq = createPQExpBuffer();
  9140. oprid = createPQExpBuffer();
  9141. details = createPQExpBuffer();
  9142. /* Make sure we are in proper schema so regoperator works correctly */
  9143. selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
  9144. if (fout->remoteVersion >= 80300)
  9145. {
  9146. appendPQExpBuffer(query, "SELECT oprkind, "
  9147. "oprcode::pg_catalog.regprocedure, "
  9148. "oprleft::pg_catalog.regtype, "
  9149. "oprright::pg_catalog.regtype, "
  9150. "oprcom::pg_catalog.regoperator, "
  9151. "oprnegate::pg_catalog.regoperator, "
  9152. "oprrest::pg_catalog.regprocedure, "
  9153. "oprjoin::pg_catalog.regprocedure, "
  9154. "oprcanmerge, oprcanhash "
  9155. "FROM pg_catalog.pg_operator "
  9156. "WHERE oid = '%u'::pg_catalog.oid",
  9157. oprinfo->dobj.catId.oid);
  9158. }
  9159. else if (fout->remoteVersion >= 70300)
  9160. {
  9161. appendPQExpBuffer(query, "SELECT oprkind, "
  9162. "oprcode::pg_catalog.regprocedure, "
  9163. "oprleft::pg_catalog.regtype, "
  9164. "oprright::pg_catalog.regtype, "
  9165. "oprcom::pg_catalog.regoperator, "
  9166. "oprnegate::pg_catalog.regoperator, "
  9167. "oprrest::pg_catalog.regprocedure, "
  9168. "oprjoin::pg_catalog.regprocedure, "
  9169. "(oprlsortop != 0) AS oprcanmerge, "
  9170. "oprcanhash "
  9171. "FROM pg_catalog.pg_operator "
  9172. "WHERE oid = '%u'::pg_catalog.oid",
  9173. oprinfo->dobj.catId.oid);
  9174. }
  9175. else if (fout->remoteVersion >= 70100)
  9176. {
  9177. appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
  9178. "CASE WHEN oprleft = 0 THEN '-' "
  9179. "ELSE format_type(oprleft, NULL) END AS oprleft, "
  9180. "CASE WHEN oprright = 0 THEN '-' "
  9181. "ELSE format_type(oprright, NULL) END AS oprright, "
  9182. "oprcom, oprnegate, oprrest, oprjoin, "
  9183. "(oprlsortop != 0) AS oprcanmerge, "
  9184. "oprcanhash "
  9185. "FROM pg_operator "
  9186. "WHERE oid = '%u'::oid",
  9187. oprinfo->dobj.catId.oid);
  9188. }
  9189. else
  9190. {
  9191. appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
  9192. "CASE WHEN oprleft = 0 THEN '-'::name "
  9193. "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
  9194. "CASE WHEN oprright = 0 THEN '-'::name "
  9195. "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
  9196. "oprcom, oprnegate, oprrest, oprjoin, "
  9197. "(oprlsortop != 0) AS oprcanmerge, "
  9198. "oprcanhash "
  9199. "FROM pg_operator "
  9200. "WHERE oid = '%u'::oid",
  9201. oprinfo->dobj.catId.oid);
  9202. }
  9203. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  9204. i_oprkind = PQfnumber(res, "oprkind");
  9205. i_oprcode = PQfnumber(res, "oprcode");
  9206. i_oprleft = PQfnumber(res, "oprleft");
  9207. i_oprright = PQfnumber(res, "oprright");
  9208. i_oprcom = PQfnumber(res, "oprcom");
  9209. i_oprnegate = PQfnumber(res, "oprnegate");
  9210. i_oprrest = PQfnumber(res, "oprrest");
  9211. i_oprjoin = PQfnumber(res, "oprjoin");
  9212. i_oprcanmerge = PQfnumber(res, "oprcanmerge");
  9213. i_oprcanhash = PQfnumber(res, "oprcanhash");
  9214. oprkind = PQgetvalue(res, 0, i_oprkind);
  9215. oprcode = PQgetvalue(res, 0, i_oprcode);
  9216. oprleft = PQgetvalue(res, 0, i_oprleft);
  9217. oprright = PQgetvalue(res, 0, i_oprright);
  9218. oprcom = PQgetvalue(res, 0, i_oprcom);
  9219. oprnegate = PQgetvalue(res, 0, i_oprnegate);
  9220. oprrest = PQgetvalue(res, 0, i_oprrest);
  9221. oprjoin = PQgetvalue(res, 0, i_oprjoin);
  9222. oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
  9223. oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
  9224. oprregproc = convertRegProcReference(fout, oprcode);
  9225. if (oprregproc)
  9226. {
  9227. appendPQExpBuffer(details, " PROCEDURE = %s", oprregproc);
  9228. free(oprregproc);
  9229. }
  9230. appendPQExpBuffer(oprid, "%s (",
  9231. oprinfo->dobj.name);
  9232. /*
  9233. * right unary means there's a left arg and left unary means there's a
  9234. * right arg
  9235. */
  9236. if (strcmp(oprkind, "r") == 0 ||
  9237. strcmp(oprkind, "b") == 0)
  9238. {
  9239. if (fout->remoteVersion >= 70100)
  9240. name = oprleft;
  9241. else
  9242. name = fmtId(oprleft);
  9243. appendPQExpBuffer(details, ",\n LEFTARG = %s", name);
  9244. appendPQExpBufferStr(oprid, name);
  9245. }
  9246. else
  9247. appendPQExpBufferStr(oprid, "NONE");
  9248. if (strcmp(oprkind, "l") == 0 ||
  9249. strcmp(oprkind, "b") == 0)
  9250. {
  9251. if (fout->remoteVersion >= 70100)
  9252. name = oprright;
  9253. else
  9254. name = fmtId(oprright);
  9255. appendPQExpBuffer(details, ",\n RIGHTARG = %s", name);
  9256. appendPQExpBuffer(oprid, ", %s)", name);
  9257. }
  9258. else
  9259. appendPQExpBufferStr(oprid, ", NONE)");
  9260. oprref = convertOperatorReference(fout, oprcom);
  9261. if (oprref)
  9262. {
  9263. appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
  9264. free(oprref);
  9265. }
  9266. oprref = convertOperatorReference(fout, oprnegate);
  9267. if (oprref)
  9268. {
  9269. appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
  9270. free(oprref);
  9271. }
  9272. if (strcmp(oprcanmerge, "t") == 0)
  9273. appendPQExpBufferStr(details, ",\n MERGES");
  9274. if (strcmp(oprcanhash, "t") == 0)
  9275. appendPQExpBufferStr(details, ",\n HASHES");
  9276. oprregproc = convertRegProcReference(fout, oprrest);
  9277. if (oprregproc)
  9278. {
  9279. appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
  9280. free(oprregproc);
  9281. }
  9282. oprregproc = convertRegProcReference(fout, oprjoin);
  9283. if (oprregproc)
  9284. {
  9285. appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
  9286. free(oprregproc);
  9287. }
  9288. /*
  9289. * DROP must be fully qualified in case same name appears in pg_catalog
  9290. */
  9291. appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
  9292. fmtId(oprinfo->dobj.namespace->dobj.name),
  9293. oprid->data);
  9294. appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
  9295. oprinfo->dobj.name, details->data);
  9296. appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
  9297. if (binary_upgrade)
  9298. binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
  9299. ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
  9300. oprinfo->dobj.name,
  9301. oprinfo->dobj.namespace->dobj.name,
  9302. NULL,
  9303. oprinfo->rolname,
  9304. false, "OPERATOR", SECTION_PRE_DATA,
  9305. q->data, delq->data, NULL,
  9306. NULL, 0,
  9307. NULL, NULL);
  9308. /* Dump Operator Comments */
  9309. dumpComment(fout, labelq->data,
  9310. oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
  9311. oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
  9312. PQclear(res);
  9313. destroyPQExpBuffer(query);
  9314. destroyPQExpBuffer(q);
  9315. destroyPQExpBuffer(delq);
  9316. destroyPQExpBuffer(labelq);
  9317. destroyPQExpBuffer(oprid);
  9318. destroyPQExpBuffer(details);
  9319. }
  9320. /*
  9321. * Convert a function reference obtained from pg_operator
  9322. *
  9323. * Returns allocated string of what to print, or NULL if function references
  9324. * is InvalidOid. Returned string is expected to be free'd by the caller.
  9325. *
  9326. * In 7.3 the input is a REGPROCEDURE display; we have to strip the
  9327. * argument-types part. In prior versions, the input is a REGPROC display.
  9328. */
  9329. static char *
  9330. convertRegProcReference(Archive *fout, const char *proc)
  9331. {
  9332. /* In all cases "-" means a null reference */
  9333. if (strcmp(proc, "-") == 0)
  9334. return NULL;
  9335. if (fout->remoteVersion >= 70300)
  9336. {
  9337. char *name;
  9338. char *paren;
  9339. bool inquote;
  9340. name = pg_strdup(proc);
  9341. /* find non-double-quoted left paren */
  9342. inquote = false;
  9343. for (paren = name; *paren; paren++)
  9344. {
  9345. if (*paren == '(' && !inquote)
  9346. {
  9347. *paren = '\0';
  9348. break;
  9349. }
  9350. if (*paren == '"')
  9351. inquote = !inquote;
  9352. }
  9353. return name;
  9354. }
  9355. /* REGPROC before 7.3 does not quote its result */
  9356. return pg_strdup(fmtId(proc));
  9357. }
  9358. /*
  9359. * Convert an operator cross-reference obtained from pg_operator
  9360. *
  9361. * Returns an allocated string of what to print, or NULL to print nothing.
  9362. * Caller is responsible for free'ing result string.
  9363. *
  9364. * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
  9365. * argument-types part, and add OPERATOR() decoration if the name is
  9366. * schema-qualified. In older versions, the input is just a numeric OID,
  9367. * which we search our operator list for.
  9368. */
  9369. static char *
  9370. convertOperatorReference(Archive *fout, const char *opr)
  9371. {
  9372. OprInfo *oprInfo;
  9373. /* In all cases "0" means a null reference */
  9374. if (strcmp(opr, "0") == 0)
  9375. return NULL;
  9376. if (fout->remoteVersion >= 70300)
  9377. {
  9378. char *name;
  9379. char *oname;
  9380. char *ptr;
  9381. bool inquote;
  9382. bool sawdot;
  9383. name = pg_strdup(opr);
  9384. /* find non-double-quoted left paren, and check for non-quoted dot */
  9385. inquote = false;
  9386. sawdot = false;
  9387. for (ptr = name; *ptr; ptr++)
  9388. {
  9389. if (*ptr == '"')
  9390. inquote = !inquote;
  9391. else if (*ptr == '.' && !inquote)
  9392. sawdot = true;
  9393. else if (*ptr == '(' && !inquote)
  9394. {
  9395. *ptr = '\0';
  9396. break;
  9397. }
  9398. }
  9399. /* If not schema-qualified, don't need to add OPERATOR() */
  9400. if (!sawdot)
  9401. return name;
  9402. oname = psprintf("OPERATOR(%s)", name);
  9403. free(name);
  9404. return oname;
  9405. }
  9406. oprInfo = findOprByOid(atooid(opr));
  9407. if (oprInfo == NULL)
  9408. {
  9409. write_msg(NULL, "WARNING: could not find operator with OID %s\n",
  9410. opr);
  9411. return NULL;
  9412. }
  9413. return pg_strdup(oprInfo->dobj.name);
  9414. }
  9415. /*
  9416. * Convert a function OID obtained from pg_ts_parser or pg_ts_template
  9417. *
  9418. * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
  9419. * argument lists of these functions are predetermined. Note that the
  9420. * caller should ensure we are in the proper schema, because the results
  9421. * are search path dependent!
  9422. */
  9423. static const char *
  9424. convertTSFunction(Archive *fout, Oid funcOid)
  9425. {
  9426. char *result;
  9427. char query[128];
  9428. PGresult *res;
  9429. snprintf(query, sizeof(query),
  9430. "SELECT '%u'::pg_catalog.regproc", funcOid);
  9431. res = ExecuteSqlQueryForSingleRow(fout, query);
  9432. result = pg_strdup(PQgetvalue(res, 0, 0));
  9433. PQclear(res);
  9434. return result;
  9435. }
  9436. /*
  9437. * dumpOpclass
  9438. * write out a single operator class definition
  9439. */
  9440. static void
  9441. dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
  9442. {
  9443. PQExpBuffer query;
  9444. PQExpBuffer q;
  9445. PQExpBuffer delq;
  9446. PQExpBuffer labelq;
  9447. PGresult *res;
  9448. int ntups;
  9449. int i_opcintype;
  9450. int i_opckeytype;
  9451. int i_opcdefault;
  9452. int i_opcfamily;
  9453. int i_opcfamilyname;
  9454. int i_opcfamilynsp;
  9455. int i_amname;
  9456. int i_amopstrategy;
  9457. int i_amopreqcheck;
  9458. int i_amopopr;
  9459. int i_sortfamily;
  9460. int i_sortfamilynsp;
  9461. int i_amprocnum;
  9462. int i_amproc;
  9463. int i_amproclefttype;
  9464. int i_amprocrighttype;
  9465. char *opcintype;
  9466. char *opckeytype;
  9467. char *opcdefault;
  9468. char *opcfamily;
  9469. char *opcfamilyname;
  9470. char *opcfamilynsp;
  9471. char *amname;
  9472. char *amopstrategy;
  9473. char *amopreqcheck;
  9474. char *amopopr;
  9475. char *sortfamily;
  9476. char *sortfamilynsp;
  9477. char *amprocnum;
  9478. char *amproc;
  9479. char *amproclefttype;
  9480. char *amprocrighttype;
  9481. bool needComma;
  9482. int i;
  9483. /* Skip if not to be dumped */
  9484. if (!opcinfo->dobj.dump || dataOnly)
  9485. return;
  9486. /*
  9487. * XXX currently we do not implement dumping of operator classes from
  9488. * pre-7.3 databases. This could be done but it seems not worth the
  9489. * trouble.
  9490. */
  9491. if (fout->remoteVersion < 70300)
  9492. return;
  9493. query = createPQExpBuffer();
  9494. q = createPQExpBuffer();
  9495. delq = createPQExpBuffer();
  9496. labelq = createPQExpBuffer();
  9497. /* Make sure we are in proper schema so regoperator works correctly */
  9498. selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
  9499. /* Get additional fields from the pg_opclass row */
  9500. if (fout->remoteVersion >= 80300)
  9501. {
  9502. appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
  9503. "opckeytype::pg_catalog.regtype, "
  9504. "opcdefault, opcfamily, "
  9505. "opfname AS opcfamilyname, "
  9506. "nspname AS opcfamilynsp, "
  9507. "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
  9508. "FROM pg_catalog.pg_opclass c "
  9509. "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
  9510. "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
  9511. "WHERE c.oid = '%u'::pg_catalog.oid",
  9512. opcinfo->dobj.catId.oid);
  9513. }
  9514. else
  9515. {
  9516. appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
  9517. "opckeytype::pg_catalog.regtype, "
  9518. "opcdefault, NULL AS opcfamily, "
  9519. "NULL AS opcfamilyname, "
  9520. "NULL AS opcfamilynsp, "
  9521. "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
  9522. "FROM pg_catalog.pg_opclass "
  9523. "WHERE oid = '%u'::pg_catalog.oid",
  9524. opcinfo->dobj.catId.oid);
  9525. }
  9526. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  9527. i_opcintype = PQfnumber(res, "opcintype");
  9528. i_opckeytype = PQfnumber(res, "opckeytype");
  9529. i_opcdefault = PQfnumber(res, "opcdefault");
  9530. i_opcfamily = PQfnumber(res, "opcfamily");
  9531. i_opcfamilyname = PQfnumber(res, "opcfamilyname");
  9532. i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
  9533. i_amname = PQfnumber(res, "amname");
  9534. opcintype = PQgetvalue(res, 0, i_opcintype);
  9535. opckeytype = PQgetvalue(res, 0, i_opckeytype);
  9536. opcdefault = PQgetvalue(res, 0, i_opcdefault);
  9537. /* opcfamily will still be needed after we PQclear res */
  9538. opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
  9539. opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
  9540. opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
  9541. /* amname will still be needed after we PQclear res */
  9542. amname = pg_strdup(PQgetvalue(res, 0, i_amname));
  9543. /*
  9544. * DROP must be fully qualified in case same name appears in pg_catalog
  9545. */
  9546. appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
  9547. fmtId(opcinfo->dobj.namespace->dobj.name));
  9548. appendPQExpBuffer(delq, ".%s",
  9549. fmtId(opcinfo->dobj.name));
  9550. appendPQExpBuffer(delq, " USING %s;\n",
  9551. fmtId(amname));
  9552. /* Build the fixed portion of the CREATE command */
  9553. appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
  9554. fmtId(opcinfo->dobj.name));
  9555. if (strcmp(opcdefault, "t") == 0)
  9556. appendPQExpBufferStr(q, "DEFAULT ");
  9557. appendPQExpBuffer(q, "FOR TYPE %s USING %s",
  9558. opcintype,
  9559. fmtId(amname));
  9560. if (strlen(opcfamilyname) > 0 &&
  9561. (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
  9562. strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
  9563. {
  9564. appendPQExpBufferStr(q, " FAMILY ");
  9565. if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
  9566. appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
  9567. appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
  9568. }
  9569. appendPQExpBufferStr(q, " AS\n ");
  9570. needComma = false;
  9571. if (strcmp(opckeytype, "-") != 0)
  9572. {
  9573. appendPQExpBuffer(q, "STORAGE %s",
  9574. opckeytype);
  9575. needComma = true;
  9576. }
  9577. PQclear(res);
  9578. /*
  9579. * Now fetch and print the OPERATOR entries (pg_amop rows).
  9580. *
  9581. * Print only those opfamily members that are tied to the opclass by
  9582. * pg_depend entries.
  9583. *
  9584. * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
  9585. * older server's opclass in which it is used. This is to avoid
  9586. * hard-to-detect breakage if a newer pg_dump is used to dump from an
  9587. * older server and then reload into that old version. This can go away
  9588. * once 8.3 is so old as to not be of interest to anyone.
  9589. */
  9590. resetPQExpBuffer(query);
  9591. if (fout->remoteVersion >= 90100)
  9592. {
  9593. appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
  9594. "amopopr::pg_catalog.regoperator, "
  9595. "opfname AS sortfamily, "
  9596. "nspname AS sortfamilynsp "
  9597. "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
  9598. "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
  9599. "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
  9600. "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
  9601. "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
  9602. "AND refobjid = '%u'::pg_catalog.oid "
  9603. "AND amopfamily = '%s'::pg_catalog.oid "
  9604. "ORDER BY amopstrategy",
  9605. opcinfo->dobj.catId.oid,
  9606. opcfamily);
  9607. }
  9608. else if (fout->remoteVersion >= 80400)
  9609. {
  9610. appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
  9611. "amopopr::pg_catalog.regoperator, "
  9612. "NULL AS sortfamily, "
  9613. "NULL AS sortfamilynsp "
  9614. "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
  9615. "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
  9616. "AND refobjid = '%u'::pg_catalog.oid "
  9617. "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
  9618. "AND objid = ao.oid "
  9619. "ORDER BY amopstrategy",
  9620. opcinfo->dobj.catId.oid);
  9621. }
  9622. else if (fout->remoteVersion >= 80300)
  9623. {
  9624. appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
  9625. "amopopr::pg_catalog.regoperator, "
  9626. "NULL AS sortfamily, "
  9627. "NULL AS sortfamilynsp "
  9628. "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
  9629. "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
  9630. "AND refobjid = '%u'::pg_catalog.oid "
  9631. "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
  9632. "AND objid = ao.oid "
  9633. "ORDER BY amopstrategy",
  9634. opcinfo->dobj.catId.oid);
  9635. }
  9636. else
  9637. {
  9638. /*
  9639. * Here, we print all entries since there are no opfamilies and hence
  9640. * no loose operators to worry about.
  9641. */
  9642. appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
  9643. "amopopr::pg_catalog.regoperator, "
  9644. "NULL AS sortfamily, "
  9645. "NULL AS sortfamilynsp "
  9646. "FROM pg_catalog.pg_amop "
  9647. "WHERE amopclaid = '%u'::pg_catalog.oid "
  9648. "ORDER BY amopstrategy",
  9649. opcinfo->dobj.catId.oid);
  9650. }
  9651. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  9652. ntups = PQntuples(res);
  9653. i_amopstrategy = PQfnumber(res, "amopstrategy");
  9654. i_amopreqcheck = PQfnumber(res, "amopreqcheck");
  9655. i_amopopr = PQfnumber(res, "amopopr");
  9656. i_sortfamily = PQfnumber(res, "sortfamily");
  9657. i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
  9658. for (i = 0; i < ntups; i++)
  9659. {
  9660. amopstrategy = PQgetvalue(res, i, i_amopstrategy);
  9661. amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
  9662. amopopr = PQgetvalue(res, i, i_amopopr);
  9663. sortfamily = PQgetvalue(res, i, i_sortfamily);
  9664. sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
  9665. if (needComma)
  9666. appendPQExpBufferStr(q, " ,\n ");
  9667. appendPQExpBuffer(q, "OPERATOR %s %s",
  9668. amopstrategy, amopopr);
  9669. if (strlen(sortfamily) > 0)
  9670. {
  9671. appendPQExpBufferStr(q, " FOR ORDER BY ");
  9672. if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
  9673. appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
  9674. appendPQExpBufferStr(q, fmtId(sortfamily));
  9675. }
  9676. if (strcmp(amopreqcheck, "t") == 0)
  9677. appendPQExpBufferStr(q, " RECHECK");
  9678. needComma = true;
  9679. }
  9680. PQclear(res);
  9681. /*
  9682. * Now fetch and print the FUNCTION entries (pg_amproc rows).
  9683. *
  9684. * Print only those opfamily members that are tied to the opclass by
  9685. * pg_depend entries.
  9686. *
  9687. * We print the amproclefttype/amprocrighttype even though in most cases
  9688. * the backend could deduce the right values, because of the corner case
  9689. * of a btree sort support function for a cross-type comparison. That's
  9690. * only allowed in 9.2 and later, but for simplicity print them in all
  9691. * versions that have the columns.
  9692. */
  9693. resetPQExpBuffer(query);
  9694. if (fout->remoteVersion >= 80300)
  9695. {
  9696. appendPQExpBuffer(query, "SELECT amprocnum, "
  9697. "amproc::pg_catalog.regprocedure, "
  9698. "amproclefttype::pg_catalog.regtype, "
  9699. "amprocrighttype::pg_catalog.regtype "
  9700. "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
  9701. "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
  9702. "AND refobjid = '%u'::pg_catalog.oid "
  9703. "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
  9704. "AND objid = ap.oid "
  9705. "ORDER BY amprocnum",
  9706. opcinfo->dobj.catId.oid);
  9707. }
  9708. else
  9709. {
  9710. appendPQExpBuffer(query, "SELECT amprocnum, "
  9711. "amproc::pg_catalog.regprocedure, "
  9712. "'' AS amproclefttype, "
  9713. "'' AS amprocrighttype "
  9714. "FROM pg_catalog.pg_amproc "
  9715. "WHERE amopclaid = '%u'::pg_catalog.oid "
  9716. "ORDER BY amprocnum",
  9717. opcinfo->dobj.catId.oid);
  9718. }
  9719. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  9720. ntups = PQntuples(res);
  9721. i_amprocnum = PQfnumber(res, "amprocnum");
  9722. i_amproc = PQfnumber(res, "amproc");
  9723. i_amproclefttype = PQfnumber(res, "amproclefttype");
  9724. i_amprocrighttype = PQfnumber(res, "amprocrighttype");
  9725. for (i = 0; i < ntups; i++)
  9726. {
  9727. amprocnum = PQgetvalue(res, i, i_amprocnum);
  9728. amproc = PQgetvalue(res, i, i_amproc);
  9729. amproclefttype = PQgetvalue(res, i, i_amproclefttype);
  9730. amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
  9731. if (needComma)
  9732. appendPQExpBufferStr(q, " ,\n ");
  9733. appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
  9734. if (*amproclefttype && *amprocrighttype)
  9735. appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
  9736. appendPQExpBuffer(q, " %s", amproc);
  9737. needComma = true;
  9738. }
  9739. PQclear(res);
  9740. appendPQExpBufferStr(q, ";\n");
  9741. appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
  9742. fmtId(opcinfo->dobj.name));
  9743. appendPQExpBuffer(labelq, " USING %s",
  9744. fmtId(amname));
  9745. if (binary_upgrade)
  9746. binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
  9747. ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
  9748. opcinfo->dobj.name,
  9749. opcinfo->dobj.namespace->dobj.name,
  9750. NULL,
  9751. opcinfo->rolname,
  9752. false, "OPERATOR CLASS", SECTION_PRE_DATA,
  9753. q->data, delq->data, NULL,
  9754. NULL, 0,
  9755. NULL, NULL);
  9756. /* Dump Operator Class Comments */
  9757. dumpComment(fout, labelq->data,
  9758. NULL, opcinfo->rolname,
  9759. opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
  9760. free(amname);
  9761. destroyPQExpBuffer(query);
  9762. destroyPQExpBuffer(q);
  9763. destroyPQExpBuffer(delq);
  9764. destroyPQExpBuffer(labelq);
  9765. }
  9766. /*
  9767. * dumpOpfamily
  9768. * write out a single operator family definition
  9769. *
  9770. * Note: this also dumps any "loose" operator members that aren't bound to a
  9771. * specific opclass within the opfamily.
  9772. */
  9773. static void
  9774. dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
  9775. {
  9776. PQExpBuffer query;
  9777. PQExpBuffer q;
  9778. PQExpBuffer delq;
  9779. PQExpBuffer labelq;
  9780. PGresult *res;
  9781. PGresult *res_ops;
  9782. PGresult *res_procs;
  9783. int ntups;
  9784. int i_amname;
  9785. int i_amopstrategy;
  9786. int i_amopreqcheck;
  9787. int i_amopopr;
  9788. int i_sortfamily;
  9789. int i_sortfamilynsp;
  9790. int i_amprocnum;
  9791. int i_amproc;
  9792. int i_amproclefttype;
  9793. int i_amprocrighttype;
  9794. char *amname;
  9795. char *amopstrategy;
  9796. char *amopreqcheck;
  9797. char *amopopr;
  9798. char *sortfamily;
  9799. char *sortfamilynsp;
  9800. char *amprocnum;
  9801. char *amproc;
  9802. char *amproclefttype;
  9803. char *amprocrighttype;
  9804. bool needComma;
  9805. int i;
  9806. /* Skip if not to be dumped */
  9807. if (!opfinfo->dobj.dump || dataOnly)
  9808. return;
  9809. /*
  9810. * We want to dump the opfamily only if (1) it contains "loose" operators
  9811. * or functions, or (2) it contains an opclass with a different name or
  9812. * owner. Otherwise it's sufficient to let it be created during creation
  9813. * of the contained opclass, and not dumping it improves portability of
  9814. * the dump. Since we have to fetch the loose operators/funcs anyway, do
  9815. * that first.
  9816. */
  9817. query = createPQExpBuffer();
  9818. q = createPQExpBuffer();
  9819. delq = createPQExpBuffer();
  9820. labelq = createPQExpBuffer();
  9821. /* Make sure we are in proper schema so regoperator works correctly */
  9822. selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
  9823. /*
  9824. * Fetch only those opfamily members that are tied directly to the
  9825. * opfamily by pg_depend entries.
  9826. *
  9827. * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
  9828. * older server's opclass in which it is used. This is to avoid
  9829. * hard-to-detect breakage if a newer pg_dump is used to dump from an
  9830. * older server and then reload into that old version. This can go away
  9831. * once 8.3 is so old as to not be of interest to anyone.
  9832. */
  9833. if (fout->remoteVersion >= 90100)
  9834. {
  9835. appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
  9836. "amopopr::pg_catalog.regoperator, "
  9837. "opfname AS sortfamily, "
  9838. "nspname AS sortfamilynsp "
  9839. "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
  9840. "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
  9841. "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
  9842. "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
  9843. "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
  9844. "AND refobjid = '%u'::pg_catalog.oid "
  9845. "AND amopfamily = '%u'::pg_catalog.oid "
  9846. "ORDER BY amopstrategy",
  9847. opfinfo->dobj.catId.oid,
  9848. opfinfo->dobj.catId.oid);
  9849. }
  9850. else if (fout->remoteVersion >= 80400)
  9851. {
  9852. appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
  9853. "amopopr::pg_catalog.regoperator, "
  9854. "NULL AS sortfamily, "
  9855. "NULL AS sortfamilynsp "
  9856. "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
  9857. "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
  9858. "AND refobjid = '%u'::pg_catalog.oid "
  9859. "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
  9860. "AND objid = ao.oid "
  9861. "ORDER BY amopstrategy",
  9862. opfinfo->dobj.catId.oid);
  9863. }
  9864. else
  9865. {
  9866. appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
  9867. "amopopr::pg_catalog.regoperator, "
  9868. "NULL AS sortfamily, "
  9869. "NULL AS sortfamilynsp "
  9870. "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
  9871. "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
  9872. "AND refobjid = '%u'::pg_catalog.oid "
  9873. "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
  9874. "AND objid = ao.oid "
  9875. "ORDER BY amopstrategy",
  9876. opfinfo->dobj.catId.oid);
  9877. }
  9878. res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  9879. resetPQExpBuffer(query);
  9880. appendPQExpBuffer(query, "SELECT amprocnum, "
  9881. "amproc::pg_catalog.regprocedure, "
  9882. "amproclefttype::pg_catalog.regtype, "
  9883. "amprocrighttype::pg_catalog.regtype "
  9884. "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
  9885. "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
  9886. "AND refobjid = '%u'::pg_catalog.oid "
  9887. "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
  9888. "AND objid = ap.oid "
  9889. "ORDER BY amprocnum",
  9890. opfinfo->dobj.catId.oid);
  9891. res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  9892. if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
  9893. {
  9894. /* No loose members, so check contained opclasses */
  9895. resetPQExpBuffer(query);
  9896. appendPQExpBuffer(query, "SELECT 1 "
  9897. "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
  9898. "WHERE f.oid = '%u'::pg_catalog.oid "
  9899. "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
  9900. "AND refobjid = f.oid "
  9901. "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
  9902. "AND objid = c.oid "
  9903. "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
  9904. "LIMIT 1",
  9905. opfinfo->dobj.catId.oid);
  9906. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  9907. if (PQntuples(res) == 0)
  9908. {
  9909. /* no need to dump it, so bail out */
  9910. PQclear(res);
  9911. PQclear(res_ops);
  9912. PQclear(res_procs);
  9913. destroyPQExpBuffer(query);
  9914. destroyPQExpBuffer(q);
  9915. destroyPQExpBuffer(delq);
  9916. destroyPQExpBuffer(labelq);
  9917. return;
  9918. }
  9919. PQclear(res);
  9920. }
  9921. /* Get additional fields from the pg_opfamily row */
  9922. resetPQExpBuffer(query);
  9923. appendPQExpBuffer(query, "SELECT "
  9924. "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
  9925. "FROM pg_catalog.pg_opfamily "
  9926. "WHERE oid = '%u'::pg_catalog.oid",
  9927. opfinfo->dobj.catId.oid);
  9928. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  9929. i_amname = PQfnumber(res, "amname");
  9930. /* amname will still be needed after we PQclear res */
  9931. amname = pg_strdup(PQgetvalue(res, 0, i_amname));
  9932. /*
  9933. * DROP must be fully qualified in case same name appears in pg_catalog
  9934. */
  9935. appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
  9936. fmtId(opfinfo->dobj.namespace->dobj.name));
  9937. appendPQExpBuffer(delq, ".%s",
  9938. fmtId(opfinfo->dobj.name));
  9939. appendPQExpBuffer(delq, " USING %s;\n",
  9940. fmtId(amname));
  9941. /* Build the fixed portion of the CREATE command */
  9942. appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
  9943. fmtId(opfinfo->dobj.name));
  9944. appendPQExpBuffer(q, " USING %s;\n",
  9945. fmtId(amname));
  9946. PQclear(res);
  9947. /* Do we need an ALTER to add loose members? */
  9948. if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
  9949. {
  9950. appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
  9951. fmtId(opfinfo->dobj.name));
  9952. appendPQExpBuffer(q, " USING %s ADD\n ",
  9953. fmtId(amname));
  9954. needComma = false;
  9955. /*
  9956. * Now fetch and print the OPERATOR entries (pg_amop rows).
  9957. */
  9958. ntups = PQntuples(res_ops);
  9959. i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
  9960. i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
  9961. i_amopopr = PQfnumber(res_ops, "amopopr");
  9962. i_sortfamily = PQfnumber(res_ops, "sortfamily");
  9963. i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
  9964. for (i = 0; i < ntups; i++)
  9965. {
  9966. amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
  9967. amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
  9968. amopopr = PQgetvalue(res_ops, i, i_amopopr);
  9969. sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
  9970. sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
  9971. if (needComma)
  9972. appendPQExpBufferStr(q, " ,\n ");
  9973. appendPQExpBuffer(q, "OPERATOR %s %s",
  9974. amopstrategy, amopopr);
  9975. if (strlen(sortfamily) > 0)
  9976. {
  9977. appendPQExpBufferStr(q, " FOR ORDER BY ");
  9978. if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
  9979. appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
  9980. appendPQExpBufferStr(q, fmtId(sortfamily));
  9981. }
  9982. if (strcmp(amopreqcheck, "t") == 0)
  9983. appendPQExpBufferStr(q, " RECHECK");
  9984. needComma = true;
  9985. }
  9986. /*
  9987. * Now fetch and print the FUNCTION entries (pg_amproc rows).
  9988. */
  9989. ntups = PQntuples(res_procs);
  9990. i_amprocnum = PQfnumber(res_procs, "amprocnum");
  9991. i_amproc = PQfnumber(res_procs, "amproc");
  9992. i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
  9993. i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
  9994. for (i = 0; i < ntups; i++)
  9995. {
  9996. amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
  9997. amproc = PQgetvalue(res_procs, i, i_amproc);
  9998. amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
  9999. amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
  10000. if (needComma)
  10001. appendPQExpBufferStr(q, " ,\n ");
  10002. appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
  10003. amprocnum, amproclefttype, amprocrighttype,
  10004. amproc);
  10005. needComma = true;
  10006. }
  10007. appendPQExpBufferStr(q, ";\n");
  10008. }
  10009. appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
  10010. fmtId(opfinfo->dobj.name));
  10011. appendPQExpBuffer(labelq, " USING %s",
  10012. fmtId(amname));
  10013. if (binary_upgrade)
  10014. binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
  10015. ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
  10016. opfinfo->dobj.name,
  10017. opfinfo->dobj.namespace->dobj.name,
  10018. NULL,
  10019. opfinfo->rolname,
  10020. false, "OPERATOR FAMILY", SECTION_PRE_DATA,
  10021. q->data, delq->data, NULL,
  10022. NULL, 0,
  10023. NULL, NULL);
  10024. /* Dump Operator Family Comments */
  10025. dumpComment(fout, labelq->data,
  10026. NULL, opfinfo->rolname,
  10027. opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
  10028. free(amname);
  10029. PQclear(res_ops);
  10030. PQclear(res_procs);
  10031. destroyPQExpBuffer(query);
  10032. destroyPQExpBuffer(q);
  10033. destroyPQExpBuffer(delq);
  10034. destroyPQExpBuffer(labelq);
  10035. }
  10036. /*
  10037. * dumpCollation
  10038. * write out a single collation definition
  10039. */
  10040. static void
  10041. dumpCollation(Archive *fout, CollInfo *collinfo)
  10042. {
  10043. PQExpBuffer query;
  10044. PQExpBuffer q;
  10045. PQExpBuffer delq;
  10046. PQExpBuffer labelq;
  10047. PGresult *res;
  10048. int i_collcollate;
  10049. int i_collctype;
  10050. const char *collcollate;
  10051. const char *collctype;
  10052. /* Skip if not to be dumped */
  10053. if (!collinfo->dobj.dump || dataOnly)
  10054. return;
  10055. query = createPQExpBuffer();
  10056. q = createPQExpBuffer();
  10057. delq = createPQExpBuffer();
  10058. labelq = createPQExpBuffer();
  10059. /* Make sure we are in proper schema */
  10060. selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
  10061. /* Get collation-specific details */
  10062. appendPQExpBuffer(query, "SELECT "
  10063. "collcollate, "
  10064. "collctype "
  10065. "FROM pg_catalog.pg_collation c "
  10066. "WHERE c.oid = '%u'::pg_catalog.oid",
  10067. collinfo->dobj.catId.oid);
  10068. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  10069. i_collcollate = PQfnumber(res, "collcollate");
  10070. i_collctype = PQfnumber(res, "collctype");
  10071. collcollate = PQgetvalue(res, 0, i_collcollate);
  10072. collctype = PQgetvalue(res, 0, i_collctype);
  10073. /*
  10074. * DROP must be fully qualified in case same name appears in pg_catalog
  10075. */
  10076. appendPQExpBuffer(delq, "DROP COLLATION %s",
  10077. fmtId(collinfo->dobj.namespace->dobj.name));
  10078. appendPQExpBuffer(delq, ".%s;\n",
  10079. fmtId(collinfo->dobj.name));
  10080. appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
  10081. fmtId(collinfo->dobj.name));
  10082. appendStringLiteralAH(q, collcollate, fout);
  10083. appendPQExpBufferStr(q, ", lc_ctype = ");
  10084. appendStringLiteralAH(q, collctype, fout);
  10085. appendPQExpBufferStr(q, ");\n");
  10086. appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
  10087. if (binary_upgrade)
  10088. binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
  10089. ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
  10090. collinfo->dobj.name,
  10091. collinfo->dobj.namespace->dobj.name,
  10092. NULL,
  10093. collinfo->rolname,
  10094. false, "COLLATION", SECTION_PRE_DATA,
  10095. q->data, delq->data, NULL,
  10096. NULL, 0,
  10097. NULL, NULL);
  10098. /* Dump Collation Comments */
  10099. dumpComment(fout, labelq->data,
  10100. collinfo->dobj.namespace->dobj.name, collinfo->rolname,
  10101. collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
  10102. PQclear(res);
  10103. destroyPQExpBuffer(query);
  10104. destroyPQExpBuffer(q);
  10105. destroyPQExpBuffer(delq);
  10106. destroyPQExpBuffer(labelq);
  10107. }
  10108. /*
  10109. * dumpConversion
  10110. * write out a single conversion definition
  10111. */
  10112. static void
  10113. dumpConversion(Archive *fout, ConvInfo *convinfo)
  10114. {
  10115. PQExpBuffer query;
  10116. PQExpBuffer q;
  10117. PQExpBuffer delq;
  10118. PQExpBuffer labelq;
  10119. PGresult *res;
  10120. int i_conforencoding;
  10121. int i_contoencoding;
  10122. int i_conproc;
  10123. int i_condefault;
  10124. const char *conforencoding;
  10125. const char *contoencoding;
  10126. const char *conproc;
  10127. bool condefault;
  10128. /* Skip if not to be dumped */
  10129. if (!convinfo->dobj.dump || dataOnly)
  10130. return;
  10131. query = createPQExpBuffer();
  10132. q = createPQExpBuffer();
  10133. delq = createPQExpBuffer();
  10134. labelq = createPQExpBuffer();
  10135. /* Make sure we are in proper schema */
  10136. selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
  10137. /* Get conversion-specific details */
  10138. appendPQExpBuffer(query, "SELECT "
  10139. "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
  10140. "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
  10141. "conproc, condefault "
  10142. "FROM pg_catalog.pg_conversion c "
  10143. "WHERE c.oid = '%u'::pg_catalog.oid",
  10144. convinfo->dobj.catId.oid);
  10145. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  10146. i_conforencoding = PQfnumber(res, "conforencoding");
  10147. i_contoencoding = PQfnumber(res, "contoencoding");
  10148. i_conproc = PQfnumber(res, "conproc");
  10149. i_condefault = PQfnumber(res, "condefault");
  10150. conforencoding = PQgetvalue(res, 0, i_conforencoding);
  10151. contoencoding = PQgetvalue(res, 0, i_contoencoding);
  10152. conproc = PQgetvalue(res, 0, i_conproc);
  10153. condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
  10154. /*
  10155. * DROP must be fully qualified in case same name appears in pg_catalog
  10156. */
  10157. appendPQExpBuffer(delq, "DROP CONVERSION %s",
  10158. fmtId(convinfo->dobj.namespace->dobj.name));
  10159. appendPQExpBuffer(delq, ".%s;\n",
  10160. fmtId(convinfo->dobj.name));
  10161. appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
  10162. (condefault) ? "DEFAULT " : "",
  10163. fmtId(convinfo->dobj.name));
  10164. appendStringLiteralAH(q, conforencoding, fout);
  10165. appendPQExpBufferStr(q, " TO ");
  10166. appendStringLiteralAH(q, contoencoding, fout);
  10167. /* regproc is automatically quoted in 7.3 and above */
  10168. appendPQExpBuffer(q, " FROM %s;\n", conproc);
  10169. appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
  10170. if (binary_upgrade)
  10171. binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
  10172. ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
  10173. convinfo->dobj.name,
  10174. convinfo->dobj.namespace->dobj.name,
  10175. NULL,
  10176. convinfo->rolname,
  10177. false, "CONVERSION", SECTION_PRE_DATA,
  10178. q->data, delq->data, NULL,
  10179. NULL, 0,
  10180. NULL, NULL);
  10181. /* Dump Conversion Comments */
  10182. dumpComment(fout, labelq->data,
  10183. convinfo->dobj.namespace->dobj.name, convinfo->rolname,
  10184. convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
  10185. PQclear(res);
  10186. destroyPQExpBuffer(query);
  10187. destroyPQExpBuffer(q);
  10188. destroyPQExpBuffer(delq);
  10189. destroyPQExpBuffer(labelq);
  10190. }
  10191. /*
  10192. * format_aggregate_signature: generate aggregate name and argument list
  10193. *
  10194. * The argument type names are qualified if needed. The aggregate name
  10195. * is never qualified.
  10196. */
  10197. static char *
  10198. format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
  10199. {
  10200. PQExpBufferData buf;
  10201. int j;
  10202. initPQExpBuffer(&buf);
  10203. if (honor_quotes)
  10204. appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
  10205. else
  10206. appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
  10207. if (agginfo->aggfn.nargs == 0)
  10208. appendPQExpBuffer(&buf, "(*)");
  10209. else
  10210. {
  10211. appendPQExpBufferChar(&buf, '(');
  10212. for (j = 0; j < agginfo->aggfn.nargs; j++)
  10213. {
  10214. char *typname;
  10215. typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
  10216. zeroAsOpaque);
  10217. appendPQExpBuffer(&buf, "%s%s",
  10218. (j > 0) ? ", " : "",
  10219. typname);
  10220. free(typname);
  10221. }
  10222. appendPQExpBufferChar(&buf, ')');
  10223. }
  10224. return buf.data;
  10225. }
  10226. /*
  10227. * dumpAgg
  10228. * write out a single aggregate definition
  10229. */
  10230. static void
  10231. dumpAgg(Archive *fout, AggInfo *agginfo)
  10232. {
  10233. PQExpBuffer query;
  10234. PQExpBuffer q;
  10235. PQExpBuffer delq;
  10236. PQExpBuffer labelq;
  10237. PQExpBuffer details;
  10238. char *aggsig; /* identity signature */
  10239. char *aggfullsig = NULL; /* full signature */
  10240. char *aggsig_tag;
  10241. PGresult *res;
  10242. int i_aggtransfn;
  10243. int i_aggfinalfn;
  10244. int i_aggmtransfn;
  10245. int i_aggminvtransfn;
  10246. int i_aggmfinalfn;
  10247. int i_aggfinalextra;
  10248. int i_aggmfinalextra;
  10249. int i_aggsortop;
  10250. int i_hypothetical;
  10251. int i_aggtranstype;
  10252. int i_aggtransspace;
  10253. int i_aggmtranstype;
  10254. int i_aggmtransspace;
  10255. int i_agginitval;
  10256. int i_aggminitval;
  10257. int i_convertok;
  10258. const char *aggtransfn;
  10259. const char *aggfinalfn;
  10260. const char *aggmtransfn;
  10261. const char *aggminvtransfn;
  10262. const char *aggmfinalfn;
  10263. bool aggfinalextra;
  10264. bool aggmfinalextra;
  10265. const char *aggsortop;
  10266. char *aggsortconvop;
  10267. bool hypothetical;
  10268. const char *aggtranstype;
  10269. const char *aggtransspace;
  10270. const char *aggmtranstype;
  10271. const char *aggmtransspace;
  10272. const char *agginitval;
  10273. const char *aggminitval;
  10274. bool convertok;
  10275. /* Skip if not to be dumped */
  10276. if (!agginfo->aggfn.dobj.dump || dataOnly)
  10277. return;
  10278. query = createPQExpBuffer();
  10279. q = createPQExpBuffer();
  10280. delq = createPQExpBuffer();
  10281. labelq = createPQExpBuffer();
  10282. details = createPQExpBuffer();
  10283. /* Make sure we are in proper schema */
  10284. selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
  10285. /* Get aggregate-specific details */
  10286. if (fout->remoteVersion >= 90400)
  10287. {
  10288. appendPQExpBuffer(query, "SELECT aggtransfn, "
  10289. "aggfinalfn, aggtranstype::pg_catalog.regtype, "
  10290. "aggmtransfn, aggminvtransfn, aggmfinalfn, "
  10291. "aggmtranstype::pg_catalog.regtype, "
  10292. "aggfinalextra, aggmfinalextra, "
  10293. "aggsortop::pg_catalog.regoperator, "
  10294. "(aggkind = 'h') AS hypothetical, "
  10295. "aggtransspace, agginitval, "
  10296. "aggmtransspace, aggminitval, "
  10297. "true AS convertok, "
  10298. "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
  10299. "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
  10300. "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
  10301. "WHERE a.aggfnoid = p.oid "
  10302. "AND p.oid = '%u'::pg_catalog.oid",
  10303. agginfo->aggfn.dobj.catId.oid);
  10304. }
  10305. else if (fout->remoteVersion >= 80400)
  10306. {
  10307. appendPQExpBuffer(query, "SELECT aggtransfn, "
  10308. "aggfinalfn, aggtranstype::pg_catalog.regtype, "
  10309. "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
  10310. "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
  10311. "false AS aggfinalextra, false AS aggmfinalextra, "
  10312. "aggsortop::pg_catalog.regoperator, "
  10313. "false AS hypothetical, "
  10314. "0 AS aggtransspace, agginitval, "
  10315. "0 AS aggmtransspace, NULL AS aggminitval, "
  10316. "true AS convertok, "
  10317. "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
  10318. "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
  10319. "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
  10320. "WHERE a.aggfnoid = p.oid "
  10321. "AND p.oid = '%u'::pg_catalog.oid",
  10322. agginfo->aggfn.dobj.catId.oid);
  10323. }
  10324. else if (fout->remoteVersion >= 80100)
  10325. {
  10326. appendPQExpBuffer(query, "SELECT aggtransfn, "
  10327. "aggfinalfn, aggtranstype::pg_catalog.regtype, "
  10328. "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
  10329. "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
  10330. "false AS aggfinalextra, false AS aggmfinalextra, "
  10331. "aggsortop::pg_catalog.regoperator, "
  10332. "false AS hypothetical, "
  10333. "0 AS aggtransspace, agginitval, "
  10334. "0 AS aggmtransspace, NULL AS aggminitval, "
  10335. "true AS convertok "
  10336. "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
  10337. "WHERE a.aggfnoid = p.oid "
  10338. "AND p.oid = '%u'::pg_catalog.oid",
  10339. agginfo->aggfn.dobj.catId.oid);
  10340. }
  10341. else if (fout->remoteVersion >= 70300)
  10342. {
  10343. appendPQExpBuffer(query, "SELECT aggtransfn, "
  10344. "aggfinalfn, aggtranstype::pg_catalog.regtype, "
  10345. "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
  10346. "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
  10347. "false AS aggfinalextra, false AS aggmfinalextra, "
  10348. "0 AS aggsortop, "
  10349. "false AS hypothetical, "
  10350. "0 AS aggtransspace, agginitval, "
  10351. "0 AS aggmtransspace, NULL AS aggminitval, "
  10352. "true AS convertok "
  10353. "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
  10354. "WHERE a.aggfnoid = p.oid "
  10355. "AND p.oid = '%u'::pg_catalog.oid",
  10356. agginfo->aggfn.dobj.catId.oid);
  10357. }
  10358. else if (fout->remoteVersion >= 70100)
  10359. {
  10360. appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
  10361. "format_type(aggtranstype, NULL) AS aggtranstype, "
  10362. "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
  10363. "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
  10364. "false AS aggfinalextra, false AS aggmfinalextra, "
  10365. "0 AS aggsortop, "
  10366. "false AS hypothetical, "
  10367. "0 AS aggtransspace, agginitval, "
  10368. "0 AS aggmtransspace, NULL AS aggminitval, "
  10369. "true AS convertok "
  10370. "FROM pg_aggregate "
  10371. "WHERE oid = '%u'::oid",
  10372. agginfo->aggfn.dobj.catId.oid);
  10373. }
  10374. else
  10375. {
  10376. appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
  10377. "aggfinalfn, "
  10378. "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
  10379. "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
  10380. "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
  10381. "false AS aggfinalextra, false AS aggmfinalextra, "
  10382. "0 AS aggsortop, "
  10383. "false AS hypothetical, "
  10384. "0 AS aggtransspace, agginitval1 AS agginitval, "
  10385. "0 AS aggmtransspace, NULL AS aggminitval, "
  10386. "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
  10387. "FROM pg_aggregate "
  10388. "WHERE oid = '%u'::oid",
  10389. agginfo->aggfn.dobj.catId.oid);
  10390. }
  10391. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  10392. i_aggtransfn = PQfnumber(res, "aggtransfn");
  10393. i_aggfinalfn = PQfnumber(res, "aggfinalfn");
  10394. i_aggmtransfn = PQfnumber(res, "aggmtransfn");
  10395. i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
  10396. i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
  10397. i_aggfinalextra = PQfnumber(res, "aggfinalextra");
  10398. i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
  10399. i_aggsortop = PQfnumber(res, "aggsortop");
  10400. i_hypothetical = PQfnumber(res, "hypothetical");
  10401. i_aggtranstype = PQfnumber(res, "aggtranstype");
  10402. i_aggtransspace = PQfnumber(res, "aggtransspace");
  10403. i_aggmtranstype = PQfnumber(res, "aggmtranstype");
  10404. i_aggmtransspace = PQfnumber(res, "aggmtransspace");
  10405. i_agginitval = PQfnumber(res, "agginitval");
  10406. i_aggminitval = PQfnumber(res, "aggminitval");
  10407. i_convertok = PQfnumber(res, "convertok");
  10408. aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
  10409. aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
  10410. aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
  10411. aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
  10412. aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
  10413. aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
  10414. aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
  10415. aggsortop = PQgetvalue(res, 0, i_aggsortop);
  10416. hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't');
  10417. aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
  10418. aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
  10419. aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
  10420. aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
  10421. agginitval = PQgetvalue(res, 0, i_agginitval);
  10422. aggminitval = PQgetvalue(res, 0, i_aggminitval);
  10423. convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
  10424. if (fout->remoteVersion >= 80400)
  10425. {
  10426. /* 8.4 or later; we rely on server-side code for most of the work */
  10427. char *funcargs;
  10428. char *funciargs;
  10429. funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
  10430. funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
  10431. aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
  10432. aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
  10433. }
  10434. else
  10435. /* pre-8.4, do it ourselves */
  10436. aggsig = format_aggregate_signature(agginfo, fout, true);
  10437. aggsig_tag = format_aggregate_signature(agginfo, fout, false);
  10438. if (!convertok)
  10439. {
  10440. write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
  10441. aggsig);
  10442. if (aggfullsig)
  10443. free(aggfullsig);
  10444. free(aggsig);
  10445. return;
  10446. }
  10447. if (fout->remoteVersion >= 70300)
  10448. {
  10449. /* If using 7.3's regproc or regtype, data is already quoted */
  10450. appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
  10451. aggtransfn,
  10452. aggtranstype);
  10453. }
  10454. else if (fout->remoteVersion >= 70100)
  10455. {
  10456. /* format_type quotes, regproc does not */
  10457. appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
  10458. fmtId(aggtransfn),
  10459. aggtranstype);
  10460. }
  10461. else
  10462. {
  10463. /* need quotes all around */
  10464. appendPQExpBuffer(details, " SFUNC = %s,\n",
  10465. fmtId(aggtransfn));
  10466. appendPQExpBuffer(details, " STYPE = %s",
  10467. fmtId(aggtranstype));
  10468. }
  10469. if (strcmp(aggtransspace, "0") != 0)
  10470. {
  10471. appendPQExpBuffer(details, ",\n SSPACE = %s",
  10472. aggtransspace);
  10473. }
  10474. if (!PQgetisnull(res, 0, i_agginitval))
  10475. {
  10476. appendPQExpBufferStr(details, ",\n INITCOND = ");
  10477. appendStringLiteralAH(details, agginitval, fout);
  10478. }
  10479. if (strcmp(aggfinalfn, "-") != 0)
  10480. {
  10481. appendPQExpBuffer(details, ",\n FINALFUNC = %s",
  10482. aggfinalfn);
  10483. if (aggfinalextra)
  10484. appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
  10485. }
  10486. if (strcmp(aggmtransfn, "-") != 0)
  10487. {
  10488. appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
  10489. aggmtransfn,
  10490. aggminvtransfn,
  10491. aggmtranstype);
  10492. }
  10493. if (strcmp(aggmtransspace, "0") != 0)
  10494. {
  10495. appendPQExpBuffer(details, ",\n MSSPACE = %s",
  10496. aggmtransspace);
  10497. }
  10498. if (!PQgetisnull(res, 0, i_aggminitval))
  10499. {
  10500. appendPQExpBufferStr(details, ",\n MINITCOND = ");
  10501. appendStringLiteralAH(details, aggminitval, fout);
  10502. }
  10503. if (strcmp(aggmfinalfn, "-") != 0)
  10504. {
  10505. appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
  10506. aggmfinalfn);
  10507. if (aggmfinalextra)
  10508. appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
  10509. }
  10510. aggsortconvop = convertOperatorReference(fout, aggsortop);
  10511. if (aggsortconvop)
  10512. {
  10513. appendPQExpBuffer(details, ",\n SORTOP = %s",
  10514. aggsortconvop);
  10515. free(aggsortconvop);
  10516. }
  10517. if (hypothetical)
  10518. appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
  10519. /*
  10520. * DROP must be fully qualified in case same name appears in pg_catalog
  10521. */
  10522. appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
  10523. fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
  10524. aggsig);
  10525. appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
  10526. aggfullsig ? aggfullsig : aggsig, details->data);
  10527. appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
  10528. if (binary_upgrade)
  10529. binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
  10530. ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
  10531. aggsig_tag,
  10532. agginfo->aggfn.dobj.namespace->dobj.name,
  10533. NULL,
  10534. agginfo->aggfn.rolname,
  10535. false, "AGGREGATE", SECTION_PRE_DATA,
  10536. q->data, delq->data, NULL,
  10537. NULL, 0,
  10538. NULL, NULL);
  10539. /* Dump Aggregate Comments */
  10540. dumpComment(fout, labelq->data,
  10541. agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
  10542. agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
  10543. dumpSecLabel(fout, labelq->data,
  10544. agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
  10545. agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
  10546. /*
  10547. * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
  10548. * command look like a function's GRANT; in particular this affects the
  10549. * syntax for zero-argument aggregates and ordered-set aggregates.
  10550. */
  10551. free(aggsig);
  10552. free(aggsig_tag);
  10553. aggsig = format_function_signature(fout, &agginfo->aggfn, true);
  10554. aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
  10555. dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
  10556. "FUNCTION",
  10557. aggsig, NULL, aggsig_tag,
  10558. agginfo->aggfn.dobj.namespace->dobj.name,
  10559. agginfo->aggfn.rolname, agginfo->aggfn.proacl);
  10560. free(aggsig);
  10561. if (aggfullsig)
  10562. free(aggfullsig);
  10563. free(aggsig_tag);
  10564. PQclear(res);
  10565. destroyPQExpBuffer(query);
  10566. destroyPQExpBuffer(q);
  10567. destroyPQExpBuffer(delq);
  10568. destroyPQExpBuffer(labelq);
  10569. destroyPQExpBuffer(details);
  10570. }
  10571. /*
  10572. * dumpTSParser
  10573. * write out a single text search parser
  10574. */
  10575. static void
  10576. dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
  10577. {
  10578. PQExpBuffer q;
  10579. PQExpBuffer delq;
  10580. PQExpBuffer labelq;
  10581. /* Skip if not to be dumped */
  10582. if (!prsinfo->dobj.dump || dataOnly)
  10583. return;
  10584. q = createPQExpBuffer();
  10585. delq = createPQExpBuffer();
  10586. labelq = createPQExpBuffer();
  10587. /* Make sure we are in proper schema */
  10588. selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
  10589. appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
  10590. fmtId(prsinfo->dobj.name));
  10591. appendPQExpBuffer(q, " START = %s,\n",
  10592. convertTSFunction(fout, prsinfo->prsstart));
  10593. appendPQExpBuffer(q, " GETTOKEN = %s,\n",
  10594. convertTSFunction(fout, prsinfo->prstoken));
  10595. appendPQExpBuffer(q, " END = %s,\n",
  10596. convertTSFunction(fout, prsinfo->prsend));
  10597. if (prsinfo->prsheadline != InvalidOid)
  10598. appendPQExpBuffer(q, " HEADLINE = %s,\n",
  10599. convertTSFunction(fout, prsinfo->prsheadline));
  10600. appendPQExpBuffer(q, " LEXTYPES = %s );\n",
  10601. convertTSFunction(fout, prsinfo->prslextype));
  10602. /*
  10603. * DROP must be fully qualified in case same name appears in pg_catalog
  10604. */
  10605. appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
  10606. fmtId(prsinfo->dobj.namespace->dobj.name));
  10607. appendPQExpBuffer(delq, ".%s;\n",
  10608. fmtId(prsinfo->dobj.name));
  10609. appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
  10610. fmtId(prsinfo->dobj.name));
  10611. if (binary_upgrade)
  10612. binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
  10613. ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
  10614. prsinfo->dobj.name,
  10615. prsinfo->dobj.namespace->dobj.name,
  10616. NULL,
  10617. "",
  10618. false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
  10619. q->data, delq->data, NULL,
  10620. NULL, 0,
  10621. NULL, NULL);
  10622. /* Dump Parser Comments */
  10623. dumpComment(fout, labelq->data,
  10624. NULL, "",
  10625. prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
  10626. destroyPQExpBuffer(q);
  10627. destroyPQExpBuffer(delq);
  10628. destroyPQExpBuffer(labelq);
  10629. }
  10630. /*
  10631. * dumpTSDictionary
  10632. * write out a single text search dictionary
  10633. */
  10634. static void
  10635. dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
  10636. {
  10637. PQExpBuffer q;
  10638. PQExpBuffer delq;
  10639. PQExpBuffer labelq;
  10640. PQExpBuffer query;
  10641. PGresult *res;
  10642. char *nspname;
  10643. char *tmplname;
  10644. /* Skip if not to be dumped */
  10645. if (!dictinfo->dobj.dump || dataOnly)
  10646. return;
  10647. q = createPQExpBuffer();
  10648. delq = createPQExpBuffer();
  10649. labelq = createPQExpBuffer();
  10650. query = createPQExpBuffer();
  10651. /* Fetch name and namespace of the dictionary's template */
  10652. selectSourceSchema(fout, "pg_catalog");
  10653. appendPQExpBuffer(query, "SELECT nspname, tmplname "
  10654. "FROM pg_ts_template p, pg_namespace n "
  10655. "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
  10656. dictinfo->dicttemplate);
  10657. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  10658. nspname = PQgetvalue(res, 0, 0);
  10659. tmplname = PQgetvalue(res, 0, 1);
  10660. /* Make sure we are in proper schema */
  10661. selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
  10662. appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
  10663. fmtId(dictinfo->dobj.name));
  10664. appendPQExpBufferStr(q, " TEMPLATE = ");
  10665. if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
  10666. appendPQExpBuffer(q, "%s.", fmtId(nspname));
  10667. appendPQExpBufferStr(q, fmtId(tmplname));
  10668. PQclear(res);
  10669. /* the dictinitoption can be dumped straight into the command */
  10670. if (dictinfo->dictinitoption)
  10671. appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
  10672. appendPQExpBufferStr(q, " );\n");
  10673. /*
  10674. * DROP must be fully qualified in case same name appears in pg_catalog
  10675. */
  10676. appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
  10677. fmtId(dictinfo->dobj.namespace->dobj.name));
  10678. appendPQExpBuffer(delq, ".%s;\n",
  10679. fmtId(dictinfo->dobj.name));
  10680. appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
  10681. fmtId(dictinfo->dobj.name));
  10682. if (binary_upgrade)
  10683. binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
  10684. ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
  10685. dictinfo->dobj.name,
  10686. dictinfo->dobj.namespace->dobj.name,
  10687. NULL,
  10688. dictinfo->rolname,
  10689. false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
  10690. q->data, delq->data, NULL,
  10691. NULL, 0,
  10692. NULL, NULL);
  10693. /* Dump Dictionary Comments */
  10694. dumpComment(fout, labelq->data,
  10695. NULL, dictinfo->rolname,
  10696. dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
  10697. destroyPQExpBuffer(q);
  10698. destroyPQExpBuffer(delq);
  10699. destroyPQExpBuffer(labelq);
  10700. destroyPQExpBuffer(query);
  10701. }
  10702. /*
  10703. * dumpTSTemplate
  10704. * write out a single text search template
  10705. */
  10706. static void
  10707. dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
  10708. {
  10709. PQExpBuffer q;
  10710. PQExpBuffer delq;
  10711. PQExpBuffer labelq;
  10712. /* Skip if not to be dumped */
  10713. if (!tmplinfo->dobj.dump || dataOnly)
  10714. return;
  10715. q = createPQExpBuffer();
  10716. delq = createPQExpBuffer();
  10717. labelq = createPQExpBuffer();
  10718. /* Make sure we are in proper schema */
  10719. selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
  10720. appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
  10721. fmtId(tmplinfo->dobj.name));
  10722. if (tmplinfo->tmplinit != InvalidOid)
  10723. appendPQExpBuffer(q, " INIT = %s,\n",
  10724. convertTSFunction(fout, tmplinfo->tmplinit));
  10725. appendPQExpBuffer(q, " LEXIZE = %s );\n",
  10726. convertTSFunction(fout, tmplinfo->tmpllexize));
  10727. /*
  10728. * DROP must be fully qualified in case same name appears in pg_catalog
  10729. */
  10730. appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
  10731. fmtId(tmplinfo->dobj.namespace->dobj.name));
  10732. appendPQExpBuffer(delq, ".%s;\n",
  10733. fmtId(tmplinfo->dobj.name));
  10734. appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
  10735. fmtId(tmplinfo->dobj.name));
  10736. if (binary_upgrade)
  10737. binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
  10738. ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
  10739. tmplinfo->dobj.name,
  10740. tmplinfo->dobj.namespace->dobj.name,
  10741. NULL,
  10742. "",
  10743. false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
  10744. q->data, delq->data, NULL,
  10745. NULL, 0,
  10746. NULL, NULL);
  10747. /* Dump Template Comments */
  10748. dumpComment(fout, labelq->data,
  10749. NULL, "",
  10750. tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
  10751. destroyPQExpBuffer(q);
  10752. destroyPQExpBuffer(delq);
  10753. destroyPQExpBuffer(labelq);
  10754. }
  10755. /*
  10756. * dumpTSConfig
  10757. * write out a single text search configuration
  10758. */
  10759. static void
  10760. dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
  10761. {
  10762. PQExpBuffer q;
  10763. PQExpBuffer delq;
  10764. PQExpBuffer labelq;
  10765. PQExpBuffer query;
  10766. PGresult *res;
  10767. char *nspname;
  10768. char *prsname;
  10769. int ntups,
  10770. i;
  10771. int i_tokenname;
  10772. int i_dictname;
  10773. /* Skip if not to be dumped */
  10774. if (!cfginfo->dobj.dump || dataOnly)
  10775. return;
  10776. q = createPQExpBuffer();
  10777. delq = createPQExpBuffer();
  10778. labelq = createPQExpBuffer();
  10779. query = createPQExpBuffer();
  10780. /* Fetch name and namespace of the config's parser */
  10781. selectSourceSchema(fout, "pg_catalog");
  10782. appendPQExpBuffer(query, "SELECT nspname, prsname "
  10783. "FROM pg_ts_parser p, pg_namespace n "
  10784. "WHERE p.oid = '%u' AND n.oid = prsnamespace",
  10785. cfginfo->cfgparser);
  10786. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  10787. nspname = PQgetvalue(res, 0, 0);
  10788. prsname = PQgetvalue(res, 0, 1);
  10789. /* Make sure we are in proper schema */
  10790. selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
  10791. appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
  10792. fmtId(cfginfo->dobj.name));
  10793. appendPQExpBufferStr(q, " PARSER = ");
  10794. if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
  10795. appendPQExpBuffer(q, "%s.", fmtId(nspname));
  10796. appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
  10797. PQclear(res);
  10798. resetPQExpBuffer(query);
  10799. appendPQExpBuffer(query,
  10800. "SELECT \n"
  10801. " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
  10802. " WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
  10803. " m.mapdict::pg_catalog.regdictionary AS dictname \n"
  10804. "FROM pg_catalog.pg_ts_config_map AS m \n"
  10805. "WHERE m.mapcfg = '%u' \n"
  10806. "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
  10807. cfginfo->cfgparser, cfginfo->dobj.catId.oid);
  10808. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  10809. ntups = PQntuples(res);
  10810. i_tokenname = PQfnumber(res, "tokenname");
  10811. i_dictname = PQfnumber(res, "dictname");
  10812. for (i = 0; i < ntups; i++)
  10813. {
  10814. char *tokenname = PQgetvalue(res, i, i_tokenname);
  10815. char *dictname = PQgetvalue(res, i, i_dictname);
  10816. if (i == 0 ||
  10817. strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
  10818. {
  10819. /* starting a new token type, so start a new command */
  10820. if (i > 0)
  10821. appendPQExpBufferStr(q, ";\n");
  10822. appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
  10823. fmtId(cfginfo->dobj.name));
  10824. /* tokenname needs quoting, dictname does NOT */
  10825. appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
  10826. fmtId(tokenname), dictname);
  10827. }
  10828. else
  10829. appendPQExpBuffer(q, ", %s", dictname);
  10830. }
  10831. if (ntups > 0)
  10832. appendPQExpBufferStr(q, ";\n");
  10833. PQclear(res);
  10834. /*
  10835. * DROP must be fully qualified in case same name appears in pg_catalog
  10836. */
  10837. appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
  10838. fmtId(cfginfo->dobj.namespace->dobj.name));
  10839. appendPQExpBuffer(delq, ".%s;\n",
  10840. fmtId(cfginfo->dobj.name));
  10841. appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
  10842. fmtId(cfginfo->dobj.name));
  10843. if (binary_upgrade)
  10844. binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
  10845. ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
  10846. cfginfo->dobj.name,
  10847. cfginfo->dobj.namespace->dobj.name,
  10848. NULL,
  10849. cfginfo->rolname,
  10850. false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
  10851. q->data, delq->data, NULL,
  10852. NULL, 0,
  10853. NULL, NULL);
  10854. /* Dump Configuration Comments */
  10855. dumpComment(fout, labelq->data,
  10856. NULL, cfginfo->rolname,
  10857. cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
  10858. destroyPQExpBuffer(q);
  10859. destroyPQExpBuffer(delq);
  10860. destroyPQExpBuffer(labelq);
  10861. destroyPQExpBuffer(query);
  10862. }
  10863. /*
  10864. * dumpForeignDataWrapper
  10865. * write out a single foreign-data wrapper definition
  10866. */
  10867. static void
  10868. dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
  10869. {
  10870. PQExpBuffer q;
  10871. PQExpBuffer delq;
  10872. PQExpBuffer labelq;
  10873. char *qfdwname;
  10874. /* Skip if not to be dumped */
  10875. if (!fdwinfo->dobj.dump || dataOnly)
  10876. return;
  10877. /*
  10878. * FDWs that belong to an extension are dumped based on their "dump"
  10879. * field. Otherwise omit them if we are only dumping some specific object.
  10880. */
  10881. if (!fdwinfo->dobj.ext_member)
  10882. if (!include_everything)
  10883. return;
  10884. q = createPQExpBuffer();
  10885. delq = createPQExpBuffer();
  10886. labelq = createPQExpBuffer();
  10887. qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
  10888. appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
  10889. qfdwname);
  10890. if (strcmp(fdwinfo->fdwhandler, "-") != 0)
  10891. appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
  10892. if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
  10893. appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
  10894. if (strlen(fdwinfo->fdwoptions) > 0)
  10895. appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
  10896. appendPQExpBufferStr(q, ";\n");
  10897. appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
  10898. qfdwname);
  10899. appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
  10900. qfdwname);
  10901. if (binary_upgrade)
  10902. binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
  10903. ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
  10904. fdwinfo->dobj.name,
  10905. NULL,
  10906. NULL,
  10907. fdwinfo->rolname,
  10908. false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
  10909. q->data, delq->data, NULL,
  10910. NULL, 0,
  10911. NULL, NULL);
  10912. /* Handle the ACL */
  10913. dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
  10914. "FOREIGN DATA WRAPPER",
  10915. qfdwname, NULL, fdwinfo->dobj.name,
  10916. NULL, fdwinfo->rolname,
  10917. fdwinfo->fdwacl);
  10918. /* Dump Foreign Data Wrapper Comments */
  10919. dumpComment(fout, labelq->data,
  10920. NULL, fdwinfo->rolname,
  10921. fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
  10922. free(qfdwname);
  10923. destroyPQExpBuffer(q);
  10924. destroyPQExpBuffer(delq);
  10925. destroyPQExpBuffer(labelq);
  10926. }
  10927. /*
  10928. * dumpForeignServer
  10929. * write out a foreign server definition
  10930. */
  10931. static void
  10932. dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
  10933. {
  10934. PQExpBuffer q;
  10935. PQExpBuffer delq;
  10936. PQExpBuffer labelq;
  10937. PQExpBuffer query;
  10938. PGresult *res;
  10939. char *qsrvname;
  10940. char *fdwname;
  10941. /* Skip if not to be dumped */
  10942. if (!srvinfo->dobj.dump || dataOnly || !include_everything)
  10943. return;
  10944. q = createPQExpBuffer();
  10945. delq = createPQExpBuffer();
  10946. labelq = createPQExpBuffer();
  10947. query = createPQExpBuffer();
  10948. qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
  10949. /* look up the foreign-data wrapper */
  10950. selectSourceSchema(fout, "pg_catalog");
  10951. appendPQExpBuffer(query, "SELECT fdwname "
  10952. "FROM pg_foreign_data_wrapper w "
  10953. "WHERE w.oid = '%u'",
  10954. srvinfo->srvfdw);
  10955. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  10956. fdwname = PQgetvalue(res, 0, 0);
  10957. appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
  10958. if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
  10959. {
  10960. appendPQExpBufferStr(q, " TYPE ");
  10961. appendStringLiteralAH(q, srvinfo->srvtype, fout);
  10962. }
  10963. if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
  10964. {
  10965. appendPQExpBufferStr(q, " VERSION ");
  10966. appendStringLiteralAH(q, srvinfo->srvversion, fout);
  10967. }
  10968. appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
  10969. appendPQExpBufferStr(q, fmtId(fdwname));
  10970. if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
  10971. appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
  10972. appendPQExpBufferStr(q, ";\n");
  10973. appendPQExpBuffer(delq, "DROP SERVER %s;\n",
  10974. qsrvname);
  10975. appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
  10976. if (binary_upgrade)
  10977. binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
  10978. ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
  10979. srvinfo->dobj.name,
  10980. NULL,
  10981. NULL,
  10982. srvinfo->rolname,
  10983. false, "SERVER", SECTION_PRE_DATA,
  10984. q->data, delq->data, NULL,
  10985. NULL, 0,
  10986. NULL, NULL);
  10987. /* Handle the ACL */
  10988. dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
  10989. "FOREIGN SERVER",
  10990. qsrvname, NULL, srvinfo->dobj.name,
  10991. NULL, srvinfo->rolname,
  10992. srvinfo->srvacl);
  10993. /* Dump user mappings */
  10994. dumpUserMappings(fout,
  10995. srvinfo->dobj.name, NULL,
  10996. srvinfo->rolname,
  10997. srvinfo->dobj.catId, srvinfo->dobj.dumpId);
  10998. /* Dump Foreign Server Comments */
  10999. dumpComment(fout, labelq->data,
  11000. NULL, srvinfo->rolname,
  11001. srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
  11002. free(qsrvname);
  11003. destroyPQExpBuffer(q);
  11004. destroyPQExpBuffer(delq);
  11005. destroyPQExpBuffer(labelq);
  11006. }
  11007. /*
  11008. * dumpUserMappings
  11009. *
  11010. * This routine is used to dump any user mappings associated with the
  11011. * server handed to this routine. Should be called after ArchiveEntry()
  11012. * for the server.
  11013. */
  11014. static void
  11015. dumpUserMappings(Archive *fout,
  11016. const char *servername, const char *namespace,
  11017. const char *owner,
  11018. CatalogId catalogId, DumpId dumpId)
  11019. {
  11020. PQExpBuffer q;
  11021. PQExpBuffer delq;
  11022. PQExpBuffer query;
  11023. PQExpBuffer tag;
  11024. PGresult *res;
  11025. int ntups;
  11026. int i_usename;
  11027. int i_umoptions;
  11028. int i;
  11029. q = createPQExpBuffer();
  11030. tag = createPQExpBuffer();
  11031. delq = createPQExpBuffer();
  11032. query = createPQExpBuffer();
  11033. /*
  11034. * We read from the publicly accessible view pg_user_mappings, so as not
  11035. * to fail if run by a non-superuser. Note that the view will show
  11036. * umoptions as null if the user hasn't got privileges for the associated
  11037. * server; this means that pg_dump will dump such a mapping, but with no
  11038. * OPTIONS clause. A possible alternative is to skip such mappings
  11039. * altogether, but it's not clear that that's an improvement.
  11040. */
  11041. selectSourceSchema(fout, "pg_catalog");
  11042. appendPQExpBuffer(query,
  11043. "SELECT usename, "
  11044. "array_to_string(ARRAY("
  11045. "SELECT quote_ident(option_name) || ' ' || "
  11046. "quote_literal(option_value) "
  11047. "FROM pg_options_to_table(umoptions) "
  11048. "ORDER BY option_name"
  11049. "), E',\n ') AS umoptions "
  11050. "FROM pg_user_mappings "
  11051. "WHERE srvid = '%u' "
  11052. "ORDER BY usename",
  11053. catalogId.oid);
  11054. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  11055. ntups = PQntuples(res);
  11056. i_usename = PQfnumber(res, "usename");
  11057. i_umoptions = PQfnumber(res, "umoptions");
  11058. for (i = 0; i < ntups; i++)
  11059. {
  11060. char *usename;
  11061. char *umoptions;
  11062. usename = PQgetvalue(res, i, i_usename);
  11063. umoptions = PQgetvalue(res, i, i_umoptions);
  11064. resetPQExpBuffer(q);
  11065. appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
  11066. appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
  11067. if (umoptions && strlen(umoptions) > 0)
  11068. appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
  11069. appendPQExpBufferStr(q, ";\n");
  11070. resetPQExpBuffer(delq);
  11071. appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
  11072. appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
  11073. resetPQExpBuffer(tag);
  11074. appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
  11075. usename, servername);
  11076. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  11077. tag->data,
  11078. namespace,
  11079. NULL,
  11080. owner, false,
  11081. "USER MAPPING", SECTION_PRE_DATA,
  11082. q->data, delq->data, NULL,
  11083. &dumpId, 1,
  11084. NULL, NULL);
  11085. }
  11086. PQclear(res);
  11087. destroyPQExpBuffer(query);
  11088. destroyPQExpBuffer(delq);
  11089. destroyPQExpBuffer(tag);
  11090. destroyPQExpBuffer(q);
  11091. }
  11092. /*
  11093. * Write out default privileges information
  11094. */
  11095. static void
  11096. dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
  11097. {
  11098. PQExpBuffer q;
  11099. PQExpBuffer tag;
  11100. const char *type;
  11101. /* Skip if not to be dumped */
  11102. if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
  11103. return;
  11104. q = createPQExpBuffer();
  11105. tag = createPQExpBuffer();
  11106. switch (daclinfo->defaclobjtype)
  11107. {
  11108. case DEFACLOBJ_RELATION:
  11109. type = "TABLES";
  11110. break;
  11111. case DEFACLOBJ_SEQUENCE:
  11112. type = "SEQUENCES";
  11113. break;
  11114. case DEFACLOBJ_FUNCTION:
  11115. type = "FUNCTIONS";
  11116. break;
  11117. case DEFACLOBJ_TYPE:
  11118. type = "TYPES";
  11119. break;
  11120. default:
  11121. /* shouldn't get here */
  11122. exit_horribly(NULL,
  11123. "unrecognized object type in default privileges: %d\n",
  11124. (int) daclinfo->defaclobjtype);
  11125. type = ""; /* keep compiler quiet */
  11126. }
  11127. appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
  11128. /* build the actual command(s) for this tuple */
  11129. if (!buildDefaultACLCommands(type,
  11130. daclinfo->dobj.namespace != NULL ?
  11131. daclinfo->dobj.namespace->dobj.name : NULL,
  11132. daclinfo->defaclacl,
  11133. daclinfo->defaclrole,
  11134. fout->remoteVersion,
  11135. q))
  11136. exit_horribly(NULL, "could not parse default ACL list (%s)\n",
  11137. daclinfo->defaclacl);
  11138. ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
  11139. tag->data,
  11140. daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
  11141. NULL,
  11142. daclinfo->defaclrole,
  11143. false, "DEFAULT ACL", SECTION_POST_DATA,
  11144. q->data, "", NULL,
  11145. NULL, 0,
  11146. NULL, NULL);
  11147. destroyPQExpBuffer(tag);
  11148. destroyPQExpBuffer(q);
  11149. }
  11150. /*----------
  11151. * Write out grant/revoke information
  11152. *
  11153. * 'objCatId' is the catalog ID of the underlying object.
  11154. * 'objDumpId' is the dump ID of the underlying object.
  11155. * 'type' must be one of
  11156. * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
  11157. * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
  11158. * 'name' is the formatted name of the object. Must be quoted etc. already.
  11159. * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
  11160. * 'tag' is the tag for the archive entry (typ. unquoted name of object).
  11161. * 'nspname' is the namespace the object is in (NULL if none).
  11162. * 'owner' is the owner, NULL if there is no owner (for languages).
  11163. * 'acls' is the string read out of the fooacl system catalog field;
  11164. * it will be parsed here.
  11165. *----------
  11166. */
  11167. static void
  11168. dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
  11169. const char *type, const char *name, const char *subname,
  11170. const char *tag, const char *nspname, const char *owner,
  11171. const char *acls)
  11172. {
  11173. PQExpBuffer sql;
  11174. /* Do nothing if ACL dump is not enabled */
  11175. if (aclsSkip)
  11176. return;
  11177. /* --data-only skips ACLs *except* BLOB ACLs */
  11178. if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
  11179. return;
  11180. sql = createPQExpBuffer();
  11181. if (!buildACLCommands(name, subname, type, acls, owner,
  11182. "", fout->remoteVersion, sql))
  11183. exit_horribly(NULL,
  11184. "could not parse ACL list (%s) for object \"%s\" (%s)\n",
  11185. acls, name, type);
  11186. if (sql->len > 0)
  11187. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  11188. tag, nspname,
  11189. NULL,
  11190. owner ? owner : "",
  11191. false, "ACL", SECTION_NONE,
  11192. sql->data, "", NULL,
  11193. &(objDumpId), 1,
  11194. NULL, NULL);
  11195. destroyPQExpBuffer(sql);
  11196. }
  11197. /*
  11198. * dumpSecLabel
  11199. *
  11200. * This routine is used to dump any security labels associated with the
  11201. * object handed to this routine. The routine takes a constant character
  11202. * string for the target part of the security-label command, plus
  11203. * the namespace and owner of the object (for labeling the ArchiveEntry),
  11204. * plus catalog ID and subid which are the lookup key for pg_seclabel,
  11205. * plus the dump ID for the object (for setting a dependency).
  11206. * If a matching pg_seclabel entry is found, it is dumped.
  11207. *
  11208. * Note: although this routine takes a dumpId for dependency purposes,
  11209. * that purpose is just to mark the dependency in the emitted dump file
  11210. * for possible future use by pg_restore. We do NOT use it for determining
  11211. * ordering of the label in the dump file, because this routine is called
  11212. * after dependency sorting occurs. This routine should be called just after
  11213. * calling ArchiveEntry() for the specified object.
  11214. */
  11215. static void
  11216. dumpSecLabel(Archive *fout, const char *target,
  11217. const char *namespace, const char *owner,
  11218. CatalogId catalogId, int subid, DumpId dumpId)
  11219. {
  11220. SecLabelItem *labels;
  11221. int nlabels;
  11222. int i;
  11223. PQExpBuffer query;
  11224. /* do nothing, if --no-security-labels is supplied */
  11225. if (no_security_labels)
  11226. return;
  11227. /* Comments are schema not data ... except blob comments are data */
  11228. if (strncmp(target, "LARGE OBJECT ", 13) != 0)
  11229. {
  11230. if (dataOnly)
  11231. return;
  11232. }
  11233. else
  11234. {
  11235. if (schemaOnly)
  11236. return;
  11237. }
  11238. /* Search for security labels associated with catalogId, using table */
  11239. nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
  11240. query = createPQExpBuffer();
  11241. for (i = 0; i < nlabels; i++)
  11242. {
  11243. /*
  11244. * Ignore label entries for which the subid doesn't match.
  11245. */
  11246. if (labels[i].objsubid != subid)
  11247. continue;
  11248. appendPQExpBuffer(query,
  11249. "SECURITY LABEL FOR %s ON %s IS ",
  11250. fmtId(labels[i].provider), target);
  11251. appendStringLiteralAH(query, labels[i].label, fout);
  11252. appendPQExpBufferStr(query, ";\n");
  11253. }
  11254. if (query->len > 0)
  11255. {
  11256. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  11257. target, namespace, NULL, owner,
  11258. false, "SECURITY LABEL", SECTION_NONE,
  11259. query->data, "", NULL,
  11260. &(dumpId), 1,
  11261. NULL, NULL);
  11262. }
  11263. destroyPQExpBuffer(query);
  11264. }
  11265. /*
  11266. * dumpTableSecLabel
  11267. *
  11268. * As above, but dump security label for both the specified table (or view)
  11269. * and its columns.
  11270. */
  11271. static void
  11272. dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
  11273. {
  11274. SecLabelItem *labels;
  11275. int nlabels;
  11276. int i;
  11277. PQExpBuffer query;
  11278. PQExpBuffer target;
  11279. /* do nothing, if --no-security-labels is supplied */
  11280. if (no_security_labels)
  11281. return;
  11282. /* SecLabel are SCHEMA not data */
  11283. if (dataOnly)
  11284. return;
  11285. /* Search for comments associated with relation, using table */
  11286. nlabels = findSecLabels(fout,
  11287. tbinfo->dobj.catId.tableoid,
  11288. tbinfo->dobj.catId.oid,
  11289. &labels);
  11290. /* If security labels exist, build SECURITY LABEL statements */
  11291. if (nlabels <= 0)
  11292. return;
  11293. query = createPQExpBuffer();
  11294. target = createPQExpBuffer();
  11295. for (i = 0; i < nlabels; i++)
  11296. {
  11297. const char *colname;
  11298. const char *provider = labels[i].provider;
  11299. const char *label = labels[i].label;
  11300. int objsubid = labels[i].objsubid;
  11301. resetPQExpBuffer(target);
  11302. if (objsubid == 0)
  11303. {
  11304. appendPQExpBuffer(target, "%s %s", reltypename,
  11305. fmtId(tbinfo->dobj.name));
  11306. }
  11307. else
  11308. {
  11309. colname = getAttrName(objsubid, tbinfo);
  11310. /* first fmtId result must be consumed before calling it again */
  11311. appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
  11312. appendPQExpBuffer(target, ".%s", fmtId(colname));
  11313. }
  11314. appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
  11315. fmtId(provider), target->data);
  11316. appendStringLiteralAH(query, label, fout);
  11317. appendPQExpBufferStr(query, ";\n");
  11318. }
  11319. if (query->len > 0)
  11320. {
  11321. resetPQExpBuffer(target);
  11322. appendPQExpBuffer(target, "%s %s", reltypename,
  11323. fmtId(tbinfo->dobj.name));
  11324. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  11325. target->data,
  11326. tbinfo->dobj.namespace->dobj.name,
  11327. NULL, tbinfo->rolname,
  11328. false, "SECURITY LABEL", SECTION_NONE,
  11329. query->data, "", NULL,
  11330. &(tbinfo->dobj.dumpId), 1,
  11331. NULL, NULL);
  11332. }
  11333. destroyPQExpBuffer(query);
  11334. destroyPQExpBuffer(target);
  11335. }
  11336. /*
  11337. * findSecLabels
  11338. *
  11339. * Find the security label(s), if any, associated with the given object.
  11340. * All the objsubid values associated with the given classoid/objoid are
  11341. * found with one search.
  11342. */
  11343. static int
  11344. findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
  11345. {
  11346. /* static storage for table of security labels */
  11347. static SecLabelItem *labels = NULL;
  11348. static int nlabels = -1;
  11349. SecLabelItem *middle = NULL;
  11350. SecLabelItem *low;
  11351. SecLabelItem *high;
  11352. int nmatch;
  11353. /* Get security labels if we didn't already */
  11354. if (nlabels < 0)
  11355. nlabels = collectSecLabels(fout, &labels);
  11356. if (nlabels <= 0) /* no labels, so no match is possible */
  11357. {
  11358. *items = NULL;
  11359. return 0;
  11360. }
  11361. /*
  11362. * Do binary search to find some item matching the object.
  11363. */
  11364. low = &labels[0];
  11365. high = &labels[nlabels - 1];
  11366. while (low <= high)
  11367. {
  11368. middle = low + (high - low) / 2;
  11369. if (classoid < middle->classoid)
  11370. high = middle - 1;
  11371. else if (classoid > middle->classoid)
  11372. low = middle + 1;
  11373. else if (objoid < middle->objoid)
  11374. high = middle - 1;
  11375. else if (objoid > middle->objoid)
  11376. low = middle + 1;
  11377. else
  11378. break; /* found a match */
  11379. }
  11380. if (low > high) /* no matches */
  11381. {
  11382. *items = NULL;
  11383. return 0;
  11384. }
  11385. /*
  11386. * Now determine how many items match the object. The search loop
  11387. * invariant still holds: only items between low and high inclusive could
  11388. * match.
  11389. */
  11390. nmatch = 1;
  11391. while (middle > low)
  11392. {
  11393. if (classoid != middle[-1].classoid ||
  11394. objoid != middle[-1].objoid)
  11395. break;
  11396. middle--;
  11397. nmatch++;
  11398. }
  11399. *items = middle;
  11400. middle += nmatch;
  11401. while (middle <= high)
  11402. {
  11403. if (classoid != middle->classoid ||
  11404. objoid != middle->objoid)
  11405. break;
  11406. middle++;
  11407. nmatch++;
  11408. }
  11409. return nmatch;
  11410. }
  11411. /*
  11412. * collectSecLabels
  11413. *
  11414. * Construct a table of all security labels available for database objects.
  11415. * It's much faster to pull them all at once.
  11416. *
  11417. * The table is sorted by classoid/objid/objsubid for speed in lookup.
  11418. */
  11419. static int
  11420. collectSecLabels(Archive *fout, SecLabelItem **items)
  11421. {
  11422. PGresult *res;
  11423. PQExpBuffer query;
  11424. int i_label;
  11425. int i_provider;
  11426. int i_classoid;
  11427. int i_objoid;
  11428. int i_objsubid;
  11429. int ntups;
  11430. int i;
  11431. SecLabelItem *labels;
  11432. query = createPQExpBuffer();
  11433. appendPQExpBufferStr(query,
  11434. "SELECT label, provider, classoid, objoid, objsubid "
  11435. "FROM pg_catalog.pg_seclabel "
  11436. "ORDER BY classoid, objoid, objsubid");
  11437. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  11438. /* Construct lookup table containing OIDs in numeric form */
  11439. i_label = PQfnumber(res, "label");
  11440. i_provider = PQfnumber(res, "provider");
  11441. i_classoid = PQfnumber(res, "classoid");
  11442. i_objoid = PQfnumber(res, "objoid");
  11443. i_objsubid = PQfnumber(res, "objsubid");
  11444. ntups = PQntuples(res);
  11445. labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
  11446. for (i = 0; i < ntups; i++)
  11447. {
  11448. labels[i].label = PQgetvalue(res, i, i_label);
  11449. labels[i].provider = PQgetvalue(res, i, i_provider);
  11450. labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
  11451. labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
  11452. labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
  11453. }
  11454. /* Do NOT free the PGresult since we are keeping pointers into it */
  11455. destroyPQExpBuffer(query);
  11456. *items = labels;
  11457. return ntups;
  11458. }
  11459. /*
  11460. * dumpTable
  11461. * write out to fout the declarations (not data) of a user-defined table
  11462. */
  11463. static void
  11464. dumpTable(Archive *fout, TableInfo *tbinfo)
  11465. {
  11466. if (tbinfo->dobj.dump && !dataOnly)
  11467. {
  11468. char *namecopy;
  11469. if (tbinfo->relkind == RELKIND_SEQUENCE)
  11470. dumpSequence(fout, tbinfo);
  11471. else
  11472. dumpTableSchema(fout, tbinfo);
  11473. /* Handle the ACL here */
  11474. namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
  11475. dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
  11476. (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
  11477. "TABLE",
  11478. namecopy, NULL, tbinfo->dobj.name,
  11479. tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
  11480. tbinfo->relacl);
  11481. /*
  11482. * Handle column ACLs, if any. Note: we pull these with a separate
  11483. * query rather than trying to fetch them during getTableAttrs, so
  11484. * that we won't miss ACLs on system columns.
  11485. */
  11486. if (fout->remoteVersion >= 80400)
  11487. {
  11488. PQExpBuffer query = createPQExpBuffer();
  11489. PGresult *res;
  11490. int i;
  11491. appendPQExpBuffer(query,
  11492. "SELECT attname, attacl FROM pg_catalog.pg_attribute "
  11493. "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
  11494. "ORDER BY attnum",
  11495. tbinfo->dobj.catId.oid);
  11496. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  11497. for (i = 0; i < PQntuples(res); i++)
  11498. {
  11499. char *attname = PQgetvalue(res, i, 0);
  11500. char *attacl = PQgetvalue(res, i, 1);
  11501. char *attnamecopy;
  11502. char *acltag;
  11503. attnamecopy = pg_strdup(fmtId(attname));
  11504. acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
  11505. /* Column's GRANT type is always TABLE */
  11506. dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
  11507. namecopy, attnamecopy, acltag,
  11508. tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
  11509. attacl);
  11510. free(attnamecopy);
  11511. free(acltag);
  11512. }
  11513. PQclear(res);
  11514. destroyPQExpBuffer(query);
  11515. }
  11516. free(namecopy);
  11517. }
  11518. }
  11519. /*
  11520. * Create the AS clause for a view or materialized view. The semicolon is
  11521. * stripped because a materialized view must add a WITH NO DATA clause.
  11522. *
  11523. * This returns a new buffer which must be freed by the caller.
  11524. */
  11525. static PQExpBuffer
  11526. createViewAsClause(Archive *fout, TableInfo *tbinfo)
  11527. {
  11528. PQExpBuffer query = createPQExpBuffer();
  11529. PQExpBuffer result = createPQExpBuffer();
  11530. PGresult *res;
  11531. int len;
  11532. /* Fetch the view definition */
  11533. if (fout->remoteVersion >= 70300)
  11534. {
  11535. /* Beginning in 7.3, viewname is not unique; rely on OID */
  11536. appendPQExpBuffer(query,
  11537. "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
  11538. tbinfo->dobj.catId.oid);
  11539. }
  11540. else
  11541. {
  11542. appendPQExpBufferStr(query, "SELECT definition AS viewdef "
  11543. "FROM pg_views WHERE viewname = ");
  11544. appendStringLiteralAH(query, tbinfo->dobj.name, fout);
  11545. }
  11546. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  11547. if (PQntuples(res) != 1)
  11548. {
  11549. if (PQntuples(res) < 1)
  11550. exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
  11551. tbinfo->dobj.name);
  11552. else
  11553. exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
  11554. tbinfo->dobj.name);
  11555. }
  11556. len = PQgetlength(res, 0, 0);
  11557. if (len == 0)
  11558. exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
  11559. tbinfo->dobj.name);
  11560. /* Strip off the trailing semicolon so that other things may follow. */
  11561. Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
  11562. appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
  11563. PQclear(res);
  11564. destroyPQExpBuffer(query);
  11565. return result;
  11566. }
  11567. /*
  11568. * dumpTableSchema
  11569. * write the declaration (not data) of one user-defined table or view
  11570. */
  11571. static void
  11572. dumpTableSchema(Archive *fout, TableInfo *tbinfo)
  11573. {
  11574. PQExpBuffer q = createPQExpBuffer();
  11575. PQExpBuffer delq = createPQExpBuffer();
  11576. PQExpBuffer labelq = createPQExpBuffer();
  11577. int numParents;
  11578. TableInfo **parents;
  11579. int actual_atts; /* number of attrs in this CREATE statement */
  11580. const char *reltypename;
  11581. char *storage;
  11582. char *srvname;
  11583. char *ftoptions;
  11584. int j,
  11585. k;
  11586. /* Make sure we are in proper schema */
  11587. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  11588. if (binary_upgrade)
  11589. binary_upgrade_set_type_oids_by_rel_oid(fout, q,
  11590. tbinfo->dobj.catId.oid);
  11591. /* Is it a table or a view? */
  11592. if (tbinfo->relkind == RELKIND_VIEW)
  11593. {
  11594. PQExpBuffer result;
  11595. reltypename = "VIEW";
  11596. /*
  11597. * DROP must be fully qualified in case same name appears in
  11598. * pg_catalog
  11599. */
  11600. appendPQExpBuffer(delq, "DROP VIEW %s.",
  11601. fmtId(tbinfo->dobj.namespace->dobj.name));
  11602. appendPQExpBuffer(delq, "%s;\n",
  11603. fmtId(tbinfo->dobj.name));
  11604. if (binary_upgrade)
  11605. binary_upgrade_set_pg_class_oids(fout, q,
  11606. tbinfo->dobj.catId.oid, false);
  11607. appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
  11608. if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
  11609. appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
  11610. result = createViewAsClause(fout, tbinfo);
  11611. appendPQExpBuffer(q, " AS\n%s", result->data);
  11612. destroyPQExpBuffer(result);
  11613. if (tbinfo->checkoption != NULL)
  11614. appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
  11615. appendPQExpBufferStr(q, ";\n");
  11616. appendPQExpBuffer(labelq, "VIEW %s",
  11617. fmtId(tbinfo->dobj.name));
  11618. }
  11619. else
  11620. {
  11621. switch (tbinfo->relkind)
  11622. {
  11623. case (RELKIND_FOREIGN_TABLE):
  11624. {
  11625. PQExpBuffer query = createPQExpBuffer();
  11626. PGresult *res;
  11627. int i_srvname;
  11628. int i_ftoptions;
  11629. reltypename = "FOREIGN TABLE";
  11630. /* retrieve name of foreign server and generic options */
  11631. appendPQExpBuffer(query,
  11632. "SELECT fs.srvname, "
  11633. "pg_catalog.array_to_string(ARRAY("
  11634. "SELECT pg_catalog.quote_ident(option_name) || "
  11635. "' ' || pg_catalog.quote_literal(option_value) "
  11636. "FROM pg_catalog.pg_options_to_table(ftoptions) "
  11637. "ORDER BY option_name"
  11638. "), E',\n ') AS ftoptions "
  11639. "FROM pg_catalog.pg_foreign_table ft "
  11640. "JOIN pg_catalog.pg_foreign_server fs "
  11641. "ON (fs.oid = ft.ftserver) "
  11642. "WHERE ft.ftrelid = '%u'",
  11643. tbinfo->dobj.catId.oid);
  11644. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  11645. i_srvname = PQfnumber(res, "srvname");
  11646. i_ftoptions = PQfnumber(res, "ftoptions");
  11647. srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
  11648. ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
  11649. PQclear(res);
  11650. destroyPQExpBuffer(query);
  11651. break;
  11652. }
  11653. case (RELKIND_MATVIEW):
  11654. reltypename = "MATERIALIZED VIEW";
  11655. srvname = NULL;
  11656. ftoptions = NULL;
  11657. break;
  11658. default:
  11659. reltypename = "TABLE";
  11660. srvname = NULL;
  11661. ftoptions = NULL;
  11662. }
  11663. numParents = tbinfo->numParents;
  11664. parents = tbinfo->parents;
  11665. /*
  11666. * DROP must be fully qualified in case same name appears in
  11667. * pg_catalog
  11668. */
  11669. appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
  11670. fmtId(tbinfo->dobj.namespace->dobj.name));
  11671. appendPQExpBuffer(delq, "%s;\n",
  11672. fmtId(tbinfo->dobj.name));
  11673. appendPQExpBuffer(labelq, "%s %s", reltypename,
  11674. fmtId(tbinfo->dobj.name));
  11675. if (binary_upgrade)
  11676. binary_upgrade_set_pg_class_oids(fout, q,
  11677. tbinfo->dobj.catId.oid, false);
  11678. appendPQExpBuffer(q, "CREATE %s%s %s",
  11679. tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
  11680. "UNLOGGED " : "",
  11681. reltypename,
  11682. fmtId(tbinfo->dobj.name));
  11683. /*
  11684. * Attach to type, if reloftype; except in case of a binary upgrade,
  11685. * we dump the table normally and attach it to the type afterward.
  11686. */
  11687. if (tbinfo->reloftype && !binary_upgrade)
  11688. appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
  11689. if (tbinfo->relkind != RELKIND_MATVIEW)
  11690. {
  11691. /* Dump the attributes */
  11692. actual_atts = 0;
  11693. for (j = 0; j < tbinfo->numatts; j++)
  11694. {
  11695. /*
  11696. * Normally, dump if it's locally defined in this table, and
  11697. * not dropped. But for binary upgrade, we'll dump all the
  11698. * columns, and then fix up the dropped and nonlocal cases
  11699. * below.
  11700. */
  11701. if (shouldPrintColumn(tbinfo, j))
  11702. {
  11703. /*
  11704. * Default value --- suppress if to be printed separately.
  11705. */
  11706. bool has_default = (tbinfo->attrdefs[j] != NULL &&
  11707. !tbinfo->attrdefs[j]->separate);
  11708. /*
  11709. * Not Null constraint --- suppress if inherited, except
  11710. * in binary-upgrade case where that won't work.
  11711. */
  11712. bool has_notnull = (tbinfo->notnull[j] &&
  11713. (!tbinfo->inhNotNull[j] ||
  11714. binary_upgrade));
  11715. /* Skip column if fully defined by reloftype */
  11716. if (tbinfo->reloftype &&
  11717. !has_default && !has_notnull && !binary_upgrade)
  11718. continue;
  11719. /* Format properly if not first attr */
  11720. if (actual_atts == 0)
  11721. appendPQExpBufferStr(q, " (");
  11722. else
  11723. appendPQExpBufferStr(q, ",");
  11724. appendPQExpBufferStr(q, "\n ");
  11725. actual_atts++;
  11726. /* Attribute name */
  11727. appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
  11728. if (tbinfo->attisdropped[j])
  11729. {
  11730. /*
  11731. * ALTER TABLE DROP COLUMN clears
  11732. * pg_attribute.atttypid, so we will not have gotten a
  11733. * valid type name; insert INTEGER as a stopgap. We'll
  11734. * clean things up later.
  11735. */
  11736. appendPQExpBufferStr(q, " INTEGER /* dummy */");
  11737. /* Skip all the rest, too */
  11738. continue;
  11739. }
  11740. /* Attribute type */
  11741. if (tbinfo->reloftype && !binary_upgrade)
  11742. {
  11743. appendPQExpBufferStr(q, " WITH OPTIONS");
  11744. }
  11745. else if (fout->remoteVersion >= 70100)
  11746. {
  11747. appendPQExpBuffer(q, " %s",
  11748. tbinfo->atttypnames[j]);
  11749. }
  11750. else
  11751. {
  11752. /* If no format_type, fake it */
  11753. appendPQExpBuffer(q, " %s",
  11754. myFormatType(tbinfo->atttypnames[j],
  11755. tbinfo->atttypmod[j]));
  11756. }
  11757. /* Add collation if not default for the type */
  11758. if (OidIsValid(tbinfo->attcollation[j]))
  11759. {
  11760. CollInfo *coll;
  11761. coll = findCollationByOid(tbinfo->attcollation[j]);
  11762. if (coll)
  11763. {
  11764. /* always schema-qualify, don't try to be smart */
  11765. appendPQExpBuffer(q, " COLLATE %s.",
  11766. fmtId(coll->dobj.namespace->dobj.name));
  11767. appendPQExpBufferStr(q, fmtId(coll->dobj.name));
  11768. }
  11769. }
  11770. if (has_default)
  11771. appendPQExpBuffer(q, " DEFAULT %s",
  11772. tbinfo->attrdefs[j]->adef_expr);
  11773. if (has_notnull)
  11774. appendPQExpBufferStr(q, " NOT NULL");
  11775. }
  11776. }
  11777. /*
  11778. * Add non-inherited CHECK constraints, if any.
  11779. */
  11780. for (j = 0; j < tbinfo->ncheck; j++)
  11781. {
  11782. ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
  11783. if (constr->separate || !constr->conislocal)
  11784. continue;
  11785. if (actual_atts == 0)
  11786. appendPQExpBufferStr(q, " (\n ");
  11787. else
  11788. appendPQExpBufferStr(q, ",\n ");
  11789. appendPQExpBuffer(q, "CONSTRAINT %s ",
  11790. fmtId(constr->dobj.name));
  11791. appendPQExpBufferStr(q, constr->condef);
  11792. actual_atts++;
  11793. }
  11794. if (actual_atts)
  11795. appendPQExpBufferStr(q, "\n)");
  11796. else if (!(tbinfo->reloftype && !binary_upgrade))
  11797. {
  11798. /*
  11799. * We must have a parenthesized attribute list, even though
  11800. * empty, when not using the OF TYPE syntax.
  11801. */
  11802. appendPQExpBufferStr(q, " (\n)");
  11803. }
  11804. if (numParents > 0 && !binary_upgrade)
  11805. {
  11806. appendPQExpBufferStr(q, "\nINHERITS (");
  11807. for (k = 0; k < numParents; k++)
  11808. {
  11809. TableInfo *parentRel = parents[k];
  11810. if (k > 0)
  11811. appendPQExpBufferStr(q, ", ");
  11812. if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
  11813. appendPQExpBuffer(q, "%s.",
  11814. fmtId(parentRel->dobj.namespace->dobj.name));
  11815. appendPQExpBufferStr(q, fmtId(parentRel->dobj.name));
  11816. }
  11817. appendPQExpBufferChar(q, ')');
  11818. }
  11819. if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
  11820. appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
  11821. }
  11822. if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
  11823. (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
  11824. {
  11825. bool addcomma = false;
  11826. appendPQExpBufferStr(q, "\nWITH (");
  11827. if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
  11828. {
  11829. addcomma = true;
  11830. appendPQExpBufferStr(q, tbinfo->reloptions);
  11831. }
  11832. if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
  11833. {
  11834. appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
  11835. tbinfo->toast_reloptions);
  11836. }
  11837. appendPQExpBufferChar(q, ')');
  11838. }
  11839. /* Dump generic options if any */
  11840. if (ftoptions && ftoptions[0])
  11841. appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
  11842. /*
  11843. * For materialized views, create the AS clause just like a view. At
  11844. * this point, we always mark the view as not populated.
  11845. */
  11846. if (tbinfo->relkind == RELKIND_MATVIEW)
  11847. {
  11848. PQExpBuffer result;
  11849. result = createViewAsClause(fout, tbinfo);
  11850. appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
  11851. result->data);
  11852. destroyPQExpBuffer(result);
  11853. }
  11854. else
  11855. appendPQExpBufferStr(q, ";\n");
  11856. /*
  11857. * To create binary-compatible heap files, we have to ensure the same
  11858. * physical column order, including dropped columns, as in the
  11859. * original. Therefore, we create dropped columns above and drop them
  11860. * here, also updating their attlen/attalign values so that the
  11861. * dropped column can be skipped properly. (We do not bother with
  11862. * restoring the original attbyval setting.) Also, inheritance
  11863. * relationships are set up by doing ALTER INHERIT rather than using
  11864. * an INHERITS clause --- the latter would possibly mess up the column
  11865. * order. That also means we have to take care about setting
  11866. * attislocal correctly, plus fix up any inherited CHECK constraints.
  11867. * Analogously, we set up typed tables using ALTER TABLE / OF here.
  11868. */
  11869. if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION ||
  11870. tbinfo->relkind == RELKIND_FOREIGN_TABLE))
  11871. {
  11872. for (j = 0; j < tbinfo->numatts; j++)
  11873. {
  11874. if (tbinfo->attisdropped[j])
  11875. {
  11876. appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
  11877. appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
  11878. "SET attlen = %d, "
  11879. "attalign = '%c', attbyval = false\n"
  11880. "WHERE attname = ",
  11881. tbinfo->attlen[j],
  11882. tbinfo->attalign[j]);
  11883. appendStringLiteralAH(q, tbinfo->attnames[j], fout);
  11884. appendPQExpBufferStr(q, "\n AND attrelid = ");
  11885. appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
  11886. appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
  11887. if (tbinfo->relkind == RELKIND_RELATION)
  11888. appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
  11889. fmtId(tbinfo->dobj.name));
  11890. else
  11891. appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
  11892. fmtId(tbinfo->dobj.name));
  11893. appendPQExpBuffer(q, "DROP COLUMN %s;\n",
  11894. fmtId(tbinfo->attnames[j]));
  11895. }
  11896. else if (!tbinfo->attislocal[j])
  11897. {
  11898. Assert(tbinfo->relkind != RELKIND_FOREIGN_TABLE);
  11899. appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
  11900. appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
  11901. "SET attislocal = false\n"
  11902. "WHERE attname = ");
  11903. appendStringLiteralAH(q, tbinfo->attnames[j], fout);
  11904. appendPQExpBufferStr(q, "\n AND attrelid = ");
  11905. appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
  11906. appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
  11907. }
  11908. }
  11909. for (k = 0; k < tbinfo->ncheck; k++)
  11910. {
  11911. ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
  11912. if (constr->separate || constr->conislocal)
  11913. continue;
  11914. appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
  11915. appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
  11916. fmtId(tbinfo->dobj.name));
  11917. appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
  11918. fmtId(constr->dobj.name));
  11919. appendPQExpBuffer(q, "%s;\n", constr->condef);
  11920. appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
  11921. "SET conislocal = false\n"
  11922. "WHERE contype = 'c' AND conname = ");
  11923. appendStringLiteralAH(q, constr->dobj.name, fout);
  11924. appendPQExpBufferStr(q, "\n AND conrelid = ");
  11925. appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
  11926. appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
  11927. }
  11928. if (numParents > 0)
  11929. {
  11930. appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
  11931. for (k = 0; k < numParents; k++)
  11932. {
  11933. TableInfo *parentRel = parents[k];
  11934. appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
  11935. fmtId(tbinfo->dobj.name));
  11936. if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
  11937. appendPQExpBuffer(q, "%s.",
  11938. fmtId(parentRel->dobj.namespace->dobj.name));
  11939. appendPQExpBuffer(q, "%s;\n",
  11940. fmtId(parentRel->dobj.name));
  11941. }
  11942. }
  11943. if (tbinfo->reloftype)
  11944. {
  11945. appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
  11946. appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
  11947. fmtId(tbinfo->dobj.name),
  11948. tbinfo->reloftype);
  11949. }
  11950. appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
  11951. appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
  11952. "SET relfrozenxid = '%u', relminmxid = '%u'\n"
  11953. "WHERE oid = ",
  11954. tbinfo->frozenxid, tbinfo->minmxid);
  11955. appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
  11956. appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
  11957. if (tbinfo->toast_oid)
  11958. {
  11959. /* We preserve the toast oids, so we can use it during restore */
  11960. appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
  11961. appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
  11962. "SET relfrozenxid = '%u', relminmxid = '%u'\n"
  11963. "WHERE oid = '%u';\n",
  11964. tbinfo->toast_frozenxid,
  11965. tbinfo->toast_minmxid, tbinfo->toast_oid);
  11966. }
  11967. }
  11968. /*
  11969. * In binary_upgrade mode, restore matviews' populated status by
  11970. * poking pg_class directly. This is pretty ugly, but we can't use
  11971. * REFRESH MATERIALIZED VIEW since it's possible that some underlying
  11972. * matview is not populated even though this matview is.
  11973. */
  11974. if (binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
  11975. tbinfo->relispopulated)
  11976. {
  11977. appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
  11978. appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
  11979. "SET relispopulated = 't'\n"
  11980. "WHERE oid = ");
  11981. appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
  11982. appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
  11983. }
  11984. /*
  11985. * Dump additional per-column properties that we can't handle in the
  11986. * main CREATE TABLE command.
  11987. */
  11988. for (j = 0; j < tbinfo->numatts; j++)
  11989. {
  11990. /* None of this applies to dropped columns */
  11991. if (tbinfo->attisdropped[j])
  11992. continue;
  11993. /*
  11994. * If we didn't dump the column definition explicitly above, and
  11995. * it is NOT NULL and did not inherit that property from a parent,
  11996. * we have to mark it separately.
  11997. */
  11998. if (!shouldPrintColumn(tbinfo, j) &&
  11999. tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
  12000. {
  12001. appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
  12002. fmtId(tbinfo->dobj.name));
  12003. appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
  12004. fmtId(tbinfo->attnames[j]));
  12005. }
  12006. /*
  12007. * Dump per-column statistics information. We only issue an ALTER
  12008. * TABLE statement if the attstattarget entry for this column is
  12009. * non-negative (i.e. it's not the default value)
  12010. */
  12011. if (tbinfo->attstattarget[j] >= 0)
  12012. {
  12013. appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
  12014. fmtId(tbinfo->dobj.name));
  12015. appendPQExpBuffer(q, "ALTER COLUMN %s ",
  12016. fmtId(tbinfo->attnames[j]));
  12017. appendPQExpBuffer(q, "SET STATISTICS %d;\n",
  12018. tbinfo->attstattarget[j]);
  12019. }
  12020. /*
  12021. * Dump per-column storage information. The statement is only
  12022. * dumped if the storage has been changed from the type's default.
  12023. */
  12024. if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
  12025. {
  12026. switch (tbinfo->attstorage[j])
  12027. {
  12028. case 'p':
  12029. storage = "PLAIN";
  12030. break;
  12031. case 'e':
  12032. storage = "EXTERNAL";
  12033. break;
  12034. case 'm':
  12035. storage = "MAIN";
  12036. break;
  12037. case 'x':
  12038. storage = "EXTENDED";
  12039. break;
  12040. default:
  12041. storage = NULL;
  12042. }
  12043. /*
  12044. * Only dump the statement if it's a storage type we recognize
  12045. */
  12046. if (storage != NULL)
  12047. {
  12048. appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
  12049. fmtId(tbinfo->dobj.name));
  12050. appendPQExpBuffer(q, "ALTER COLUMN %s ",
  12051. fmtId(tbinfo->attnames[j]));
  12052. appendPQExpBuffer(q, "SET STORAGE %s;\n",
  12053. storage);
  12054. }
  12055. }
  12056. /*
  12057. * Dump per-column attributes.
  12058. */
  12059. if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
  12060. {
  12061. appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
  12062. fmtId(tbinfo->dobj.name));
  12063. appendPQExpBuffer(q, "ALTER COLUMN %s ",
  12064. fmtId(tbinfo->attnames[j]));
  12065. appendPQExpBuffer(q, "SET (%s);\n",
  12066. tbinfo->attoptions[j]);
  12067. }
  12068. /*
  12069. * Dump per-column fdw options.
  12070. */
  12071. if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
  12072. tbinfo->attfdwoptions[j] &&
  12073. tbinfo->attfdwoptions[j][0] != '\0')
  12074. {
  12075. appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
  12076. fmtId(tbinfo->dobj.name));
  12077. appendPQExpBuffer(q, "ALTER COLUMN %s ",
  12078. fmtId(tbinfo->attnames[j]));
  12079. appendPQExpBuffer(q, "OPTIONS (\n %s\n);\n",
  12080. tbinfo->attfdwoptions[j]);
  12081. }
  12082. }
  12083. }
  12084. /*
  12085. * dump properties we only have ALTER TABLE syntax for
  12086. */
  12087. if ((tbinfo->relkind == RELKIND_RELATION || tbinfo->relkind == RELKIND_MATVIEW) &&
  12088. tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
  12089. {
  12090. if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
  12091. {
  12092. /* nothing to do, will be set when the index is dumped */
  12093. }
  12094. else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
  12095. {
  12096. appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
  12097. fmtId(tbinfo->dobj.name));
  12098. }
  12099. else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
  12100. {
  12101. appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
  12102. fmtId(tbinfo->dobj.name));
  12103. }
  12104. }
  12105. if (binary_upgrade)
  12106. binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
  12107. ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
  12108. tbinfo->dobj.name,
  12109. tbinfo->dobj.namespace->dobj.name,
  12110. (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
  12111. tbinfo->rolname,
  12112. (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
  12113. reltypename,
  12114. tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA,
  12115. q->data, delq->data, NULL,
  12116. NULL, 0,
  12117. NULL, NULL);
  12118. /* Dump Table Comments */
  12119. dumpTableComment(fout, tbinfo, reltypename);
  12120. /* Dump Table Security Labels */
  12121. dumpTableSecLabel(fout, tbinfo, reltypename);
  12122. /* Dump comments on inlined table constraints */
  12123. for (j = 0; j < tbinfo->ncheck; j++)
  12124. {
  12125. ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
  12126. if (constr->separate || !constr->conislocal)
  12127. continue;
  12128. dumpTableConstraintComment(fout, constr);
  12129. }
  12130. destroyPQExpBuffer(q);
  12131. destroyPQExpBuffer(delq);
  12132. destroyPQExpBuffer(labelq);
  12133. }
  12134. /*
  12135. * dumpAttrDef --- dump an attribute's default-value declaration
  12136. */
  12137. static void
  12138. dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
  12139. {
  12140. TableInfo *tbinfo = adinfo->adtable;
  12141. int adnum = adinfo->adnum;
  12142. PQExpBuffer q;
  12143. PQExpBuffer delq;
  12144. /* Skip if table definition not to be dumped */
  12145. if (!tbinfo->dobj.dump || dataOnly)
  12146. return;
  12147. /* Skip if not "separate"; it was dumped in the table's definition */
  12148. if (!adinfo->separate)
  12149. return;
  12150. q = createPQExpBuffer();
  12151. delq = createPQExpBuffer();
  12152. appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
  12153. fmtId(tbinfo->dobj.name));
  12154. appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
  12155. fmtId(tbinfo->attnames[adnum - 1]),
  12156. adinfo->adef_expr);
  12157. /*
  12158. * DROP must be fully qualified in case same name appears in pg_catalog
  12159. */
  12160. appendPQExpBuffer(delq, "ALTER TABLE %s.",
  12161. fmtId(tbinfo->dobj.namespace->dobj.name));
  12162. appendPQExpBuffer(delq, "%s ",
  12163. fmtId(tbinfo->dobj.name));
  12164. appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
  12165. fmtId(tbinfo->attnames[adnum - 1]));
  12166. ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
  12167. tbinfo->attnames[adnum - 1],
  12168. tbinfo->dobj.namespace->dobj.name,
  12169. NULL,
  12170. tbinfo->rolname,
  12171. false, "DEFAULT", SECTION_PRE_DATA,
  12172. q->data, delq->data, NULL,
  12173. NULL, 0,
  12174. NULL, NULL);
  12175. destroyPQExpBuffer(q);
  12176. destroyPQExpBuffer(delq);
  12177. }
  12178. /*
  12179. * getAttrName: extract the correct name for an attribute
  12180. *
  12181. * The array tblInfo->attnames[] only provides names of user attributes;
  12182. * if a system attribute number is supplied, we have to fake it.
  12183. * We also do a little bit of bounds checking for safety's sake.
  12184. */
  12185. static const char *
  12186. getAttrName(int attrnum, TableInfo *tblInfo)
  12187. {
  12188. if (attrnum > 0 && attrnum <= tblInfo->numatts)
  12189. return tblInfo->attnames[attrnum - 1];
  12190. switch (attrnum)
  12191. {
  12192. case SelfItemPointerAttributeNumber:
  12193. return "ctid";
  12194. case ObjectIdAttributeNumber:
  12195. return "oid";
  12196. case MinTransactionIdAttributeNumber:
  12197. return "xmin";
  12198. case MinCommandIdAttributeNumber:
  12199. return "cmin";
  12200. case MaxTransactionIdAttributeNumber:
  12201. return "xmax";
  12202. case MaxCommandIdAttributeNumber:
  12203. return "cmax";
  12204. case TableOidAttributeNumber:
  12205. return "tableoid";
  12206. }
  12207. exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
  12208. attrnum, tblInfo->dobj.name);
  12209. return NULL; /* keep compiler quiet */
  12210. }
  12211. /*
  12212. * dumpIndex
  12213. * write out to fout a user-defined index
  12214. */
  12215. static void
  12216. dumpIndex(Archive *fout, IndxInfo *indxinfo)
  12217. {
  12218. TableInfo *tbinfo = indxinfo->indextable;
  12219. bool is_constraint = (indxinfo->indexconstraint != 0);
  12220. PQExpBuffer q;
  12221. PQExpBuffer delq;
  12222. PQExpBuffer labelq;
  12223. if (dataOnly)
  12224. return;
  12225. q = createPQExpBuffer();
  12226. delq = createPQExpBuffer();
  12227. labelq = createPQExpBuffer();
  12228. appendPQExpBuffer(labelq, "INDEX %s",
  12229. fmtId(indxinfo->dobj.name));
  12230. /*
  12231. * If there's an associated constraint, don't dump the index per se, but
  12232. * do dump any comment for it. (This is safe because dependency ordering
  12233. * will have ensured the constraint is emitted first.) Note that the
  12234. * emitted comment has to be shown as depending on the constraint, not the
  12235. * index, in such cases.
  12236. */
  12237. if (!is_constraint)
  12238. {
  12239. if (binary_upgrade)
  12240. binary_upgrade_set_pg_class_oids(fout, q,
  12241. indxinfo->dobj.catId.oid, true);
  12242. /* Plain secondary index */
  12243. appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
  12244. /* If the index is clustered, we need to record that. */
  12245. if (indxinfo->indisclustered)
  12246. {
  12247. appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
  12248. fmtId(tbinfo->dobj.name));
  12249. appendPQExpBuffer(q, " ON %s;\n",
  12250. fmtId(indxinfo->dobj.name));
  12251. }
  12252. /* If the index defines identity, we need to record that. */
  12253. if (indxinfo->indisreplident)
  12254. {
  12255. appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
  12256. fmtId(tbinfo->dobj.name));
  12257. appendPQExpBuffer(q, " INDEX %s;\n",
  12258. fmtId(indxinfo->dobj.name));
  12259. }
  12260. /*
  12261. * DROP must be fully qualified in case same name appears in
  12262. * pg_catalog
  12263. */
  12264. appendPQExpBuffer(delq, "DROP INDEX %s.",
  12265. fmtId(tbinfo->dobj.namespace->dobj.name));
  12266. appendPQExpBuffer(delq, "%s;\n",
  12267. fmtId(indxinfo->dobj.name));
  12268. ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
  12269. indxinfo->dobj.name,
  12270. tbinfo->dobj.namespace->dobj.name,
  12271. indxinfo->tablespace,
  12272. tbinfo->rolname, false,
  12273. "INDEX", SECTION_POST_DATA,
  12274. q->data, delq->data, NULL,
  12275. NULL, 0,
  12276. NULL, NULL);
  12277. }
  12278. /* Dump Index Comments */
  12279. dumpComment(fout, labelq->data,
  12280. tbinfo->dobj.namespace->dobj.name,
  12281. tbinfo->rolname,
  12282. indxinfo->dobj.catId, 0,
  12283. is_constraint ? indxinfo->indexconstraint :
  12284. indxinfo->dobj.dumpId);
  12285. destroyPQExpBuffer(q);
  12286. destroyPQExpBuffer(delq);
  12287. destroyPQExpBuffer(labelq);
  12288. }
  12289. /*
  12290. * dumpConstraint
  12291. * write out to fout a user-defined constraint
  12292. */
  12293. static void
  12294. dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
  12295. {
  12296. TableInfo *tbinfo = coninfo->contable;
  12297. PQExpBuffer q;
  12298. PQExpBuffer delq;
  12299. /* Skip if not to be dumped */
  12300. if (!coninfo->dobj.dump || dataOnly)
  12301. return;
  12302. q = createPQExpBuffer();
  12303. delq = createPQExpBuffer();
  12304. if (coninfo->contype == 'p' ||
  12305. coninfo->contype == 'u' ||
  12306. coninfo->contype == 'x')
  12307. {
  12308. /* Index-related constraint */
  12309. IndxInfo *indxinfo;
  12310. int k;
  12311. indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
  12312. if (indxinfo == NULL)
  12313. exit_horribly(NULL, "missing index for constraint \"%s\"\n",
  12314. coninfo->dobj.name);
  12315. if (binary_upgrade)
  12316. binary_upgrade_set_pg_class_oids(fout, q,
  12317. indxinfo->dobj.catId.oid, true);
  12318. appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
  12319. fmtId(tbinfo->dobj.name));
  12320. appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
  12321. fmtId(coninfo->dobj.name));
  12322. if (coninfo->condef)
  12323. {
  12324. /* pg_get_constraintdef should have provided everything */
  12325. appendPQExpBuffer(q, "%s;\n", coninfo->condef);
  12326. }
  12327. else
  12328. {
  12329. appendPQExpBuffer(q, "%s (",
  12330. coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
  12331. for (k = 0; k < indxinfo->indnkeys; k++)
  12332. {
  12333. int indkey = (int) indxinfo->indkeys[k];
  12334. const char *attname;
  12335. if (indkey == InvalidAttrNumber)
  12336. break;
  12337. attname = getAttrName(indkey, tbinfo);
  12338. appendPQExpBuffer(q, "%s%s",
  12339. (k == 0) ? "" : ", ",
  12340. fmtId(attname));
  12341. }
  12342. appendPQExpBufferChar(q, ')');
  12343. if (indxinfo->options && strlen(indxinfo->options) > 0)
  12344. appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
  12345. if (coninfo->condeferrable)
  12346. {
  12347. appendPQExpBufferStr(q, " DEFERRABLE");
  12348. if (coninfo->condeferred)
  12349. appendPQExpBufferStr(q, " INITIALLY DEFERRED");
  12350. }
  12351. appendPQExpBufferStr(q, ";\n");
  12352. }
  12353. /* If the index is clustered, we need to record that. */
  12354. if (indxinfo->indisclustered)
  12355. {
  12356. appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
  12357. fmtId(tbinfo->dobj.name));
  12358. appendPQExpBuffer(q, " ON %s;\n",
  12359. fmtId(indxinfo->dobj.name));
  12360. }
  12361. /*
  12362. * DROP must be fully qualified in case same name appears in
  12363. * pg_catalog
  12364. */
  12365. appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
  12366. fmtId(tbinfo->dobj.namespace->dobj.name));
  12367. appendPQExpBuffer(delq, "%s ",
  12368. fmtId(tbinfo->dobj.name));
  12369. appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
  12370. fmtId(coninfo->dobj.name));
  12371. ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
  12372. coninfo->dobj.name,
  12373. tbinfo->dobj.namespace->dobj.name,
  12374. indxinfo->tablespace,
  12375. tbinfo->rolname, false,
  12376. "CONSTRAINT", SECTION_POST_DATA,
  12377. q->data, delq->data, NULL,
  12378. NULL, 0,
  12379. NULL, NULL);
  12380. }
  12381. else if (coninfo->contype == 'f')
  12382. {
  12383. /*
  12384. * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
  12385. * current table data is not processed
  12386. */
  12387. appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
  12388. fmtId(tbinfo->dobj.name));
  12389. appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
  12390. fmtId(coninfo->dobj.name),
  12391. coninfo->condef);
  12392. /*
  12393. * DROP must be fully qualified in case same name appears in
  12394. * pg_catalog
  12395. */
  12396. appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
  12397. fmtId(tbinfo->dobj.namespace->dobj.name));
  12398. appendPQExpBuffer(delq, "%s ",
  12399. fmtId(tbinfo->dobj.name));
  12400. appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
  12401. fmtId(coninfo->dobj.name));
  12402. ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
  12403. coninfo->dobj.name,
  12404. tbinfo->dobj.namespace->dobj.name,
  12405. NULL,
  12406. tbinfo->rolname, false,
  12407. "FK CONSTRAINT", SECTION_POST_DATA,
  12408. q->data, delq->data, NULL,
  12409. NULL, 0,
  12410. NULL, NULL);
  12411. }
  12412. else if (coninfo->contype == 'c' && tbinfo)
  12413. {
  12414. /* CHECK constraint on a table */
  12415. /* Ignore if not to be dumped separately */
  12416. if (coninfo->separate)
  12417. {
  12418. /* not ONLY since we want it to propagate to children */
  12419. appendPQExpBuffer(q, "ALTER TABLE %s\n",
  12420. fmtId(tbinfo->dobj.name));
  12421. appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
  12422. fmtId(coninfo->dobj.name),
  12423. coninfo->condef);
  12424. /*
  12425. * DROP must be fully qualified in case same name appears in
  12426. * pg_catalog
  12427. */
  12428. appendPQExpBuffer(delq, "ALTER TABLE %s.",
  12429. fmtId(tbinfo->dobj.namespace->dobj.name));
  12430. appendPQExpBuffer(delq, "%s ",
  12431. fmtId(tbinfo->dobj.name));
  12432. appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
  12433. fmtId(coninfo->dobj.name));
  12434. ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
  12435. coninfo->dobj.name,
  12436. tbinfo->dobj.namespace->dobj.name,
  12437. NULL,
  12438. tbinfo->rolname, false,
  12439. "CHECK CONSTRAINT", SECTION_POST_DATA,
  12440. q->data, delq->data, NULL,
  12441. NULL, 0,
  12442. NULL, NULL);
  12443. }
  12444. }
  12445. else if (coninfo->contype == 'c' && tbinfo == NULL)
  12446. {
  12447. /* CHECK constraint on a domain */
  12448. TypeInfo *tyinfo = coninfo->condomain;
  12449. /* Ignore if not to be dumped separately */
  12450. if (coninfo->separate)
  12451. {
  12452. appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
  12453. fmtId(tyinfo->dobj.name));
  12454. appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
  12455. fmtId(coninfo->dobj.name),
  12456. coninfo->condef);
  12457. /*
  12458. * DROP must be fully qualified in case same name appears in
  12459. * pg_catalog
  12460. */
  12461. appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
  12462. fmtId(tyinfo->dobj.namespace->dobj.name));
  12463. appendPQExpBuffer(delq, "%s ",
  12464. fmtId(tyinfo->dobj.name));
  12465. appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
  12466. fmtId(coninfo->dobj.name));
  12467. ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
  12468. coninfo->dobj.name,
  12469. tyinfo->dobj.namespace->dobj.name,
  12470. NULL,
  12471. tyinfo->rolname, false,
  12472. "CHECK CONSTRAINT", SECTION_POST_DATA,
  12473. q->data, delq->data, NULL,
  12474. NULL, 0,
  12475. NULL, NULL);
  12476. }
  12477. }
  12478. else
  12479. {
  12480. exit_horribly(NULL, "unrecognized constraint type: %c\n",
  12481. coninfo->contype);
  12482. }
  12483. /* Dump Constraint Comments --- only works for table constraints */
  12484. if (tbinfo && coninfo->separate)
  12485. dumpTableConstraintComment(fout, coninfo);
  12486. destroyPQExpBuffer(q);
  12487. destroyPQExpBuffer(delq);
  12488. }
  12489. /*
  12490. * dumpTableConstraintComment --- dump a constraint's comment if any
  12491. *
  12492. * This is split out because we need the function in two different places
  12493. * depending on whether the constraint is dumped as part of CREATE TABLE
  12494. * or as a separate ALTER command.
  12495. */
  12496. static void
  12497. dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
  12498. {
  12499. TableInfo *tbinfo = coninfo->contable;
  12500. PQExpBuffer labelq = createPQExpBuffer();
  12501. appendPQExpBuffer(labelq, "CONSTRAINT %s ",
  12502. fmtId(coninfo->dobj.name));
  12503. appendPQExpBuffer(labelq, "ON %s",
  12504. fmtId(tbinfo->dobj.name));
  12505. dumpComment(fout, labelq->data,
  12506. tbinfo->dobj.namespace->dobj.name,
  12507. tbinfo->rolname,
  12508. coninfo->dobj.catId, 0,
  12509. coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
  12510. destroyPQExpBuffer(labelq);
  12511. }
  12512. /*
  12513. * findLastBuiltInOid -
  12514. * find the last built in oid
  12515. *
  12516. * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
  12517. * pg_database entry for the current database
  12518. */
  12519. static Oid
  12520. findLastBuiltinOid_V71(Archive *fout, const char *dbname)
  12521. {
  12522. PGresult *res;
  12523. Oid last_oid;
  12524. PQExpBuffer query = createPQExpBuffer();
  12525. resetPQExpBuffer(query);
  12526. appendPQExpBufferStr(query, "SELECT datlastsysoid from pg_database where datname = ");
  12527. appendStringLiteralAH(query, dbname, fout);
  12528. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  12529. last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
  12530. PQclear(res);
  12531. destroyPQExpBuffer(query);
  12532. return last_oid;
  12533. }
  12534. /*
  12535. * findLastBuiltInOid -
  12536. * find the last built in oid
  12537. *
  12538. * For 7.0, we do this by assuming that the last thing that initdb does is to
  12539. * create the pg_indexes view. This sucks in general, but seeing that 7.0.x
  12540. * initdb won't be changing anymore, it'll do.
  12541. */
  12542. static Oid
  12543. findLastBuiltinOid_V70(Archive *fout)
  12544. {
  12545. PGresult *res;
  12546. int last_oid;
  12547. res = ExecuteSqlQueryForSingleRow(fout,
  12548. "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
  12549. last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
  12550. PQclear(res);
  12551. return last_oid;
  12552. }
  12553. /*
  12554. * dumpSequence
  12555. * write the declaration (not data) of one user-defined sequence
  12556. */
  12557. static void
  12558. dumpSequence(Archive *fout, TableInfo *tbinfo)
  12559. {
  12560. PGresult *res;
  12561. char *startv,
  12562. *incby,
  12563. *maxv = NULL,
  12564. *minv = NULL,
  12565. *cache;
  12566. char bufm[100],
  12567. bufx[100];
  12568. bool cycled;
  12569. PQExpBuffer query = createPQExpBuffer();
  12570. PQExpBuffer delqry = createPQExpBuffer();
  12571. PQExpBuffer labelq = createPQExpBuffer();
  12572. /* Make sure we are in proper schema */
  12573. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  12574. snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
  12575. snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
  12576. if (fout->remoteVersion >= 80400)
  12577. {
  12578. appendPQExpBuffer(query,
  12579. "SELECT sequence_name, "
  12580. "start_value, increment_by, "
  12581. "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
  12582. " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
  12583. " ELSE max_value "
  12584. "END AS max_value, "
  12585. "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
  12586. " WHEN increment_by < 0 AND min_value = %s THEN NULL "
  12587. " ELSE min_value "
  12588. "END AS min_value, "
  12589. "cache_value, is_cycled FROM %s",
  12590. bufx, bufm,
  12591. fmtId(tbinfo->dobj.name));
  12592. }
  12593. else
  12594. {
  12595. appendPQExpBuffer(query,
  12596. "SELECT sequence_name, "
  12597. "0 AS start_value, increment_by, "
  12598. "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
  12599. " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
  12600. " ELSE max_value "
  12601. "END AS max_value, "
  12602. "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
  12603. " WHEN increment_by < 0 AND min_value = %s THEN NULL "
  12604. " ELSE min_value "
  12605. "END AS min_value, "
  12606. "cache_value, is_cycled FROM %s",
  12607. bufx, bufm,
  12608. fmtId(tbinfo->dobj.name));
  12609. }
  12610. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  12611. if (PQntuples(res) != 1)
  12612. {
  12613. write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
  12614. "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
  12615. PQntuples(res)),
  12616. tbinfo->dobj.name, PQntuples(res));
  12617. exit_nicely(1);
  12618. }
  12619. /* Disable this check: it fails if sequence has been renamed */
  12620. #ifdef NOT_USED
  12621. if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
  12622. {
  12623. write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
  12624. tbinfo->dobj.name, PQgetvalue(res, 0, 0));
  12625. exit_nicely(1);
  12626. }
  12627. #endif
  12628. startv = PQgetvalue(res, 0, 1);
  12629. incby = PQgetvalue(res, 0, 2);
  12630. if (!PQgetisnull(res, 0, 3))
  12631. maxv = PQgetvalue(res, 0, 3);
  12632. if (!PQgetisnull(res, 0, 4))
  12633. minv = PQgetvalue(res, 0, 4);
  12634. cache = PQgetvalue(res, 0, 5);
  12635. cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
  12636. /*
  12637. * DROP must be fully qualified in case same name appears in pg_catalog
  12638. */
  12639. appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
  12640. fmtId(tbinfo->dobj.namespace->dobj.name));
  12641. appendPQExpBuffer(delqry, "%s;\n",
  12642. fmtId(tbinfo->dobj.name));
  12643. resetPQExpBuffer(query);
  12644. if (binary_upgrade)
  12645. {
  12646. binary_upgrade_set_pg_class_oids(fout, query,
  12647. tbinfo->dobj.catId.oid, false);
  12648. binary_upgrade_set_type_oids_by_rel_oid(fout, query,
  12649. tbinfo->dobj.catId.oid);
  12650. }
  12651. appendPQExpBuffer(query,
  12652. "CREATE SEQUENCE %s\n",
  12653. fmtId(tbinfo->dobj.name));
  12654. if (fout->remoteVersion >= 80400)
  12655. appendPQExpBuffer(query, " START WITH %s\n", startv);
  12656. appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
  12657. if (minv)
  12658. appendPQExpBuffer(query, " MINVALUE %s\n", minv);
  12659. else
  12660. appendPQExpBufferStr(query, " NO MINVALUE\n");
  12661. if (maxv)
  12662. appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
  12663. else
  12664. appendPQExpBufferStr(query, " NO MAXVALUE\n");
  12665. appendPQExpBuffer(query,
  12666. " CACHE %s%s",
  12667. cache, (cycled ? "\n CYCLE" : ""));
  12668. appendPQExpBufferStr(query, ";\n");
  12669. appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
  12670. /* binary_upgrade: no need to clear TOAST table oid */
  12671. if (binary_upgrade)
  12672. binary_upgrade_extension_member(query, &tbinfo->dobj,
  12673. labelq->data);
  12674. ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
  12675. tbinfo->dobj.name,
  12676. tbinfo->dobj.namespace->dobj.name,
  12677. NULL,
  12678. tbinfo->rolname,
  12679. false, "SEQUENCE", SECTION_PRE_DATA,
  12680. query->data, delqry->data, NULL,
  12681. NULL, 0,
  12682. NULL, NULL);
  12683. /*
  12684. * If the sequence is owned by a table column, emit the ALTER for it as a
  12685. * separate TOC entry immediately following the sequence's own entry. It's
  12686. * OK to do this rather than using full sorting logic, because the
  12687. * dependency that tells us it's owned will have forced the table to be
  12688. * created first. We can't just include the ALTER in the TOC entry
  12689. * because it will fail if we haven't reassigned the sequence owner to
  12690. * match the table's owner.
  12691. *
  12692. * We need not schema-qualify the table reference because both sequence
  12693. * and table must be in the same schema.
  12694. */
  12695. if (OidIsValid(tbinfo->owning_tab))
  12696. {
  12697. TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
  12698. if (owning_tab && owning_tab->dobj.dump)
  12699. {
  12700. resetPQExpBuffer(query);
  12701. appendPQExpBuffer(query, "ALTER SEQUENCE %s",
  12702. fmtId(tbinfo->dobj.name));
  12703. appendPQExpBuffer(query, " OWNED BY %s",
  12704. fmtId(owning_tab->dobj.name));
  12705. appendPQExpBuffer(query, ".%s;\n",
  12706. fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
  12707. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  12708. tbinfo->dobj.name,
  12709. tbinfo->dobj.namespace->dobj.name,
  12710. NULL,
  12711. tbinfo->rolname,
  12712. false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
  12713. query->data, "", NULL,
  12714. &(tbinfo->dobj.dumpId), 1,
  12715. NULL, NULL);
  12716. }
  12717. }
  12718. /* Dump Sequence Comments and Security Labels */
  12719. dumpComment(fout, labelq->data,
  12720. tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
  12721. tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
  12722. dumpSecLabel(fout, labelq->data,
  12723. tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
  12724. tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
  12725. PQclear(res);
  12726. destroyPQExpBuffer(query);
  12727. destroyPQExpBuffer(delqry);
  12728. destroyPQExpBuffer(labelq);
  12729. }
  12730. /*
  12731. * dumpSequenceData
  12732. * write the data of one user-defined sequence
  12733. */
  12734. static void
  12735. dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
  12736. {
  12737. TableInfo *tbinfo = tdinfo->tdtable;
  12738. PGresult *res;
  12739. char *last;
  12740. bool called;
  12741. PQExpBuffer query = createPQExpBuffer();
  12742. /* Make sure we are in proper schema */
  12743. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  12744. appendPQExpBuffer(query,
  12745. "SELECT last_value, is_called FROM %s",
  12746. fmtId(tbinfo->dobj.name));
  12747. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  12748. if (PQntuples(res) != 1)
  12749. {
  12750. write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
  12751. "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
  12752. PQntuples(res)),
  12753. tbinfo->dobj.name, PQntuples(res));
  12754. exit_nicely(1);
  12755. }
  12756. last = PQgetvalue(res, 0, 0);
  12757. called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
  12758. resetPQExpBuffer(query);
  12759. appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
  12760. appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
  12761. appendPQExpBuffer(query, ", %s, %s);\n",
  12762. last, (called ? "true" : "false"));
  12763. ArchiveEntry(fout, nilCatalogId, createDumpId(),
  12764. tbinfo->dobj.name,
  12765. tbinfo->dobj.namespace->dobj.name,
  12766. NULL,
  12767. tbinfo->rolname,
  12768. false, "SEQUENCE SET", SECTION_DATA,
  12769. query->data, "", NULL,
  12770. &(tbinfo->dobj.dumpId), 1,
  12771. NULL, NULL);
  12772. PQclear(res);
  12773. destroyPQExpBuffer(query);
  12774. }
  12775. /*
  12776. * dumpTrigger
  12777. * write the declaration of one user-defined table trigger
  12778. */
  12779. static void
  12780. dumpTrigger(Archive *fout, TriggerInfo *tginfo)
  12781. {
  12782. TableInfo *tbinfo = tginfo->tgtable;
  12783. PQExpBuffer query;
  12784. PQExpBuffer delqry;
  12785. PQExpBuffer labelq;
  12786. char *tgargs;
  12787. size_t lentgargs;
  12788. const char *p;
  12789. int findx;
  12790. /*
  12791. * we needn't check dobj.dump because TriggerInfo wouldn't have been
  12792. * created in the first place for non-dumpable triggers
  12793. */
  12794. if (dataOnly)
  12795. return;
  12796. query = createPQExpBuffer();
  12797. delqry = createPQExpBuffer();
  12798. labelq = createPQExpBuffer();
  12799. /*
  12800. * DROP must be fully qualified in case same name appears in pg_catalog
  12801. */
  12802. appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
  12803. fmtId(tginfo->dobj.name));
  12804. appendPQExpBuffer(delqry, "ON %s.",
  12805. fmtId(tbinfo->dobj.namespace->dobj.name));
  12806. appendPQExpBuffer(delqry, "%s;\n",
  12807. fmtId(tbinfo->dobj.name));
  12808. if (tginfo->tgdef)
  12809. {
  12810. appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
  12811. }
  12812. else
  12813. {
  12814. if (tginfo->tgisconstraint)
  12815. {
  12816. appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
  12817. appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
  12818. }
  12819. else
  12820. {
  12821. appendPQExpBufferStr(query, "CREATE TRIGGER ");
  12822. appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
  12823. }
  12824. appendPQExpBufferStr(query, "\n ");
  12825. /* Trigger type */
  12826. if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
  12827. appendPQExpBufferStr(query, "BEFORE");
  12828. else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
  12829. appendPQExpBufferStr(query, "AFTER");
  12830. else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
  12831. appendPQExpBufferStr(query, "INSTEAD OF");
  12832. else
  12833. {
  12834. write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
  12835. exit_nicely(1);
  12836. }
  12837. findx = 0;
  12838. if (TRIGGER_FOR_INSERT(tginfo->tgtype))
  12839. {
  12840. appendPQExpBufferStr(query, " INSERT");
  12841. findx++;
  12842. }
  12843. if (TRIGGER_FOR_DELETE(tginfo->tgtype))
  12844. {
  12845. if (findx > 0)
  12846. appendPQExpBufferStr(query, " OR DELETE");
  12847. else
  12848. appendPQExpBufferStr(query, " DELETE");
  12849. findx++;
  12850. }
  12851. if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
  12852. {
  12853. if (findx > 0)
  12854. appendPQExpBufferStr(query, " OR UPDATE");
  12855. else
  12856. appendPQExpBufferStr(query, " UPDATE");
  12857. findx++;
  12858. }
  12859. if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
  12860. {
  12861. if (findx > 0)
  12862. appendPQExpBufferStr(query, " OR TRUNCATE");
  12863. else
  12864. appendPQExpBufferStr(query, " TRUNCATE");
  12865. findx++;
  12866. }
  12867. appendPQExpBuffer(query, " ON %s\n",
  12868. fmtId(tbinfo->dobj.name));
  12869. if (tginfo->tgisconstraint)
  12870. {
  12871. if (OidIsValid(tginfo->tgconstrrelid))
  12872. {
  12873. /* If we are using regclass, name is already quoted */
  12874. if (fout->remoteVersion >= 70300)
  12875. appendPQExpBuffer(query, " FROM %s\n ",
  12876. tginfo->tgconstrrelname);
  12877. else
  12878. appendPQExpBuffer(query, " FROM %s\n ",
  12879. fmtId(tginfo->tgconstrrelname));
  12880. }
  12881. if (!tginfo->tgdeferrable)
  12882. appendPQExpBufferStr(query, "NOT ");
  12883. appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
  12884. if (tginfo->tginitdeferred)
  12885. appendPQExpBufferStr(query, "DEFERRED\n");
  12886. else
  12887. appendPQExpBufferStr(query, "IMMEDIATE\n");
  12888. }
  12889. if (TRIGGER_FOR_ROW(tginfo->tgtype))
  12890. appendPQExpBufferStr(query, " FOR EACH ROW\n ");
  12891. else
  12892. appendPQExpBufferStr(query, " FOR EACH STATEMENT\n ");
  12893. /* In 7.3, result of regproc is already quoted */
  12894. if (fout->remoteVersion >= 70300)
  12895. appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
  12896. tginfo->tgfname);
  12897. else
  12898. appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
  12899. fmtId(tginfo->tgfname));
  12900. tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
  12901. &lentgargs);
  12902. p = tgargs;
  12903. for (findx = 0; findx < tginfo->tgnargs; findx++)
  12904. {
  12905. /* find the embedded null that terminates this trigger argument */
  12906. size_t tlen = strlen(p);
  12907. if (p + tlen >= tgargs + lentgargs)
  12908. {
  12909. /* hm, not found before end of bytea value... */
  12910. write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
  12911. tginfo->tgargs,
  12912. tginfo->dobj.name,
  12913. tbinfo->dobj.name);
  12914. exit_nicely(1);
  12915. }
  12916. if (findx > 0)
  12917. appendPQExpBufferStr(query, ", ");
  12918. appendStringLiteralAH(query, p, fout);
  12919. p += tlen + 1;
  12920. }
  12921. free(tgargs);
  12922. appendPQExpBufferStr(query, ");\n");
  12923. }
  12924. if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
  12925. {
  12926. appendPQExpBuffer(query, "\nALTER TABLE %s ",
  12927. fmtId(tbinfo->dobj.name));
  12928. switch (tginfo->tgenabled)
  12929. {
  12930. case 'D':
  12931. case 'f':
  12932. appendPQExpBufferStr(query, "DISABLE");
  12933. break;
  12934. case 'A':
  12935. appendPQExpBufferStr(query, "ENABLE ALWAYS");
  12936. break;
  12937. case 'R':
  12938. appendPQExpBufferStr(query, "ENABLE REPLICA");
  12939. break;
  12940. default:
  12941. appendPQExpBufferStr(query, "ENABLE");
  12942. break;
  12943. }
  12944. appendPQExpBuffer(query, " TRIGGER %s;\n",
  12945. fmtId(tginfo->dobj.name));
  12946. }
  12947. appendPQExpBuffer(labelq, "TRIGGER %s ",
  12948. fmtId(tginfo->dobj.name));
  12949. appendPQExpBuffer(labelq, "ON %s",
  12950. fmtId(tbinfo->dobj.name));
  12951. ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
  12952. tginfo->dobj.name,
  12953. tbinfo->dobj.namespace->dobj.name,
  12954. NULL,
  12955. tbinfo->rolname, false,
  12956. "TRIGGER", SECTION_POST_DATA,
  12957. query->data, delqry->data, NULL,
  12958. NULL, 0,
  12959. NULL, NULL);
  12960. dumpComment(fout, labelq->data,
  12961. tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
  12962. tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
  12963. destroyPQExpBuffer(query);
  12964. destroyPQExpBuffer(delqry);
  12965. destroyPQExpBuffer(labelq);
  12966. }
  12967. /*
  12968. * dumpEventTrigger
  12969. * write the declaration of one user-defined event trigger
  12970. */
  12971. static void
  12972. dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
  12973. {
  12974. PQExpBuffer query;
  12975. PQExpBuffer labelq;
  12976. /* Skip if not to be dumped */
  12977. if (!evtinfo->dobj.dump || dataOnly)
  12978. return;
  12979. query = createPQExpBuffer();
  12980. labelq = createPQExpBuffer();
  12981. appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
  12982. appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
  12983. appendPQExpBufferStr(query, " ON ");
  12984. appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
  12985. appendPQExpBufferStr(query, " ");
  12986. if (strcmp("", evtinfo->evttags) != 0)
  12987. {
  12988. appendPQExpBufferStr(query, "\n WHEN TAG IN (");
  12989. appendPQExpBufferStr(query, evtinfo->evttags);
  12990. appendPQExpBufferStr(query, ") ");
  12991. }
  12992. appendPQExpBufferStr(query, "\n EXECUTE PROCEDURE ");
  12993. appendPQExpBufferStr(query, evtinfo->evtfname);
  12994. appendPQExpBufferStr(query, "();\n");
  12995. if (evtinfo->evtenabled != 'O')
  12996. {
  12997. appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
  12998. fmtId(evtinfo->dobj.name));
  12999. switch (evtinfo->evtenabled)
  13000. {
  13001. case 'D':
  13002. appendPQExpBufferStr(query, "DISABLE");
  13003. break;
  13004. case 'A':
  13005. appendPQExpBufferStr(query, "ENABLE ALWAYS");
  13006. break;
  13007. case 'R':
  13008. appendPQExpBufferStr(query, "ENABLE REPLICA");
  13009. break;
  13010. default:
  13011. appendPQExpBufferStr(query, "ENABLE");
  13012. break;
  13013. }
  13014. appendPQExpBufferStr(query, ";\n");
  13015. }
  13016. appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
  13017. fmtId(evtinfo->dobj.name));
  13018. ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
  13019. evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
  13020. "EVENT TRIGGER", SECTION_POST_DATA,
  13021. query->data, "", NULL, NULL, 0, NULL, NULL);
  13022. dumpComment(fout, labelq->data,
  13023. NULL, NULL,
  13024. evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
  13025. destroyPQExpBuffer(query);
  13026. destroyPQExpBuffer(labelq);
  13027. }
  13028. /*
  13029. * dumpRule
  13030. * Dump a rule
  13031. */
  13032. static void
  13033. dumpRule(Archive *fout, RuleInfo *rinfo)
  13034. {
  13035. TableInfo *tbinfo = rinfo->ruletable;
  13036. PQExpBuffer query;
  13037. PQExpBuffer cmd;
  13038. PQExpBuffer delcmd;
  13039. PQExpBuffer labelq;
  13040. PGresult *res;
  13041. /* Skip if not to be dumped */
  13042. if (!rinfo->dobj.dump || dataOnly)
  13043. return;
  13044. /*
  13045. * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
  13046. * we do not want to dump it as a separate object.
  13047. */
  13048. if (!rinfo->separate)
  13049. return;
  13050. /*
  13051. * Make sure we are in proper schema.
  13052. */
  13053. selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
  13054. query = createPQExpBuffer();
  13055. cmd = createPQExpBuffer();
  13056. delcmd = createPQExpBuffer();
  13057. labelq = createPQExpBuffer();
  13058. if (fout->remoteVersion >= 70300)
  13059. {
  13060. appendPQExpBuffer(query,
  13061. "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
  13062. rinfo->dobj.catId.oid);
  13063. }
  13064. else
  13065. {
  13066. /* Rule name was unique before 7.3 ... */
  13067. appendPQExpBuffer(query,
  13068. "SELECT pg_get_ruledef('%s') AS definition",
  13069. rinfo->dobj.name);
  13070. }
  13071. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  13072. if (PQntuples(res) != 1)
  13073. {
  13074. write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
  13075. rinfo->dobj.name, tbinfo->dobj.name);
  13076. exit_nicely(1);
  13077. }
  13078. printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
  13079. /*
  13080. * Add the command to alter the rules replication firing semantics if it
  13081. * differs from the default.
  13082. */
  13083. if (rinfo->ev_enabled != 'O')
  13084. {
  13085. appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
  13086. switch (rinfo->ev_enabled)
  13087. {
  13088. case 'A':
  13089. appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
  13090. fmtId(rinfo->dobj.name));
  13091. break;
  13092. case 'R':
  13093. appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
  13094. fmtId(rinfo->dobj.name));
  13095. break;
  13096. case 'D':
  13097. appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
  13098. fmtId(rinfo->dobj.name));
  13099. break;
  13100. }
  13101. }
  13102. /*
  13103. * Apply view's reloptions when its ON SELECT rule is separate.
  13104. */
  13105. if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
  13106. {
  13107. appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
  13108. fmtId(tbinfo->dobj.name),
  13109. rinfo->reloptions);
  13110. }
  13111. /*
  13112. * DROP must be fully qualified in case same name appears in pg_catalog
  13113. */
  13114. appendPQExpBuffer(delcmd, "DROP RULE %s ",
  13115. fmtId(rinfo->dobj.name));
  13116. appendPQExpBuffer(delcmd, "ON %s.",
  13117. fmtId(tbinfo->dobj.namespace->dobj.name));
  13118. appendPQExpBuffer(delcmd, "%s;\n",
  13119. fmtId(tbinfo->dobj.name));
  13120. appendPQExpBuffer(labelq, "RULE %s",
  13121. fmtId(rinfo->dobj.name));
  13122. appendPQExpBuffer(labelq, " ON %s",
  13123. fmtId(tbinfo->dobj.name));
  13124. ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
  13125. rinfo->dobj.name,
  13126. tbinfo->dobj.namespace->dobj.name,
  13127. NULL,
  13128. tbinfo->rolname, false,
  13129. "RULE", SECTION_POST_DATA,
  13130. cmd->data, delcmd->data, NULL,
  13131. NULL, 0,
  13132. NULL, NULL);
  13133. /* Dump rule comments */
  13134. dumpComment(fout, labelq->data,
  13135. tbinfo->dobj.namespace->dobj.name,
  13136. tbinfo->rolname,
  13137. rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
  13138. PQclear(res);
  13139. destroyPQExpBuffer(query);
  13140. destroyPQExpBuffer(cmd);
  13141. destroyPQExpBuffer(delcmd);
  13142. destroyPQExpBuffer(labelq);
  13143. }
  13144. /*
  13145. * getExtensionMembership --- obtain extension membership data
  13146. */
  13147. void
  13148. getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
  13149. int numExtensions)
  13150. {
  13151. PQExpBuffer query;
  13152. PGresult *res;
  13153. int ntups,
  13154. i;
  13155. int i_classid,
  13156. i_objid,
  13157. i_refclassid,
  13158. i_refobjid;
  13159. DumpableObject *dobj,
  13160. *refdobj;
  13161. /* Nothing to do if no extensions */
  13162. if (numExtensions == 0)
  13163. return;
  13164. /* Make sure we are in proper schema */
  13165. selectSourceSchema(fout, "pg_catalog");
  13166. query = createPQExpBuffer();
  13167. /* refclassid constraint is redundant but may speed the search */
  13168. appendPQExpBufferStr(query, "SELECT "
  13169. "classid, objid, refclassid, refobjid "
  13170. "FROM pg_depend "
  13171. "WHERE refclassid = 'pg_extension'::regclass "
  13172. "AND deptype = 'e' "
  13173. "ORDER BY 3,4");
  13174. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  13175. ntups = PQntuples(res);
  13176. i_classid = PQfnumber(res, "classid");
  13177. i_objid = PQfnumber(res, "objid");
  13178. i_refclassid = PQfnumber(res, "refclassid");
  13179. i_refobjid = PQfnumber(res, "refobjid");
  13180. /*
  13181. * Since we ordered the SELECT by referenced ID, we can expect that
  13182. * multiple entries for the same extension will appear together; this
  13183. * saves on searches.
  13184. */
  13185. refdobj = NULL;
  13186. for (i = 0; i < ntups; i++)
  13187. {
  13188. CatalogId objId;
  13189. CatalogId refobjId;
  13190. objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
  13191. objId.oid = atooid(PQgetvalue(res, i, i_objid));
  13192. refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
  13193. refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
  13194. if (refdobj == NULL ||
  13195. refdobj->catId.tableoid != refobjId.tableoid ||
  13196. refdobj->catId.oid != refobjId.oid)
  13197. refdobj = findObjectByCatalogId(refobjId);
  13198. /*
  13199. * Failure to find objects mentioned in pg_depend is not unexpected,
  13200. * since for example we don't collect info about TOAST tables.
  13201. */
  13202. if (refdobj == NULL)
  13203. {
  13204. #ifdef NOT_USED
  13205. fprintf(stderr, "no referenced object %u %u\n",
  13206. refobjId.tableoid, refobjId.oid);
  13207. #endif
  13208. continue;
  13209. }
  13210. dobj = findObjectByCatalogId(objId);
  13211. if (dobj == NULL)
  13212. {
  13213. #ifdef NOT_USED
  13214. fprintf(stderr, "no referencing object %u %u\n",
  13215. objId.tableoid, objId.oid);
  13216. #endif
  13217. continue;
  13218. }
  13219. /* Record dependency so that getDependencies needn't repeat this */
  13220. addObjectDependency(dobj, refdobj->dumpId);
  13221. dobj->ext_member = true;
  13222. /*
  13223. * Normally, mark the member object as not to be dumped. But in
  13224. * binary upgrades, we still dump the members individually, since the
  13225. * idea is to exactly reproduce the database contents rather than
  13226. * replace the extension contents with something different.
  13227. */
  13228. if (!binary_upgrade)
  13229. dobj->dump = false;
  13230. else
  13231. dobj->dump = refdobj->dump;
  13232. }
  13233. PQclear(res);
  13234. /*
  13235. * Now identify extension configuration tables and create TableDataInfo
  13236. * objects for them, ensuring their data will be dumped even though the
  13237. * tables themselves won't be.
  13238. *
  13239. * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
  13240. * user data in a configuration table is treated like schema data. This
  13241. * seems appropriate since system data in a config table would get
  13242. * reloaded by CREATE EXTENSION.
  13243. */
  13244. for (i = 0; i < numExtensions; i++)
  13245. {
  13246. ExtensionInfo *curext = &(extinfo[i]);
  13247. char *extconfig = curext->extconfig;
  13248. char *extcondition = curext->extcondition;
  13249. char **extconfigarray = NULL;
  13250. char **extconditionarray = NULL;
  13251. int nconfigitems;
  13252. int nconditionitems;
  13253. if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
  13254. parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
  13255. nconfigitems == nconditionitems)
  13256. {
  13257. int j;
  13258. for (j = 0; j < nconfigitems; j++)
  13259. {
  13260. TableInfo *configtbl;
  13261. Oid configtbloid = atooid(extconfigarray[j]);
  13262. bool dumpobj = curext->dobj.dump;
  13263. configtbl = findTableByOid(configtbloid);
  13264. if (configtbl == NULL)
  13265. continue;
  13266. /*
  13267. * Tables of not-to-be-dumped extensions shouldn't be dumped
  13268. * unless the table or its schema is explicitly included
  13269. */
  13270. if (!curext->dobj.dump)
  13271. {
  13272. /* check table explicitly requested */
  13273. if (table_include_oids.head != NULL &&
  13274. simple_oid_list_member(&table_include_oids,
  13275. configtbloid))
  13276. dumpobj = true;
  13277. /* check table's schema explicitly requested */
  13278. if (configtbl->dobj.namespace->dobj.dump)
  13279. dumpobj = true;
  13280. }
  13281. /* check table excluded by an exclusion switch */
  13282. if (table_exclude_oids.head != NULL &&
  13283. simple_oid_list_member(&table_exclude_oids,
  13284. configtbloid))
  13285. dumpobj = false;
  13286. /* check schema excluded by an exclusion switch */
  13287. if (simple_oid_list_member(&schema_exclude_oids,
  13288. configtbl->dobj.namespace->dobj.catId.oid))
  13289. dumpobj = false;
  13290. if (dumpobj)
  13291. {
  13292. /*
  13293. * Note: config tables are dumped without OIDs regardless
  13294. * of the --oids setting. This is because row filtering
  13295. * conditions aren't compatible with dumping OIDs.
  13296. */
  13297. makeTableDataInfo(configtbl, false);
  13298. if (configtbl->dataObj != NULL)
  13299. {
  13300. if (strlen(extconditionarray[j]) > 0)
  13301. configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
  13302. }
  13303. }
  13304. }
  13305. }
  13306. if (extconfigarray)
  13307. free(extconfigarray);
  13308. if (extconditionarray)
  13309. free(extconditionarray);
  13310. }
  13311. destroyPQExpBuffer(query);
  13312. }
  13313. /*
  13314. * getDependencies --- obtain available dependency data
  13315. */
  13316. static void
  13317. getDependencies(Archive *fout)
  13318. {
  13319. PQExpBuffer query;
  13320. PGresult *res;
  13321. int ntups,
  13322. i;
  13323. int i_classid,
  13324. i_objid,
  13325. i_refclassid,
  13326. i_refobjid,
  13327. i_deptype;
  13328. DumpableObject *dobj,
  13329. *refdobj;
  13330. /* No dependency info available before 7.3 */
  13331. if (fout->remoteVersion < 70300)
  13332. return;
  13333. if (g_verbose)
  13334. write_msg(NULL, "reading dependency data\n");
  13335. /* Make sure we are in proper schema */
  13336. selectSourceSchema(fout, "pg_catalog");
  13337. query = createPQExpBuffer();
  13338. /*
  13339. * PIN dependencies aren't interesting, and EXTENSION dependencies were
  13340. * already processed by getExtensionMembership.
  13341. */
  13342. appendPQExpBufferStr(query, "SELECT "
  13343. "classid, objid, refclassid, refobjid, deptype "
  13344. "FROM pg_depend "
  13345. "WHERE deptype != 'p' AND deptype != 'e' "
  13346. "ORDER BY 1,2");
  13347. res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
  13348. ntups = PQntuples(res);
  13349. i_classid = PQfnumber(res, "classid");
  13350. i_objid = PQfnumber(res, "objid");
  13351. i_refclassid = PQfnumber(res, "refclassid");
  13352. i_refobjid = PQfnumber(res, "refobjid");
  13353. i_deptype = PQfnumber(res, "deptype");
  13354. /*
  13355. * Since we ordered the SELECT by referencing ID, we can expect that
  13356. * multiple entries for the same object will appear together; this saves
  13357. * on searches.
  13358. */
  13359. dobj = NULL;
  13360. for (i = 0; i < ntups; i++)
  13361. {
  13362. CatalogId objId;
  13363. CatalogId refobjId;
  13364. char deptype;
  13365. objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
  13366. objId.oid = atooid(PQgetvalue(res, i, i_objid));
  13367. refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
  13368. refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
  13369. deptype = *(PQgetvalue(res, i, i_deptype));
  13370. if (dobj == NULL ||
  13371. dobj->catId.tableoid != objId.tableoid ||
  13372. dobj->catId.oid != objId.oid)
  13373. dobj = findObjectByCatalogId(objId);
  13374. /*
  13375. * Failure to find objects mentioned in pg_depend is not unexpected,
  13376. * since for example we don't collect info about TOAST tables.
  13377. */
  13378. if (dobj == NULL)
  13379. {
  13380. #ifdef NOT_USED
  13381. fprintf(stderr, "no referencing object %u %u\n",
  13382. objId.tableoid, objId.oid);
  13383. #endif
  13384. continue;
  13385. }
  13386. refdobj = findObjectByCatalogId(refobjId);
  13387. if (refdobj == NULL)
  13388. {
  13389. #ifdef NOT_USED
  13390. fprintf(stderr, "no referenced object %u %u\n",
  13391. refobjId.tableoid, refobjId.oid);
  13392. #endif
  13393. continue;
  13394. }
  13395. /*
  13396. * Ordinarily, table rowtypes have implicit dependencies on their
  13397. * tables. However, for a composite type the implicit dependency goes
  13398. * the other way in pg_depend; which is the right thing for DROP but
  13399. * it doesn't produce the dependency ordering we need. So in that one
  13400. * case, we reverse the direction of the dependency.
  13401. */
  13402. if (deptype == 'i' &&
  13403. dobj->objType == DO_TABLE &&
  13404. refdobj->objType == DO_TYPE)
  13405. addObjectDependency(refdobj, dobj->dumpId);
  13406. else
  13407. /* normal case */
  13408. addObjectDependency(dobj, refdobj->dumpId);
  13409. }
  13410. PQclear(res);
  13411. destroyPQExpBuffer(query);
  13412. }
  13413. /*
  13414. * createBoundaryObjects - create dummy DumpableObjects to represent
  13415. * dump section boundaries.
  13416. */
  13417. static DumpableObject *
  13418. createBoundaryObjects(void)
  13419. {
  13420. DumpableObject *dobjs;
  13421. dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
  13422. dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
  13423. dobjs[0].catId = nilCatalogId;
  13424. AssignDumpId(dobjs + 0);
  13425. dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
  13426. dobjs[1].objType = DO_POST_DATA_BOUNDARY;
  13427. dobjs[1].catId = nilCatalogId;
  13428. AssignDumpId(dobjs + 1);
  13429. dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
  13430. return dobjs;
  13431. }
  13432. /*
  13433. * addBoundaryDependencies - add dependencies as needed to enforce the dump
  13434. * section boundaries.
  13435. */
  13436. static void
  13437. addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
  13438. DumpableObject *boundaryObjs)
  13439. {
  13440. DumpableObject *preDataBound = boundaryObjs + 0;
  13441. DumpableObject *postDataBound = boundaryObjs + 1;
  13442. int i;
  13443. for (i = 0; i < numObjs; i++)
  13444. {
  13445. DumpableObject *dobj = dobjs[i];
  13446. /*
  13447. * The classification of object types here must match the SECTION_xxx
  13448. * values assigned during subsequent ArchiveEntry calls!
  13449. */
  13450. switch (dobj->objType)
  13451. {
  13452. case DO_NAMESPACE:
  13453. case DO_EXTENSION:
  13454. case DO_TYPE:
  13455. case DO_SHELL_TYPE:
  13456. case DO_FUNC:
  13457. case DO_AGG:
  13458. case DO_OPERATOR:
  13459. case DO_OPCLASS:
  13460. case DO_OPFAMILY:
  13461. case DO_COLLATION:
  13462. case DO_CONVERSION:
  13463. case DO_TABLE:
  13464. case DO_ATTRDEF:
  13465. case DO_PROCLANG:
  13466. case DO_CAST:
  13467. case DO_DUMMY_TYPE:
  13468. case DO_TSPARSER:
  13469. case DO_TSDICT:
  13470. case DO_TSTEMPLATE:
  13471. case DO_TSCONFIG:
  13472. case DO_FDW:
  13473. case DO_FOREIGN_SERVER:
  13474. case DO_BLOB:
  13475. /* Pre-data objects: must come before the pre-data boundary */
  13476. addObjectDependency(preDataBound, dobj->dumpId);
  13477. break;
  13478. case DO_TABLE_DATA:
  13479. case DO_BLOB_DATA:
  13480. /* Data objects: must come between the boundaries */
  13481. addObjectDependency(dobj, preDataBound->dumpId);
  13482. addObjectDependency(postDataBound, dobj->dumpId);
  13483. break;
  13484. case DO_INDEX:
  13485. case DO_REFRESH_MATVIEW:
  13486. case DO_TRIGGER:
  13487. case DO_EVENT_TRIGGER:
  13488. case DO_DEFAULT_ACL:
  13489. /* Post-data objects: must come after the post-data boundary */
  13490. addObjectDependency(dobj, postDataBound->dumpId);
  13491. break;
  13492. case DO_RULE:
  13493. /* Rules are post-data, but only if dumped separately */
  13494. if (((RuleInfo *) dobj)->separate)
  13495. addObjectDependency(dobj, postDataBound->dumpId);
  13496. break;
  13497. case DO_CONSTRAINT:
  13498. case DO_FK_CONSTRAINT:
  13499. /* Constraints are post-data, but only if dumped separately */
  13500. if (((ConstraintInfo *) dobj)->separate)
  13501. addObjectDependency(dobj, postDataBound->dumpId);
  13502. break;
  13503. case DO_PRE_DATA_BOUNDARY:
  13504. /* nothing to do */
  13505. break;
  13506. case DO_POST_DATA_BOUNDARY:
  13507. /* must come after the pre-data boundary */
  13508. addObjectDependency(dobj, preDataBound->dumpId);
  13509. break;
  13510. }
  13511. }
  13512. }
  13513. /*
  13514. * BuildArchiveDependencies - create dependency data for archive TOC entries
  13515. *
  13516. * The raw dependency data obtained by getDependencies() is not terribly
  13517. * useful in an archive dump, because in many cases there are dependency
  13518. * chains linking through objects that don't appear explicitly in the dump.
  13519. * For example, a view will depend on its _RETURN rule while the _RETURN rule
  13520. * will depend on other objects --- but the rule will not appear as a separate
  13521. * object in the dump. We need to adjust the view's dependencies to include
  13522. * whatever the rule depends on that is included in the dump.
  13523. *
  13524. * Just to make things more complicated, there are also "special" dependencies
  13525. * such as the dependency of a TABLE DATA item on its TABLE, which we must
  13526. * not rearrange because pg_restore knows that TABLE DATA only depends on
  13527. * its table. In these cases we must leave the dependencies strictly as-is
  13528. * even if they refer to not-to-be-dumped objects.
  13529. *
  13530. * To handle this, the convention is that "special" dependencies are created
  13531. * during ArchiveEntry calls, and an archive TOC item that has any such
  13532. * entries will not be touched here. Otherwise, we recursively search the
  13533. * DumpableObject data structures to build the correct dependencies for each
  13534. * archive TOC item.
  13535. */
  13536. static void
  13537. BuildArchiveDependencies(Archive *fout)
  13538. {
  13539. ArchiveHandle *AH = (ArchiveHandle *) fout;
  13540. TocEntry *te;
  13541. /* Scan all TOC entries in the archive */
  13542. for (te = AH->toc->next; te != AH->toc; te = te->next)
  13543. {
  13544. DumpableObject *dobj;
  13545. DumpId *dependencies;
  13546. int nDeps;
  13547. int allocDeps;
  13548. /* No need to process entries that will not be dumped */
  13549. if (te->reqs == 0)
  13550. continue;
  13551. /* Ignore entries that already have "special" dependencies */
  13552. if (te->nDeps > 0)
  13553. continue;
  13554. /* Otherwise, look up the item's original DumpableObject, if any */
  13555. dobj = findObjectByDumpId(te->dumpId);
  13556. if (dobj == NULL)
  13557. continue;
  13558. /* No work if it has no dependencies */
  13559. if (dobj->nDeps <= 0)
  13560. continue;
  13561. /* Set up work array */
  13562. allocDeps = 64;
  13563. dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
  13564. nDeps = 0;
  13565. /* Recursively find all dumpable dependencies */
  13566. findDumpableDependencies(AH, dobj,
  13567. &dependencies, &nDeps, &allocDeps);
  13568. /* And save 'em ... */
  13569. if (nDeps > 0)
  13570. {
  13571. dependencies = (DumpId *) pg_realloc(dependencies,
  13572. nDeps * sizeof(DumpId));
  13573. te->dependencies = dependencies;
  13574. te->nDeps = nDeps;
  13575. }
  13576. else
  13577. free(dependencies);
  13578. }
  13579. }
  13580. /* Recursive search subroutine for BuildArchiveDependencies */
  13581. static void
  13582. findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
  13583. DumpId **dependencies, int *nDeps, int *allocDeps)
  13584. {
  13585. int i;
  13586. /*
  13587. * Ignore section boundary objects: if we search through them, we'll
  13588. * report lots of bogus dependencies.
  13589. */
  13590. if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
  13591. dobj->objType == DO_POST_DATA_BOUNDARY)
  13592. return;
  13593. for (i = 0; i < dobj->nDeps; i++)
  13594. {
  13595. DumpId depid = dobj->dependencies[i];
  13596. if (TocIDRequired(AH, depid) != 0)
  13597. {
  13598. /* Object will be dumped, so just reference it as a dependency */
  13599. if (*nDeps >= *allocDeps)
  13600. {
  13601. *allocDeps *= 2;
  13602. *dependencies = (DumpId *) pg_realloc(*dependencies,
  13603. *allocDeps * sizeof(DumpId));
  13604. }
  13605. (*dependencies)[*nDeps] = depid;
  13606. (*nDeps)++;
  13607. }
  13608. else
  13609. {
  13610. /*
  13611. * Object will not be dumped, so recursively consider its deps. We
  13612. * rely on the assumption that sortDumpableObjects already broke
  13613. * any dependency loops, else we might recurse infinitely.
  13614. */
  13615. DumpableObject *otherdobj = findObjectByDumpId(depid);
  13616. if (otherdobj)
  13617. findDumpableDependencies(AH, otherdobj,
  13618. dependencies, nDeps, allocDeps);
  13619. }
  13620. }
  13621. }
  13622. /*
  13623. * selectSourceSchema - make the specified schema the active search path
  13624. * in the source database.
  13625. *
  13626. * NB: pg_catalog is explicitly searched after the specified schema;
  13627. * so user names are only qualified if they are cross-schema references,
  13628. * and system names are only qualified if they conflict with a user name
  13629. * in the current schema.
  13630. *
  13631. * Whenever the selected schema is not pg_catalog, be careful to qualify
  13632. * references to system catalogs and types in our emitted commands!
  13633. *
  13634. * This function is called only from selectSourceSchemaOnAH and
  13635. * selectSourceSchema.
  13636. */
  13637. static void
  13638. selectSourceSchema(Archive *fout, const char *schemaName)
  13639. {
  13640. PQExpBuffer query;
  13641. /* This is checked by the callers already */
  13642. Assert(schemaName != NULL && *schemaName != '\0');
  13643. /* Not relevant if fetching from pre-7.3 DB */
  13644. if (fout->remoteVersion < 70300)
  13645. return;
  13646. query = createPQExpBuffer();
  13647. appendPQExpBuffer(query, "SET search_path = %s",
  13648. fmtId(schemaName));
  13649. if (strcmp(schemaName, "pg_catalog") != 0)
  13650. appendPQExpBufferStr(query, ", pg_catalog");
  13651. ExecuteSqlStatement(fout, query->data);
  13652. destroyPQExpBuffer(query);
  13653. }
  13654. /*
  13655. * getFormattedTypeName - retrieve a nicely-formatted type name for the
  13656. * given type name.
  13657. *
  13658. * NB: in 7.3 and up the result may depend on the currently-selected
  13659. * schema; this is why we don't try to cache the names.
  13660. */
  13661. static char *
  13662. getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
  13663. {
  13664. char *result;
  13665. PQExpBuffer query;
  13666. PGresult *res;
  13667. if (oid == 0)
  13668. {
  13669. if ((opts & zeroAsOpaque) != 0)
  13670. return pg_strdup(g_opaque_type);
  13671. else if ((opts & zeroAsAny) != 0)
  13672. return pg_strdup("'any'");
  13673. else if ((opts & zeroAsStar) != 0)
  13674. return pg_strdup("*");
  13675. else if ((opts & zeroAsNone) != 0)
  13676. return pg_strdup("NONE");
  13677. }
  13678. query = createPQExpBuffer();
  13679. if (fout->remoteVersion >= 70300)
  13680. {
  13681. appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
  13682. oid);
  13683. }
  13684. else if (fout->remoteVersion >= 70100)
  13685. {
  13686. appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
  13687. oid);
  13688. }
  13689. else
  13690. {
  13691. appendPQExpBuffer(query, "SELECT typname "
  13692. "FROM pg_type "
  13693. "WHERE oid = '%u'::oid",
  13694. oid);
  13695. }
  13696. res = ExecuteSqlQueryForSingleRow(fout, query->data);
  13697. if (fout->remoteVersion >= 70100)
  13698. {
  13699. /* already quoted */
  13700. result = pg_strdup(PQgetvalue(res, 0, 0));
  13701. }
  13702. else
  13703. {
  13704. /* may need to quote it */
  13705. result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
  13706. }
  13707. PQclear(res);
  13708. destroyPQExpBuffer(query);
  13709. return result;
  13710. }
  13711. /*
  13712. * myFormatType --- local implementation of format_type for use with 7.0.
  13713. */
  13714. static char *
  13715. myFormatType(const char *typname, int32 typmod)
  13716. {
  13717. char *result;
  13718. bool isarray = false;
  13719. PQExpBuffer buf = createPQExpBuffer();
  13720. /* Handle array types */
  13721. if (typname[0] == '_')
  13722. {
  13723. isarray = true;
  13724. typname++;
  13725. }
  13726. /* Show lengths on bpchar and varchar */
  13727. if (strcmp(typname, "bpchar") == 0)
  13728. {
  13729. int len = (typmod - VARHDRSZ);
  13730. appendPQExpBufferStr(buf, "character");
  13731. if (len > 1)
  13732. appendPQExpBuffer(buf, "(%d)",
  13733. typmod - VARHDRSZ);
  13734. }
  13735. else if (strcmp(typname, "varchar") == 0)
  13736. {
  13737. appendPQExpBufferStr(buf, "character varying");
  13738. if (typmod != -1)
  13739. appendPQExpBuffer(buf, "(%d)",
  13740. typmod - VARHDRSZ);
  13741. }
  13742. else if (strcmp(typname, "numeric") == 0)
  13743. {
  13744. appendPQExpBufferStr(buf, "numeric");
  13745. if (typmod != -1)
  13746. {
  13747. int32 tmp_typmod;
  13748. int precision;
  13749. int scale;
  13750. tmp_typmod = typmod - VARHDRSZ;
  13751. precision = (tmp_typmod >> 16) & 0xffff;
  13752. scale = tmp_typmod & 0xffff;
  13753. appendPQExpBuffer(buf, "(%d,%d)",
  13754. precision, scale);
  13755. }
  13756. }
  13757. /*
  13758. * char is an internal single-byte data type; Let's make sure we force it
  13759. * through with quotes. - thomas 1998-12-13
  13760. */
  13761. else if (strcmp(typname, "char") == 0)
  13762. appendPQExpBufferStr(buf, "\"char\"");
  13763. else
  13764. appendPQExpBufferStr(buf, fmtId(typname));
  13765. /* Append array qualifier for array types */
  13766. if (isarray)
  13767. appendPQExpBufferStr(buf, "[]");
  13768. result = pg_strdup(buf->data);
  13769. destroyPQExpBuffer(buf);
  13770. return result;
  13771. }
  13772. /*
  13773. * Return a column list clause for the given relation.
  13774. *
  13775. * Special case: if there are no undropped columns in the relation, return
  13776. * "", not an invalid "()" column list.
  13777. */
  13778. static const char *
  13779. fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
  13780. {
  13781. int numatts = ti->numatts;
  13782. char **attnames = ti->attnames;
  13783. bool *attisdropped = ti->attisdropped;
  13784. bool needComma;
  13785. int i;
  13786. appendPQExpBufferChar(buffer, '(');
  13787. needComma = false;
  13788. for (i = 0; i < numatts; i++)
  13789. {
  13790. if (attisdropped[i])
  13791. continue;
  13792. if (needComma)
  13793. appendPQExpBufferStr(buffer, ", ");
  13794. appendPQExpBufferStr(buffer, fmtId(attnames[i]));
  13795. needComma = true;
  13796. }
  13797. if (!needComma)
  13798. return ""; /* no undropped columns */
  13799. appendPQExpBufferChar(buffer, ')');
  13800. return buffer->data;
  13801. }
  13802. /*
  13803. * Execute an SQL query and verify that we got exactly one row back.
  13804. */
  13805. static PGresult *
  13806. ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
  13807. {
  13808. PGresult *res;
  13809. int ntups;
  13810. res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
  13811. /* Expecting a single result only */
  13812. ntups = PQntuples(res);
  13813. if (ntups != 1)
  13814. exit_horribly(NULL,
  13815. ngettext("query returned %d row instead of one: %s\n",
  13816. "query returned %d rows instead of one: %s\n",
  13817. ntups),
  13818. ntups, query);
  13819. return res;
  13820. }