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