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