pg_dumpall.c 38.6 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * pg_dumpall.c
4
 *
5
 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
6 7 8
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
9
 * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.106 2008/08/29 17:28:43 alvherre Exp $
10 11 12 13 14 15
 *
 *-------------------------------------------------------------------------
 */

#include "postgres_fe.h"

16
#include <time.h>
17
#include <unistd.h>
18

19 20 21 22
#ifdef ENABLE_NLS
#include <locale.h>
#endif

23
#include "getopt_long.h"
24

25
#ifndef HAVE_INT_OPTRESET
Bruce Momjian's avatar
Bruce Momjian committed
26
int			optreset;
27 28
#endif

29 30 31
#include "dumputils.h"


32 33
/* version string we expect back from pg_dump */
#define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
34

35

36
static const char *progname;
37 38

static void help(void);
39

40
static void dumpRoles(PGconn *conn);
41
static void dumpRoleMembership(PGconn *conn);
42
static void dumpGroups(PGconn *conn);
43
static void dumpTablespaces(PGconn *conn);
44
static void dumpCreateDB(PGconn *conn);
45 46
static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
static void dumpUserConfig(PGconn *conn, const char *username);
47
static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
Bruce Momjian's avatar
Bruce Momjian committed
48
					   const char *type, const char *name);
49
static void dumpDatabases(PGconn *conn);
50
static void dumpTimestamp(char *msg);
51

Bruce Momjian's avatar
Bruce Momjian committed
52
static int	runPgDump(const char *dbname);
53
static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
54
			  const char *pguser, bool require_password, bool fail_on_error);
55
static PGresult *executeQuery(PGconn *conn, const char *query);
56 57
static void executeCommand(PGconn *conn, const char *query);

58
static char pg_dump_bin[MAXPGPATH];
59
static PQExpBuffer pgdumpopts;
60 61 62 63 64 65
static bool output_clean = false;
static bool skip_acls = false;
static bool verbose = false;

static int	disable_dollar_quoting = 0;
static int	disable_triggers = 0;
66
static int	no_tablespaces = 0;
67 68
static int	use_setsessauth = 0;
static int	server_version;
69

Bruce Momjian's avatar
Bruce Momjian committed
70 71
static FILE *OPF;
static char *filename = NULL;
72 73 74 75

int
main(int argc, char *argv[])
{
Bruce Momjian's avatar
Bruce Momjian committed
76 77 78 79
	char	   *pghost = NULL;
	char	   *pgport = NULL;
	char	   *pguser = NULL;
	char	   *pgdb = NULL;
80
	bool		force_password = false;
81
	bool		data_only = false;
82
	bool		globals_only = false;
83 84
	bool		roles_only = false;
	bool		tablespaces_only = false;
85
	bool		schema_only = false;
Bruce Momjian's avatar
Bruce Momjian committed
86
	PGconn	   *conn;
87
	int			encoding;
Bruce Momjian's avatar
Bruce Momjian committed
88
	const char *std_strings;
Bruce Momjian's avatar
Bruce Momjian committed
89 90
	int			c,
				ret;
91 92

	static struct option long_options[] = {
93
		{"data-only", no_argument, NULL, 'a'},
94 95 96 97
		{"clean", no_argument, NULL, 'c'},
		{"inserts", no_argument, NULL, 'd'},
		{"attribute-inserts", no_argument, NULL, 'D'},
		{"column-inserts", no_argument, NULL, 'D'},
98
		{"file", required_argument, NULL, 'f'},
99
		{"globals-only", no_argument, NULL, 'g'},
100 101
		{"host", required_argument, NULL, 'h'},
		{"ignore-version", no_argument, NULL, 'i'},
102
		{"database", required_argument, NULL, 'l'},
103
		{"oids", no_argument, NULL, 'o'},
104
		{"no-owner", no_argument, NULL, 'O'},
105
		{"port", required_argument, NULL, 'p'},
106
		{"roles-only", no_argument, NULL, 'r'},
107
		{"schema-only", no_argument, NULL, 's'},
108
		{"superuser", required_argument, NULL, 'S'},
109
		{"tablespaces-only", no_argument, NULL, 't'},
110 111
		{"username", required_argument, NULL, 'U'},
		{"verbose", no_argument, NULL, 'v'},
112
		{"password", no_argument, NULL, 'W'},
113 114
		{"no-privileges", no_argument, NULL, 'x'},
		{"no-acl", no_argument, NULL, 'x'},
115 116

		/*
117
		 * the following options don't have an equivalent short option letter
118 119 120
		 */
		{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
		{"disable-triggers", no_argument, &disable_triggers, 1},
121
		{"no-tablespaces", no_argument, &no_tablespaces, 1},
122
		{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
123
		{"lock-wait-timeout", required_argument, NULL, 2},
124

125 126 127 128 129
		{NULL, 0, NULL, 0}
	};

	int			optindex;

130
	set_pglocale_pgservice(argv[0], "pg_dump");
131

132
	progname = get_progname(argv[0]);
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

	if (argc > 1)
	{
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
		{
			help();
			exit(0);
		}
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
		{
			puts("pg_dumpall (PostgreSQL) " PG_VERSION);
			exit(0);
		}
	}

148
	if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR,
149
							   pg_dump_bin)) < 0)
150
	{
151
		char		full_path[MAXPGPATH];
152 153

		if (find_my_exec(argv[0], full_path) < 0)
154
			strlcpy(full_path, progname, sizeof(full_path));
155

156 157
		if (ret == -1)
			fprintf(stderr,
Bruce Momjian's avatar
Bruce Momjian committed
158
					_("The program \"pg_dump\" is needed by %s "
159 160
					  "but was not found in the\n"
					  "same directory as \"%s\".\n"
Bruce Momjian's avatar
Bruce Momjian committed
161
					  "Check your installation.\n"),
162
					progname, full_path);
163 164
		else
			fprintf(stderr,
165 166
					_("The program \"pg_dump\" was found by \"%s\"\n"
					  "but was not the same version as %s.\n"
Bruce Momjian's avatar
Bruce Momjian committed
167
					  "Check your installation.\n"),
168
					full_path, progname);
169 170 171
		exit(1);
	}

172 173
	pgdumpopts = createPQExpBuffer();

174
	while ((c = getopt_long(argc, argv, "acdDf:gh:il:oOp:rsS:tU:vWxX:", long_options, &optindex)) != -1)
175 176 177
	{
		switch (c)
		{
178 179 180 181 182
			case 'a':
				data_only = true;
				appendPQExpBuffer(pgdumpopts, " -a");
				break;

183 184 185 186 187 188 189 190
			case 'c':
				output_clean = true;
				break;

			case 'd':
			case 'D':
				appendPQExpBuffer(pgdumpopts, " -%c", c);
				break;
Bruce Momjian's avatar
Bruce Momjian committed
191

192 193 194 195 196 197 198 199 200
			case 'f':
				filename = optarg;
#ifndef WIN32
				appendPQExpBuffer(pgdumpopts, " -f '%s'", filename);
#else
				appendPQExpBuffer(pgdumpopts, " -f \"%s\"", filename);
#endif

				break;
201 202 203 204 205 206 207

			case 'g':
				globals_only = true;
				break;

			case 'h':
				pghost = optarg;
208
#ifndef WIN32
209
				appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost);
210
#else
211
				appendPQExpBuffer(pgdumpopts, " -h \"%s\"", pghost);
212 213
#endif

214 215 216
				break;

			case 'i':
217
				/* ignored, deprecated option */
218
				break;
Bruce Momjian's avatar
Bruce Momjian committed
219

220 221 222
			case 'l':
				pgdb = optarg;
				break;
223

224
			case 'o':
225
				appendPQExpBuffer(pgdumpopts, " -o");
226 227
				break;

228 229 230 231
			case 'O':
				appendPQExpBuffer(pgdumpopts, " -O");
				break;

232 233
			case 'p':
				pgport = optarg;
234
#ifndef WIN32
235
				appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport);
236
#else
237
				appendPQExpBuffer(pgdumpopts, " -p \"%s\"", pgport);
238
#endif
239
				break;
Bruce Momjian's avatar
Bruce Momjian committed
240

241 242 243
			case 'r':
				roles_only = true;
				break;
244

245 246 247 248 249
			case 's':
				schema_only = true;
				appendPQExpBuffer(pgdumpopts, " -s");
				break;

250
			case 'S':
251
#ifndef WIN32
252
				appendPQExpBuffer(pgdumpopts, " -S '%s'", optarg);
253
#else
254
				appendPQExpBuffer(pgdumpopts, " -S \"%s\"", optarg);
255
#endif
256
				break;
Bruce Momjian's avatar
Bruce Momjian committed
257

258 259 260
			case 't':
				tablespaces_only = true;
				break;
261

262 263
			case 'U':
				pguser = optarg;
264
#ifndef WIN32
265
				appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser);
266
#else
267
				appendPQExpBuffer(pgdumpopts, " -U \"%s\"", pguser);
268
#endif
269 270 271 272 273 274 275 276 277 278 279 280
				break;

			case 'v':
				verbose = true;
				appendPQExpBuffer(pgdumpopts, " -v");
				break;

			case 'W':
				force_password = true;
				appendPQExpBuffer(pgdumpopts, " -W");
				break;

281 282 283 284 285
			case 'x':
				skip_acls = true;
				appendPQExpBuffer(pgdumpopts, " -x");
				break;

286
			case 'X':
287
				/* -X is a deprecated alternative to long options */
288
				if (strcmp(optarg, "disable-dollar-quoting") == 0)
289
					disable_dollar_quoting = 1;
290
				else if (strcmp(optarg, "disable-triggers") == 0)
291 292 293
					disable_triggers = 1;
				else if (strcmp(optarg, "no-tablespaces") == 0) 
					no_tablespaces = 1;
294
				else if (strcmp(optarg, "use-set-session-authorization") == 0)
295
					use_setsessauth = 1;
296 297 298 299 300 301 302 303 304 305 306 307 308
				else
				{
					fprintf(stderr,
							_("%s: invalid -X option -- %s\n"),
							progname, optarg);
					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
					exit(1);
				}
				break;

			case 0:
				break;

309 310 311 312 313
			case 2:
				appendPQExpBuffer(pgdumpopts, " --lock-wait-timeout=");
				appendPQExpBuffer(pgdumpopts, optarg);
				break;

Bruce Momjian's avatar
Bruce Momjian committed
314
			default:
315
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
Bruce Momjian's avatar
Bruce Momjian committed
316
				exit(1);
317 318 319
		}
	}

Bruce Momjian's avatar
Bruce Momjian committed
320
	/* Add long options to the pg_dump argument list */
321
	if (disable_dollar_quoting)
322
		appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting");
323
	if (disable_triggers)
324
		appendPQExpBuffer(pgdumpopts, " --disable-triggers");
325 326
	if (no_tablespaces)
		appendPQExpBuffer(pgdumpopts, " --no-tablespaces");
327
	if (use_setsessauth)
328
		appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
Bruce Momjian's avatar
Bruce Momjian committed
329

Bruce Momjian's avatar
Bruce Momjian committed
330 331
	if (optind < argc)
	{
332 333 334 335
		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
				progname, argv[optind]);
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
				progname);
Bruce Momjian's avatar
Bruce Momjian committed
336 337
		exit(1);
	}
Bruce Momjian's avatar
Bruce Momjian committed
338

339 340 341
	/* Make sure the user hasn't specified a mix of globals-only options */
	if (globals_only && roles_only)
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
342
		fprintf(stderr, _("%s: options -g/--globals-only and -r/--roles-only cannot be used together\n"),
343 344 345 346 347
				progname);
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
				progname);
		exit(1);
	}
Bruce Momjian's avatar
Bruce Momjian committed
348

349 350
	if (globals_only && tablespaces_only)
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
351
		fprintf(stderr, _("%s: options -g/--globals-only and -t/--tablespaces-only cannot be used together\n"),
352 353 354 355 356
				progname);
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
				progname);
		exit(1);
	}
Bruce Momjian's avatar
Bruce Momjian committed
357

358 359
	if (roles_only && tablespaces_only)
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
360
		fprintf(stderr, _("%s: options -r/--roles-only and -t/--tablespaces-only cannot be used together\n"),
361 362 363 364 365
				progname);
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
				progname);
		exit(1);
	}
366

367
	/*
368 369
	 * If there was a database specified on the command line, use that,
	 * otherwise try to connect to database "postgres", and failing that
370 371 372
	 * "template1".  "postgres" is the preferred choice for 8.1 and later
	 * servers, but it usually will not exist on older ones.
	 */
373 374 375
	if (pgdb)
	{
		conn = connectDatabase(pgdb, pghost, pgport, pguser,
Bruce Momjian's avatar
Bruce Momjian committed
376 377
							   force_password, false);

378 379 380 381 382 383 384 385 386 387
		if (!conn)
		{
			fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
					progname, pgdb);
			exit(1);
		}
	}
	else
	{
		conn = connectDatabase("postgres", pghost, pgport, pguser,
Bruce Momjian's avatar
Bruce Momjian committed
388
							   force_password, false);
389 390
		if (!conn)
			conn = connectDatabase("template1", pghost, pgport, pguser,
Bruce Momjian's avatar
Bruce Momjian committed
391 392
								   force_password, true);

393 394
		if (!conn)
		{
Peter Eisentraut's avatar
Peter Eisentraut committed
395
			fprintf(stderr, _("%s: could not connect to databases \"postgres\" or \"template1\"\n"
Bruce Momjian's avatar
Bruce Momjian committed
396
							  "Please specify an alternative database.\n"),
397 398 399 400 401 402
					progname);
			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
					progname);
			exit(1);
		}
	}
Bruce Momjian's avatar
Bruce Momjian committed
403

404 405 406 407 408 409 410 411
	/*
	 * Open the output file if required, otherwise use stdout
	 */
	if (filename)
	{
		OPF = fopen(filename, PG_BINARY_W);
		if (!OPF)
		{
412 413
			fprintf(stderr, _("%s: could not open the output file \"%s\": %s\n"),
					progname, filename, strerror(errno));
414 415 416 417 418
			exit(1);
		}
	}
	else
		OPF = stdout;
419

420
	/*
Bruce Momjian's avatar
Bruce Momjian committed
421 422
	 * Get the active encoding and the standard_conforming_strings setting, so
	 * we know how to escape strings.
423 424 425 426 427 428
	 */
	encoding = PQclientEncoding(conn);
	std_strings = PQparameterStatus(conn, "standard_conforming_strings");
	if (!std_strings)
		std_strings = "off";

429
	fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n");
430
	if (verbose)
Bruce Momjian's avatar
Bruce Momjian committed
431
		dumpTimestamp("Started on");
432

433
	fprintf(OPF, "\\connect postgres\n\n");
434

435 436
	if (!data_only)
	{
437
		/* Replicate encoding and std_strings in output */
438
		fprintf(OPF, "SET client_encoding = '%s';\n",
Bruce Momjian's avatar
Bruce Momjian committed
439
				pg_encoding_to_char(encoding));
440
		fprintf(OPF, "SET standard_conforming_strings = %s;\n", std_strings);
Bruce Momjian's avatar
Bruce Momjian committed
441
		if (strcmp(std_strings, "off") == 0)
442 443
			fprintf(OPF, "SET escape_string_warning = 'off';\n");
		fprintf(OPF, "\n");
444

445 446 447 448 449 450 451 452 453 454 455
		if (!tablespaces_only)
		{
			/* Dump roles (users) */
			dumpRoles(conn);

			/* Dump role memberships --- need different method for pre-8.1 */
			if (server_version >= 80100)
				dumpRoleMembership(conn);
			else
				dumpGroups(conn);
		}
456

457
		if (!roles_only && !no_tablespaces)
458 459 460 461 462
		{
			/* Dump tablespaces */
			if (server_version >= 80000)
				dumpTablespaces(conn);
		}
463

464
		/* Dump CREATE DATABASE commands */
465
		if (!globals_only && !roles_only && !tablespaces_only)
466
			dumpCreateDB(conn);
467
	}
468

469
	if (!globals_only && !roles_only && !tablespaces_only)
470
		dumpDatabases(conn);
471 472

	PQfinish(conn);
473

474 475
	if (verbose)
		dumpTimestamp("Completed on");
476
	fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n");
Bruce Momjian's avatar
Bruce Momjian committed
477

478 479
	if (filename)
		fclose(OPF);
480

481 482 483 484 485 486 487 488 489 490
	exit(0);
}



static void
help(void)
{
	printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
	printf(_("Usage:\n"));
491
	printf(_("  %s [OPTION]...\n"), progname);
492

493
	printf(_("\nGeneral options:\n"));
494
	printf(_("  -f, --file=FILENAME      output file name\n"));
495 496
	printf(_("  --help                   show this help, then exit\n"));
	printf(_("  --version                output version information, then exit\n"));
497 498
	printf(_("  --lock-wait-timeout=TIMEOUT\n"
			 "                           fail after waiting TIMEOUT for a table lock\n"));
499
	printf(_("\nOptions controlling the output content:\n"));
500
	printf(_("  -a, --data-only          dump only the data, not the schema\n"));
501
	printf(_("  -c, --clean              clean (drop) databases prior to create\n"));
502 503
	printf(_("  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"));
	printf(_("  -D, --column-inserts     dump data as INSERT commands with column names\n"));
504
	printf(_("  -g, --globals-only       dump only global objects, no databases\n"));
505
	printf(_("  -o, --oids               include OIDs in dump\n"));
506
	printf(_("  -O, --no-owner           skip restoration of object ownership\n"));
507
	printf(_("  -r, --roles-only         dump only roles, no databases or tablespaces\n"));
508 509
	printf(_("  -s, --schema-only        dump only the schema, no data\n"));
	printf(_("  -S, --superuser=NAME     specify the superuser user name to use in the dump\n"));
510
	printf(_("  -t, --tablespaces-only   dump only tablespaces, no databases or roles\n"));
511
	printf(_("  -x, --no-privileges      do not dump privileges (grant/revoke)\n"));
512
	printf(_("  --disable-dollar-quoting\n"
513
			 "                           disable dollar quoting, use SQL standard quoting\n"));
514
	printf(_("  --disable-triggers       disable triggers during data-only restore\n"));
515
	printf(_("  --no-tablespaces         do not dump tablespace assignments\n"));
516
	printf(_("  --use-set-session-authorization\n"
517 518
			 "                           use SESSION AUTHORIZATION commands instead of\n"
			 "                           OWNER TO commands\n"));
519 520

	printf(_("\nConnection options:\n"));
521
	printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
522
	printf(_("  -l, --database=DBNAME    specify an alternative default database\n"));
523 524 525
	printf(_("  -p, --port=PORT          database server port number\n"));
	printf(_("  -U, --username=NAME      connect as specified database user\n"));
	printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
526 527 528 529 530 531 532 533

	printf(_("\nThe SQL script will be written to the standard output.\n\n"));
	printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
}



/*
534
 * Dump roles
535 536
 */
static void
537
dumpRoles(PGconn *conn)
538
{
539
	PQExpBuffer buf = createPQExpBuffer();
Bruce Momjian's avatar
Bruce Momjian committed
540
	PGresult   *res;
541 542 543 544 545 546 547 548 549
	int			i_rolname,
				i_rolsuper,
				i_rolinherit,
				i_rolcreaterole,
				i_rolcreatedb,
				i_rolcatupdate,
				i_rolcanlogin,
				i_rolconnlimit,
				i_rolpassword,
550 551
				i_rolvaliduntil,
				i_rolcomment;
Bruce Momjian's avatar
Bruce Momjian committed
552
	int			i;
553

554
	/* note: rolconfig is dumped later */
555
	if (server_version >= 80200)
556 557 558 559
		printfPQExpBuffer(buf,
						  "SELECT rolname, rolsuper, rolinherit, "
						  "rolcreaterole, rolcreatedb, rolcatupdate, "
						  "rolcanlogin, rolconnlimit, rolpassword, "
560
						  "rolvaliduntil, "
Bruce Momjian's avatar
Bruce Momjian committed
561
			  "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment "
562 563
						  "FROM pg_authid "
						  "ORDER BY 1");
564 565 566 567 568 569
	else if (server_version >= 80100)
		printfPQExpBuffer(buf,
						  "SELECT rolname, rolsuper, rolinherit, "
						  "rolcreaterole, rolcreatedb, rolcatupdate, "
						  "rolcanlogin, rolconnlimit, rolpassword, "
						  "rolvaliduntil, null as rolcomment "
570 571
						  "FROM pg_authid "
						  "ORDER BY 1");
572
	else
573 574 575 576 577 578 579 580 581 582
		printfPQExpBuffer(buf,
						  "SELECT usename as rolname, "
						  "usesuper as rolsuper, "
						  "true as rolinherit, "
						  "usesuper as rolcreaterole, "
						  "usecreatedb as rolcreatedb, "
						  "usecatupd as rolcatupdate, "
						  "true as rolcanlogin, "
						  "-1 as rolconnlimit, "
						  "passwd as rolpassword, "
583
						  "valuntil as rolvaliduntil, "
584
						  "null as rolcomment "
585 586 587 588 589 590 591 592 593 594 595
						  "FROM pg_shadow "
						  "UNION ALL "
						  "SELECT groname as rolname, "
						  "false as rolsuper, "
						  "true as rolinherit, "
						  "false as rolcreaterole, "
						  "false as rolcreatedb, "
						  "false as rolcatupdate, "
						  "false as rolcanlogin, "
						  "-1 as rolconnlimit, "
						  "null::text as rolpassword, "
596 597
						  "null::abstime as rolvaliduntil, "
						  "null as rolcomment "
598 599 600 601
						  "FROM pg_group "
						  "WHERE NOT EXISTS (SELECT 1 FROM pg_shadow "
						  " WHERE usename = groname) "
						  "ORDER BY 1");
602 603 604 605 606 607 608 609 610 611 612 613 614

	res = executeQuery(conn, buf->data);

	i_rolname = PQfnumber(res, "rolname");
	i_rolsuper = PQfnumber(res, "rolsuper");
	i_rolinherit = PQfnumber(res, "rolinherit");
	i_rolcreaterole = PQfnumber(res, "rolcreaterole");
	i_rolcreatedb = PQfnumber(res, "rolcreatedb");
	i_rolcatupdate = PQfnumber(res, "rolcatupdate");
	i_rolcanlogin = PQfnumber(res, "rolcanlogin");
	i_rolconnlimit = PQfnumber(res, "rolconnlimit");
	i_rolpassword = PQfnumber(res, "rolpassword");
	i_rolvaliduntil = PQfnumber(res, "rolvaliduntil");
615
	i_rolcomment = PQfnumber(res, "rolcomment");
616

617
	if (PQntuples(res) > 0)
618
		fprintf(OPF, "--\n-- Roles\n--\n\n");
619 620 621

	for (i = 0; i < PQntuples(res); i++)
	{
622
		const char *rolename;
Bruce Momjian's avatar
Bruce Momjian committed
623

624
		rolename = PQgetvalue(res, i, i_rolname);
625

626 627 628 629
		resetPQExpBuffer(buf);

		if (output_clean)
			appendPQExpBuffer(buf, "DROP ROLE %s;\n", fmtId(rolename));
630

Bruce Momjian's avatar
Bruce Momjian committed
631
		/*
632 633 634
		 * We dump CREATE ROLE followed by ALTER ROLE to ensure that the role
		 * will acquire the right properties even if it already exists. (The
		 * above DROP may therefore seem redundant, but it isn't really,
635
		 * because this technique doesn't get rid of role memberships.)
Bruce Momjian's avatar
Bruce Momjian committed
636
		 */
637 638
		appendPQExpBuffer(buf, "CREATE ROLE %s;\n", fmtId(rolename));
		appendPQExpBuffer(buf, "ALTER ROLE %s WITH", fmtId(rolename));
639

640 641 642 643
		if (strcmp(PQgetvalue(res, i, i_rolsuper), "t") == 0)
			appendPQExpBuffer(buf, " SUPERUSER");
		else
			appendPQExpBuffer(buf, " NOSUPERUSER");
644

645 646 647 648 649 650 651 652 653 654 655
		if (strcmp(PQgetvalue(res, i, i_rolinherit), "t") == 0)
			appendPQExpBuffer(buf, " INHERIT");
		else
			appendPQExpBuffer(buf, " NOINHERIT");

		if (strcmp(PQgetvalue(res, i, i_rolcreaterole), "t") == 0)
			appendPQExpBuffer(buf, " CREATEROLE");
		else
			appendPQExpBuffer(buf, " NOCREATEROLE");

		if (strcmp(PQgetvalue(res, i, i_rolcreatedb), "t") == 0)
656 657 658 659
			appendPQExpBuffer(buf, " CREATEDB");
		else
			appendPQExpBuffer(buf, " NOCREATEDB");

660 661
		if (strcmp(PQgetvalue(res, i, i_rolcanlogin), "t") == 0)
			appendPQExpBuffer(buf, " LOGIN");
662
		else
663 664 665 666 667
			appendPQExpBuffer(buf, " NOLOGIN");

		if (strcmp(PQgetvalue(res, i, i_rolconnlimit), "-1") != 0)
			appendPQExpBuffer(buf, " CONNECTION LIMIT %s",
							  PQgetvalue(res, i, i_rolconnlimit));
668

669 670 671
		if (!PQgetisnull(res, i, i_rolpassword))
		{
			appendPQExpBuffer(buf, " PASSWORD ");
672
			appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolpassword), conn);
673 674 675
		}

		if (!PQgetisnull(res, i, i_rolvaliduntil))
676
			appendPQExpBuffer(buf, " VALID UNTIL '%s'",
677
							  PQgetvalue(res, i, i_rolvaliduntil));
678 679 680

		appendPQExpBuffer(buf, ";\n");

Bruce Momjian's avatar
Bruce Momjian committed
681 682
		if (!PQgetisnull(res, i, i_rolcomment))
		{
683
			appendPQExpBuffer(buf, "COMMENT ON ROLE %s IS ", fmtId(rolename));
684
			appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolcomment), conn);
685 686 687
			appendPQExpBuffer(buf, ";\n");
		}

688
		fprintf(OPF, "%s", buf->data);
689

690
		if (server_version >= 70300)
691
			dumpUserConfig(conn, rolename);
692 693 694
	}

	PQclear(res);
695

696
	fprintf(OPF, "\n\n");
697 698

	destroyPQExpBuffer(buf);
699 700 701
}


702 703 704 705 706 707 708 709 710 711 712 713 714 715
/*
 * Dump role memberships.  This code is used for 8.1 and later servers.
 *
 * Note: we expect dumpRoles already created all the roles, but there is
 * no membership yet.
 */
static void
dumpRoleMembership(PGconn *conn)
{
	PGresult   *res;
	int			i;

	res = executeQuery(conn, "SELECT ur.rolname AS roleid, "
					   "um.rolname AS member, "
716 717
					   "a.admin_option, "
					   "ug.rolname AS grantor "
718 719 720
					   "FROM pg_auth_members a "
					   "LEFT JOIN pg_authid ur on ur.oid = a.roleid "
					   "LEFT JOIN pg_authid um on um.oid = a.member "
721 722
					   "LEFT JOIN pg_authid ug on ug.oid = a.grantor "
					   "ORDER BY 1,2,3");
723

724
	if (PQntuples(res) > 0)
725
		fprintf(OPF, "--\n-- Role memberships\n--\n\n");
726 727 728 729 730

	for (i = 0; i < PQntuples(res); i++)
	{
		char	   *roleid = PQgetvalue(res, i, 0);
		char	   *member = PQgetvalue(res, i, 1);
731
		char	   *option = PQgetvalue(res, i, 2);
732

733 734
		fprintf(OPF, "GRANT %s", fmtId(roleid));
		fprintf(OPF, " TO %s", fmtId(member));
735
		if (*option == 't')
736
			fprintf(OPF, " WITH ADMIN OPTION");
737 738 739 740 741 742 743

		/*
		 * We don't track the grantor very carefully in the backend, so cope
		 * with the possibility that it has been dropped.
		 */
		if (!PQgetisnull(res, i, 3))
		{
Bruce Momjian's avatar
Bruce Momjian committed
744
			char	   *grantor = PQgetvalue(res, i, 3);
745 746 747 748

			fprintf(OPF, " GRANTED BY %s", fmtId(grantor));
		}
		fprintf(OPF, ";\n");
749 750 751 752
	}

	PQclear(res);

753
	fprintf(OPF, "\n\n");
754
}
755 756

/*
757 758 759 760 761 762
 * Dump group memberships from a pre-8.1 server.  It's annoying that we
 * can't share any useful amount of code with the post-8.1 case, but
 * the catalog representations are too different.
 *
 * Note: we expect dumpRoles already created all the roles, but there is
 * no membership yet.
763 764 765 766
 */
static void
dumpGroups(PGconn *conn)
{
767
	PQExpBuffer buf = createPQExpBuffer();
Bruce Momjian's avatar
Bruce Momjian committed
768 769
	PGresult   *res;
	int			i;
770

771 772
	res = executeQuery(conn,
					   "SELECT groname, grolist FROM pg_group ORDER BY 1");
773

774
	if (PQntuples(res) > 0)
775
		fprintf(OPF, "--\n-- Role memberships\n--\n\n");
776

777 778
	for (i = 0; i < PQntuples(res); i++)
	{
779
		char	   *groname = PQgetvalue(res, i, 0);
780 781 782
		char	   *grolist = PQgetvalue(res, i, 1);
		PGresult   *res2;
		int			j;
783

784 785 786 787 788
		/*
		 * Array representation is {1,2,3} ... convert to (1,2,3)
		 */
		if (strlen(grolist) < 3)
			continue;
789

790 791 792 793 794 795 796 797
		grolist = strdup(grolist);
		grolist[0] = '(';
		grolist[strlen(grolist) - 1] = ')';
		printfPQExpBuffer(buf,
						  "SELECT usename FROM pg_shadow "
						  "WHERE usesysid IN %s ORDER BY 1",
						  grolist);
		free(grolist);
798

799
		res2 = executeQuery(conn, buf->data);
800

801 802 803
		for (j = 0; j < PQntuples(res2); j++)
		{
			char	   *usename = PQgetvalue(res2, j, 0);
804

805 806 807 808 809 810
			/*
			 * Don't try to grant a role to itself; can happen if old
			 * installation has identically named user and group.
			 */
			if (strcmp(groname, usename) == 0)
				continue;
811

812 813
			fprintf(OPF, "GRANT %s", fmtId(groname));
			fprintf(OPF, " TO %s;\n", fmtId(usename));
814
		}
815 816

		PQclear(res2);
817 818 819
	}

	PQclear(res);
820 821
	destroyPQExpBuffer(buf);

822
	fprintf(OPF, "\n\n");
823 824
}

825 826 827 828 829 830 831 832 833 834
/*
 * Dump tablespaces.
 */
static void
dumpTablespaces(PGconn *conn)
{
	PGresult   *res;
	int			i;

	/*
835 836
	 * Get all tablespaces except built-in ones (which we assume are named
	 * pg_xxx)
837
	 */
838 839
	if (server_version >= 80200)
		res = executeQuery(conn, "SELECT spcname, "
Bruce Momjian's avatar
Bruce Momjian committed
840
						 "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
841
						   "spclocation, spcacl, "
Bruce Momjian's avatar
Bruce Momjian committed
842
						"pg_catalog.shobj_description(oid, 'pg_tablespace') "
843 844 845
						   "FROM pg_catalog.pg_tablespace "
						   "WHERE spcname !~ '^pg_' "
						   "ORDER BY 1");
Bruce Momjian's avatar
Bruce Momjian committed
846
	else
847
		res = executeQuery(conn, "SELECT spcname, "
Bruce Momjian's avatar
Bruce Momjian committed
848
						 "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
849 850 851 852 853
						   "spclocation, spcacl, "
						   "null "
						   "FROM pg_catalog.pg_tablespace "
						   "WHERE spcname !~ '^pg_' "
						   "ORDER BY 1");
Bruce Momjian's avatar
Bruce Momjian committed
854

855
	if (PQntuples(res) > 0)
856
		fprintf(OPF, "--\n-- Tablespaces\n--\n\n");
857 858 859 860

	for (i = 0; i < PQntuples(res); i++)
	{
		PQExpBuffer buf = createPQExpBuffer();
Bruce Momjian's avatar
Bruce Momjian committed
861 862 863 864
		char	   *spcname = PQgetvalue(res, i, 0);
		char	   *spcowner = PQgetvalue(res, i, 1);
		char	   *spclocation = PQgetvalue(res, i, 2);
		char	   *spcacl = PQgetvalue(res, i, 3);
865
		char	   *spccomment = PQgetvalue(res, i, 4);
Bruce Momjian's avatar
Bruce Momjian committed
866
		char	   *fspcname;
867 868 869 870 871 872 873 874 875

		/* needed for buildACLCommands() */
		fspcname = strdup(fmtId(spcname));

		if (output_clean)
			appendPQExpBuffer(buf, "DROP TABLESPACE %s;\n", fspcname);

		appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
		appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
876

877
		appendPQExpBuffer(buf, " LOCATION ");
878
		appendStringLiteralConn(buf, spclocation, conn);
879 880 881 882 883 884 885 886 887 888 889 890
		appendPQExpBuffer(buf, ";\n");

		if (!skip_acls &&
			!buildACLCommands(fspcname, "TABLESPACE", spcacl, spcowner,
							  server_version, buf))
		{
			fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
					progname, spcacl, fspcname);
			PQfinish(conn);
			exit(1);
		}

Bruce Momjian's avatar
Bruce Momjian committed
891 892
		if (spccomment && strlen(spccomment))
		{
893
			appendPQExpBuffer(buf, "COMMENT ON TABLESPACE %s IS ", fspcname);
894
			appendStringLiteralConn(buf, spccomment, conn);
895 896 897
			appendPQExpBuffer(buf, ";\n");
		}

898
		fprintf(OPF, "%s", buf->data);
899 900 901 902 903 904

		free(fspcname);
		destroyPQExpBuffer(buf);
	}

	PQclear(res);
905
	fprintf(OPF, "\n\n");
906
}
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921

/*
 * Dump commands to create each database.
 *
 * To minimize the number of reconnections (and possibly ensuing
 * password prompts) required by the output script, we emit all CREATE
 * DATABASE commands during the initial phase of the script, and then
 * run pg_dump for each database to dump the contents of that
 * database.  We skip databases marked not datallowconn, since we'd be
 * unable to connect to them anyway (and besides, we don't want to
 * dump template0).
 */
static void
dumpCreateDB(PGconn *conn)
{
922
	PQExpBuffer buf = createPQExpBuffer();
Bruce Momjian's avatar
Bruce Momjian committed
923 924
	PGresult   *res;
	int			i;
925

926
	fprintf(OPF, "--\n-- Database creation\n--\n\n");
927

928 929 930 931 932 933 934
	if (server_version >= 80100)
		res = executeQuery(conn,
						   "SELECT datname, "
						   "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
						   "pg_encoding_to_char(d.encoding), "
						   "datistemplate, datacl, datconnlimit, "
						   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
935
			  "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
936 937
						   "WHERE datallowconn ORDER BY 1");
	else if (server_version >= 80000)
938 939 940 941
		res = executeQuery(conn,
						   "SELECT datname, "
						   "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
						   "pg_encoding_to_char(d.encoding), "
942
						   "datistemplate, datacl, -1 as datconnlimit, "
943
						   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
944
		   "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
945 946 947 948 949 950
						   "WHERE datallowconn ORDER BY 1");
	else if (server_version >= 70300)
		res = executeQuery(conn,
						   "SELECT datname, "
						   "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
						   "pg_encoding_to_char(d.encoding), "
951
						   "datistemplate, datacl, -1 as datconnlimit, "
952
						   "'pg_default' AS dattablespace "
953
		   "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
954 955 956 957 958
						   "WHERE datallowconn ORDER BY 1");
	else if (server_version >= 70100)
		res = executeQuery(conn,
						   "SELECT datname, "
						   "coalesce("
959
					"(select usename from pg_shadow where usesysid=datdba), "
960 961
						   "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
						   "pg_encoding_to_char(d.encoding), "
962
						   "datistemplate, '' as datacl, -1 as datconnlimit, "
963
						   "'pg_default' AS dattablespace "
964 965 966 967 968
						   "FROM pg_database d "
						   "WHERE datallowconn ORDER BY 1");
	else
	{
		/*
969 970
		 * Note: 7.0 fails to cope with sub-select in COALESCE, so just deal
		 * with getting a NULL by not printing any OWNER clause.
971 972 973
		 */
		res = executeQuery(conn,
						   "SELECT datname, "
974
					"(select usename from pg_shadow where usesysid=datdba), "
975
						   "pg_encoding_to_char(d.encoding), "
976
						   "'f' as datistemplate, "
977
						   "'' as datacl, -1 as datconnlimit, "
978
						   "'pg_default' AS dattablespace "
979 980 981
						   "FROM pg_database d "
						   "ORDER BY 1");
	}
982 983 984

	for (i = 0; i < PQntuples(res); i++)
	{
Bruce Momjian's avatar
Bruce Momjian committed
985 986 987 988
		char	   *dbname = PQgetvalue(res, i, 0);
		char	   *dbowner = PQgetvalue(res, i, 1);
		char	   *dbencoding = PQgetvalue(res, i, 2);
		char	   *dbistemplate = PQgetvalue(res, i, 3);
989
		char	   *dbacl = PQgetvalue(res, i, 4);
990 991
		char	   *dbconnlimit = PQgetvalue(res, i, 5);
		char	   *dbtablespace = PQgetvalue(res, i, 6);
992
		char	   *fdbname;
993

994 995
		fdbname = strdup(fmtId(dbname));

996 997
		resetPQExpBuffer(buf);

998 999 1000 1001 1002 1003 1004 1005 1006 1007
		/*
		 * Skip the CREATE DATABASE commands for "template1" and "postgres",
		 * since they are presumably already there in the destination cluster.
		 * We do want to emit their ACLs and config options if any, however.
		 */
		if (strcmp(dbname, "template1") != 0 &&
			strcmp(dbname, "postgres") != 0)
		{
			if (output_clean)
				appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
1008

1009
			appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
1010

1011
			appendPQExpBuffer(buf, " WITH TEMPLATE = template0");
1012

1013 1014
			if (strlen(dbowner) != 0)
				appendPQExpBuffer(buf, " OWNER = %s", fmtId(dbowner));
1015

1016
			appendPQExpBuffer(buf, " ENCODING = ");
1017
			appendStringLiteralConn(buf, dbencoding, conn);
1018

1019
			/*
Bruce Momjian's avatar
Bruce Momjian committed
1020 1021 1022 1023 1024 1025
			 * Output tablespace if it isn't the default.  For default, it
			 * uses the default from the template database.  If tablespace is
			 * specified and tablespace creation failed earlier, (e.g. no such
			 * directory), the database creation will fail too.  One solution
			 * would be to use 'SET default_tablespace' like we do in pg_dump
			 * for setting non-default database locations.
1026
			 */
1027
			if (strcmp(dbtablespace, "pg_default") != 0 && !no_tablespaces)
1028 1029
				appendPQExpBuffer(buf, " TABLESPACE = %s",
								  fmtId(dbtablespace));
1030

1031 1032 1033 1034
			if (strcmp(dbconnlimit, "-1") != 0)
				appendPQExpBuffer(buf, " CONNECTION LIMIT = %s",
								  dbconnlimit);

1035
			appendPQExpBuffer(buf, ";\n");
1036 1037 1038 1039

			if (strcmp(dbistemplate, "t") == 0)
			{
				appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
1040
				appendStringLiteralConn(buf, dbname, conn);
1041 1042
				appendPQExpBuffer(buf, ";\n");
			}
1043
		}
1044

1045 1046
		if (!skip_acls &&
			!buildACLCommands(fdbname, "DATABASE", dbacl, dbowner,
1047 1048
							  server_version, buf))
		{
1049
			fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
1050 1051 1052 1053 1054
					progname, dbacl, fdbname);
			PQfinish(conn);
			exit(1);
		}

1055
		fprintf(OPF, "%s", buf->data);
1056

1057 1058
		if (server_version >= 70300)
			dumpDatabaseConfig(conn, dbname);
1059 1060

		free(fdbname);
1061 1062 1063
	}

	PQclear(res);
1064 1065
	destroyPQExpBuffer(buf);

1066
	fprintf(OPF, "\n\n");
1067 1068 1069 1070
}



1071 1072 1073 1074 1075 1076 1077
/*
 * Dump database-specific configuration
 */
static void
dumpDatabaseConfig(PGconn *conn, const char *dbname)
{
	PQExpBuffer buf = createPQExpBuffer();
Bruce Momjian's avatar
Bruce Momjian committed
1078
	int			count = 1;
1079

Bruce Momjian's avatar
Bruce Momjian committed
1080
	for (;;)
1081 1082 1083 1084
	{
		PGresult   *res;

		printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
1085
		appendStringLiteralConn(buf, dbname, conn);
1086 1087 1088 1089 1090
		appendPQExpBuffer(buf, ";");

		res = executeQuery(conn, buf->data);
		if (!PQgetisnull(res, 0, 0))
		{
1091 1092
			makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
								   "DATABASE", dbname);
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
			PQclear(res);
			count++;
		}
		else
		{
			PQclear(res);
			break;
		}
	}

	destroyPQExpBuffer(buf);
}



/*
 * Dump user-specific configuration
 */
static void
dumpUserConfig(PGconn *conn, const char *username)
{
	PQExpBuffer buf = createPQExpBuffer();
Bruce Momjian's avatar
Bruce Momjian committed
1115
	int			count = 1;
1116

Bruce Momjian's avatar
Bruce Momjian committed
1117
	for (;;)
1118 1119 1120
	{
		PGresult   *res;

1121 1122 1123 1124
		if (server_version >= 80100)
			printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM pg_authid WHERE rolname = ", count);
		else
			printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
1125
		appendStringLiteralConn(buf, username, conn);
1126 1127

		res = executeQuery(conn, buf->data);
1128 1129
		if (PQntuples(res) == 1 &&
			!PQgetisnull(res, 0, 0))
1130
		{
1131 1132
			makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
								   "ROLE", username);
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
			PQclear(res);
			count++;
		}
		else
		{
			PQclear(res);
			break;
		}
	}

	destroyPQExpBuffer(buf);
}



/*
 * Helper function for dumpXXXConfig().
 */
static void
1152 1153
makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
					   const char *type, const char *name)
1154
{
Bruce Momjian's avatar
Bruce Momjian committed
1155 1156
	char	   *pos;
	char	   *mine;
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
	PQExpBuffer buf = createPQExpBuffer();

	mine = strdup(arrayitem);
	pos = strchr(mine, '=');
	if (pos == NULL)
		return;

	*pos = 0;
	appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
	appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
Bruce Momjian's avatar
Bruce Momjian committed
1167 1168

	/*
1169
	 * Some GUC variable names are 'LIST' type and hence must not be quoted.
Bruce Momjian's avatar
Bruce Momjian committed
1170
	 */
1171 1172
	if (pg_strcasecmp(mine, "DateStyle") == 0
		|| pg_strcasecmp(mine, "search_path") == 0)
1173
		appendPQExpBuffer(buf, "%s", pos + 1);
Bruce Momjian's avatar
Bruce Momjian committed
1174
	else
1175
		appendStringLiteralConn(buf, pos + 1, conn);
1176 1177
	appendPQExpBuffer(buf, ";\n");

1178
	fprintf(OPF, "%s", buf->data);
1179 1180 1181 1182 1183 1184
	destroyPQExpBuffer(buf);
	free(mine);
}



1185 1186 1187 1188 1189 1190
/*
 * Dump contents of databases.
 */
static void
dumpDatabases(PGconn *conn)
{
Bruce Momjian's avatar
Bruce Momjian committed
1191 1192
	PGresult   *res;
	int			i;
1193

1194 1195 1196 1197 1198
	if (server_version >= 70100)
		res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1");
	else
		res = executeQuery(conn, "SELECT datname FROM pg_database ORDER BY 1");

1199 1200
	for (i = 0; i < PQntuples(res); i++)
	{
Bruce Momjian's avatar
Bruce Momjian committed
1201 1202 1203
		int			ret;

		char	   *dbname = PQgetvalue(res, i, 0);
1204 1205 1206 1207

		if (verbose)
			fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);

1208
		fprintf(OPF, "\\connect %s\n\n", fmtId(dbname));
Bruce Momjian's avatar
Bruce Momjian committed
1209

1210 1211
		if (filename)
			fclose(OPF);
Bruce Momjian's avatar
Bruce Momjian committed
1212

1213 1214 1215
		ret = runPgDump(dbname);
		if (ret != 0)
		{
1216
			fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname);
1217 1218
			exit(1);
		}
Bruce Momjian's avatar
Bruce Momjian committed
1219

1220 1221 1222 1223 1224
		if (filename)
		{
			OPF = fopen(filename, PG_BINARY_A);
			if (!OPF)
			{
1225 1226
				fprintf(stderr, _("%s: could not re-open the output file \"%s\": %s\n"),
						progname, filename, strerror(errno));
1227 1228 1229
				exit(1);
			}
		}
Bruce Momjian's avatar
Bruce Momjian committed
1230

1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
	}

	PQclear(res);
}



/*
 * Run pg_dump on dbname.
 */
static int
runPgDump(const char *dbname)
{
	PQExpBuffer cmd = createPQExpBuffer();
1245
	const char *p;
Bruce Momjian's avatar
Bruce Momjian committed
1246
	int			ret;
1247

1248
	/*
Bruce Momjian's avatar
Bruce Momjian committed
1249
	 * Win32 has to use double-quotes for args, rather than single quotes.
1250 1251
	 * Strangely enough, this is the only place we pass a database name on the
	 * command line, except "postgres" which doesn't need quoting.
1252
	 *
Bruce Momjian's avatar
Bruce Momjian committed
1253 1254
	 * If we have a filename, use the undocumented plain-append pg_dump
	 * format.
Bruce Momjian's avatar
Bruce Momjian committed
1255
	 */
1256 1257 1258
	if (filename)
	{
#ifndef WIN32
1259
		appendPQExpBuffer(cmd, SYSTEMQUOTE"\"%s\" %s -Fa '", pg_dump_bin,
1260
#else
1261
		appendPQExpBuffer(cmd, SYSTEMQUOTE"\"%s\" %s -Fa \"", pg_dump_bin,
1262
#endif
Bruce Momjian's avatar
Bruce Momjian committed
1263
						  pgdumpopts->data);
1264 1265 1266
	}
	else
	{
1267
#ifndef WIN32
1268
		appendPQExpBuffer(cmd, SYSTEMQUOTE "\"%s\" %s -Fp '", pg_dump_bin,
1269
#else
1270
		appendPQExpBuffer(cmd, SYSTEMQUOTE "\"%s\" %s -Fp \"", pg_dump_bin,
1271
#endif
Bruce Momjian's avatar
Bruce Momjian committed
1272 1273 1274
						  pgdumpopts->data);
	}

1275 1276 1277 1278

	/* Shell quoting is not quite like SQL quoting, so can't use fmtId */
	for (p = dbname; *p; p++)
	{
1279
#ifndef WIN32
1280 1281
		if (*p == '\'')
			appendPQExpBuffer(cmd, "'\"'\"'");
1282 1283 1284
#else
		if (*p == '"')
			appendPQExpBuffer(cmd, "\\\"");
1285
#endif
1286
		else
1287 1288 1289
			appendPQExpBufferChar(cmd, *p);
	}

1290
#ifndef WIN32
1291
	appendPQExpBufferChar(cmd, '\'');
1292 1293 1294
#else
	appendPQExpBufferChar(cmd, '"');
#endif
Bruce Momjian's avatar
Bruce Momjian committed
1295

1296 1297
	appendPQExpBuffer(cmd, "%s", SYSTEMQUOTE);

1298
	if (verbose)
1299
		fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
1300

1301 1302 1303
	fflush(stdout);
	fflush(stderr);

1304
	ret = system(cmd->data);
1305

1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
	destroyPQExpBuffer(cmd);

	return ret;
}



/*
 * Make a database connection with the given parameters.  An
 * interactive password prompt is automatically issued if required.
1316 1317 1318
 *
 * If fail_on_error is false, we return NULL without printing any message
 * on failure, but preserve any prompted password for the next try.
1319 1320 1321
 */
static PGconn *
connectDatabase(const char *dbname, const char *pghost, const char *pgport,
1322
				const char *pguser, bool require_password, bool fail_on_error)
1323 1324
{
	PGconn	   *conn;
1325
	bool		new_pass;
1326
	const char *remoteversion_str;
1327
	int			my_version;
1328
	static char *password = NULL;
1329

1330
	if (require_password && !password)
1331 1332 1333
		password = simple_prompt("Password: ", 100, false);

	/*
1334 1335
	 * Start the connection.  Loop until we have a password if requested by
	 * backend.
1336 1337 1338
	 */
	do
	{
1339
		new_pass = false;
1340 1341 1342 1343
		conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);

		if (!conn)
		{
1344
			fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
1345
					progname, dbname);
1346
			exit(1);
1347 1348 1349
		}

		if (PQstatus(conn) == CONNECTION_BAD &&
1350
			PQconnectionNeedsPassword(conn) &&
1351
			password == NULL &&
1352 1353 1354 1355
			!feof(stdin))
		{
			PQfinish(conn);
			password = simple_prompt("Password: ", 100, false);
1356
			new_pass = true;
1357
		}
1358
	} while (new_pass);
1359 1360 1361 1362

	/* check to see that the backend connection was successfully made */
	if (PQstatus(conn) == CONNECTION_BAD)
	{
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
		if (fail_on_error)
		{
			fprintf(stderr,
					_("%s: could not connect to database \"%s\": %s\n"),
					progname, dbname, PQerrorMessage(conn));
			exit(1);
		}
		else
		{
			PQfinish(conn);
			return NULL;
		}
1375 1376
	}

1377 1378
	remoteversion_str = PQparameterStatus(conn, "server_version");
	if (!remoteversion_str)
1379 1380 1381 1382
	{
		fprintf(stderr, _("%s: could not get server version\n"), progname);
		exit(1);
	}
1383 1384
	server_version = parse_version(remoteversion_str);
	if (server_version < 0)
1385
	{
1386 1387 1388
		fprintf(stderr, _("%s: could not parse server version \"%s\"\n"),
				progname, remoteversion_str);
		exit(1);
1389 1390
	}

1391 1392 1393 1394 1395 1396 1397 1398
	my_version = parse_version(PG_VERSION);
	if (my_version < 0)
	{
		fprintf(stderr, _("%s: could not parse version \"%s\"\n"),
				progname, PG_VERSION);
		exit(1);
	}

1399 1400 1401 1402
	/*
	 * We allow the server to be back to 7.0, and up to any minor release
	 * of our own major version.  (See also version check in pg_dump.c.)
	 */
1403
	if (my_version != server_version
1404 1405
		&& (server_version < 70000 ||
			(server_version / 100) > (my_version / 100)))
1406 1407 1408
	{
		fprintf(stderr, _("server version: %s; %s version: %s\n"),
				remoteversion_str, progname, PG_VERSION);
1409 1410
		fprintf(stderr, _("aborting because of server version mismatch\n"));
		exit(1);
1411 1412
	}

1413
	/*
1414 1415
	 * On 7.3 and later, make sure we are not fooled by non-system schemas in
	 * the search path.
1416 1417 1418 1419
	 */
	if (server_version >= 70300)
		executeCommand(conn, "SET search_path = pg_catalog");

1420 1421 1422 1423 1424 1425 1426 1427 1428 1429
	return conn;
}


/*
 * Run a query, return the results, exit program on failure.
 */
static PGresult *
executeQuery(PGconn *conn, const char *query)
{
Bruce Momjian's avatar
Bruce Momjian committed
1430
	PGresult   *res;
1431

1432 1433 1434
	if (verbose)
		fprintf(stderr, _("%s: executing %s\n"), progname, query);

1435 1436 1437 1438
	res = PQexec(conn, query);
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
1439 1440 1441 1442
		fprintf(stderr, _("%s: query failed: %s"),
				progname, PQerrorMessage(conn));
		fprintf(stderr, _("%s: query was: %s\n"),
				progname, query);
1443 1444 1445 1446 1447 1448
		PQfinish(conn);
		exit(1);
	}

	return res;
}
1449

1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475
/*
 * As above for a SQL command (which returns nothing).
 */
static void
executeCommand(PGconn *conn, const char *query)
{
	PGresult   *res;

	if (verbose)
		fprintf(stderr, _("%s: executing %s\n"), progname, query);

	res = PQexec(conn, query);
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
		fprintf(stderr, _("%s: query failed: %s"),
				progname, PQerrorMessage(conn));
		fprintf(stderr, _("%s: query was: %s\n"),
				progname, query);
		PQfinish(conn);
		exit(1);
	}

	PQclear(res);
}

1476 1477 1478 1479 1480 1481 1482

/*
 * dumpTimestamp
 */
static void
dumpTimestamp(char *msg)
{
Bruce Momjian's avatar
Bruce Momjian committed
1483 1484
	char		buf[256];
	time_t		now = time(NULL);
1485

1486 1487 1488
	/*
	 * We don't print the timezone on Win32, because the names are long and
	 * localized, which means they may contain characters in various random
Bruce Momjian's avatar
Bruce Momjian committed
1489 1490
	 * encodings; this has been seen to cause encoding errors when reading the
	 * dump script.
1491 1492 1493 1494 1495 1496 1497 1498
	 */
	if (strftime(buf, sizeof(buf),
#ifndef WIN32
				 "%Y-%m-%d %H:%M:%S %Z",
#else
				 "%Y-%m-%d %H:%M:%S",
#endif
				 localtime(&now)) != 0)
1499
		fprintf(OPF, "-- %s %s\n\n", msg, buf);
1500
}