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