1 /*-------------------------------------------------------------------------
2 *
3 * pg_dumpall.c
4 *
5 * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
7 *
8 * pg_dumpall forces all pg_dump output to be text, since it also outputs
9 * text into the same output stream.
10 *
11 * src/bin/pg_dump/pg_dumpall.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16 #include "postgres_fe.h"
17
18 #include <time.h>
19 #include <unistd.h>
20
21 #include "common/connect.h"
22 #include "common/file_utils.h"
23 #include "common/logging.h"
24 #include "common/string.h"
25 #include "dumputils.h"
26 #include "fe_utils/string_utils.h"
27 #include "getopt_long.h"
28 #include "pg_backup.h"
29
30 /* version string we expect back from pg_dump */
31 #define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
32
33
34 static void help(void);
35
36 static void dropRoles(PGconn *conn);
37 static void dumpRoles(PGconn *conn);
38 static void dumpRoleMembership(PGconn *conn);
39 static void dumpGroups(PGconn *conn);
40 static void dropTablespaces(PGconn *conn);
41 static void dumpTablespaces(PGconn *conn);
42 static void dropDBs(PGconn *conn);
43 static void dumpUserConfig(PGconn *conn, const char *username);
44 static void dumpDatabases(PGconn *conn);
45 static void dumpTimestamp(const char *msg);
46 static int runPgDump(const char *dbname, const char *create_opts);
47 static void buildShSecLabels(PGconn *conn,
48 const char *catalog_name, Oid objectId,
49 const char *objtype, const char *objname,
50 PQExpBuffer buffer);
51 static PGconn *connectDatabase(const char *dbname, const char *connstr, const char *pghost, const char *pgport,
52 const char *pguser, trivalue prompt_password, bool fail_on_error);
53 static char *constructConnStr(const char **keywords, const char **values);
54 static PGresult *executeQuery(PGconn *conn, const char *query);
55 static void executeCommand(PGconn *conn, const char *query);
56 static void expand_dbname_patterns(PGconn *conn, SimpleStringList *patterns,
57 SimpleStringList *names);
58
59 static char pg_dump_bin[MAXPGPATH];
60 static const char *progname;
61 static PQExpBuffer pgdumpopts;
62 static char *connstr = "";
63 static bool output_clean = false;
64 static bool skip_acls = false;
65 static bool verbose = false;
66 static bool dosync = true;
67
68 static int binary_upgrade = 0;
69 static int column_inserts = 0;
70 static int disable_dollar_quoting = 0;
71 static int disable_triggers = 0;
72 static int if_exists = 0;
73 static int inserts = 0;
74 static int no_tablespaces = 0;
75 static int use_setsessauth = 0;
76 static int no_comments = 0;
77 static int no_publications = 0;
78 static int no_security_labels = 0;
79 static int no_subscriptions = 0;
80 static int no_toast_compression = 0;
81 static int no_unlogged_table_data = 0;
82 static int no_role_passwords = 0;
83 static int server_version;
84 static int load_via_partition_root = 0;
85 static int on_conflict_do_nothing = 0;
86
87 static char role_catalog[10];
88 #define PG_AUTHID "pg_authid"
89 #define PG_ROLES "pg_roles "
90
91 static FILE *OPF;
92 static char *filename = NULL;
93
94 static SimpleStringList database_exclude_patterns = {NULL, NULL};
95 static SimpleStringList database_exclude_names = {NULL, NULL};
96
97 #define exit_nicely(code) exit(code)
98
99 int
main(int argc,char * argv[])100 main(int argc, char *argv[])
101 {
102 static struct option long_options[] = {
103 {"data-only", no_argument, NULL, 'a'},
104 {"clean", no_argument, NULL, 'c'},
105 {"encoding", required_argument, NULL, 'E'},
106 {"file", required_argument, NULL, 'f'},
107 {"globals-only", no_argument, NULL, 'g'},
108 {"host", required_argument, NULL, 'h'},
109 {"dbname", required_argument, NULL, 'd'},
110 {"database", required_argument, NULL, 'l'},
111 {"no-owner", no_argument, NULL, 'O'},
112 {"port", required_argument, NULL, 'p'},
113 {"roles-only", no_argument, NULL, 'r'},
114 {"schema-only", no_argument, NULL, 's'},
115 {"superuser", required_argument, NULL, 'S'},
116 {"tablespaces-only", no_argument, NULL, 't'},
117 {"username", required_argument, NULL, 'U'},
118 {"verbose", no_argument, NULL, 'v'},
119 {"no-password", no_argument, NULL, 'w'},
120 {"password", no_argument, NULL, 'W'},
121 {"no-privileges", no_argument, NULL, 'x'},
122 {"no-acl", no_argument, NULL, 'x'},
123
124 /*
125 * the following options don't have an equivalent short option letter
126 */
127 {"attribute-inserts", no_argument, &column_inserts, 1},
128 {"binary-upgrade", no_argument, &binary_upgrade, 1},
129 {"column-inserts", no_argument, &column_inserts, 1},
130 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
131 {"disable-triggers", no_argument, &disable_triggers, 1},
132 {"exclude-database", required_argument, NULL, 6},
133 {"extra-float-digits", required_argument, NULL, 5},
134 {"if-exists", no_argument, &if_exists, 1},
135 {"inserts", no_argument, &inserts, 1},
136 {"lock-wait-timeout", required_argument, NULL, 2},
137 {"no-tablespaces", no_argument, &no_tablespaces, 1},
138 {"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
139 {"load-via-partition-root", no_argument, &load_via_partition_root, 1},
140 {"role", required_argument, NULL, 3},
141 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
142 {"no-comments", no_argument, &no_comments, 1},
143 {"no-publications", no_argument, &no_publications, 1},
144 {"no-role-passwords", no_argument, &no_role_passwords, 1},
145 {"no-security-labels", no_argument, &no_security_labels, 1},
146 {"no-subscriptions", no_argument, &no_subscriptions, 1},
147 {"no-sync", no_argument, NULL, 4},
148 {"no-toast-compression", no_argument, &no_toast_compression, 1},
149 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
150 {"on-conflict-do-nothing", no_argument, &on_conflict_do_nothing, 1},
151 {"rows-per-insert", required_argument, NULL, 7},
152
153 {NULL, 0, NULL, 0}
154 };
155
156 char *pghost = NULL;
157 char *pgport = NULL;
158 char *pguser = NULL;
159 char *pgdb = NULL;
160 char *use_role = NULL;
161 const char *dumpencoding = NULL;
162 trivalue prompt_password = TRI_DEFAULT;
163 bool data_only = false;
164 bool globals_only = false;
165 bool roles_only = false;
166 bool tablespaces_only = false;
167 PGconn *conn;
168 int encoding;
169 const char *std_strings;
170 int c,
171 ret;
172 int optindex;
173
174 pg_logging_init(argv[0]);
175 pg_logging_set_level(PG_LOG_WARNING);
176 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
177 progname = get_progname(argv[0]);
178
179 if (argc > 1)
180 {
181 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
182 {
183 help();
184 exit_nicely(0);
185 }
186 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
187 {
188 puts("pg_dumpall (PostgreSQL) " PG_VERSION);
189 exit_nicely(0);
190 }
191 }
192
193 if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR,
194 pg_dump_bin)) < 0)
195 {
196 char full_path[MAXPGPATH];
197
198 if (find_my_exec(argv[0], full_path) < 0)
199 strlcpy(full_path, progname, sizeof(full_path));
200
201 if (ret == -1)
202 pg_log_error("The program \"%s\" is needed by %s but was not found in the\n"
203 "same directory as \"%s\".\n"
204 "Check your installation.",
205 "pg_dump", progname, full_path);
206 else
207 pg_log_error("The program \"%s\" was found by \"%s\"\n"
208 "but was not the same version as %s.\n"
209 "Check your installation.",
210 "pg_dump", full_path, progname);
211 exit_nicely(1);
212 }
213
214 pgdumpopts = createPQExpBuffer();
215
216 while ((c = getopt_long(argc, argv, "acd:E:f:gh:l:Op:rsS:tU:vwWx", long_options, &optindex)) != -1)
217 {
218 switch (c)
219 {
220 case 'a':
221 data_only = true;
222 appendPQExpBufferStr(pgdumpopts, " -a");
223 break;
224
225 case 'c':
226 output_clean = true;
227 break;
228
229 case 'd':
230 connstr = pg_strdup(optarg);
231 break;
232
233 case 'E':
234 dumpencoding = pg_strdup(optarg);
235 appendPQExpBufferStr(pgdumpopts, " -E ");
236 appendShellString(pgdumpopts, optarg);
237 break;
238
239 case 'f':
240 filename = pg_strdup(optarg);
241 appendPQExpBufferStr(pgdumpopts, " -f ");
242 appendShellString(pgdumpopts, filename);
243 break;
244
245 case 'g':
246 globals_only = true;
247 break;
248
249 case 'h':
250 pghost = pg_strdup(optarg);
251 break;
252
253 case 'l':
254 pgdb = pg_strdup(optarg);
255 break;
256
257 case 'O':
258 appendPQExpBufferStr(pgdumpopts, " -O");
259 break;
260
261 case 'p':
262 pgport = pg_strdup(optarg);
263 break;
264
265 case 'r':
266 roles_only = true;
267 break;
268
269 case 's':
270 appendPQExpBufferStr(pgdumpopts, " -s");
271 break;
272
273 case 'S':
274 appendPQExpBufferStr(pgdumpopts, " -S ");
275 appendShellString(pgdumpopts, optarg);
276 break;
277
278 case 't':
279 tablespaces_only = true;
280 break;
281
282 case 'U':
283 pguser = pg_strdup(optarg);
284 break;
285
286 case 'v':
287 verbose = true;
288 pg_logging_increase_verbosity();
289 appendPQExpBufferStr(pgdumpopts, " -v");
290 break;
291
292 case 'w':
293 prompt_password = TRI_NO;
294 appendPQExpBufferStr(pgdumpopts, " -w");
295 break;
296
297 case 'W':
298 prompt_password = TRI_YES;
299 appendPQExpBufferStr(pgdumpopts, " -W");
300 break;
301
302 case 'x':
303 skip_acls = true;
304 appendPQExpBufferStr(pgdumpopts, " -x");
305 break;
306
307 case 0:
308 break;
309
310 case 2:
311 appendPQExpBufferStr(pgdumpopts, " --lock-wait-timeout ");
312 appendShellString(pgdumpopts, optarg);
313 break;
314
315 case 3:
316 use_role = pg_strdup(optarg);
317 appendPQExpBufferStr(pgdumpopts, " --role ");
318 appendShellString(pgdumpopts, use_role);
319 break;
320
321 case 4:
322 dosync = false;
323 appendPQExpBufferStr(pgdumpopts, " --no-sync");
324 break;
325
326 case 5:
327 appendPQExpBufferStr(pgdumpopts, " --extra-float-digits ");
328 appendShellString(pgdumpopts, optarg);
329 break;
330
331 case 6:
332 simple_string_list_append(&database_exclude_patterns, optarg);
333 break;
334
335 case 7:
336 appendPQExpBufferStr(pgdumpopts, " --rows-per-insert ");
337 appendShellString(pgdumpopts, optarg);
338 break;
339
340 default:
341 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
342 exit_nicely(1);
343 }
344 }
345
346 /* Complain if any arguments remain */
347 if (optind < argc)
348 {
349 pg_log_error("too many command-line arguments (first is \"%s\")",
350 argv[optind]);
351 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
352 progname);
353 exit_nicely(1);
354 }
355
356 if (database_exclude_patterns.head != NULL &&
357 (globals_only || roles_only || tablespaces_only))
358 {
359 pg_log_error("option --exclude-database cannot be used together with -g/--globals-only, -r/--roles-only, or -t/--tablespaces-only");
360 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
361 progname);
362 exit_nicely(1);
363 }
364
365 /* Make sure the user hasn't specified a mix of globals-only options */
366 if (globals_only && roles_only)
367 {
368 pg_log_error("options -g/--globals-only and -r/--roles-only cannot be used together");
369 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
370 progname);
371 exit_nicely(1);
372 }
373
374 if (globals_only && tablespaces_only)
375 {
376 pg_log_error("options -g/--globals-only and -t/--tablespaces-only cannot be used together");
377 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
378 progname);
379 exit_nicely(1);
380 }
381
382 if (if_exists && !output_clean)
383 {
384 pg_log_error("option --if-exists requires option -c/--clean");
385 exit_nicely(1);
386 }
387
388 if (roles_only && tablespaces_only)
389 {
390 pg_log_error("options -r/--roles-only and -t/--tablespaces-only cannot be used together");
391 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
392 progname);
393 exit_nicely(1);
394 }
395
396 /*
397 * If password values are not required in the dump, switch to using
398 * pg_roles which is equally useful, just more likely to have unrestricted
399 * access than pg_authid.
400 */
401 if (no_role_passwords)
402 sprintf(role_catalog, "%s", PG_ROLES);
403 else
404 sprintf(role_catalog, "%s", PG_AUTHID);
405
406 /* Add long options to the pg_dump argument list */
407 if (binary_upgrade)
408 appendPQExpBufferStr(pgdumpopts, " --binary-upgrade");
409 if (column_inserts)
410 appendPQExpBufferStr(pgdumpopts, " --column-inserts");
411 if (disable_dollar_quoting)
412 appendPQExpBufferStr(pgdumpopts, " --disable-dollar-quoting");
413 if (disable_triggers)
414 appendPQExpBufferStr(pgdumpopts, " --disable-triggers");
415 if (inserts)
416 appendPQExpBufferStr(pgdumpopts, " --inserts");
417 if (no_tablespaces)
418 appendPQExpBufferStr(pgdumpopts, " --no-tablespaces");
419 if (quote_all_identifiers)
420 appendPQExpBufferStr(pgdumpopts, " --quote-all-identifiers");
421 if (load_via_partition_root)
422 appendPQExpBufferStr(pgdumpopts, " --load-via-partition-root");
423 if (use_setsessauth)
424 appendPQExpBufferStr(pgdumpopts, " --use-set-session-authorization");
425 if (no_comments)
426 appendPQExpBufferStr(pgdumpopts, " --no-comments");
427 if (no_publications)
428 appendPQExpBufferStr(pgdumpopts, " --no-publications");
429 if (no_security_labels)
430 appendPQExpBufferStr(pgdumpopts, " --no-security-labels");
431 if (no_subscriptions)
432 appendPQExpBufferStr(pgdumpopts, " --no-subscriptions");
433 if (no_toast_compression)
434 appendPQExpBufferStr(pgdumpopts, " --no-toast-compression");
435 if (no_unlogged_table_data)
436 appendPQExpBufferStr(pgdumpopts, " --no-unlogged-table-data");
437 if (on_conflict_do_nothing)
438 appendPQExpBufferStr(pgdumpopts, " --on-conflict-do-nothing");
439
440 /*
441 * If there was a database specified on the command line, use that,
442 * otherwise try to connect to database "postgres", and failing that
443 * "template1". "postgres" is the preferred choice for 8.1 and later
444 * servers, but it usually will not exist on older ones.
445 */
446 if (pgdb)
447 {
448 conn = connectDatabase(pgdb, connstr, pghost, pgport, pguser,
449 prompt_password, false);
450
451 if (!conn)
452 {
453 pg_log_error("could not connect to database \"%s\"", pgdb);
454 exit_nicely(1);
455 }
456 }
457 else
458 {
459 conn = connectDatabase("postgres", connstr, pghost, pgport, pguser,
460 prompt_password, false);
461 if (!conn)
462 conn = connectDatabase("template1", connstr, pghost, pgport, pguser,
463 prompt_password, true);
464
465 if (!conn)
466 {
467 pg_log_error("could not connect to databases \"postgres\" or \"template1\"\n"
468 "Please specify an alternative database.");
469 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
470 progname);
471 exit_nicely(1);
472 }
473 }
474
475 /*
476 * Get a list of database names that match the exclude patterns
477 */
478 expand_dbname_patterns(conn, &database_exclude_patterns,
479 &database_exclude_names);
480
481 /*
482 * Open the output file if required, otherwise use stdout
483 */
484 if (filename)
485 {
486 OPF = fopen(filename, PG_BINARY_W);
487 if (!OPF)
488 {
489 pg_log_error("could not open output file \"%s\": %m",
490 filename);
491 exit_nicely(1);
492 }
493 }
494 else
495 OPF = stdout;
496
497 /*
498 * Set the client encoding if requested.
499 */
500 if (dumpencoding)
501 {
502 if (PQsetClientEncoding(conn, dumpencoding) < 0)
503 {
504 pg_log_error("invalid client encoding \"%s\" specified",
505 dumpencoding);
506 exit_nicely(1);
507 }
508 }
509
510 /*
511 * Get the active encoding and the standard_conforming_strings setting, so
512 * we know how to escape strings.
513 */
514 encoding = PQclientEncoding(conn);
515 std_strings = PQparameterStatus(conn, "standard_conforming_strings");
516 if (!std_strings)
517 std_strings = "off";
518
519 /* Set the role if requested */
520 if (use_role && server_version >= 80100)
521 {
522 PQExpBuffer query = createPQExpBuffer();
523
524 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
525 executeCommand(conn, query->data);
526 destroyPQExpBuffer(query);
527 }
528
529 /* Force quoting of all identifiers if requested. */
530 if (quote_all_identifiers && server_version >= 90100)
531 executeCommand(conn, "SET quote_all_identifiers = true");
532
533 fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n");
534 if (verbose)
535 dumpTimestamp("Started on");
536
537 /*
538 * We used to emit \connect postgres here, but that served no purpose
539 * other than to break things for installations without a postgres
540 * database. Everything we're restoring here is a global, so whichever
541 * database we're connected to at the moment is fine.
542 */
543
544 /* Restore will need to write to the target cluster */
545 fprintf(OPF, "SET default_transaction_read_only = off;\n\n");
546
547 /* Replicate encoding and std_strings in output */
548 fprintf(OPF, "SET client_encoding = '%s';\n",
549 pg_encoding_to_char(encoding));
550 fprintf(OPF, "SET standard_conforming_strings = %s;\n", std_strings);
551 if (strcmp(std_strings, "off") == 0)
552 fprintf(OPF, "SET escape_string_warning = off;\n");
553 fprintf(OPF, "\n");
554
555 if (!data_only)
556 {
557 /*
558 * If asked to --clean, do that first. We can avoid detailed
559 * dependency analysis because databases never depend on each other,
560 * and tablespaces never depend on each other. Roles could have
561 * grants to each other, but DROP ROLE will clean those up silently.
562 */
563 if (output_clean)
564 {
565 if (!globals_only && !roles_only && !tablespaces_only)
566 dropDBs(conn);
567
568 if (!roles_only && !no_tablespaces)
569 dropTablespaces(conn);
570
571 if (!tablespaces_only)
572 dropRoles(conn);
573 }
574
575 /*
576 * Now create objects as requested. Be careful that option logic here
577 * is the same as for drops above.
578 */
579 if (!tablespaces_only)
580 {
581 /* Dump roles (users) */
582 dumpRoles(conn);
583
584 /* Dump role memberships --- need different method for pre-8.1 */
585 if (server_version >= 80100)
586 dumpRoleMembership(conn);
587 else
588 dumpGroups(conn);
589 }
590
591 /* Dump tablespaces */
592 if (!roles_only && !no_tablespaces)
593 dumpTablespaces(conn);
594 }
595
596 if (!globals_only && !roles_only && !tablespaces_only)
597 dumpDatabases(conn);
598
599 PQfinish(conn);
600
601 if (verbose)
602 dumpTimestamp("Completed on");
603 fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n");
604
605 if (filename)
606 {
607 fclose(OPF);
608
609 /* sync the resulting file, errors are not fatal */
610 if (dosync)
611 (void) fsync_fname(filename, false);
612 }
613
614 exit_nicely(0);
615 }
616
617
618 static void
help(void)619 help(void)
620 {
621 printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
622 printf(_("Usage:\n"));
623 printf(_(" %s [OPTION]...\n"), progname);
624
625 printf(_("\nGeneral options:\n"));
626 printf(_(" -f, --file=FILENAME output file name\n"));
627 printf(_(" -v, --verbose verbose mode\n"));
628 printf(_(" -V, --version output version information, then exit\n"));
629 printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
630 printf(_(" -?, --help show this help, then exit\n"));
631 printf(_("\nOptions controlling the output content:\n"));
632 printf(_(" -a, --data-only dump only the data, not the schema\n"));
633 printf(_(" -c, --clean clean (drop) databases before recreating\n"));
634 printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
635 printf(_(" -g, --globals-only dump only global objects, no databases\n"));
636 printf(_(" -O, --no-owner skip restoration of object ownership\n"));
637 printf(_(" -r, --roles-only dump only roles, no databases or tablespaces\n"));
638 printf(_(" -s, --schema-only dump only the schema, no data\n"));
639 printf(_(" -S, --superuser=NAME superuser user name to use in the dump\n"));
640 printf(_(" -t, --tablespaces-only dump only tablespaces, no databases or roles\n"));
641 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
642 printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
643 printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
644 printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
645 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
646 printf(_(" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n"));
647 printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
648 printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
649 printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
650 printf(_(" --load-via-partition-root load partitions via the root table\n"));
651 printf(_(" --no-comments do not dump comments\n"));
652 printf(_(" --no-publications do not dump publications\n"));
653 printf(_(" --no-role-passwords do not dump passwords for roles\n"));
654 printf(_(" --no-security-labels do not dump security label assignments\n"));
655 printf(_(" --no-subscriptions do not dump subscriptions\n"));
656 printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
657 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
658 printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
659 printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
660 printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
661 printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
662 printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
663 printf(_(" --use-set-session-authorization\n"
664 " use SET SESSION AUTHORIZATION commands instead of\n"
665 " ALTER OWNER commands to set ownership\n"));
666
667 printf(_("\nConnection options:\n"));
668 printf(_(" -d, --dbname=CONNSTR connect using connection string\n"));
669 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
670 printf(_(" -l, --database=DBNAME alternative default database\n"));
671 printf(_(" -p, --port=PORT database server port number\n"));
672 printf(_(" -U, --username=NAME connect as specified database user\n"));
673 printf(_(" -w, --no-password never prompt for password\n"));
674 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
675 printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
676
677 printf(_("\nIf -f/--file is not used, then the SQL script will be written to the standard\n"
678 "output.\n\n"));
679 printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
680 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
681 }
682
683
684 /*
685 * Drop roles
686 */
687 static void
dropRoles(PGconn * conn)688 dropRoles(PGconn *conn)
689 {
690 PQExpBuffer buf = createPQExpBuffer();
691 PGresult *res;
692 int i_rolname;
693 int i;
694
695 if (server_version >= 90600)
696 printfPQExpBuffer(buf,
697 "SELECT rolname "
698 "FROM %s "
699 "WHERE rolname !~ '^pg_' "
700 "ORDER BY 1", role_catalog);
701 else if (server_version >= 80100)
702 printfPQExpBuffer(buf,
703 "SELECT rolname "
704 "FROM %s "
705 "ORDER BY 1", role_catalog);
706 else
707 printfPQExpBuffer(buf,
708 "SELECT usename as rolname "
709 "FROM pg_shadow "
710 "UNION "
711 "SELECT groname as rolname "
712 "FROM pg_group "
713 "ORDER BY 1");
714
715 res = executeQuery(conn, buf->data);
716
717 i_rolname = PQfnumber(res, "rolname");
718
719 if (PQntuples(res) > 0)
720 fprintf(OPF, "--\n-- Drop roles\n--\n\n");
721
722 for (i = 0; i < PQntuples(res); i++)
723 {
724 const char *rolename;
725
726 rolename = PQgetvalue(res, i, i_rolname);
727
728 fprintf(OPF, "DROP ROLE %s%s;\n",
729 if_exists ? "IF EXISTS " : "",
730 fmtId(rolename));
731 }
732
733 PQclear(res);
734 destroyPQExpBuffer(buf);
735
736 fprintf(OPF, "\n\n");
737 }
738
739 /*
740 * Dump roles
741 */
742 static void
dumpRoles(PGconn * conn)743 dumpRoles(PGconn *conn)
744 {
745 PQExpBuffer buf = createPQExpBuffer();
746 PGresult *res;
747 int i_oid,
748 i_rolname,
749 i_rolsuper,
750 i_rolinherit,
751 i_rolcreaterole,
752 i_rolcreatedb,
753 i_rolcanlogin,
754 i_rolconnlimit,
755 i_rolpassword,
756 i_rolvaliduntil,
757 i_rolreplication,
758 i_rolbypassrls,
759 i_rolcomment,
760 i_is_current_user;
761 int i;
762
763 /* note: rolconfig is dumped later */
764 if (server_version >= 90600)
765 printfPQExpBuffer(buf,
766 "SELECT oid, rolname, rolsuper, rolinherit, "
767 "rolcreaterole, rolcreatedb, "
768 "rolcanlogin, rolconnlimit, rolpassword, "
769 "rolvaliduntil, rolreplication, rolbypassrls, "
770 "pg_catalog.shobj_description(oid, '%s') as rolcomment, "
771 "rolname = current_user AS is_current_user "
772 "FROM %s "
773 "WHERE rolname !~ '^pg_' "
774 "ORDER BY 2", role_catalog, role_catalog);
775 else if (server_version >= 90500)
776 printfPQExpBuffer(buf,
777 "SELECT oid, rolname, rolsuper, rolinherit, "
778 "rolcreaterole, rolcreatedb, "
779 "rolcanlogin, rolconnlimit, rolpassword, "
780 "rolvaliduntil, rolreplication, rolbypassrls, "
781 "pg_catalog.shobj_description(oid, '%s') as rolcomment, "
782 "rolname = current_user AS is_current_user "
783 "FROM %s "
784 "ORDER BY 2", role_catalog, role_catalog);
785 else if (server_version >= 90100)
786 printfPQExpBuffer(buf,
787 "SELECT oid, rolname, rolsuper, rolinherit, "
788 "rolcreaterole, rolcreatedb, "
789 "rolcanlogin, rolconnlimit, rolpassword, "
790 "rolvaliduntil, rolreplication, "
791 "false as rolbypassrls, "
792 "pg_catalog.shobj_description(oid, '%s') as rolcomment, "
793 "rolname = current_user AS is_current_user "
794 "FROM %s "
795 "ORDER BY 2", role_catalog, role_catalog);
796 else if (server_version >= 80200)
797 printfPQExpBuffer(buf,
798 "SELECT oid, rolname, rolsuper, rolinherit, "
799 "rolcreaterole, rolcreatedb, "
800 "rolcanlogin, rolconnlimit, rolpassword, "
801 "rolvaliduntil, false as rolreplication, "
802 "false as rolbypassrls, "
803 "pg_catalog.shobj_description(oid, '%s') as rolcomment, "
804 "rolname = current_user AS is_current_user "
805 "FROM %s "
806 "ORDER BY 2", role_catalog, role_catalog);
807 else if (server_version >= 80100)
808 printfPQExpBuffer(buf,
809 "SELECT oid, rolname, rolsuper, rolinherit, "
810 "rolcreaterole, rolcreatedb, "
811 "rolcanlogin, rolconnlimit, rolpassword, "
812 "rolvaliduntil, false as rolreplication, "
813 "false as rolbypassrls, "
814 "null as rolcomment, "
815 "rolname = current_user AS is_current_user "
816 "FROM %s "
817 "ORDER BY 2", role_catalog);
818 else
819 printfPQExpBuffer(buf,
820 "SELECT 0 as oid, usename as rolname, "
821 "usesuper as rolsuper, "
822 "true as rolinherit, "
823 "usesuper as rolcreaterole, "
824 "usecreatedb as rolcreatedb, "
825 "true as rolcanlogin, "
826 "-1 as rolconnlimit, "
827 "passwd as rolpassword, "
828 "valuntil as rolvaliduntil, "
829 "false as rolreplication, "
830 "false as rolbypassrls, "
831 "null as rolcomment, "
832 "usename = current_user AS is_current_user "
833 "FROM pg_shadow "
834 "UNION ALL "
835 "SELECT 0 as oid, groname as rolname, "
836 "false as rolsuper, "
837 "true as rolinherit, "
838 "false as rolcreaterole, "
839 "false as rolcreatedb, "
840 "false as rolcanlogin, "
841 "-1 as rolconnlimit, "
842 "null::text as rolpassword, "
843 "null::timestamptz as rolvaliduntil, "
844 "false as rolreplication, "
845 "false as rolbypassrls, "
846 "null as rolcomment, "
847 "false AS is_current_user "
848 "FROM pg_group "
849 "WHERE NOT EXISTS (SELECT 1 FROM pg_shadow "
850 " WHERE usename = groname) "
851 "ORDER BY 2");
852
853 res = executeQuery(conn, buf->data);
854
855 i_oid = PQfnumber(res, "oid");
856 i_rolname = PQfnumber(res, "rolname");
857 i_rolsuper = PQfnumber(res, "rolsuper");
858 i_rolinherit = PQfnumber(res, "rolinherit");
859 i_rolcreaterole = PQfnumber(res, "rolcreaterole");
860 i_rolcreatedb = PQfnumber(res, "rolcreatedb");
861 i_rolcanlogin = PQfnumber(res, "rolcanlogin");
862 i_rolconnlimit = PQfnumber(res, "rolconnlimit");
863 i_rolpassword = PQfnumber(res, "rolpassword");
864 i_rolvaliduntil = PQfnumber(res, "rolvaliduntil");
865 i_rolreplication = PQfnumber(res, "rolreplication");
866 i_rolbypassrls = PQfnumber(res, "rolbypassrls");
867 i_rolcomment = PQfnumber(res, "rolcomment");
868 i_is_current_user = PQfnumber(res, "is_current_user");
869
870 if (PQntuples(res) > 0)
871 fprintf(OPF, "--\n-- Roles\n--\n\n");
872
873 for (i = 0; i < PQntuples(res); i++)
874 {
875 const char *rolename;
876 Oid auth_oid;
877
878 auth_oid = atooid(PQgetvalue(res, i, i_oid));
879 rolename = PQgetvalue(res, i, i_rolname);
880
881 if (strncmp(rolename, "pg_", 3) == 0)
882 {
883 pg_log_warning("role name starting with \"pg_\" skipped (%s)",
884 rolename);
885 continue;
886 }
887
888 resetPQExpBuffer(buf);
889
890 if (binary_upgrade)
891 {
892 appendPQExpBufferStr(buf, "\n-- For binary upgrade, must preserve pg_authid.oid\n");
893 appendPQExpBuffer(buf,
894 "SELECT pg_catalog.binary_upgrade_set_next_pg_authid_oid('%u'::pg_catalog.oid);\n\n",
895 auth_oid);
896 }
897
898 /*
899 * We dump CREATE ROLE followed by ALTER ROLE to ensure that the role
900 * will acquire the right properties even if it already exists (ie, it
901 * won't hurt for the CREATE to fail). This is particularly important
902 * for the role we are connected as, since even with --clean we will
903 * have failed to drop it. binary_upgrade cannot generate any errors,
904 * so we assume the current role is already created.
905 */
906 if (!binary_upgrade ||
907 strcmp(PQgetvalue(res, i, i_is_current_user), "f") == 0)
908 appendPQExpBuffer(buf, "CREATE ROLE %s;\n", fmtId(rolename));
909 appendPQExpBuffer(buf, "ALTER ROLE %s WITH", fmtId(rolename));
910
911 if (strcmp(PQgetvalue(res, i, i_rolsuper), "t") == 0)
912 appendPQExpBufferStr(buf, " SUPERUSER");
913 else
914 appendPQExpBufferStr(buf, " NOSUPERUSER");
915
916 if (strcmp(PQgetvalue(res, i, i_rolinherit), "t") == 0)
917 appendPQExpBufferStr(buf, " INHERIT");
918 else
919 appendPQExpBufferStr(buf, " NOINHERIT");
920
921 if (strcmp(PQgetvalue(res, i, i_rolcreaterole), "t") == 0)
922 appendPQExpBufferStr(buf, " CREATEROLE");
923 else
924 appendPQExpBufferStr(buf, " NOCREATEROLE");
925
926 if (strcmp(PQgetvalue(res, i, i_rolcreatedb), "t") == 0)
927 appendPQExpBufferStr(buf, " CREATEDB");
928 else
929 appendPQExpBufferStr(buf, " NOCREATEDB");
930
931 if (strcmp(PQgetvalue(res, i, i_rolcanlogin), "t") == 0)
932 appendPQExpBufferStr(buf, " LOGIN");
933 else
934 appendPQExpBufferStr(buf, " NOLOGIN");
935
936 if (strcmp(PQgetvalue(res, i, i_rolreplication), "t") == 0)
937 appendPQExpBufferStr(buf, " REPLICATION");
938 else
939 appendPQExpBufferStr(buf, " NOREPLICATION");
940
941 if (strcmp(PQgetvalue(res, i, i_rolbypassrls), "t") == 0)
942 appendPQExpBufferStr(buf, " BYPASSRLS");
943 else
944 appendPQExpBufferStr(buf, " NOBYPASSRLS");
945
946 if (strcmp(PQgetvalue(res, i, i_rolconnlimit), "-1") != 0)
947 appendPQExpBuffer(buf, " CONNECTION LIMIT %s",
948 PQgetvalue(res, i, i_rolconnlimit));
949
950
951 if (!PQgetisnull(res, i, i_rolpassword) && !no_role_passwords)
952 {
953 appendPQExpBufferStr(buf, " PASSWORD ");
954 appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolpassword), conn);
955 }
956
957 if (!PQgetisnull(res, i, i_rolvaliduntil))
958 appendPQExpBuffer(buf, " VALID UNTIL '%s'",
959 PQgetvalue(res, i, i_rolvaliduntil));
960
961 appendPQExpBufferStr(buf, ";\n");
962
963 if (!no_comments && !PQgetisnull(res, i, i_rolcomment))
964 {
965 appendPQExpBuffer(buf, "COMMENT ON ROLE %s IS ", fmtId(rolename));
966 appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolcomment), conn);
967 appendPQExpBufferStr(buf, ";\n");
968 }
969
970 if (!no_security_labels && server_version >= 90200)
971 buildShSecLabels(conn, "pg_authid", auth_oid,
972 "ROLE", rolename,
973 buf);
974
975 fprintf(OPF, "%s", buf->data);
976 }
977
978 /*
979 * Dump configuration settings for roles after all roles have been dumped.
980 * We do it this way because config settings for roles could mention the
981 * names of other roles.
982 */
983 for (i = 0; i < PQntuples(res); i++)
984 dumpUserConfig(conn, PQgetvalue(res, i, i_rolname));
985
986 PQclear(res);
987
988 fprintf(OPF, "\n\n");
989
990 destroyPQExpBuffer(buf);
991 }
992
993
994 /*
995 * Dump role memberships. This code is used for 8.1 and later servers.
996 *
997 * Note: we expect dumpRoles already created all the roles, but there is
998 * no membership yet.
999 */
1000 static void
dumpRoleMembership(PGconn * conn)1001 dumpRoleMembership(PGconn *conn)
1002 {
1003 PQExpBuffer buf = createPQExpBuffer();
1004 PGresult *res;
1005 int i;
1006
1007 printfPQExpBuffer(buf, "SELECT ur.rolname AS roleid, "
1008 "um.rolname AS member, "
1009 "a.admin_option, "
1010 "ug.rolname AS grantor "
1011 "FROM pg_auth_members a "
1012 "LEFT JOIN %s ur on ur.oid = a.roleid "
1013 "LEFT JOIN %s um on um.oid = a.member "
1014 "LEFT JOIN %s ug on ug.oid = a.grantor "
1015 "WHERE NOT (ur.rolname ~ '^pg_' AND um.rolname ~ '^pg_')"
1016 "ORDER BY 1,2,3", role_catalog, role_catalog, role_catalog);
1017 res = executeQuery(conn, buf->data);
1018
1019 if (PQntuples(res) > 0)
1020 fprintf(OPF, "--\n-- Role memberships\n--\n\n");
1021
1022 for (i = 0; i < PQntuples(res); i++)
1023 {
1024 char *roleid = PQgetvalue(res, i, 0);
1025 char *member = PQgetvalue(res, i, 1);
1026 char *option = PQgetvalue(res, i, 2);
1027
1028 fprintf(OPF, "GRANT %s", fmtId(roleid));
1029 fprintf(OPF, " TO %s", fmtId(member));
1030 if (*option == 't')
1031 fprintf(OPF, " WITH ADMIN OPTION");
1032
1033 /*
1034 * We don't track the grantor very carefully in the backend, so cope
1035 * with the possibility that it has been dropped.
1036 */
1037 if (!PQgetisnull(res, i, 3))
1038 {
1039 char *grantor = PQgetvalue(res, i, 3);
1040
1041 fprintf(OPF, " GRANTED BY %s", fmtId(grantor));
1042 }
1043 fprintf(OPF, ";\n");
1044 }
1045
1046 PQclear(res);
1047 destroyPQExpBuffer(buf);
1048
1049 fprintf(OPF, "\n\n");
1050 }
1051
1052 /*
1053 * Dump group memberships from a pre-8.1 server. It's annoying that we
1054 * can't share any useful amount of code with the post-8.1 case, but
1055 * the catalog representations are too different.
1056 *
1057 * Note: we expect dumpRoles already created all the roles, but there is
1058 * no membership yet.
1059 */
1060 static void
dumpGroups(PGconn * conn)1061 dumpGroups(PGconn *conn)
1062 {
1063 PQExpBuffer buf = createPQExpBuffer();
1064 PGresult *res;
1065 int i;
1066
1067 res = executeQuery(conn,
1068 "SELECT groname, grolist FROM pg_group ORDER BY 1");
1069
1070 if (PQntuples(res) > 0)
1071 fprintf(OPF, "--\n-- Role memberships\n--\n\n");
1072
1073 for (i = 0; i < PQntuples(res); i++)
1074 {
1075 char *groname = PQgetvalue(res, i, 0);
1076 char *grolist = PQgetvalue(res, i, 1);
1077 PGresult *res2;
1078 int j;
1079
1080 /*
1081 * Array representation is {1,2,3} ... convert to (1,2,3)
1082 */
1083 if (strlen(grolist) < 3)
1084 continue;
1085
1086 grolist = pg_strdup(grolist);
1087 grolist[0] = '(';
1088 grolist[strlen(grolist) - 1] = ')';
1089 printfPQExpBuffer(buf,
1090 "SELECT usename FROM pg_shadow "
1091 "WHERE usesysid IN %s ORDER BY 1",
1092 grolist);
1093 free(grolist);
1094
1095 res2 = executeQuery(conn, buf->data);
1096
1097 for (j = 0; j < PQntuples(res2); j++)
1098 {
1099 char *usename = PQgetvalue(res2, j, 0);
1100
1101 /*
1102 * Don't try to grant a role to itself; can happen if old
1103 * installation has identically named user and group.
1104 */
1105 if (strcmp(groname, usename) == 0)
1106 continue;
1107
1108 fprintf(OPF, "GRANT %s", fmtId(groname));
1109 fprintf(OPF, " TO %s;\n", fmtId(usename));
1110 }
1111
1112 PQclear(res2);
1113 }
1114
1115 PQclear(res);
1116 destroyPQExpBuffer(buf);
1117
1118 fprintf(OPF, "\n\n");
1119 }
1120
1121
1122 /*
1123 * Drop tablespaces.
1124 */
1125 static void
dropTablespaces(PGconn * conn)1126 dropTablespaces(PGconn *conn)
1127 {
1128 PGresult *res;
1129 int i;
1130
1131 /*
1132 * Get all tablespaces except built-in ones (which we assume are named
1133 * pg_xxx)
1134 */
1135 res = executeQuery(conn, "SELECT spcname "
1136 "FROM pg_catalog.pg_tablespace "
1137 "WHERE spcname !~ '^pg_' "
1138 "ORDER BY 1");
1139
1140 if (PQntuples(res) > 0)
1141 fprintf(OPF, "--\n-- Drop tablespaces\n--\n\n");
1142
1143 for (i = 0; i < PQntuples(res); i++)
1144 {
1145 char *spcname = PQgetvalue(res, i, 0);
1146
1147 fprintf(OPF, "DROP TABLESPACE %s%s;\n",
1148 if_exists ? "IF EXISTS " : "",
1149 fmtId(spcname));
1150 }
1151
1152 PQclear(res);
1153
1154 fprintf(OPF, "\n\n");
1155 }
1156
1157 /*
1158 * Dump tablespaces.
1159 */
1160 static void
dumpTablespaces(PGconn * conn)1161 dumpTablespaces(PGconn *conn)
1162 {
1163 PGresult *res;
1164 int i;
1165
1166 /*
1167 * Get all tablespaces except built-in ones (which we assume are named
1168 * pg_xxx)
1169 *
1170 * For the tablespace ACLs, as of 9.6, we extract both the positive (as
1171 * spcacl) and negative (as rspcacl) ACLs, relative to the default ACL for
1172 * tablespaces, which are then passed to buildACLCommands() below.
1173 *
1174 * See buildACLQueries() and buildACLCommands().
1175 *
1176 * The order in which privileges are in the ACL string (the order they
1177 * have been GRANT'd in, which the backend maintains) must be preserved to
1178 * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
1179 * those are dumped in the correct order.
1180 *
1181 * Note that we do not support initial privileges (pg_init_privs) on
1182 * tablespaces, so this logic cannot make use of buildACLQueries().
1183 */
1184 if (server_version >= 90600)
1185 res = executeQuery(conn, "SELECT oid, spcname, "
1186 "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
1187 "pg_catalog.pg_tablespace_location(oid), "
1188 "(SELECT array_agg(acl ORDER BY row_n) FROM "
1189 " (SELECT acl, row_n FROM "
1190 " unnest(coalesce(spcacl,acldefault('t',spcowner))) "
1191 " WITH ORDINALITY AS perm(acl,row_n) "
1192 " WHERE NOT EXISTS ( "
1193 " SELECT 1 "
1194 " FROM unnest(acldefault('t',spcowner)) "
1195 " AS init(init_acl) "
1196 " WHERE acl = init_acl)) AS spcacls) "
1197 " AS spcacl, "
1198 "(SELECT array_agg(acl ORDER BY row_n) FROM "
1199 " (SELECT acl, row_n FROM "
1200 " unnest(acldefault('t',spcowner)) "
1201 " WITH ORDINALITY AS initp(acl,row_n) "
1202 " WHERE NOT EXISTS ( "
1203 " SELECT 1 "
1204 " FROM unnest(coalesce(spcacl,acldefault('t',spcowner))) "
1205 " AS permp(orig_acl) "
1206 " WHERE acl = orig_acl)) AS rspcacls) "
1207 " AS rspcacl, "
1208 "array_to_string(spcoptions, ', '),"
1209 "pg_catalog.shobj_description(oid, 'pg_tablespace') "
1210 "FROM pg_catalog.pg_tablespace "
1211 "WHERE spcname !~ '^pg_' "
1212 "ORDER BY 1");
1213 else if (server_version >= 90200)
1214 res = executeQuery(conn, "SELECT oid, spcname, "
1215 "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
1216 "pg_catalog.pg_tablespace_location(oid), "
1217 "spcacl, '' as rspcacl, "
1218 "array_to_string(spcoptions, ', '),"
1219 "pg_catalog.shobj_description(oid, 'pg_tablespace') "
1220 "FROM pg_catalog.pg_tablespace "
1221 "WHERE spcname !~ '^pg_' "
1222 "ORDER BY 1");
1223 else if (server_version >= 90000)
1224 res = executeQuery(conn, "SELECT oid, spcname, "
1225 "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
1226 "spclocation, spcacl, '' as rspcacl, "
1227 "array_to_string(spcoptions, ', '),"
1228 "pg_catalog.shobj_description(oid, 'pg_tablespace') "
1229 "FROM pg_catalog.pg_tablespace "
1230 "WHERE spcname !~ '^pg_' "
1231 "ORDER BY 1");
1232 else if (server_version >= 80200)
1233 res = executeQuery(conn, "SELECT oid, spcname, "
1234 "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
1235 "spclocation, spcacl, '' as rspcacl, null, "
1236 "pg_catalog.shobj_description(oid, 'pg_tablespace') "
1237 "FROM pg_catalog.pg_tablespace "
1238 "WHERE spcname !~ '^pg_' "
1239 "ORDER BY 1");
1240 else
1241 res = executeQuery(conn, "SELECT oid, spcname, "
1242 "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
1243 "spclocation, spcacl, '' as rspcacl, "
1244 "null, null "
1245 "FROM pg_catalog.pg_tablespace "
1246 "WHERE spcname !~ '^pg_' "
1247 "ORDER BY 1");
1248
1249 if (PQntuples(res) > 0)
1250 fprintf(OPF, "--\n-- Tablespaces\n--\n\n");
1251
1252 for (i = 0; i < PQntuples(res); i++)
1253 {
1254 PQExpBuffer buf = createPQExpBuffer();
1255 Oid spcoid = atooid(PQgetvalue(res, i, 0));
1256 char *spcname = PQgetvalue(res, i, 1);
1257 char *spcowner = PQgetvalue(res, i, 2);
1258 char *spclocation = PQgetvalue(res, i, 3);
1259 char *spcacl = PQgetvalue(res, i, 4);
1260 char *rspcacl = PQgetvalue(res, i, 5);
1261 char *spcoptions = PQgetvalue(res, i, 6);
1262 char *spccomment = PQgetvalue(res, i, 7);
1263 char *fspcname;
1264
1265 /* needed for buildACLCommands() */
1266 fspcname = pg_strdup(fmtId(spcname));
1267
1268 appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
1269 appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
1270
1271 appendPQExpBufferStr(buf, " LOCATION ");
1272 appendStringLiteralConn(buf, spclocation, conn);
1273 appendPQExpBufferStr(buf, ";\n");
1274
1275 if (spcoptions && spcoptions[0] != '\0')
1276 appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n",
1277 fspcname, spcoptions);
1278
1279 if (!skip_acls &&
1280 !buildACLCommands(fspcname, NULL, NULL, "TABLESPACE",
1281 spcacl, rspcacl,
1282 spcowner, "", server_version, buf))
1283 {
1284 pg_log_error("could not parse ACL list (%s) for tablespace \"%s\"",
1285 spcacl, spcname);
1286 PQfinish(conn);
1287 exit_nicely(1);
1288 }
1289
1290 if (!no_comments && spccomment && spccomment[0] != '\0')
1291 {
1292 appendPQExpBuffer(buf, "COMMENT ON TABLESPACE %s IS ", fspcname);
1293 appendStringLiteralConn(buf, spccomment, conn);
1294 appendPQExpBufferStr(buf, ";\n");
1295 }
1296
1297 if (!no_security_labels && server_version >= 90200)
1298 buildShSecLabels(conn, "pg_tablespace", spcoid,
1299 "TABLESPACE", spcname,
1300 buf);
1301
1302 fprintf(OPF, "%s", buf->data);
1303
1304 free(fspcname);
1305 destroyPQExpBuffer(buf);
1306 }
1307
1308 PQclear(res);
1309 fprintf(OPF, "\n\n");
1310 }
1311
1312
1313 /*
1314 * Dump commands to drop each database.
1315 */
1316 static void
dropDBs(PGconn * conn)1317 dropDBs(PGconn *conn)
1318 {
1319 PGresult *res;
1320 int i;
1321
1322 /*
1323 * Skip databases marked not datallowconn, since we'd be unable to connect
1324 * to them anyway. This must agree with dumpDatabases().
1325 */
1326 res = executeQuery(conn,
1327 "SELECT datname "
1328 "FROM pg_database d "
1329 "WHERE datallowconn "
1330 "ORDER BY datname");
1331
1332 if (PQntuples(res) > 0)
1333 fprintf(OPF, "--\n-- Drop databases (except postgres and template1)\n--\n\n");
1334
1335 for (i = 0; i < PQntuples(res); i++)
1336 {
1337 char *dbname = PQgetvalue(res, i, 0);
1338
1339 /*
1340 * Skip "postgres" and "template1"; dumpDatabases() will deal with
1341 * them specially. Also, be sure to skip "template0", even if for
1342 * some reason it's not marked !datallowconn.
1343 */
1344 if (strcmp(dbname, "template1") != 0 &&
1345 strcmp(dbname, "template0") != 0 &&
1346 strcmp(dbname, "postgres") != 0)
1347 {
1348 fprintf(OPF, "DROP DATABASE %s%s;\n",
1349 if_exists ? "IF EXISTS " : "",
1350 fmtId(dbname));
1351 }
1352 }
1353
1354 PQclear(res);
1355
1356 fprintf(OPF, "\n\n");
1357 }
1358
1359
1360 /*
1361 * Dump user-specific configuration
1362 */
1363 static void
dumpUserConfig(PGconn * conn,const char * username)1364 dumpUserConfig(PGconn *conn, const char *username)
1365 {
1366 PQExpBuffer buf = createPQExpBuffer();
1367 int count = 1;
1368 bool first = true;
1369
1370 for (;;)
1371 {
1372 PGresult *res;
1373
1374 if (server_version >= 90000)
1375 printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting WHERE "
1376 "setdatabase = 0 AND setrole = "
1377 "(SELECT oid FROM %s WHERE rolname = ", count, role_catalog);
1378 else if (server_version >= 80100)
1379 printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM %s WHERE rolname = ", count, role_catalog);
1380 else
1381 printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
1382 appendStringLiteralConn(buf, username, conn);
1383 if (server_version >= 90000)
1384 appendPQExpBufferChar(buf, ')');
1385
1386 res = executeQuery(conn, buf->data);
1387 if (PQntuples(res) == 1 &&
1388 !PQgetisnull(res, 0, 0))
1389 {
1390 /* comment at section start, only if needed */
1391 if (first)
1392 {
1393 fprintf(OPF, "--\n-- User Configurations\n--\n\n");
1394 first = false;
1395 }
1396
1397 fprintf(OPF, "--\n-- User Config \"%s\"\n--\n\n", username);
1398 resetPQExpBuffer(buf);
1399 makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
1400 "ROLE", username, NULL, NULL,
1401 buf);
1402 fprintf(OPF, "%s", buf->data);
1403 PQclear(res);
1404 count++;
1405 }
1406 else
1407 {
1408 PQclear(res);
1409 break;
1410 }
1411 }
1412
1413 destroyPQExpBuffer(buf);
1414 }
1415
1416 /*
1417 * Find a list of database names that match the given patterns.
1418 * See also expand_table_name_patterns() in pg_dump.c
1419 */
1420 static void
expand_dbname_patterns(PGconn * conn,SimpleStringList * patterns,SimpleStringList * names)1421 expand_dbname_patterns(PGconn *conn,
1422 SimpleStringList *patterns,
1423 SimpleStringList *names)
1424 {
1425 PQExpBuffer query;
1426 PGresult *res;
1427
1428 if (patterns->head == NULL)
1429 return; /* nothing to do */
1430
1431 query = createPQExpBuffer();
1432
1433 /*
1434 * The loop below runs multiple SELECTs, which might sometimes result in
1435 * duplicate entries in the name list, but we don't care, since all we're
1436 * going to do is test membership of the list.
1437 */
1438
1439 for (SimpleStringListCell *cell = patterns->head; cell; cell = cell->next)
1440 {
1441 appendPQExpBufferStr(query,
1442 "SELECT datname FROM pg_catalog.pg_database n\n");
1443 processSQLNamePattern(conn, query, cell->val, false,
1444 false, NULL, "datname", NULL, NULL);
1445
1446 res = executeQuery(conn, query->data);
1447 for (int i = 0; i < PQntuples(res); i++)
1448 {
1449 simple_string_list_append(names, PQgetvalue(res, i, 0));
1450 }
1451
1452 PQclear(res);
1453 resetPQExpBuffer(query);
1454 }
1455
1456 destroyPQExpBuffer(query);
1457 }
1458
1459 /*
1460 * Dump contents of databases.
1461 */
1462 static void
dumpDatabases(PGconn * conn)1463 dumpDatabases(PGconn *conn)
1464 {
1465 PGresult *res;
1466 int i;
1467
1468 /*
1469 * Skip databases marked not datallowconn, since we'd be unable to connect
1470 * to them anyway. This must agree with dropDBs().
1471 *
1472 * We arrange for template1 to be processed first, then we process other
1473 * DBs in alphabetical order. If we just did them all alphabetically, we
1474 * might find ourselves trying to drop the "postgres" database while still
1475 * connected to it. This makes trying to run the restore script while
1476 * connected to "template1" a bad idea, but there's no fixed order that
1477 * doesn't have some failure mode with --clean.
1478 */
1479 res = executeQuery(conn,
1480 "SELECT datname "
1481 "FROM pg_database d "
1482 "WHERE datallowconn "
1483 "ORDER BY (datname <> 'template1'), datname");
1484
1485 if (PQntuples(res) > 0)
1486 fprintf(OPF, "--\n-- Databases\n--\n\n");
1487
1488 for (i = 0; i < PQntuples(res); i++)
1489 {
1490 char *dbname = PQgetvalue(res, i, 0);
1491 const char *create_opts;
1492 int ret;
1493
1494 /* Skip template0, even if it's not marked !datallowconn. */
1495 if (strcmp(dbname, "template0") == 0)
1496 continue;
1497
1498 /* Skip any explicitly excluded database */
1499 if (simple_string_list_member(&database_exclude_names, dbname))
1500 {
1501 pg_log_info("excluding database \"%s\"", dbname);
1502 continue;
1503 }
1504
1505 pg_log_info("dumping database \"%s\"", dbname);
1506
1507 fprintf(OPF, "--\n-- Database \"%s\" dump\n--\n\n", dbname);
1508
1509 /*
1510 * We assume that "template1" and "postgres" already exist in the
1511 * target installation. dropDBs() won't have removed them, for fear
1512 * of removing the DB the restore script is initially connected to. If
1513 * --clean was specified, tell pg_dump to drop and recreate them;
1514 * otherwise we'll merely restore their contents. Other databases
1515 * should simply be created.
1516 */
1517 if (strcmp(dbname, "template1") == 0 || strcmp(dbname, "postgres") == 0)
1518 {
1519 if (output_clean)
1520 create_opts = "--clean --create";
1521 else
1522 {
1523 create_opts = "";
1524 /* Since pg_dump won't emit a \connect command, we must */
1525 fprintf(OPF, "\\connect %s\n\n", dbname);
1526 }
1527 }
1528 else
1529 create_opts = "--create";
1530
1531 if (filename)
1532 fclose(OPF);
1533
1534 ret = runPgDump(dbname, create_opts);
1535 if (ret != 0)
1536 {
1537 pg_log_error("pg_dump failed on database \"%s\", exiting", dbname);
1538 exit_nicely(1);
1539 }
1540
1541 if (filename)
1542 {
1543 OPF = fopen(filename, PG_BINARY_A);
1544 if (!OPF)
1545 {
1546 pg_log_error("could not re-open the output file \"%s\": %m",
1547 filename);
1548 exit_nicely(1);
1549 }
1550 }
1551
1552 }
1553
1554 PQclear(res);
1555 }
1556
1557
1558
1559 /*
1560 * Run pg_dump on dbname, with specified options.
1561 */
1562 static int
runPgDump(const char * dbname,const char * create_opts)1563 runPgDump(const char *dbname, const char *create_opts)
1564 {
1565 PQExpBuffer connstrbuf = createPQExpBuffer();
1566 PQExpBuffer cmd = createPQExpBuffer();
1567 int ret;
1568
1569 appendPQExpBuffer(cmd, "\"%s\" %s %s", pg_dump_bin,
1570 pgdumpopts->data, create_opts);
1571
1572 /*
1573 * If we have a filename, use the undocumented plain-append pg_dump
1574 * format.
1575 */
1576 if (filename)
1577 appendPQExpBufferStr(cmd, " -Fa ");
1578 else
1579 appendPQExpBufferStr(cmd, " -Fp ");
1580
1581 /*
1582 * Append the database name to the already-constructed stem of connection
1583 * string.
1584 */
1585 appendPQExpBuffer(connstrbuf, "%s dbname=", connstr);
1586 appendConnStrVal(connstrbuf, dbname);
1587
1588 appendShellString(cmd, connstrbuf->data);
1589
1590 pg_log_info("running \"%s\"", cmd->data);
1591
1592 fflush(stdout);
1593 fflush(stderr);
1594
1595 ret = system(cmd->data);
1596
1597 destroyPQExpBuffer(cmd);
1598 destroyPQExpBuffer(connstrbuf);
1599
1600 return ret;
1601 }
1602
1603 /*
1604 * buildShSecLabels
1605 *
1606 * Build SECURITY LABEL command(s) for a shared object
1607 *
1608 * The caller has to provide object type and identity in two separate formats:
1609 * catalog_name (e.g., "pg_database") and object OID, as well as
1610 * type name (e.g., "DATABASE") and object name (not pre-quoted).
1611 *
1612 * The command(s) are appended to "buffer".
1613 */
1614 static void
buildShSecLabels(PGconn * conn,const char * catalog_name,Oid objectId,const char * objtype,const char * objname,PQExpBuffer buffer)1615 buildShSecLabels(PGconn *conn, const char *catalog_name, Oid objectId,
1616 const char *objtype, const char *objname,
1617 PQExpBuffer buffer)
1618 {
1619 PQExpBuffer sql = createPQExpBuffer();
1620 PGresult *res;
1621
1622 buildShSecLabelQuery(catalog_name, objectId, sql);
1623 res = executeQuery(conn, sql->data);
1624 emitShSecLabels(conn, res, buffer, objtype, objname);
1625
1626 PQclear(res);
1627 destroyPQExpBuffer(sql);
1628 }
1629
1630 /*
1631 * Make a database connection with the given parameters. An
1632 * interactive password prompt is automatically issued if required.
1633 *
1634 * If fail_on_error is false, we return NULL without printing any message
1635 * on failure, but preserve any prompted password for the next try.
1636 *
1637 * On success, the global variable 'connstr' is set to a connection string
1638 * containing the options used.
1639 */
1640 static PGconn *
connectDatabase(const char * dbname,const char * connection_string,const char * pghost,const char * pgport,const char * pguser,trivalue prompt_password,bool fail_on_error)1641 connectDatabase(const char *dbname, const char *connection_string,
1642 const char *pghost, const char *pgport, const char *pguser,
1643 trivalue prompt_password, bool fail_on_error)
1644 {
1645 PGconn *conn;
1646 bool new_pass;
1647 const char *remoteversion_str;
1648 int my_version;
1649 const char **keywords = NULL;
1650 const char **values = NULL;
1651 PQconninfoOption *conn_opts = NULL;
1652 static char *password = NULL;
1653
1654 if (prompt_password == TRI_YES && !password)
1655 password = simple_prompt("Password: ", false);
1656
1657 /*
1658 * Start the connection. Loop until we have a password if requested by
1659 * backend.
1660 */
1661 do
1662 {
1663 int argcount = 6;
1664 PQconninfoOption *conn_opt;
1665 char *err_msg = NULL;
1666 int i = 0;
1667
1668 if (keywords)
1669 free(keywords);
1670 if (values)
1671 free(values);
1672 if (conn_opts)
1673 PQconninfoFree(conn_opts);
1674
1675 /*
1676 * Merge the connection info inputs given in form of connection string
1677 * and other options. Explicitly discard any dbname value in the
1678 * connection string; otherwise, PQconnectdbParams() would interpret
1679 * that value as being itself a connection string.
1680 */
1681 if (connection_string)
1682 {
1683 conn_opts = PQconninfoParse(connection_string, &err_msg);
1684 if (conn_opts == NULL)
1685 {
1686 pg_log_error("%s", err_msg);
1687 exit_nicely(1);
1688 }
1689
1690 for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
1691 {
1692 if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
1693 strcmp(conn_opt->keyword, "dbname") != 0)
1694 argcount++;
1695 }
1696
1697 keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
1698 values = pg_malloc0((argcount + 1) * sizeof(*values));
1699
1700 for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
1701 {
1702 if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
1703 strcmp(conn_opt->keyword, "dbname") != 0)
1704 {
1705 keywords[i] = conn_opt->keyword;
1706 values[i] = conn_opt->val;
1707 i++;
1708 }
1709 }
1710 }
1711 else
1712 {
1713 keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
1714 values = pg_malloc0((argcount + 1) * sizeof(*values));
1715 }
1716
1717 if (pghost)
1718 {
1719 keywords[i] = "host";
1720 values[i] = pghost;
1721 i++;
1722 }
1723 if (pgport)
1724 {
1725 keywords[i] = "port";
1726 values[i] = pgport;
1727 i++;
1728 }
1729 if (pguser)
1730 {
1731 keywords[i] = "user";
1732 values[i] = pguser;
1733 i++;
1734 }
1735 if (password)
1736 {
1737 keywords[i] = "password";
1738 values[i] = password;
1739 i++;
1740 }
1741 if (dbname)
1742 {
1743 keywords[i] = "dbname";
1744 values[i] = dbname;
1745 i++;
1746 }
1747 keywords[i] = "fallback_application_name";
1748 values[i] = progname;
1749 i++;
1750
1751 new_pass = false;
1752 conn = PQconnectdbParams(keywords, values, true);
1753
1754 if (!conn)
1755 {
1756 pg_log_error("could not connect to database \"%s\"", dbname);
1757 exit_nicely(1);
1758 }
1759
1760 if (PQstatus(conn) == CONNECTION_BAD &&
1761 PQconnectionNeedsPassword(conn) &&
1762 !password &&
1763 prompt_password != TRI_NO)
1764 {
1765 PQfinish(conn);
1766 password = simple_prompt("Password: ", false);
1767 new_pass = true;
1768 }
1769 } while (new_pass);
1770
1771 /* check to see that the backend connection was successfully made */
1772 if (PQstatus(conn) == CONNECTION_BAD)
1773 {
1774 if (fail_on_error)
1775 {
1776 pg_log_error("%s", PQerrorMessage(conn));
1777 exit_nicely(1);
1778 }
1779 else
1780 {
1781 PQfinish(conn);
1782
1783 free(keywords);
1784 free(values);
1785 PQconninfoFree(conn_opts);
1786
1787 return NULL;
1788 }
1789 }
1790
1791 /*
1792 * Ok, connected successfully. Remember the options used, in the form of a
1793 * connection string.
1794 */
1795 connstr = constructConnStr(keywords, values);
1796
1797 free(keywords);
1798 free(values);
1799 PQconninfoFree(conn_opts);
1800
1801 /* Check version */
1802 remoteversion_str = PQparameterStatus(conn, "server_version");
1803 if (!remoteversion_str)
1804 {
1805 pg_log_error("could not get server version");
1806 exit_nicely(1);
1807 }
1808 server_version = PQserverVersion(conn);
1809 if (server_version == 0)
1810 {
1811 pg_log_error("could not parse server version \"%s\"",
1812 remoteversion_str);
1813 exit_nicely(1);
1814 }
1815
1816 my_version = PG_VERSION_NUM;
1817
1818 /*
1819 * We allow the server to be back to 8.0, and up to any minor release of
1820 * our own major version. (See also version check in pg_dump.c.)
1821 */
1822 if (my_version != server_version
1823 && (server_version < 80000 ||
1824 (server_version / 100) > (my_version / 100)))
1825 {
1826 pg_log_error("server version: %s; %s version: %s",
1827 remoteversion_str, progname, PG_VERSION);
1828 pg_log_error("aborting because of server version mismatch");
1829 exit_nicely(1);
1830 }
1831
1832 PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL));
1833
1834 return conn;
1835 }
1836
1837 /* ----------
1838 * Construct a connection string from the given keyword/value pairs. It is
1839 * used to pass the connection options to the pg_dump subprocess.
1840 *
1841 * The following parameters are excluded:
1842 * dbname - varies in each pg_dump invocation
1843 * password - it's not secure to pass a password on the command line
1844 * fallback_application_name - we'll let pg_dump set it
1845 * ----------
1846 */
1847 static char *
constructConnStr(const char ** keywords,const char ** values)1848 constructConnStr(const char **keywords, const char **values)
1849 {
1850 PQExpBuffer buf = createPQExpBuffer();
1851 char *connstr;
1852 int i;
1853 bool firstkeyword = true;
1854
1855 /* Construct a new connection string in key='value' format. */
1856 for (i = 0; keywords[i] != NULL; i++)
1857 {
1858 if (strcmp(keywords[i], "dbname") == 0 ||
1859 strcmp(keywords[i], "password") == 0 ||
1860 strcmp(keywords[i], "fallback_application_name") == 0)
1861 continue;
1862
1863 if (!firstkeyword)
1864 appendPQExpBufferChar(buf, ' ');
1865 firstkeyword = false;
1866 appendPQExpBuffer(buf, "%s=", keywords[i]);
1867 appendConnStrVal(buf, values[i]);
1868 }
1869
1870 connstr = pg_strdup(buf->data);
1871 destroyPQExpBuffer(buf);
1872 return connstr;
1873 }
1874
1875 /*
1876 * Run a query, return the results, exit program on failure.
1877 */
1878 static PGresult *
executeQuery(PGconn * conn,const char * query)1879 executeQuery(PGconn *conn, const char *query)
1880 {
1881 PGresult *res;
1882
1883 pg_log_info("executing %s", query);
1884
1885 res = PQexec(conn, query);
1886 if (!res ||
1887 PQresultStatus(res) != PGRES_TUPLES_OK)
1888 {
1889 pg_log_error("query failed: %s", PQerrorMessage(conn));
1890 pg_log_error("query was: %s", query);
1891 PQfinish(conn);
1892 exit_nicely(1);
1893 }
1894
1895 return res;
1896 }
1897
1898 /*
1899 * As above for a SQL command (which returns nothing).
1900 */
1901 static void
executeCommand(PGconn * conn,const char * query)1902 executeCommand(PGconn *conn, const char *query)
1903 {
1904 PGresult *res;
1905
1906 pg_log_info("executing %s", query);
1907
1908 res = PQexec(conn, query);
1909 if (!res ||
1910 PQresultStatus(res) != PGRES_COMMAND_OK)
1911 {
1912 pg_log_error("query failed: %s", PQerrorMessage(conn));
1913 pg_log_error("query was: %s", query);
1914 PQfinish(conn);
1915 exit_nicely(1);
1916 }
1917
1918 PQclear(res);
1919 }
1920
1921
1922 /*
1923 * dumpTimestamp
1924 */
1925 static void
dumpTimestamp(const char * msg)1926 dumpTimestamp(const char *msg)
1927 {
1928 char buf[64];
1929 time_t now = time(NULL);
1930
1931 if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&now)) != 0)
1932 fprintf(OPF, "-- %s %s\n\n", msg, buf);
1933 }
1934