Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_dumpall.c
4 : * pg_dumpall dumps all databases and global objects (roles and
5 : * tablespaces) from a PostgreSQL cluster.
6 : *
7 : * For text format output, globals are written directly and pg_dump is
8 : * invoked for each database, with all output going to stdout or a file.
9 : *
10 : * For non-text formats (custom, directory, tar), a directory is created
11 : * containing a toc.glo file with global objects, a map.dat file mapping
12 : * database OIDs to names, and a databases/ subdirectory with individual
13 : * pg_dump archives for each database.
14 : *
15 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
16 : * Portions Copyright (c) 1994, Regents of the University of California
17 : *
18 : * src/bin/pg_dump/pg_dumpall.c
19 : *
20 : *-------------------------------------------------------------------------
21 : */
22 :
23 : #include "postgres_fe.h"
24 :
25 : #include <time.h>
26 : #include <unistd.h>
27 :
28 : #include "catalog/pg_authid_d.h"
29 : #include "common/connect.h"
30 : #include "common/file_perm.h"
31 : #include "common/file_utils.h"
32 : #include "common/hashfn_unstable.h"
33 : #include "common/logging.h"
34 : #include "common/string.h"
35 : #include "connectdb.h"
36 : #include "dumputils.h"
37 : #include "fe_utils/option_utils.h"
38 : #include "fe_utils/string_utils.h"
39 : #include "filter.h"
40 : #include "getopt_long.h"
41 : #include "pg_backup_archiver.h"
42 :
43 : /* version string we expect back from pg_dump */
44 : #define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
45 :
46 : typedef struct
47 : {
48 : uint32 status;
49 : uint32 hashval;
50 : char *rolename;
51 : } RoleNameEntry;
52 :
53 : #define SH_PREFIX rolename
54 : #define SH_ELEMENT_TYPE RoleNameEntry
55 : #define SH_KEY_TYPE char *
56 : #define SH_KEY rolename
57 : #define SH_HASH_KEY(tb, key) hash_string(key)
58 : #define SH_EQUAL(tb, a, b) (strcmp(a, b) == 0)
59 : #define SH_STORE_HASH
60 : #define SH_GET_HASH(tb, a) (a)->hashval
61 : #define SH_SCOPE static inline
62 : #define SH_RAW_ALLOCATOR pg_malloc0
63 : #define SH_DECLARE
64 : #define SH_DEFINE
65 : #include "lib/simplehash.h"
66 :
67 : static void help(void);
68 :
69 : static void dropRoles(PGconn *conn);
70 : static void dumpRoles(PGconn *conn);
71 : static void dumpRoleMembership(PGconn *conn);
72 : static void dumpRoleGUCPrivs(PGconn *conn);
73 : static void dropTablespaces(PGconn *conn);
74 : static void dumpTablespaces(PGconn *conn);
75 : static void dropDBs(PGconn *conn);
76 : static void dumpUserConfig(PGconn *conn, const char *username);
77 : static void dumpDatabases(PGconn *conn);
78 : static void dumpTimestamp(const char *msg);
79 : static int runPgDump(const char *dbname, const char *create_opts, char *dbfile);
80 : static void buildShSecLabels(PGconn *conn,
81 : const char *catalog_name, Oid objectId,
82 : const char *objtype, const char *objname,
83 : PQExpBuffer buffer);
84 : static void executeCommand(PGconn *conn, const char *query);
85 : static void check_for_invalid_global_names(PGconn *conn,
86 : SimpleStringList *database_exclude_names);
87 : static void expand_dbname_patterns(PGconn *conn, SimpleStringList *patterns,
88 : SimpleStringList *names);
89 : static void read_dumpall_filters(const char *filename, SimpleStringList *pattern);
90 : static ArchiveFormat parseDumpFormat(const char *format);
91 : static int createDumpId(void);
92 :
93 : static char pg_dump_bin[MAXPGPATH];
94 : static PQExpBuffer pgdumpopts;
95 : static const char *connstr = "";
96 : static bool output_clean = false;
97 : static bool skip_acls = false;
98 : static bool verbose = false;
99 : static bool dosync = true;
100 :
101 : static int binary_upgrade = 0;
102 : static int column_inserts = 0;
103 : static int disable_dollar_quoting = 0;
104 : static int disable_triggers = 0;
105 : static int if_exists = 0;
106 : static int inserts = 0;
107 : static int no_table_access_method = 0;
108 : static int no_tablespaces = 0;
109 : static int use_setsessauth = 0;
110 : static int no_comments = 0;
111 : static int no_policies = 0;
112 : static int no_publications = 0;
113 : static int no_security_labels = 0;
114 : static int no_data = 0;
115 : static int no_schema = 0;
116 : static int no_statistics = 0;
117 : static int no_subscriptions = 0;
118 : static int no_toast_compression = 0;
119 : static int no_unlogged_table_data = 0;
120 : static int no_role_passwords = 0;
121 : static int with_statistics = 0;
122 : static int server_version;
123 : static int load_via_partition_root = 0;
124 : static int on_conflict_do_nothing = 0;
125 : static int statistics_only = 0;
126 : static int sequence_data = 0;
127 :
128 : static char role_catalog[10];
129 : #define PG_AUTHID "pg_authid"
130 : #define PG_ROLES "pg_roles "
131 :
132 : static FILE *OPF;
133 : static char *filename = NULL;
134 :
135 : static SimpleStringList database_exclude_patterns = {NULL, NULL};
136 : static SimpleStringList database_exclude_names = {NULL, NULL};
137 :
138 : static char *restrict_key;
139 : static Archive *fout = NULL;
140 : static int dumpIdVal = 0;
141 : static ArchiveFormat archDumpFormat = archNull;
142 : static const CatalogId nilCatalogId = {0, 0};
143 :
144 : int
145 85 : main(int argc, char *argv[])
146 : {
147 : static struct option long_options[] = {
148 : {"data-only", no_argument, NULL, 'a'},
149 : {"clean", no_argument, NULL, 'c'},
150 : {"encoding", required_argument, NULL, 'E'},
151 : {"file", required_argument, NULL, 'f'},
152 : {"globals-only", no_argument, NULL, 'g'},
153 : {"host", required_argument, NULL, 'h'},
154 : {"dbname", required_argument, NULL, 'd'},
155 : {"database", required_argument, NULL, 'l'},
156 : {"no-owner", no_argument, NULL, 'O'},
157 : {"port", required_argument, NULL, 'p'},
158 : {"roles-only", no_argument, NULL, 'r'},
159 : {"schema-only", no_argument, NULL, 's'},
160 : {"superuser", required_argument, NULL, 'S'},
161 : {"tablespaces-only", no_argument, NULL, 't'},
162 : {"username", required_argument, NULL, 'U'},
163 : {"verbose", no_argument, NULL, 'v'},
164 : {"no-password", no_argument, NULL, 'w'},
165 : {"password", no_argument, NULL, 'W'},
166 : {"no-privileges", no_argument, NULL, 'x'},
167 : {"no-acl", no_argument, NULL, 'x'},
168 : {"format", required_argument, NULL, 'F'},
169 :
170 : /*
171 : * the following options don't have an equivalent short option letter
172 : */
173 : {"attribute-inserts", no_argument, &column_inserts, 1},
174 : {"binary-upgrade", no_argument, &binary_upgrade, 1},
175 : {"column-inserts", no_argument, &column_inserts, 1},
176 : {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
177 : {"disable-triggers", no_argument, &disable_triggers, 1},
178 : {"exclude-database", required_argument, NULL, 6},
179 : {"extra-float-digits", required_argument, NULL, 5},
180 : {"if-exists", no_argument, &if_exists, 1},
181 : {"inserts", no_argument, &inserts, 1},
182 : {"lock-wait-timeout", required_argument, NULL, 2},
183 : {"no-table-access-method", no_argument, &no_table_access_method, 1},
184 : {"no-tablespaces", no_argument, &no_tablespaces, 1},
185 : {"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
186 : {"load-via-partition-root", no_argument, &load_via_partition_root, 1},
187 : {"role", required_argument, NULL, 3},
188 : {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
189 : {"no-comments", no_argument, &no_comments, 1},
190 : {"no-data", no_argument, &no_data, 1},
191 : {"no-policies", no_argument, &no_policies, 1},
192 : {"no-publications", no_argument, &no_publications, 1},
193 : {"no-role-passwords", no_argument, &no_role_passwords, 1},
194 : {"no-schema", no_argument, &no_schema, 1},
195 : {"no-security-labels", no_argument, &no_security_labels, 1},
196 : {"no-subscriptions", no_argument, &no_subscriptions, 1},
197 : {"no-statistics", no_argument, &no_statistics, 1},
198 : {"no-sync", no_argument, NULL, 4},
199 : {"no-toast-compression", no_argument, &no_toast_compression, 1},
200 : {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
201 : {"on-conflict-do-nothing", no_argument, &on_conflict_do_nothing, 1},
202 : {"rows-per-insert", required_argument, NULL, 7},
203 : {"statistics", no_argument, &with_statistics, 1},
204 : {"statistics-only", no_argument, &statistics_only, 1},
205 : {"filter", required_argument, NULL, 8},
206 : {"sequence-data", no_argument, &sequence_data, 1},
207 : {"restrict-key", required_argument, NULL, 9},
208 :
209 : {NULL, 0, NULL, 0}
210 : };
211 :
212 85 : char *pghost = NULL;
213 85 : char *pgport = NULL;
214 85 : char *pguser = NULL;
215 85 : char *pgdb = NULL;
216 85 : char *use_role = NULL;
217 85 : const char *dumpencoding = NULL;
218 85 : const char *format_name = "p";
219 85 : trivalue prompt_password = TRI_DEFAULT;
220 85 : bool data_only = false;
221 85 : bool globals_only = false;
222 85 : bool roles_only = false;
223 85 : bool schema_only = false;
224 85 : bool tablespaces_only = false;
225 : PGconn *conn;
226 : int encoding;
227 : int c,
228 : ret;
229 : int optindex;
230 : DumpOptions dopt;
231 :
232 85 : pg_logging_init(argv[0]);
233 85 : pg_logging_set_level(PG_LOG_WARNING);
234 85 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
235 85 : progname = get_progname(argv[0]);
236 :
237 85 : if (argc > 1)
238 : {
239 85 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
240 : {
241 1 : help();
242 1 : exit_nicely(0);
243 : }
244 84 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
245 : {
246 20 : puts("pg_dumpall (PostgreSQL) " PG_VERSION);
247 20 : exit_nicely(0);
248 : }
249 : }
250 :
251 64 : if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR,
252 : pg_dump_bin)) < 0)
253 : {
254 : char full_path[MAXPGPATH];
255 :
256 0 : if (find_my_exec(argv[0], full_path) < 0)
257 0 : strlcpy(full_path, progname, sizeof(full_path));
258 :
259 0 : if (ret == -1)
260 0 : pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"",
261 : "pg_dump", progname, full_path);
262 : else
263 0 : pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s",
264 : "pg_dump", full_path, progname);
265 : }
266 :
267 64 : pgdumpopts = createPQExpBuffer();
268 64 : InitDumpOptions(&dopt);
269 :
270 304 : while ((c = getopt_long(argc, argv, "acd:E:f:F:gh:l:Op:rsS:tU:vwWx", long_options, &optindex)) != -1)
271 : {
272 244 : switch (c)
273 : {
274 2 : case 'a':
275 2 : data_only = true;
276 2 : appendPQExpBufferStr(pgdumpopts, " -a");
277 2 : break;
278 :
279 3 : case 'c':
280 3 : output_clean = true;
281 3 : break;
282 :
283 9 : case 'd':
284 9 : connstr = pg_strdup(optarg);
285 9 : break;
286 :
287 0 : case 'E':
288 0 : dumpencoding = pg_strdup(optarg);
289 0 : appendPQExpBufferStr(pgdumpopts, " -E ");
290 0 : appendShellString(pgdumpopts, optarg);
291 0 : break;
292 :
293 46 : case 'f':
294 46 : filename = pg_strdup(optarg);
295 46 : appendPQExpBufferStr(pgdumpopts, " -f ");
296 46 : appendShellString(pgdumpopts, filename);
297 46 : break;
298 14 : case 'F':
299 14 : format_name = pg_strdup(optarg);
300 14 : break;
301 21 : case 'g':
302 21 : globals_only = true;
303 21 : break;
304 :
305 12 : case 'h':
306 12 : pghost = pg_strdup(optarg);
307 12 : break;
308 :
309 0 : case 'l':
310 0 : pgdb = pg_strdup(optarg);
311 0 : break;
312 :
313 0 : case 'O':
314 0 : appendPQExpBufferStr(pgdumpopts, " -O");
315 0 : break;
316 :
317 20 : case 'p':
318 20 : pgport = pg_strdup(optarg);
319 20 : break;
320 :
321 7 : case 'r':
322 7 : roles_only = true;
323 7 : break;
324 :
325 1 : case 's':
326 1 : schema_only = true;
327 1 : appendPQExpBufferStr(pgdumpopts, " -s");
328 1 : break;
329 :
330 0 : case 'S':
331 0 : appendPQExpBufferStr(pgdumpopts, " -S ");
332 0 : appendShellString(pgdumpopts, optarg);
333 0 : break;
334 :
335 3 : case 't':
336 3 : tablespaces_only = true;
337 3 : break;
338 :
339 18 : case 'U':
340 18 : pguser = pg_strdup(optarg);
341 18 : dopt.cparams.username = pg_strdup(optarg);
342 18 : break;
343 :
344 2 : case 'v':
345 2 : verbose = true;
346 2 : pg_logging_increase_verbosity();
347 2 : appendPQExpBufferStr(pgdumpopts, " -v");
348 2 : break;
349 :
350 0 : case 'w':
351 0 : prompt_password = TRI_NO;
352 0 : appendPQExpBufferStr(pgdumpopts, " -w");
353 0 : break;
354 :
355 0 : case 'W':
356 0 : prompt_password = TRI_YES;
357 0 : appendPQExpBufferStr(pgdumpopts, " -W");
358 0 : break;
359 :
360 0 : case 'x':
361 0 : skip_acls = true;
362 0 : appendPQExpBufferStr(pgdumpopts, " -x");
363 0 : break;
364 :
365 39 : case 0:
366 39 : break;
367 :
368 0 : case 2:
369 0 : appendPQExpBufferStr(pgdumpopts, " --lock-wait-timeout ");
370 0 : appendShellString(pgdumpopts, optarg);
371 0 : break;
372 :
373 0 : case 3:
374 0 : use_role = pg_strdup(optarg);
375 0 : appendPQExpBufferStr(pgdumpopts, " --role ");
376 0 : appendShellString(pgdumpopts, use_role);
377 0 : break;
378 :
379 28 : case 4:
380 28 : dosync = false;
381 28 : appendPQExpBufferStr(pgdumpopts, " --no-sync");
382 28 : break;
383 :
384 0 : case 5:
385 0 : appendPQExpBufferStr(pgdumpopts, " --extra-float-digits ");
386 0 : appendShellString(pgdumpopts, optarg);
387 0 : break;
388 :
389 6 : case 6:
390 6 : simple_string_list_append(&database_exclude_patterns, optarg);
391 6 : break;
392 :
393 0 : case 7:
394 0 : appendPQExpBufferStr(pgdumpopts, " --rows-per-insert ");
395 0 : appendShellString(pgdumpopts, optarg);
396 0 : break;
397 :
398 5 : case 8:
399 5 : read_dumpall_filters(optarg, &database_exclude_patterns);
400 2 : break;
401 :
402 7 : case 9:
403 7 : restrict_key = pg_strdup(optarg);
404 7 : appendPQExpBufferStr(pgdumpopts, " --restrict-key ");
405 7 : appendShellString(pgdumpopts, optarg);
406 7 : break;
407 :
408 1 : default:
409 : /* getopt_long already emitted a complaint */
410 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
411 1 : exit_nicely(1);
412 : }
413 : }
414 :
415 : /* Complain if any arguments remain */
416 60 : if (optind < argc)
417 : {
418 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
419 : argv[optind]);
420 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
421 1 : exit_nicely(1);
422 : }
423 :
424 : /* --exclude-database is incompatible with global *-only options */
425 59 : check_mut_excl_opts(database_exclude_patterns.head, "--exclude-database",
426 : globals_only, "-g/--globals-only",
427 : roles_only, "-r/--roles-only",
428 : tablespaces_only, "-t/--tablespaces-only");
429 :
430 : /* *-only options are incompatible with each other */
431 54 : check_mut_excl_opts(data_only, "-a/--data-only",
432 : globals_only, "-g/--globals-only",
433 : roles_only, "-r/--roles-only",
434 : schema_only, "-s/--schema-only",
435 : statistics_only, "--statistics-only",
436 : tablespaces_only, "-t/--tablespaces-only");
437 :
438 : /* --no-* and *-only for same thing are incompatible */
439 54 : check_mut_excl_opts(data_only, "-a/--data-only",
440 : no_data, "--no-data");
441 53 : check_mut_excl_opts(schema_only, "-s/--schema-only",
442 : no_schema, "--no-schema");
443 52 : check_mut_excl_opts(statistics_only, "--statistics-only",
444 : no_statistics, "--no-statistics");
445 :
446 : /* --statistics and --no-statistics are incompatible */
447 51 : check_mut_excl_opts(with_statistics, "--statistics",
448 : no_statistics, "--no-statistics");
449 :
450 : /* --statistics is incompatible with *-only (except --statistics-only) */
451 50 : check_mut_excl_opts(with_statistics, "--statistics",
452 : data_only, "-a/--data-only",
453 : globals_only, "-g/--globals-only",
454 : roles_only, "-r/--roles-only",
455 : schema_only, "-s/--schema-only",
456 : tablespaces_only, "-t/--tablespaces-only");
457 :
458 : /* --clean and --data-only are incompatible */
459 49 : check_mut_excl_opts(output_clean, "-c/--clean",
460 : data_only, "-a/--data-only");
461 :
462 48 : if (if_exists && !output_clean)
463 1 : pg_fatal("option %s requires option %s",
464 : "--if-exists", "-c/--clean");
465 :
466 : /* Get format for dump. */
467 47 : archDumpFormat = parseDumpFormat(format_name);
468 :
469 : /*
470 : * If a non-plain format is specified, a file name is also required as the
471 : * path to the main directory.
472 : */
473 46 : if (archDumpFormat != archNull &&
474 13 : (!filename || strcmp(filename, "") == 0))
475 : {
476 1 : pg_log_error("option %s=d|c|t requires option %s",
477 : "-F/--format", "-f/--file");
478 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
479 1 : exit_nicely(1);
480 : }
481 :
482 : /* restrict-key is only supported with --format=plain */
483 45 : if (archDumpFormat != archNull && restrict_key)
484 1 : pg_fatal("option %s can only be used with %s=plain",
485 : "--restrict-key", "--format");
486 :
487 : /* --clean and -g/--globals-only cannot be used together in non-text dump */
488 44 : if (archDumpFormat != archNull && output_clean && globals_only)
489 1 : pg_fatal("options %s and %s cannot be used together in non-text dump",
490 : "--clean", "-g/--globals-only");
491 :
492 : /*
493 : * If password values are not required in the dump, switch to using
494 : * pg_roles which is equally useful, just more likely to have unrestricted
495 : * access than pg_authid.
496 : */
497 43 : if (no_role_passwords)
498 0 : sprintf(role_catalog, "%s", PG_ROLES);
499 : else
500 43 : sprintf(role_catalog, "%s", PG_AUTHID);
501 :
502 : /* Add long options to the pg_dump argument list */
503 43 : if (binary_upgrade)
504 12 : appendPQExpBufferStr(pgdumpopts, " --binary-upgrade");
505 43 : if (column_inserts)
506 0 : appendPQExpBufferStr(pgdumpopts, " --column-inserts");
507 43 : if (disable_dollar_quoting)
508 0 : appendPQExpBufferStr(pgdumpopts, " --disable-dollar-quoting");
509 43 : if (disable_triggers)
510 0 : appendPQExpBufferStr(pgdumpopts, " --disable-triggers");
511 43 : if (inserts)
512 0 : appendPQExpBufferStr(pgdumpopts, " --inserts");
513 43 : if (no_table_access_method)
514 0 : appendPQExpBufferStr(pgdumpopts, " --no-table-access-method");
515 43 : if (no_tablespaces)
516 0 : appendPQExpBufferStr(pgdumpopts, " --no-tablespaces");
517 43 : if (quote_all_identifiers)
518 12 : appendPQExpBufferStr(pgdumpopts, " --quote-all-identifiers");
519 43 : if (load_via_partition_root)
520 0 : appendPQExpBufferStr(pgdumpopts, " --load-via-partition-root");
521 43 : if (use_setsessauth)
522 0 : appendPQExpBufferStr(pgdumpopts, " --use-set-session-authorization");
523 43 : if (no_comments)
524 0 : appendPQExpBufferStr(pgdumpopts, " --no-comments");
525 43 : if (no_data)
526 0 : appendPQExpBufferStr(pgdumpopts, " --no-data");
527 43 : if (no_policies)
528 0 : appendPQExpBufferStr(pgdumpopts, " --no-policies");
529 43 : if (no_publications)
530 0 : appendPQExpBufferStr(pgdumpopts, " --no-publications");
531 43 : if (no_security_labels)
532 0 : appendPQExpBufferStr(pgdumpopts, " --no-security-labels");
533 43 : if (no_schema)
534 0 : appendPQExpBufferStr(pgdumpopts, " --no-schema");
535 43 : if (no_statistics)
536 2 : appendPQExpBufferStr(pgdumpopts, " --no-statistics");
537 43 : if (no_subscriptions)
538 0 : appendPQExpBufferStr(pgdumpopts, " --no-subscriptions");
539 43 : if (no_toast_compression)
540 0 : appendPQExpBufferStr(pgdumpopts, " --no-toast-compression");
541 43 : if (no_unlogged_table_data)
542 3 : appendPQExpBufferStr(pgdumpopts, " --no-unlogged-table-data");
543 43 : if (with_statistics)
544 2 : appendPQExpBufferStr(pgdumpopts, " --statistics");
545 43 : if (on_conflict_do_nothing)
546 0 : appendPQExpBufferStr(pgdumpopts, " --on-conflict-do-nothing");
547 43 : if (statistics_only)
548 0 : appendPQExpBufferStr(pgdumpopts, " --statistics-only");
549 43 : if (sequence_data)
550 0 : appendPQExpBufferStr(pgdumpopts, " --sequence-data");
551 :
552 : /*
553 : * Open the output file if required, otherwise use stdout. If required,
554 : * then create new directory.
555 : */
556 43 : if (archDumpFormat != archNull)
557 : {
558 : Assert(filename);
559 :
560 : /* Create new directory or accept the empty existing directory. */
561 10 : create_or_open_dir(filename);
562 : }
563 33 : else if (filename)
564 : {
565 30 : OPF = fopen(filename, PG_BINARY_W);
566 30 : if (!OPF)
567 0 : pg_fatal("could not open output file \"%s\": %m",
568 : filename);
569 : }
570 : else
571 3 : OPF = stdout;
572 :
573 : /*
574 : * If you don't provide a restrict key, one will be appointed for you.
575 : */
576 43 : if (!restrict_key)
577 37 : restrict_key = generate_restrict_key();
578 43 : if (!restrict_key)
579 0 : pg_fatal("could not generate restrict key");
580 43 : if (!valid_restrict_key(restrict_key))
581 0 : pg_fatal("invalid restrict key");
582 :
583 : /*
584 : * If there was a database specified on the command line, use that,
585 : * otherwise try to connect to database "postgres", and failing that
586 : * "template1".
587 : */
588 43 : if (pgdb)
589 : {
590 0 : conn = ConnectDatabase(pgdb, connstr, pghost, pgport, pguser,
591 : prompt_password, false,
592 : progname, &connstr, &server_version, NULL, NULL);
593 :
594 0 : if (!conn)
595 0 : pg_fatal("could not connect to database \"%s\"", pgdb);
596 : }
597 : else
598 : {
599 43 : conn = ConnectDatabase("postgres", connstr, pghost, pgport, pguser,
600 : prompt_password, false,
601 : progname, &connstr, &server_version, NULL, NULL);
602 43 : if (!conn)
603 0 : conn = ConnectDatabase("template1", connstr, pghost, pgport, pguser,
604 : prompt_password, true,
605 : progname, &connstr, &server_version, NULL, NULL);
606 :
607 43 : if (!conn)
608 : {
609 0 : pg_log_error("could not connect to databases \"postgres\" or \"template1\"\n"
610 : "Please specify an alternative database.");
611 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
612 0 : exit_nicely(1);
613 : }
614 : }
615 :
616 : /*
617 : * Get a list of database names that match the exclude patterns
618 : */
619 43 : expand_dbname_patterns(conn, &database_exclude_patterns,
620 : &database_exclude_names);
621 :
622 : /*
623 : * Set the client encoding if requested.
624 : */
625 41 : if (dumpencoding)
626 : {
627 0 : if (PQsetClientEncoding(conn, dumpencoding) < 0)
628 0 : pg_fatal("invalid client encoding \"%s\" specified",
629 : dumpencoding);
630 : }
631 :
632 : /*
633 : * Force standard_conforming_strings on, just in case we are dumping from
634 : * an old server that has it disabled. Without this, literals in views,
635 : * expressions, etc, would be incorrect for modern servers.
636 : */
637 41 : executeCommand(conn, "SET standard_conforming_strings = on");
638 :
639 : /*
640 : * Get the active encoding, so we know how to escape strings.
641 : */
642 41 : encoding = PQclientEncoding(conn);
643 41 : setFmtEncoding(encoding);
644 :
645 : /* Set the role if requested */
646 41 : if (use_role)
647 : {
648 0 : PQExpBuffer query = createPQExpBuffer();
649 :
650 0 : appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
651 0 : executeCommand(conn, query->data);
652 0 : destroyPQExpBuffer(query);
653 : }
654 :
655 : /* Force quoting of all identifiers if requested. */
656 41 : if (quote_all_identifiers)
657 12 : executeCommand(conn, "SET quote_all_identifiers = true");
658 :
659 : /* create a archive file for global commands. */
660 41 : if (archDumpFormat != archNull)
661 : {
662 10 : PQExpBuffer qry = createPQExpBuffer();
663 : char global_path[MAXPGPATH];
664 : const char *encname;
665 10 : pg_compress_specification compression_spec = {0};
666 :
667 : /*
668 : * Check that no global object names contain newlines or carriage
669 : * returns, which would break the map.dat file format. This is only
670 : * needed for servers older than v19, which started prohibiting such
671 : * names.
672 : */
673 10 : if (server_version < 190000)
674 0 : check_for_invalid_global_names(conn, &database_exclude_names);
675 :
676 : /* Set file path for global sql commands. */
677 10 : snprintf(global_path, MAXPGPATH, "%s/toc.glo", filename);
678 :
679 : /* Open the output file */
680 10 : fout = CreateArchive(global_path, archCustom, compression_spec,
681 : dosync, archModeWrite, NULL, DATA_DIR_SYNC_METHOD_FSYNC);
682 :
683 : /* Make dump options accessible right away */
684 10 : SetArchiveOptions(fout, &dopt, NULL);
685 :
686 10 : ((ArchiveHandle *) fout)->connection = conn;
687 10 : ((ArchiveHandle *) fout)->public.numWorkers = 1;
688 :
689 : /* Register the cleanup hook */
690 10 : on_exit_close_archive(fout);
691 :
692 : /* Let the archiver know how noisy to be */
693 10 : fout->verbose = verbose;
694 :
695 : /*
696 : * We allow the server to be back to 9.2, and up to any minor release
697 : * of our own major version. (See also version check in
698 : * pg_dumpall.c.)
699 : */
700 10 : fout->minRemoteVersion = 90200;
701 10 : fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
702 10 : fout->numWorkers = 1;
703 :
704 : /* Dump default_transaction_read_only. */
705 10 : appendPQExpBufferStr(qry, "SET default_transaction_read_only = off;\n\n");
706 10 : ArchiveEntry(fout,
707 : nilCatalogId, /* catalog ID */
708 : createDumpId(), /* dump ID */
709 10 : ARCHIVE_OPTS(.tag = "default_transaction_read_only",
710 : .description = "default_transaction_read_only",
711 : .section = SECTION_PRE_DATA,
712 : .createStmt = qry->data));
713 10 : resetPQExpBuffer(qry);
714 :
715 : /* Put the correct encoding into the archive */
716 10 : encname = pg_encoding_to_char(encoding);
717 :
718 10 : appendPQExpBufferStr(qry, "SET client_encoding = ");
719 10 : appendStringLiteralAH(qry, encname, fout);
720 10 : appendPQExpBufferStr(qry, ";\n");
721 10 : ArchiveEntry(fout,
722 : nilCatalogId, /* catalog ID */
723 : createDumpId(), /* dump ID */
724 10 : ARCHIVE_OPTS(.tag = "client_encoding",
725 : .description = "client_encoding",
726 : .section = SECTION_PRE_DATA,
727 : .createStmt = qry->data));
728 10 : resetPQExpBuffer(qry);
729 :
730 : /* Put the correct escape string behavior into the archive. */
731 10 : appendPQExpBuffer(qry, "SET standard_conforming_strings = 'on';\n");
732 10 : ArchiveEntry(fout,
733 : nilCatalogId, /* catalog ID */
734 : createDumpId(), /* dump ID */
735 10 : ARCHIVE_OPTS(.tag = "standard_conforming_strings",
736 : .description = "standard_conforming_strings",
737 : .section = SECTION_PRE_DATA,
738 : .createStmt = qry->data));
739 10 : destroyPQExpBuffer(qry);
740 : }
741 : else
742 : {
743 31 : fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n");
744 :
745 31 : if (verbose)
746 2 : dumpTimestamp("Started on");
747 :
748 : /*
749 : * Enter restricted mode to block any unexpected psql meta-commands. A
750 : * malicious source might try to inject a variety of things via bogus
751 : * responses to queries. While we cannot prevent such sources from
752 : * affecting the destination at restore time, we can block psql
753 : * meta-commands so that the client machine that runs psql with the
754 : * dump output remains unaffected.
755 : */
756 31 : fprintf(OPF, "\\restrict %s\n\n", restrict_key);
757 :
758 : /*
759 : * We used to emit \connect postgres here, but that served no purpose
760 : * other than to break things for installations without a postgres
761 : * database. Everything we're restoring here is a global, so
762 : * whichever database we're connected to at the moment is fine.
763 : */
764 :
765 : /* Restore will need to write to the target cluster */
766 31 : fprintf(OPF, "SET default_transaction_read_only = off;\n\n");
767 :
768 : /* Replicate encoding and standard_conforming_strings in output */
769 31 : fprintf(OPF, "SET client_encoding = '%s';\n",
770 : pg_encoding_to_char(encoding));
771 31 : fprintf(OPF, "SET standard_conforming_strings = on;\n");
772 31 : fprintf(OPF, "\n");
773 : }
774 :
775 41 : if (!data_only && !statistics_only && !no_schema)
776 : {
777 : /*
778 : * If asked to --clean, do that first. We can avoid detailed
779 : * dependency analysis because databases never depend on each other,
780 : * and tablespaces never depend on each other. Roles could have
781 : * grants to each other, but DROP ROLE will clean those up silently.
782 : *
783 : * For non-text formats, pg_dumpall unconditionally process --clean
784 : * option. In contrast, pg_restore only applies it if the user
785 : * explicitly provides the flag. This discrepancy resolves corner
786 : * cases where pg_restore requires cleanup instructions that may be
787 : * missing from a standard pg_dumpall output.
788 : */
789 41 : if (output_clean || archDumpFormat != archNull)
790 : {
791 11 : if (!globals_only && !roles_only && !tablespaces_only)
792 9 : dropDBs(conn);
793 :
794 11 : if (!roles_only && !no_tablespaces)
795 11 : dropTablespaces(conn);
796 :
797 11 : if (!tablespaces_only)
798 11 : dropRoles(conn);
799 : }
800 :
801 : /*
802 : * Now create objects as requested. Be careful that option logic here
803 : * is the same as for drops above.
804 : */
805 41 : if (!tablespaces_only)
806 : {
807 : /* Dump roles (users) */
808 41 : dumpRoles(conn);
809 :
810 : /* Dump role memberships */
811 41 : dumpRoleMembership(conn);
812 :
813 : /* Dump role GUC privileges */
814 41 : if (server_version >= 150000 && !skip_acls)
815 41 : dumpRoleGUCPrivs(conn);
816 : }
817 :
818 : /* Dump tablespaces */
819 41 : if (!roles_only && !no_tablespaces)
820 36 : dumpTablespaces(conn);
821 : }
822 :
823 41 : if (archDumpFormat == archNull)
824 : {
825 : /*
826 : * Exit restricted mode just before dumping the databases. pg_dump
827 : * will handle entering restricted mode again as appropriate.
828 : */
829 31 : fprintf(OPF, "\\unrestrict %s\n\n", restrict_key);
830 : }
831 :
832 41 : if (!globals_only && !roles_only && !tablespaces_only)
833 20 : dumpDatabases(conn);
834 :
835 41 : if (archDumpFormat == archNull)
836 : {
837 31 : PQfinish(conn);
838 :
839 31 : if (verbose)
840 2 : dumpTimestamp("Completed on");
841 31 : fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n");
842 :
843 31 : if (filename)
844 : {
845 30 : fclose(OPF);
846 :
847 : /* sync the resulting file, errors are not fatal */
848 30 : if (dosync)
849 3 : (void) fsync_fname(filename, false);
850 : }
851 : }
852 : else
853 : {
854 : RestoreOptions *ropt;
855 :
856 10 : ropt = NewRestoreOptions();
857 10 : SetArchiveOptions(fout, &dopt, ropt);
858 :
859 : /* Mark which entries should be output */
860 10 : ProcessArchiveRestoreOptions(fout);
861 10 : CloseArchive(fout);
862 : }
863 :
864 41 : exit_nicely(0);
865 : }
866 :
867 :
868 : static void
869 1 : help(void)
870 : {
871 1 : printf(_("%s exports a PostgreSQL database cluster as an SQL script or to other formats.\n\n"), progname);
872 1 : printf(_("Usage:\n"));
873 1 : printf(_(" %s [OPTION]...\n"), progname);
874 :
875 1 : printf(_("\nGeneral options:\n"));
876 1 : printf(_(" -f, --file=FILENAME output file name\n"));
877 1 : printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
878 : " plain text (default))\n"));
879 1 : printf(_(" -v, --verbose verbose mode\n"));
880 1 : printf(_(" -V, --version output version information, then exit\n"));
881 1 : printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
882 1 : printf(_(" -?, --help show this help, then exit\n"));
883 1 : printf(_("\nOptions controlling the output content:\n"));
884 1 : printf(_(" -a, --data-only dump only the data, not the schema or statistics\n"));
885 1 : printf(_(" -c, --clean clean (drop) databases before recreating\n"));
886 1 : printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
887 1 : printf(_(" -g, --globals-only dump only global objects, no databases\n"));
888 1 : printf(_(" -O, --no-owner skip restoration of object ownership\n"));
889 1 : printf(_(" -r, --roles-only dump only roles, no databases or tablespaces\n"));
890 1 : printf(_(" -s, --schema-only dump only the schema, no data or statistics\n"));
891 1 : printf(_(" -S, --superuser=NAME superuser user name to use in the dump\n"));
892 1 : printf(_(" -t, --tablespaces-only dump only tablespaces, no databases or roles\n"));
893 1 : printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
894 1 : printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
895 1 : printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
896 1 : printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
897 1 : printf(_(" --disable-triggers disable triggers during data-only restore\n"));
898 1 : printf(_(" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n"));
899 1 : printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
900 1 : printf(_(" --filter=FILENAME exclude databases based on expressions in FILENAME\n"));
901 1 : printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
902 1 : printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
903 1 : printf(_(" --load-via-partition-root load partitions via the root table\n"));
904 1 : printf(_(" --no-comments do not dump comment commands\n"));
905 1 : printf(_(" --no-data do not dump data\n"));
906 1 : printf(_(" --no-policies do not dump row security policies\n"));
907 1 : printf(_(" --no-publications do not dump publications\n"));
908 1 : printf(_(" --no-role-passwords do not dump passwords for roles\n"));
909 1 : printf(_(" --no-schema do not dump schema\n"));
910 1 : printf(_(" --no-security-labels do not dump security label assignments\n"));
911 1 : printf(_(" --no-statistics do not dump statistics\n"));
912 1 : printf(_(" --no-subscriptions do not dump subscriptions\n"));
913 1 : printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
914 1 : printf(_(" --no-table-access-method do not dump table access methods\n"));
915 1 : printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
916 1 : printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
917 1 : printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
918 1 : printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
919 1 : printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
920 1 : printf(_(" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n"));
921 1 : printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
922 1 : printf(_(" --sequence-data include sequence data in dump\n"));
923 1 : printf(_(" --statistics dump the statistics\n"));
924 1 : printf(_(" --statistics-only dump only the statistics, not schema or data\n"));
925 1 : printf(_(" --use-set-session-authorization\n"
926 : " use SET SESSION AUTHORIZATION commands instead of\n"
927 : " ALTER OWNER commands to set ownership\n"));
928 :
929 1 : printf(_("\nConnection options:\n"));
930 1 : printf(_(" -d, --dbname=CONNSTR connect using connection string\n"));
931 1 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
932 1 : printf(_(" -l, --database=DBNAME alternative default database\n"));
933 1 : printf(_(" -p, --port=PORT database server port number\n"));
934 1 : printf(_(" -U, --username=NAME connect as specified database user\n"));
935 1 : printf(_(" -w, --no-password never prompt for password\n"));
936 1 : printf(_(" -W, --password force password prompt (should happen automatically)\n"));
937 1 : printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
938 :
939 1 : printf(_("\nIf -f/--file is not used, then the SQL script will be written to the standard\n"
940 : "output.\n\n"));
941 1 : printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
942 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
943 1 : }
944 :
945 :
946 : /*
947 : * Drop roles
948 : */
949 : static void
950 11 : dropRoles(PGconn *conn)
951 : {
952 11 : PQExpBuffer buf = createPQExpBuffer();
953 : PGresult *res;
954 : int i_rolname;
955 : int i;
956 :
957 11 : if (server_version >= 90600)
958 11 : printfPQExpBuffer(buf,
959 : "SELECT rolname "
960 : "FROM %s "
961 : "WHERE rolname !~ '^pg_' "
962 : "ORDER BY 1", role_catalog);
963 : else
964 0 : printfPQExpBuffer(buf,
965 : "SELECT rolname "
966 : "FROM %s "
967 : "ORDER BY 1", role_catalog);
968 :
969 11 : res = executeQuery(conn, buf->data);
970 :
971 11 : i_rolname = PQfnumber(res, "rolname");
972 :
973 11 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
974 1 : fprintf(OPF, "--\n-- Drop roles\n--\n\n");
975 :
976 144 : for (i = 0; i < PQntuples(res); i++)
977 : {
978 : const char *rolename;
979 133 : PQExpBuffer delQry = createPQExpBuffer();
980 :
981 133 : rolename = PQgetvalue(res, i, i_rolname);
982 :
983 133 : if (archDumpFormat == archNull)
984 : {
985 6 : appendPQExpBuffer(delQry, "DROP ROLE %s%s;\n",
986 3 : if_exists ? "IF EXISTS " : "",
987 : fmtId(rolename));
988 3 : fprintf(OPF, "%s", delQry->data);
989 : }
990 : else
991 : {
992 130 : appendPQExpBuffer(delQry, "DROP ROLE IF EXISTS %s;\n",
993 : fmtId(rolename));
994 :
995 130 : ArchiveEntry(fout,
996 : nilCatalogId, /* catalog ID */
997 : createDumpId(), /* dump ID */
998 130 : ARCHIVE_OPTS(.tag = psprintf("ROLE %s", fmtId(rolename)),
999 : .description = "DROP_GLOBAL",
1000 : .section = SECTION_PRE_DATA,
1001 : .createStmt = delQry->data));
1002 : }
1003 :
1004 133 : destroyPQExpBuffer(delQry);
1005 : }
1006 :
1007 11 : PQclear(res);
1008 11 : destroyPQExpBuffer(buf);
1009 :
1010 11 : if (archDumpFormat == archNull)
1011 1 : fprintf(OPF, "\n\n");
1012 11 : }
1013 :
1014 : /*
1015 : * Dump roles
1016 : */
1017 : static void
1018 41 : dumpRoles(PGconn *conn)
1019 : {
1020 41 : PQExpBuffer buf = createPQExpBuffer();
1021 41 : PQExpBuffer comment_buf = createPQExpBuffer();
1022 41 : PQExpBuffer seclabel_buf = createPQExpBuffer();
1023 : PGresult *res;
1024 : int i_oid,
1025 : i_rolname,
1026 : i_rolsuper,
1027 : i_rolinherit,
1028 : i_rolcreaterole,
1029 : i_rolcreatedb,
1030 : i_rolcanlogin,
1031 : i_rolconnlimit,
1032 : i_rolpassword,
1033 : i_rolvaliduntil,
1034 : i_rolreplication,
1035 : i_rolbypassrls,
1036 : i_rolcomment,
1037 : i_is_current_user;
1038 : int i;
1039 :
1040 : /*
1041 : * Notes: rolconfig is dumped later, and pg_authid must be used for
1042 : * extracting rolcomment regardless of role_catalog.
1043 : */
1044 41 : if (server_version >= 90600)
1045 41 : printfPQExpBuffer(buf,
1046 : "SELECT oid, rolname, rolsuper, rolinherit, "
1047 : "rolcreaterole, rolcreatedb, "
1048 : "rolcanlogin, rolconnlimit, rolpassword, "
1049 : "rolvaliduntil, rolreplication, rolbypassrls, "
1050 : "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
1051 : "rolname = current_user AS is_current_user "
1052 : "FROM %s "
1053 : "WHERE rolname !~ '^pg_' "
1054 : "ORDER BY 2", role_catalog);
1055 0 : else if (server_version >= 90500)
1056 0 : printfPQExpBuffer(buf,
1057 : "SELECT oid, rolname, rolsuper, rolinherit, "
1058 : "rolcreaterole, rolcreatedb, "
1059 : "rolcanlogin, rolconnlimit, rolpassword, "
1060 : "rolvaliduntil, rolreplication, rolbypassrls, "
1061 : "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
1062 : "rolname = current_user AS is_current_user "
1063 : "FROM %s "
1064 : "ORDER BY 2", role_catalog);
1065 : else
1066 0 : printfPQExpBuffer(buf,
1067 : "SELECT oid, rolname, rolsuper, rolinherit, "
1068 : "rolcreaterole, rolcreatedb, "
1069 : "rolcanlogin, rolconnlimit, rolpassword, "
1070 : "rolvaliduntil, rolreplication, "
1071 : "false as rolbypassrls, "
1072 : "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
1073 : "rolname = current_user AS is_current_user "
1074 : "FROM %s "
1075 : "ORDER BY 2", role_catalog);
1076 :
1077 41 : res = executeQuery(conn, buf->data);
1078 :
1079 41 : i_oid = PQfnumber(res, "oid");
1080 41 : i_rolname = PQfnumber(res, "rolname");
1081 41 : i_rolsuper = PQfnumber(res, "rolsuper");
1082 41 : i_rolinherit = PQfnumber(res, "rolinherit");
1083 41 : i_rolcreaterole = PQfnumber(res, "rolcreaterole");
1084 41 : i_rolcreatedb = PQfnumber(res, "rolcreatedb");
1085 41 : i_rolcanlogin = PQfnumber(res, "rolcanlogin");
1086 41 : i_rolconnlimit = PQfnumber(res, "rolconnlimit");
1087 41 : i_rolpassword = PQfnumber(res, "rolpassword");
1088 41 : i_rolvaliduntil = PQfnumber(res, "rolvaliduntil");
1089 41 : i_rolreplication = PQfnumber(res, "rolreplication");
1090 41 : i_rolbypassrls = PQfnumber(res, "rolbypassrls");
1091 41 : i_rolcomment = PQfnumber(res, "rolcomment");
1092 41 : i_is_current_user = PQfnumber(res, "is_current_user");
1093 :
1094 41 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1095 31 : fprintf(OPF, "--\n-- Roles\n--\n\n");
1096 :
1097 248 : for (i = 0; i < PQntuples(res); i++)
1098 : {
1099 : const char *rolename;
1100 : Oid auth_oid;
1101 :
1102 207 : auth_oid = atooid(PQgetvalue(res, i, i_oid));
1103 207 : rolename = PQgetvalue(res, i, i_rolname);
1104 :
1105 207 : if (strncmp(rolename, "pg_", 3) == 0)
1106 : {
1107 0 : pg_log_warning("role name starting with \"pg_\" skipped (%s)",
1108 : rolename);
1109 0 : continue;
1110 : }
1111 :
1112 207 : resetPQExpBuffer(buf);
1113 207 : resetPQExpBuffer(comment_buf);
1114 207 : resetPQExpBuffer(seclabel_buf);
1115 :
1116 207 : if (binary_upgrade)
1117 : {
1118 22 : appendPQExpBufferStr(buf, "\n-- For binary upgrade, must preserve pg_authid.oid\n");
1119 22 : appendPQExpBuffer(buf,
1120 : "SELECT pg_catalog.binary_upgrade_set_next_pg_authid_oid('%u'::pg_catalog.oid);\n\n",
1121 : auth_oid);
1122 : }
1123 :
1124 : /*
1125 : * We dump CREATE ROLE followed by ALTER ROLE to ensure that the role
1126 : * will acquire the right properties even if it already exists (ie, it
1127 : * won't hurt for the CREATE to fail). This is particularly important
1128 : * for the role we are connected as, since even with --clean we will
1129 : * have failed to drop it. binary_upgrade cannot generate any errors,
1130 : * so we assume the current role is already created.
1131 : */
1132 207 : if (!binary_upgrade ||
1133 22 : strcmp(PQgetvalue(res, i, i_is_current_user), "f") == 0)
1134 195 : appendPQExpBuffer(buf, "CREATE ROLE %s;\n", fmtId(rolename));
1135 207 : appendPQExpBuffer(buf, "ALTER ROLE %s WITH", fmtId(rolename));
1136 :
1137 207 : if (strcmp(PQgetvalue(res, i, i_rolsuper), "t") == 0)
1138 75 : appendPQExpBufferStr(buf, " SUPERUSER");
1139 : else
1140 132 : appendPQExpBufferStr(buf, " NOSUPERUSER");
1141 :
1142 207 : if (strcmp(PQgetvalue(res, i, i_rolinherit), "t") == 0)
1143 207 : appendPQExpBufferStr(buf, " INHERIT");
1144 : else
1145 0 : appendPQExpBufferStr(buf, " NOINHERIT");
1146 :
1147 207 : if (strcmp(PQgetvalue(res, i, i_rolcreaterole), "t") == 0)
1148 65 : appendPQExpBufferStr(buf, " CREATEROLE");
1149 : else
1150 142 : appendPQExpBufferStr(buf, " NOCREATEROLE");
1151 :
1152 207 : if (strcmp(PQgetvalue(res, i, i_rolcreatedb), "t") == 0)
1153 65 : appendPQExpBufferStr(buf, " CREATEDB");
1154 : else
1155 142 : appendPQExpBufferStr(buf, " NOCREATEDB");
1156 :
1157 207 : if (strcmp(PQgetvalue(res, i, i_rolcanlogin), "t") == 0)
1158 66 : appendPQExpBufferStr(buf, " LOGIN");
1159 : else
1160 141 : appendPQExpBufferStr(buf, " NOLOGIN");
1161 :
1162 207 : if (strcmp(PQgetvalue(res, i, i_rolreplication), "t") == 0)
1163 51 : appendPQExpBufferStr(buf, " REPLICATION");
1164 : else
1165 156 : appendPQExpBufferStr(buf, " NOREPLICATION");
1166 :
1167 207 : if (strcmp(PQgetvalue(res, i, i_rolbypassrls), "t") == 0)
1168 41 : appendPQExpBufferStr(buf, " BYPASSRLS");
1169 : else
1170 166 : appendPQExpBufferStr(buf, " NOBYPASSRLS");
1171 :
1172 207 : if (strcmp(PQgetvalue(res, i, i_rolconnlimit), "-1") != 0)
1173 10 : appendPQExpBuffer(buf, " CONNECTION LIMIT %s",
1174 : PQgetvalue(res, i, i_rolconnlimit));
1175 :
1176 :
1177 207 : if (!PQgetisnull(res, i, i_rolpassword) && !no_role_passwords)
1178 : {
1179 10 : appendPQExpBufferStr(buf, " PASSWORD ");
1180 10 : appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolpassword), conn);
1181 : }
1182 :
1183 207 : if (!PQgetisnull(res, i, i_rolvaliduntil))
1184 0 : appendPQExpBuffer(buf, " VALID UNTIL '%s'",
1185 : PQgetvalue(res, i, i_rolvaliduntil));
1186 :
1187 207 : appendPQExpBufferStr(buf, ";\n");
1188 :
1189 207 : if (!no_comments && !PQgetisnull(res, i, i_rolcomment))
1190 : {
1191 0 : appendPQExpBuffer(comment_buf, "COMMENT ON ROLE %s IS ", fmtId(rolename));
1192 0 : appendStringLiteralConn(comment_buf, PQgetvalue(res, i, i_rolcomment), conn);
1193 0 : appendPQExpBufferStr(comment_buf, ";\n");
1194 : }
1195 :
1196 207 : if (!no_security_labels)
1197 207 : buildShSecLabels(conn, "pg_authid", auth_oid,
1198 : "ROLE", rolename,
1199 : seclabel_buf);
1200 :
1201 207 : if (archDumpFormat == archNull)
1202 : {
1203 77 : fprintf(OPF, "%s", buf->data);
1204 77 : fprintf(OPF, "%s", comment_buf->data);
1205 :
1206 77 : if (seclabel_buf->data[0] != '\0')
1207 0 : fprintf(OPF, "%s", seclabel_buf->data);
1208 : }
1209 : else
1210 : {
1211 130 : char *tag = psprintf("ROLE %s", fmtId(rolename));
1212 :
1213 130 : ArchiveEntry(fout,
1214 : nilCatalogId, /* catalog ID */
1215 : createDumpId(), /* dump ID */
1216 130 : ARCHIVE_OPTS(.tag = tag,
1217 : .description = "ROLE",
1218 : .section = SECTION_PRE_DATA,
1219 : .createStmt = buf->data));
1220 130 : if (comment_buf->data[0] != '\0')
1221 0 : ArchiveEntry(fout,
1222 : nilCatalogId, /* catalog ID */
1223 : createDumpId(), /* dump ID */
1224 0 : ARCHIVE_OPTS(.tag = tag,
1225 : .description = "COMMENT",
1226 : .section = SECTION_PRE_DATA,
1227 : .createStmt = comment_buf->data));
1228 :
1229 130 : if (seclabel_buf->data[0] != '\0')
1230 0 : ArchiveEntry(fout,
1231 : nilCatalogId, /* catalog ID */
1232 : createDumpId(), /* dump ID */
1233 0 : ARCHIVE_OPTS(.tag = tag,
1234 : .description = "SECURITY LABEL",
1235 : .section = SECTION_PRE_DATA,
1236 : .createStmt = seclabel_buf->data));
1237 : }
1238 : }
1239 :
1240 : /*
1241 : * Dump configuration settings for roles after all roles have been dumped.
1242 : * We do it this way because config settings for roles could mention the
1243 : * names of other roles.
1244 : */
1245 41 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1246 31 : fprintf(OPF, "\n--\n-- User Configurations\n--\n");
1247 :
1248 248 : for (i = 0; i < PQntuples(res); i++)
1249 207 : dumpUserConfig(conn, PQgetvalue(res, i, i_rolname));
1250 :
1251 41 : PQclear(res);
1252 :
1253 41 : if (archDumpFormat == archNull)
1254 31 : fprintf(OPF, "\n\n");
1255 :
1256 41 : destroyPQExpBuffer(buf);
1257 41 : destroyPQExpBuffer(comment_buf);
1258 41 : destroyPQExpBuffer(seclabel_buf);
1259 41 : }
1260 :
1261 :
1262 : /*
1263 : * Dump role memberships.
1264 : *
1265 : * Note: we expect dumpRoles already created all the roles, but there is
1266 : * no membership yet.
1267 : */
1268 : static void
1269 41 : dumpRoleMembership(PGconn *conn)
1270 : {
1271 41 : PQExpBuffer buf = createPQExpBuffer();
1272 41 : PQExpBuffer querybuf = createPQExpBuffer();
1273 41 : PQExpBuffer optbuf = createPQExpBuffer();
1274 : PGresult *res;
1275 41 : int start = 0,
1276 : end,
1277 : total;
1278 : bool dump_grantors;
1279 : bool dump_grant_options;
1280 : int i_role;
1281 : int i_member;
1282 : int i_grantor;
1283 : int i_roleid;
1284 : int i_memberid;
1285 : int i_grantorid;
1286 : int i_admin_option;
1287 : int i_inherit_option;
1288 : int i_set_option;
1289 :
1290 : /*
1291 : * Previous versions of PostgreSQL didn't used to track the grantor very
1292 : * carefully in the backend, and the grantor could be any user even if
1293 : * they didn't have ADMIN OPTION on the role, or a user that no longer
1294 : * existed. To avoid dump and restore failures, don't dump the grantor
1295 : * when talking to an old server version.
1296 : *
1297 : * Also, in older versions the roleid and/or member could be role OIDs
1298 : * that no longer exist. If we find such cases, print a warning and skip
1299 : * the entry.
1300 : */
1301 41 : dump_grantors = (server_version >= 160000);
1302 :
1303 : /*
1304 : * Previous versions of PostgreSQL also did not have grant-level options.
1305 : */
1306 41 : dump_grant_options = (server_version >= 160000);
1307 :
1308 : /* Generate and execute query. */
1309 41 : printfPQExpBuffer(buf, "SELECT ur.rolname AS role, "
1310 : "um.rolname AS member, "
1311 : "ug.rolname AS grantor, "
1312 : "a.roleid AS roleid, "
1313 : "a.member AS memberid, "
1314 : "a.grantor AS grantorid, "
1315 : "a.admin_option");
1316 41 : if (dump_grant_options)
1317 41 : appendPQExpBufferStr(buf, ", a.inherit_option, a.set_option");
1318 41 : appendPQExpBuffer(buf, " FROM pg_auth_members a "
1319 : "LEFT JOIN %s ur on ur.oid = a.roleid "
1320 : "LEFT JOIN %s um on um.oid = a.member "
1321 : "LEFT JOIN %s ug on ug.oid = a.grantor "
1322 : "WHERE NOT (ur.rolname ~ '^pg_' AND um.rolname ~ '^pg_')"
1323 : "ORDER BY 1,2,3", role_catalog, role_catalog, role_catalog);
1324 41 : res = executeQuery(conn, buf->data);
1325 41 : i_role = PQfnumber(res, "role");
1326 41 : i_member = PQfnumber(res, "member");
1327 41 : i_grantor = PQfnumber(res, "grantor");
1328 41 : i_roleid = PQfnumber(res, "roleid");
1329 41 : i_memberid = PQfnumber(res, "memberid");
1330 41 : i_grantorid = PQfnumber(res, "grantorid");
1331 41 : i_admin_option = PQfnumber(res, "admin_option");
1332 41 : i_inherit_option = PQfnumber(res, "inherit_option");
1333 41 : i_set_option = PQfnumber(res, "set_option");
1334 :
1335 41 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1336 0 : fprintf(OPF, "--\n-- Role memberships\n--\n\n");
1337 :
1338 : /*
1339 : * We can't dump these GRANT commands in arbitrary order, because a role
1340 : * that is named as a grantor must already have ADMIN OPTION on the role
1341 : * for which it is granting permissions, except for the bootstrap
1342 : * superuser, who can always be named as the grantor.
1343 : *
1344 : * We handle this by considering these grants role by role. For each role,
1345 : * we initially consider the only allowable grantor to be the bootstrap
1346 : * superuser. Every time we grant ADMIN OPTION on the role to some user,
1347 : * that user also becomes an allowable grantor. We make repeated passes
1348 : * over the grants for the role, each time dumping those whose grantors
1349 : * are allowable and which we haven't done yet. Eventually this should let
1350 : * us dump all the grants.
1351 : */
1352 41 : total = PQntuples(res);
1353 51 : while (start < total)
1354 : {
1355 10 : char *role = PQgetvalue(res, start, i_role);
1356 : int i;
1357 : bool *done;
1358 : int remaining;
1359 10 : int prev_remaining = 0;
1360 : rolename_hash *ht;
1361 :
1362 : /* If we hit a null roleid, we're done (nulls sort to the end). */
1363 10 : if (PQgetisnull(res, start, i_role))
1364 : {
1365 : /* translator: %s represents a numeric role OID */
1366 0 : pg_log_warning("ignoring role grant for missing role with OID %s",
1367 : PQgetvalue(res, start, i_roleid));
1368 0 : break;
1369 : }
1370 :
1371 : /* All memberships for a single role should be adjacent. */
1372 20 : for (end = start; end < total; ++end)
1373 : {
1374 : char *otherrole;
1375 :
1376 10 : otherrole = PQgetvalue(res, end, i_role);
1377 10 : if (strcmp(role, otherrole) != 0)
1378 0 : break;
1379 : }
1380 :
1381 10 : remaining = end - start;
1382 10 : done = pg_malloc0_array(bool, remaining);
1383 :
1384 : /*
1385 : * We use a hashtable to track the member names that have been granted
1386 : * admin option. Usually a hashtable is overkill, but sometimes not.
1387 : */
1388 10 : ht = rolename_create(remaining, NULL);
1389 :
1390 : /*
1391 : * Make repeated passes over the grants for this role until all have
1392 : * been dumped.
1393 : */
1394 20 : while (remaining > 0)
1395 : {
1396 : /*
1397 : * We should make progress on every iteration, because a notional
1398 : * graph whose vertices are grants and whose edges point from
1399 : * grantors to members should be connected and acyclic. If we fail
1400 : * to make progress, either we or the server have messed up.
1401 : */
1402 10 : if (remaining == prev_remaining)
1403 : {
1404 0 : pg_log_error("could not find a legal dump ordering for memberships in role \"%s\"",
1405 : role);
1406 0 : PQfinish(conn);
1407 0 : exit_nicely(1);
1408 : }
1409 10 : prev_remaining = remaining;
1410 :
1411 : /* Make one pass over the grants for this role. */
1412 20 : for (i = start; i < end; ++i)
1413 : {
1414 : char *member;
1415 : char *grantorid;
1416 10 : char *grantor = NULL;
1417 10 : bool dump_this_grantor = dump_grantors;
1418 10 : char *set_option = "true";
1419 : char *admin_option;
1420 : bool found;
1421 :
1422 : /* If we already did this grant, don't do it again. */
1423 10 : if (done[i - start])
1424 0 : continue;
1425 :
1426 : /* Complain about, then ignore, entries for unknown members. */
1427 10 : if (PQgetisnull(res, i, i_member))
1428 : {
1429 : /* translator: %s represents a numeric role OID */
1430 0 : pg_log_warning("ignoring role grant to missing role with OID %s",
1431 : PQgetvalue(res, i, i_memberid));
1432 0 : done[i - start] = true;
1433 0 : --remaining;
1434 0 : continue;
1435 : }
1436 10 : member = PQgetvalue(res, i, i_member);
1437 :
1438 : /* If the grantor is unknown, complain and dump without it. */
1439 10 : grantorid = PQgetvalue(res, i, i_grantorid);
1440 10 : if (dump_this_grantor)
1441 : {
1442 10 : if (PQgetisnull(res, i, i_grantor))
1443 : {
1444 : /* translator: %s represents a numeric role OID */
1445 0 : pg_log_warning("grant of role \"%s\" to \"%s\" has invalid grantor OID %s",
1446 : role, member, grantorid);
1447 0 : pg_log_warning_detail("This grant will be dumped without GRANTED BY.");
1448 0 : dump_this_grantor = false;
1449 : }
1450 : else
1451 10 : grantor = PQgetvalue(res, i, i_grantor);
1452 : }
1453 :
1454 10 : admin_option = PQgetvalue(res, i, i_admin_option);
1455 10 : if (dump_grant_options)
1456 10 : set_option = PQgetvalue(res, i, i_set_option);
1457 :
1458 : /*
1459 : * If we're not dumping the grantor or if the grantor is the
1460 : * bootstrap superuser, it's fine to dump this now. Otherwise,
1461 : * it's got to be someone who has already been granted ADMIN
1462 : * OPTION.
1463 : */
1464 10 : if (dump_this_grantor &&
1465 10 : atooid(grantorid) != BOOTSTRAP_SUPERUSERID &&
1466 0 : rolename_lookup(ht, grantor) == NULL)
1467 0 : continue;
1468 :
1469 : /* Remember that we did this so that we don't do it again. */
1470 10 : done[i - start] = true;
1471 10 : --remaining;
1472 :
1473 : /*
1474 : * If ADMIN OPTION is being granted, remember that grants
1475 : * listing this member as the grantor can now be dumped.
1476 : */
1477 10 : if (*admin_option == 't')
1478 0 : rolename_insert(ht, member, &found);
1479 :
1480 : /* Generate the actual GRANT statement. */
1481 10 : resetPQExpBuffer(optbuf);
1482 10 : resetPQExpBuffer(querybuf);
1483 10 : appendPQExpBuffer(querybuf, "GRANT %s", fmtId(role));
1484 10 : appendPQExpBuffer(querybuf, " TO %s", fmtId(member));
1485 10 : if (*admin_option == 't')
1486 0 : appendPQExpBufferStr(optbuf, "ADMIN OPTION");
1487 10 : if (dump_grant_options)
1488 : {
1489 : char *inherit_option;
1490 :
1491 10 : if (optbuf->data[0] != '\0')
1492 0 : appendPQExpBufferStr(optbuf, ", ");
1493 10 : inherit_option = PQgetvalue(res, i, i_inherit_option);
1494 10 : appendPQExpBuffer(optbuf, "INHERIT %s",
1495 10 : *inherit_option == 't' ?
1496 : "TRUE" : "FALSE");
1497 : }
1498 10 : if (*set_option != 't')
1499 : {
1500 0 : if (optbuf->data[0] != '\0')
1501 0 : appendPQExpBufferStr(optbuf, ", ");
1502 0 : appendPQExpBufferStr(optbuf, "SET FALSE");
1503 : }
1504 10 : if (optbuf->data[0] != '\0')
1505 10 : appendPQExpBuffer(querybuf, " WITH %s", optbuf->data);
1506 10 : if (dump_this_grantor)
1507 10 : appendPQExpBuffer(querybuf, " GRANTED BY %s", fmtId(grantor));
1508 10 : appendPQExpBuffer(querybuf, ";\n");
1509 :
1510 10 : if (archDumpFormat == archNull)
1511 0 : fprintf(OPF, "%s", querybuf->data);
1512 : else
1513 10 : ArchiveEntry(fout,
1514 : nilCatalogId, /* catalog ID */
1515 : createDumpId(), /* dump ID */
1516 10 : ARCHIVE_OPTS(.tag = psprintf("ROLE %s", fmtId(role)),
1517 : .description = "ROLE PROPERTIES",
1518 : .section = SECTION_PRE_DATA,
1519 : .createStmt = querybuf->data));
1520 : }
1521 : }
1522 :
1523 10 : rolename_destroy(ht);
1524 10 : pg_free(done);
1525 10 : start = end;
1526 : }
1527 :
1528 41 : PQclear(res);
1529 41 : destroyPQExpBuffer(buf);
1530 41 : destroyPQExpBuffer(querybuf);
1531 41 : destroyPQExpBuffer(optbuf);
1532 :
1533 41 : if (archDumpFormat == archNull)
1534 31 : fprintf(OPF, "\n\n");
1535 41 : }
1536 :
1537 :
1538 : /*
1539 : * Dump role configuration parameter privileges. This code is used for 15.0
1540 : * and later servers.
1541 : *
1542 : * Note: we expect dumpRoles already created all the roles, but there are
1543 : * no per-role configuration parameter privileges yet.
1544 : */
1545 : static void
1546 41 : dumpRoleGUCPrivs(PGconn *conn)
1547 : {
1548 : PGresult *res;
1549 : int i;
1550 :
1551 : /*
1552 : * Get all parameters that have non-default acls defined.
1553 : */
1554 41 : res = executeQuery(conn, "SELECT parname, "
1555 : "pg_catalog.pg_get_userbyid(" CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS parowner, "
1556 : "paracl, "
1557 : "pg_catalog.acldefault('p', " CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS acldefault "
1558 : "FROM pg_catalog.pg_parameter_acl "
1559 : "ORDER BY 1");
1560 :
1561 41 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1562 1 : fprintf(OPF, "--\n-- Role privileges on configuration parameters\n--\n\n");
1563 :
1564 44 : for (i = 0; i < PQntuples(res); i++)
1565 : {
1566 3 : PQExpBuffer buf = createPQExpBuffer();
1567 3 : char *parname = PQgetvalue(res, i, 0);
1568 3 : char *parowner = PQgetvalue(res, i, 1);
1569 3 : char *paracl = PQgetvalue(res, i, 2);
1570 3 : char *acldefault = PQgetvalue(res, i, 3);
1571 : char *fparname;
1572 :
1573 : /* needed for buildACLCommands() */
1574 3 : fparname = pg_strdup(fmtId(parname));
1575 :
1576 3 : if (!buildACLCommands(fparname, NULL, NULL, "PARAMETER",
1577 : paracl, acldefault,
1578 : parowner, "", server_version, buf))
1579 : {
1580 0 : pg_log_error("could not parse ACL list (%s) for parameter \"%s\"",
1581 : paracl, parname);
1582 0 : PQfinish(conn);
1583 0 : exit_nicely(1);
1584 : }
1585 :
1586 3 : if (archDumpFormat == archNull)
1587 3 : fprintf(OPF, "%s", buf->data);
1588 : else
1589 0 : ArchiveEntry(fout,
1590 : nilCatalogId, /* catalog ID */
1591 : createDumpId(), /* dump ID */
1592 0 : ARCHIVE_OPTS(.tag = psprintf("ROLE %s", fmtId(parowner)),
1593 : .description = "ROLE PROPERTIES",
1594 : .section = SECTION_PRE_DATA,
1595 : .createStmt = buf->data));
1596 :
1597 3 : free(fparname);
1598 3 : destroyPQExpBuffer(buf);
1599 : }
1600 :
1601 41 : PQclear(res);
1602 :
1603 41 : if (archDumpFormat == archNull)
1604 31 : fprintf(OPF, "\n\n");
1605 41 : }
1606 :
1607 :
1608 : /*
1609 : * Drop tablespaces.
1610 : */
1611 : static void
1612 11 : dropTablespaces(PGconn *conn)
1613 : {
1614 : PGresult *res;
1615 : int i;
1616 :
1617 : /*
1618 : * Get all tablespaces except built-in ones (which we assume are named
1619 : * pg_xxx)
1620 : */
1621 11 : res = executeQuery(conn, "SELECT spcname "
1622 : "FROM pg_catalog.pg_tablespace "
1623 : "WHERE spcname !~ '^pg_' "
1624 : "ORDER BY 1");
1625 :
1626 11 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1627 1 : fprintf(OPF, "--\n-- Drop tablespaces\n--\n\n");
1628 :
1629 32 : for (i = 0; i < PQntuples(res); i++)
1630 : {
1631 21 : char *spcname = PQgetvalue(res, i, 0);
1632 21 : PQExpBuffer delQry = createPQExpBuffer();
1633 :
1634 21 : if (archDumpFormat == archNull)
1635 : {
1636 2 : appendPQExpBuffer(delQry, "DROP TABLESPACE %s%s;\n",
1637 1 : if_exists ? "IF EXISTS " : "",
1638 : fmtId(spcname));
1639 1 : fprintf(OPF, "%s", delQry->data);
1640 : }
1641 : else
1642 : {
1643 20 : appendPQExpBuffer(delQry, "DROP TABLESPACE IF EXISTS %s;\n",
1644 : fmtId(spcname));
1645 20 : ArchiveEntry(fout,
1646 : nilCatalogId, /* catalog ID */
1647 : createDumpId(), /* dump ID */
1648 20 : ARCHIVE_OPTS(.tag = psprintf("TABLESPACE %s", fmtId(spcname)),
1649 : .description = "DROP_GLOBAL",
1650 : .section = SECTION_PRE_DATA,
1651 : .createStmt = delQry->data));
1652 : }
1653 :
1654 21 : destroyPQExpBuffer(delQry);
1655 : }
1656 :
1657 11 : PQclear(res);
1658 :
1659 11 : if (archDumpFormat == archNull)
1660 1 : fprintf(OPF, "\n\n");
1661 11 : }
1662 :
1663 : /*
1664 : * Dump tablespaces.
1665 : */
1666 : static void
1667 36 : dumpTablespaces(PGconn *conn)
1668 : {
1669 : PGresult *res;
1670 36 : PQExpBuffer comment_buf = createPQExpBuffer();
1671 36 : PQExpBuffer seclabel_buf = createPQExpBuffer();
1672 : int i;
1673 :
1674 : /*
1675 : * Get all tablespaces except built-in ones (which we assume are named
1676 : * pg_xxx)
1677 : */
1678 36 : res = executeQuery(conn, "SELECT oid, spcname, "
1679 : "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
1680 : "pg_catalog.pg_tablespace_location(oid), "
1681 : "spcacl, acldefault('t', spcowner) AS acldefault, "
1682 : "array_to_string(spcoptions, ', '),"
1683 : "pg_catalog.shobj_description(oid, 'pg_tablespace') "
1684 : "FROM pg_catalog.pg_tablespace "
1685 : "WHERE spcname !~ '^pg_' "
1686 : "ORDER BY 1");
1687 :
1688 36 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1689 12 : fprintf(OPF, "--\n-- Tablespaces\n--\n\n");
1690 :
1691 68 : for (i = 0; i < PQntuples(res); i++)
1692 : {
1693 32 : PQExpBuffer buf = createPQExpBuffer();
1694 32 : Oid spcoid = atooid(PQgetvalue(res, i, 0));
1695 32 : char *spcname = PQgetvalue(res, i, 1);
1696 32 : char *spcowner = PQgetvalue(res, i, 2);
1697 32 : char *spclocation = PQgetvalue(res, i, 3);
1698 32 : char *spcacl = PQgetvalue(res, i, 4);
1699 32 : char *acldefault = PQgetvalue(res, i, 5);
1700 32 : char *spcoptions = PQgetvalue(res, i, 6);
1701 32 : char *spccomment = PQgetvalue(res, i, 7);
1702 : char *fspcname;
1703 :
1704 : /* needed for buildACLCommands() */
1705 32 : fspcname = pg_strdup(fmtId(spcname));
1706 :
1707 32 : resetPQExpBuffer(comment_buf);
1708 32 : resetPQExpBuffer(seclabel_buf);
1709 :
1710 32 : if (binary_upgrade)
1711 : {
1712 5 : appendPQExpBufferStr(buf, "\n-- For binary upgrade, must preserve pg_tablespace oid\n");
1713 5 : appendPQExpBuffer(buf, "SELECT pg_catalog.binary_upgrade_set_next_pg_tablespace_oid('%u'::pg_catalog.oid);\n", spcoid);
1714 : }
1715 :
1716 32 : appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
1717 32 : appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
1718 :
1719 32 : appendPQExpBufferStr(buf, " LOCATION ");
1720 :
1721 : /*
1722 : * In-place tablespaces use a relative path, and need to be dumped
1723 : * with an empty string as location.
1724 : */
1725 32 : if (is_absolute_path(spclocation))
1726 22 : appendStringLiteralConn(buf, spclocation, conn);
1727 : else
1728 10 : appendStringLiteralConn(buf, "", conn);
1729 :
1730 32 : appendPQExpBufferStr(buf, ";\n");
1731 :
1732 32 : if (spcoptions && spcoptions[0] != '\0')
1733 10 : appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n",
1734 : fspcname, spcoptions);
1735 :
1736 : /* tablespaces can't have initprivs */
1737 :
1738 32 : if (!skip_acls &&
1739 32 : !buildACLCommands(fspcname, NULL, NULL, "TABLESPACE",
1740 : spcacl, acldefault,
1741 : spcowner, "", server_version, buf))
1742 : {
1743 0 : pg_log_error("could not parse ACL list (%s) for tablespace \"%s\"",
1744 : spcacl, spcname);
1745 0 : PQfinish(conn);
1746 0 : exit_nicely(1);
1747 : }
1748 :
1749 32 : if (!no_comments && spccomment && spccomment[0] != '\0')
1750 : {
1751 0 : appendPQExpBuffer(comment_buf, "COMMENT ON TABLESPACE %s IS ", fspcname);
1752 0 : appendStringLiteralConn(comment_buf, spccomment, conn);
1753 0 : appendPQExpBufferStr(comment_buf, ";\n");
1754 : }
1755 :
1756 32 : if (!no_security_labels)
1757 32 : buildShSecLabels(conn, "pg_tablespace", spcoid,
1758 : "TABLESPACE", spcname,
1759 : seclabel_buf);
1760 :
1761 32 : if (archDumpFormat == archNull)
1762 : {
1763 12 : fprintf(OPF, "%s", buf->data);
1764 :
1765 12 : if (comment_buf->data[0] != '\0')
1766 0 : fprintf(OPF, "%s", comment_buf->data);
1767 :
1768 12 : if (seclabel_buf->data[0] != '\0')
1769 0 : fprintf(OPF, "%s", seclabel_buf->data);
1770 : }
1771 : else
1772 : {
1773 20 : char *tag = psprintf("TABLESPACE %s", fmtId(fspcname));
1774 :
1775 20 : ArchiveEntry(fout,
1776 : nilCatalogId, /* catalog ID */
1777 : createDumpId(), /* dump ID */
1778 20 : ARCHIVE_OPTS(.tag = tag,
1779 : .description = "TABLESPACE",
1780 : .section = SECTION_PRE_DATA,
1781 : .createStmt = buf->data));
1782 :
1783 20 : if (comment_buf->data[0] != '\0')
1784 0 : ArchiveEntry(fout,
1785 : nilCatalogId, /* catalog ID */
1786 : createDumpId(), /* dump ID */
1787 0 : ARCHIVE_OPTS(.tag = tag,
1788 : .description = "COMMENT",
1789 : .section = SECTION_PRE_DATA,
1790 : .createStmt = comment_buf->data));
1791 :
1792 20 : if (seclabel_buf->data[0] != '\0')
1793 0 : ArchiveEntry(fout,
1794 : nilCatalogId, /* catalog ID */
1795 : createDumpId(), /* dump ID */
1796 0 : ARCHIVE_OPTS(.tag = tag,
1797 : .description = "SECURITY LABEL",
1798 : .section = SECTION_PRE_DATA,
1799 : .createStmt = seclabel_buf->data));
1800 : }
1801 :
1802 32 : free(fspcname);
1803 32 : destroyPQExpBuffer(buf);
1804 : }
1805 :
1806 36 : PQclear(res);
1807 36 : destroyPQExpBuffer(comment_buf);
1808 36 : destroyPQExpBuffer(seclabel_buf);
1809 :
1810 36 : if (archDumpFormat == archNull)
1811 26 : fprintf(OPF, "\n\n");
1812 36 : }
1813 :
1814 :
1815 : /*
1816 : * Dump commands to drop each database.
1817 : */
1818 : static void
1819 9 : dropDBs(PGconn *conn)
1820 : {
1821 : PGresult *res;
1822 : int i;
1823 :
1824 : /*
1825 : * Skip databases marked not datallowconn, since we'd be unable to connect
1826 : * to them anyway. This must agree with dumpDatabases().
1827 : */
1828 9 : res = executeQuery(conn,
1829 : "SELECT datname "
1830 : "FROM pg_database d "
1831 : "WHERE datallowconn AND datconnlimit != -2 "
1832 : "ORDER BY datname");
1833 :
1834 9 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1835 0 : fprintf(OPF, "--\n-- Drop databases (except postgres and template1)\n--\n\n");
1836 :
1837 82 : for (i = 0; i < PQntuples(res); i++)
1838 : {
1839 73 : char *dbname = PQgetvalue(res, i, 0);
1840 :
1841 : /*
1842 : * Skip "postgres" and "template1"; dumpDatabases() will deal with
1843 : * them specially. Also, be sure to skip "template0", even if for
1844 : * some reason it's not marked !datallowconn.
1845 : */
1846 73 : if (strcmp(dbname, "template1") != 0 &&
1847 64 : strcmp(dbname, "template0") != 0 &&
1848 64 : strcmp(dbname, "postgres") != 0)
1849 : {
1850 55 : if (archDumpFormat == archNull)
1851 : {
1852 0 : fprintf(OPF, "DROP DATABASE %s%s;\n",
1853 0 : if_exists ? "IF EXISTS " : "",
1854 : fmtId(dbname));
1855 : }
1856 : else
1857 : {
1858 55 : char *stmt = psprintf("DROP DATABASE IF EXISTS %s;\n",
1859 : fmtId(dbname));
1860 :
1861 55 : ArchiveEntry(fout,
1862 : nilCatalogId, /* catalog ID */
1863 : createDumpId(), /* dump ID */
1864 55 : ARCHIVE_OPTS(.tag = psprintf("DATABASE %s", fmtId(dbname)),
1865 : .description = "DROP_GLOBAL",
1866 : .section = SECTION_PRE_DATA,
1867 : .createStmt = stmt));
1868 55 : pg_free(stmt);
1869 : }
1870 : }
1871 : }
1872 :
1873 9 : PQclear(res);
1874 :
1875 9 : if (archDumpFormat == archNull)
1876 0 : fprintf(OPF, "\n\n");
1877 9 : }
1878 :
1879 :
1880 : /*
1881 : * Dump user-specific configuration
1882 : */
1883 : static void
1884 207 : dumpUserConfig(PGconn *conn, const char *username)
1885 : {
1886 207 : PQExpBuffer buf = createPQExpBuffer();
1887 : PGresult *res;
1888 :
1889 207 : printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
1890 : "WHERE setdatabase = 0 AND setrole = "
1891 : "(SELECT oid FROM %s WHERE rolname = ",
1892 : role_catalog);
1893 207 : appendStringLiteralConn(buf, username, conn);
1894 207 : appendPQExpBufferChar(buf, ')');
1895 :
1896 207 : res = executeQuery(conn, buf->data);
1897 :
1898 207 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1899 : {
1900 : char *sanitized;
1901 :
1902 0 : sanitized = sanitize_line(username, true);
1903 0 : fprintf(OPF, "\n--\n-- User Config \"%s\"\n--\n\n", sanitized);
1904 0 : free(sanitized);
1905 : }
1906 :
1907 207 : for (int i = 0; i < PQntuples(res); i++)
1908 : {
1909 0 : resetPQExpBuffer(buf);
1910 0 : makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
1911 : "ROLE", username, NULL, NULL,
1912 : buf);
1913 :
1914 0 : if (archDumpFormat == archNull)
1915 0 : fprintf(OPF, "%s", buf->data);
1916 : else
1917 0 : ArchiveEntry(fout,
1918 : nilCatalogId, /* catalog ID */
1919 : createDumpId(), /* dump ID */
1920 0 : ARCHIVE_OPTS(.tag = psprintf("ROLE %s", fmtId(username)),
1921 : .description = "ROLE PROPERTIES",
1922 : .section = SECTION_PRE_DATA,
1923 : .createStmt = buf->data));
1924 : }
1925 :
1926 207 : PQclear(res);
1927 :
1928 207 : destroyPQExpBuffer(buf);
1929 207 : }
1930 :
1931 : /*
1932 : * Find a list of database names that match the given patterns.
1933 : * See also expand_table_name_patterns() in pg_dump.c
1934 : */
1935 : static void
1936 43 : expand_dbname_patterns(PGconn *conn,
1937 : SimpleStringList *patterns,
1938 : SimpleStringList *names)
1939 : {
1940 : PQExpBuffer query;
1941 : PGresult *res;
1942 :
1943 43 : if (patterns->head == NULL)
1944 37 : return; /* nothing to do */
1945 :
1946 6 : query = createPQExpBuffer();
1947 :
1948 : /*
1949 : * The loop below runs multiple SELECTs, which might sometimes result in
1950 : * duplicate entries in the name list, but we don't care, since all we're
1951 : * going to do is test membership of the list.
1952 : */
1953 :
1954 10 : for (SimpleStringListCell *cell = patterns->head; cell; cell = cell->next)
1955 : {
1956 : int dotcnt;
1957 :
1958 6 : appendPQExpBufferStr(query,
1959 : "SELECT datname FROM pg_catalog.pg_database n\n");
1960 6 : processSQLNamePattern(conn, query, cell->val, false,
1961 : false, NULL, "datname", NULL, NULL, NULL,
1962 : &dotcnt);
1963 :
1964 6 : if (dotcnt > 0)
1965 : {
1966 2 : pg_log_error("improper qualified name (too many dotted names): %s",
1967 : cell->val);
1968 2 : PQfinish(conn);
1969 2 : exit_nicely(1);
1970 : }
1971 :
1972 4 : res = executeQuery(conn, query->data);
1973 10 : for (int i = 0; i < PQntuples(res); i++)
1974 : {
1975 6 : simple_string_list_append(names, PQgetvalue(res, i, 0));
1976 : }
1977 :
1978 4 : PQclear(res);
1979 4 : resetPQExpBuffer(query);
1980 : }
1981 :
1982 4 : destroyPQExpBuffer(query);
1983 : }
1984 :
1985 : /*
1986 : * Dump contents of databases.
1987 : */
1988 : static void
1989 20 : dumpDatabases(PGconn *conn)
1990 : {
1991 : PGresult *res;
1992 : int i;
1993 : char db_subdir[MAXPGPATH];
1994 : char dbfilepath[MAXPGPATH];
1995 20 : FILE *map_file = NULL;
1996 :
1997 : /*
1998 : * Skip databases marked not datallowconn, since we'd be unable to connect
1999 : * to them anyway. This must agree with dropDBs().
2000 : *
2001 : * We arrange for template1 to be processed first, then we process other
2002 : * DBs in alphabetical order. If we just did them all alphabetically, we
2003 : * might find ourselves trying to drop the "postgres" database while still
2004 : * connected to it. This makes trying to run the restore script while
2005 : * connected to "template1" a bad idea, but there's no fixed order that
2006 : * doesn't have some failure mode with --clean.
2007 : */
2008 20 : res = executeQuery(conn,
2009 : "SELECT datname, oid "
2010 : "FROM pg_database d "
2011 : "WHERE datallowconn AND datconnlimit != -2 "
2012 : "ORDER BY (datname <> 'template1'), datname");
2013 :
2014 20 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
2015 11 : fprintf(OPF, "--\n-- Databases\n--\n\n");
2016 :
2017 : /*
2018 : * If directory/tar/custom format is specified, create a subdirectory
2019 : * under the main directory and each database dump file or subdirectory
2020 : * will be created in that subdirectory by pg_dump.
2021 : */
2022 20 : if (archDumpFormat != archNull)
2023 : {
2024 : char map_file_path[MAXPGPATH];
2025 :
2026 9 : snprintf(db_subdir, MAXPGPATH, "%s/databases", filename);
2027 :
2028 : /* Create a subdirectory with 'databases' name under main directory. */
2029 9 : if (mkdir(db_subdir, pg_dir_create_mode) != 0)
2030 0 : pg_fatal("could not create directory \"%s\": %m", db_subdir);
2031 :
2032 9 : snprintf(map_file_path, MAXPGPATH, "%s/map.dat", filename);
2033 :
2034 : /* Create a map file (to store dboid and dbname) */
2035 9 : map_file = fopen(map_file_path, PG_BINARY_W);
2036 9 : if (!map_file)
2037 0 : pg_fatal("could not open file \"%s\": %m", map_file_path);
2038 :
2039 9 : fprintf(map_file,
2040 : "#################################################################\n"
2041 : "# map.dat\n"
2042 : "#\n"
2043 : "# This file maps oids to database names\n"
2044 : "#\n"
2045 : "# pg_restore will restore all the databases listed here, unless\n"
2046 : "# otherwise excluded. You can also inhibit restoration of a\n"
2047 : "# database by removing the line or commenting out the line with\n"
2048 : "# a # mark.\n"
2049 : "#################################################################\n");
2050 : }
2051 :
2052 145 : for (i = 0; i < PQntuples(res); i++)
2053 : {
2054 125 : char *dbname = PQgetvalue(res, i, 0);
2055 : char *sanitized;
2056 125 : char *oid = PQgetvalue(res, i, 1);
2057 125 : const char *create_opts = "";
2058 : int ret;
2059 :
2060 : /* Skip template0, even if it's not marked !datallowconn. */
2061 125 : if (strcmp(dbname, "template0") == 0)
2062 0 : continue;
2063 :
2064 : /* Skip any explicitly excluded database */
2065 125 : if (simple_string_list_member(&database_exclude_names, dbname))
2066 : {
2067 6 : pg_log_info("excluding database \"%s\"", dbname);
2068 6 : continue;
2069 : }
2070 :
2071 119 : pg_log_info("dumping database \"%s\"", dbname);
2072 :
2073 119 : sanitized = sanitize_line(dbname, true);
2074 :
2075 119 : if (archDumpFormat == archNull)
2076 48 : fprintf(OPF, "--\n-- Database \"%s\" dump\n--\n\n", sanitized);
2077 :
2078 119 : free(sanitized);
2079 :
2080 : /*
2081 : * We assume that "template1" and "postgres" already exist in the
2082 : * target installation. dropDBs() won't have removed them, for fear
2083 : * of removing the DB the restore script is initially connected to. If
2084 : * --clean was specified, tell pg_dump to drop and recreate them;
2085 : * otherwise we'll merely restore their contents. Other databases
2086 : * should simply be created.
2087 : */
2088 119 : if (strcmp(dbname, "template1") == 0 || strcmp(dbname, "postgres") == 0)
2089 : {
2090 39 : if (output_clean)
2091 0 : create_opts = "--clean --create";
2092 : /* Since pg_dump won't emit a \connect command, we must */
2093 39 : else if (archDumpFormat == archNull)
2094 21 : fprintf(OPF, "\\connect %s\n\n", dbname);
2095 : else
2096 18 : create_opts = "";
2097 : }
2098 : else
2099 80 : create_opts = "--create";
2100 :
2101 119 : if (filename && archDumpFormat == archNull)
2102 48 : fclose(OPF);
2103 :
2104 : /*
2105 : * If this is not a plain format dump, then append dboid and dbname to
2106 : * the map.dat file.
2107 : */
2108 119 : if (archDumpFormat != archNull)
2109 : {
2110 71 : if (archDumpFormat == archCustom)
2111 8 : snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\".dmp", db_subdir, oid);
2112 63 : else if (archDumpFormat == archTar)
2113 8 : snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\".tar", db_subdir, oid);
2114 : else
2115 55 : snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\"", db_subdir, oid);
2116 :
2117 : /* Put one line entry for dboid and dbname in map file. */
2118 71 : fprintf(map_file, "%s %s\n", oid, dbname);
2119 : }
2120 :
2121 119 : ret = runPgDump(dbname, create_opts, dbfilepath);
2122 119 : if (ret != 0)
2123 0 : pg_fatal("pg_dump failed on database \"%s\", exiting", dbname);
2124 :
2125 119 : if (filename && archDumpFormat == archNull)
2126 : {
2127 48 : OPF = fopen(filename, PG_BINARY_A);
2128 48 : if (!OPF)
2129 0 : pg_fatal("could not re-open the output file \"%s\": %m",
2130 : filename);
2131 : }
2132 : }
2133 :
2134 : /* Close map file */
2135 20 : if (archDumpFormat != archNull)
2136 9 : fclose(map_file);
2137 :
2138 20 : PQclear(res);
2139 20 : }
2140 :
2141 :
2142 :
2143 : /*
2144 : * Run pg_dump on dbname, with specified options.
2145 : */
2146 : static int
2147 119 : runPgDump(const char *dbname, const char *create_opts, char *dbfile)
2148 : {
2149 : PQExpBufferData connstrbuf;
2150 : PQExpBufferData cmd;
2151 : int ret;
2152 :
2153 119 : initPQExpBuffer(&connstrbuf);
2154 119 : initPQExpBuffer(&cmd);
2155 :
2156 : /*
2157 : * If this is not a plain format dump, then append file name and dump
2158 : * format to the pg_dump command to get archive dump.
2159 : */
2160 119 : if (archDumpFormat != archNull)
2161 : {
2162 71 : printfPQExpBuffer(&cmd, "\"%s\" %s -f %s %s", pg_dump_bin,
2163 71 : pgdumpopts->data, dbfile, create_opts);
2164 :
2165 71 : if (archDumpFormat == archDirectory)
2166 55 : appendPQExpBufferStr(&cmd, " --format=directory ");
2167 16 : else if (archDumpFormat == archCustom)
2168 8 : appendPQExpBufferStr(&cmd, " --format=custom ");
2169 8 : else if (archDumpFormat == archTar)
2170 8 : appendPQExpBufferStr(&cmd, " --format=tar ");
2171 : }
2172 : else
2173 : {
2174 48 : printfPQExpBuffer(&cmd, "\"%s\" %s %s", pg_dump_bin,
2175 48 : pgdumpopts->data, create_opts);
2176 :
2177 : /*
2178 : * If we have a filename, use the undocumented plain-append pg_dump
2179 : * format.
2180 : */
2181 48 : if (filename)
2182 48 : appendPQExpBufferStr(&cmd, " -Fa ");
2183 : else
2184 0 : appendPQExpBufferStr(&cmd, " -Fp ");
2185 : }
2186 :
2187 : /*
2188 : * Append the database name to the already-constructed stem of connection
2189 : * string.
2190 : */
2191 119 : appendPQExpBuffer(&connstrbuf, "%s dbname=", connstr);
2192 119 : appendConnStrVal(&connstrbuf, dbname);
2193 :
2194 119 : appendShellString(&cmd, connstrbuf.data);
2195 :
2196 119 : pg_log_info("running \"%s\"", cmd.data);
2197 :
2198 119 : fflush(NULL);
2199 :
2200 119 : ret = system(cmd.data);
2201 :
2202 119 : termPQExpBuffer(&cmd);
2203 119 : termPQExpBuffer(&connstrbuf);
2204 :
2205 119 : return ret;
2206 : }
2207 :
2208 : /*
2209 : * buildShSecLabels
2210 : *
2211 : * Build SECURITY LABEL command(s) for a shared object
2212 : *
2213 : * The caller has to provide object type and identity in two separate formats:
2214 : * catalog_name (e.g., "pg_database") and object OID, as well as
2215 : * type name (e.g., "DATABASE") and object name (not pre-quoted).
2216 : *
2217 : * The command(s) are appended to "buffer".
2218 : */
2219 : static void
2220 239 : buildShSecLabels(PGconn *conn, const char *catalog_name, Oid objectId,
2221 : const char *objtype, const char *objname,
2222 : PQExpBuffer buffer)
2223 : {
2224 239 : PQExpBuffer sql = createPQExpBuffer();
2225 : PGresult *res;
2226 :
2227 239 : buildShSecLabelQuery(catalog_name, objectId, sql);
2228 239 : res = executeQuery(conn, sql->data);
2229 239 : emitShSecLabels(conn, res, buffer, objtype, objname);
2230 :
2231 239 : PQclear(res);
2232 239 : destroyPQExpBuffer(sql);
2233 239 : }
2234 :
2235 : /*
2236 : * As above for a SQL command (which returns nothing).
2237 : */
2238 : static void
2239 53 : executeCommand(PGconn *conn, const char *query)
2240 : {
2241 : PGresult *res;
2242 :
2243 53 : pg_log_info("executing %s", query);
2244 :
2245 53 : res = PQexec(conn, query);
2246 106 : if (!res ||
2247 53 : PQresultStatus(res) != PGRES_COMMAND_OK)
2248 : {
2249 0 : pg_log_error("query failed: %s", PQerrorMessage(conn));
2250 0 : pg_log_error_detail("Query was: %s", query);
2251 0 : PQfinish(conn);
2252 0 : exit_nicely(1);
2253 : }
2254 :
2255 53 : PQclear(res);
2256 53 : }
2257 :
2258 :
2259 : /*
2260 : * check_for_invalid_global_names
2261 : *
2262 : * Check that no database, role, or tablespace name contains a newline or
2263 : * carriage return character. Such characters in database names would break
2264 : * the map.dat file format used for non-plain-text dumps. Role and tablespace
2265 : * names are also checked because such characters were forbidden starting in
2266 : * v19.
2267 : *
2268 : * Excluded databases are skipped since they won't appear in map.dat.
2269 : */
2270 : static void
2271 0 : check_for_invalid_global_names(PGconn *conn,
2272 : SimpleStringList *database_exclude_names)
2273 : {
2274 : PGresult *res;
2275 : int i;
2276 : PQExpBuffer names;
2277 0 : int count = 0;
2278 :
2279 0 : res = executeQuery(conn,
2280 : "SELECT datname AS objname, 'database' AS objtype "
2281 : "FROM pg_catalog.pg_database "
2282 : "WHERE datallowconn AND datconnlimit != -2 "
2283 : "UNION ALL "
2284 : "SELECT rolname AS objname, 'role' AS objtype "
2285 : "FROM pg_catalog.pg_roles "
2286 : "UNION ALL "
2287 : "SELECT spcname AS objname, 'tablespace' AS objtype "
2288 : "FROM pg_catalog.pg_tablespace");
2289 :
2290 0 : names = createPQExpBuffer();
2291 :
2292 0 : for (i = 0; i < PQntuples(res); i++)
2293 : {
2294 0 : char *objname = PQgetvalue(res, i, 0);
2295 0 : char *objtype = PQgetvalue(res, i, 1);
2296 :
2297 : /* Skip excluded databases since they won't be in map.dat */
2298 0 : if (strcmp(objtype, "database") == 0 &&
2299 0 : simple_string_list_member(database_exclude_names, objname))
2300 0 : continue;
2301 :
2302 0 : if (strpbrk(objname, "\n\r"))
2303 : {
2304 0 : appendPQExpBuffer(names, " %s: \"", objtype);
2305 0 : for (char *p = objname; *p; p++)
2306 : {
2307 0 : if (*p == '\n')
2308 0 : appendPQExpBufferStr(names, "\\n");
2309 0 : else if (*p == '\r')
2310 0 : appendPQExpBufferStr(names, "\\r");
2311 : else
2312 0 : appendPQExpBufferChar(names, *p);
2313 : }
2314 0 : appendPQExpBufferStr(names, "\"\n");
2315 0 : count++;
2316 : }
2317 : }
2318 :
2319 0 : PQclear(res);
2320 :
2321 0 : if (count > 0)
2322 0 : pg_fatal("database, role, or tablespace names contain a newline or carriage return character, which is not supported in non-plain-text dumps:\n%s",
2323 : names->data);
2324 :
2325 0 : destroyPQExpBuffer(names);
2326 0 : }
2327 :
2328 :
2329 : /*
2330 : * dumpTimestamp
2331 : */
2332 : static void
2333 4 : dumpTimestamp(const char *msg)
2334 : {
2335 : char buf[64];
2336 4 : time_t now = time(NULL);
2337 :
2338 4 : if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&now)) != 0)
2339 4 : fprintf(OPF, "-- %s %s\n\n", msg, buf);
2340 4 : }
2341 :
2342 : /*
2343 : * read_dumpall_filters - retrieve database identifier patterns from file
2344 : *
2345 : * Parse the specified filter file for include and exclude patterns, and add
2346 : * them to the relevant lists. If the filename is "-" then filters will be
2347 : * read from STDIN rather than a file.
2348 : *
2349 : * At the moment, the only allowed filter is for database exclusion.
2350 : */
2351 : static void
2352 5 : read_dumpall_filters(const char *filename, SimpleStringList *pattern)
2353 : {
2354 : FilterStateData fstate;
2355 : char *objname;
2356 : FilterCommandType comtype;
2357 : FilterObjectType objtype;
2358 :
2359 5 : filter_init(&fstate, filename, exit);
2360 :
2361 12 : while (filter_read_item(&fstate, &objname, &comtype, &objtype))
2362 : {
2363 3 : if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
2364 : {
2365 0 : pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
2366 : "include",
2367 : filter_object_type_name(objtype));
2368 0 : exit_nicely(1);
2369 : }
2370 :
2371 3 : switch (objtype)
2372 : {
2373 0 : case FILTER_OBJECT_TYPE_NONE:
2374 0 : break;
2375 1 : case FILTER_OBJECT_TYPE_FUNCTION:
2376 : case FILTER_OBJECT_TYPE_INDEX:
2377 : case FILTER_OBJECT_TYPE_TABLE_DATA:
2378 : case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
2379 : case FILTER_OBJECT_TYPE_TRIGGER:
2380 : case FILTER_OBJECT_TYPE_EXTENSION:
2381 : case FILTER_OBJECT_TYPE_FOREIGN_DATA:
2382 : case FILTER_OBJECT_TYPE_SCHEMA:
2383 : case FILTER_OBJECT_TYPE_TABLE:
2384 : case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
2385 1 : pg_log_filter_error(&fstate, _("unsupported filter object"));
2386 1 : exit_nicely(1);
2387 : break;
2388 :
2389 2 : case FILTER_OBJECT_TYPE_DATABASE:
2390 2 : simple_string_list_append(pattern, objname);
2391 2 : break;
2392 : }
2393 :
2394 2 : if (objname)
2395 2 : free(objname);
2396 : }
2397 :
2398 2 : filter_free(&fstate);
2399 2 : }
2400 :
2401 : /*
2402 : * parseDumpFormat
2403 : *
2404 : * This will validate dump formats.
2405 : */
2406 : static ArchiveFormat
2407 47 : parseDumpFormat(const char *format)
2408 : {
2409 : ArchiveFormat archDumpFormat;
2410 :
2411 47 : if (pg_strcasecmp(format, "c") == 0)
2412 0 : archDumpFormat = archCustom;
2413 47 : else if (pg_strcasecmp(format, "custom") == 0)
2414 1 : archDumpFormat = archCustom;
2415 46 : else if (pg_strcasecmp(format, "d") == 0)
2416 3 : archDumpFormat = archDirectory;
2417 43 : else if (pg_strcasecmp(format, "directory") == 0)
2418 8 : archDumpFormat = archDirectory;
2419 35 : else if (pg_strcasecmp(format, "p") == 0)
2420 33 : archDumpFormat = archNull;
2421 2 : else if (pg_strcasecmp(format, "plain") == 0)
2422 0 : archDumpFormat = archNull;
2423 2 : else if (pg_strcasecmp(format, "t") == 0)
2424 0 : archDumpFormat = archTar;
2425 2 : else if (pg_strcasecmp(format, "tar") == 0)
2426 1 : archDumpFormat = archTar;
2427 : else
2428 1 : pg_fatal("unrecognized output format \"%s\"; please specify \"c\", \"d\", \"p\", or \"t\"",
2429 : format);
2430 :
2431 46 : return archDumpFormat;
2432 : }
2433 :
2434 : /*
2435 : * createDumpId
2436 : *
2437 : * Return the next dumpId.
2438 : */
2439 : static int
2440 395 : createDumpId(void)
2441 : {
2442 395 : return ++dumpIdVal;
2443 : }
|