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