pg_dumpall.c 19.2 KB
Newer Older
1 2 3 4 5 6 7 8
/*-------------------------------------------------------------------------
 *
 * pg_dumpall
 *
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
9
 * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.24 2003/07/29 14:17:37 tgl Exp $
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 *-------------------------------------------------------------------------
 */

#include "postgres_fe.h"

#include <unistd.h>
#ifdef ENABLE_NLS
#include <locale.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifndef HAVE_STRDUP
#include "strdup.h"
#endif
#include <errno.h>

28 29 30 31 32
#ifndef HAVE_GETOPT_LONG
#include "getopt_long.h"
int optreset;
#endif

33 34 35 36 37 38 39 40 41 42 43
#include "dumputils.h"
#include "libpq-fe.h"
#include "pg_backup.h"
#include "pqexpbuffer.h"

#define _(x) gettext((x))


static char *progname;

static void help(void);
44

45 46 47
static void dumpUsers(PGconn *conn);
static void dumpGroups(PGconn *conn);
static void dumpCreateDB(PGconn *conn);
48 49 50
static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
static void dumpUserConfig(PGconn *conn, const char *username);
static void makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name);
51
static void dumpDatabases(PGconn *conn);
52

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


Bruce Momjian's avatar
Bruce Momjian committed
60
char	   *pgdumploc;
61
PQExpBuffer pgdumpopts;
Bruce Momjian's avatar
Bruce Momjian committed
62
bool		output_clean = false;
63
bool		skip_acls = false;
Bruce Momjian's avatar
Bruce Momjian committed
64
bool		verbose = false;
65
int			server_version;
66 67 68 69 70 71 72 73 74 75



int
main(int argc, char *argv[])
{
	char	   *pghost = NULL;
	char	   *pgport = NULL;
	char	   *pguser = NULL;
	bool		force_password = false;
76
	bool		data_only = false;
77
	bool		globals_only = false;
78
	bool		schema_only = false;
79 80 81 82
	PGconn	   *conn;
	int			c;

	static struct option long_options[] = {
83
		{"data-only", no_argument, NULL, 'a'},
84 85 86 87
		{"clean", no_argument, NULL, 'c'},
		{"inserts", no_argument, NULL, 'd'},
		{"attribute-inserts", no_argument, NULL, 'D'},
		{"column-inserts", no_argument, NULL, 'D'},
88
		{"globals-only", no_argument, NULL, 'g'},
89 90 91 92 93
		{"host", required_argument, NULL, 'h'},
		{"ignore-version", no_argument, NULL, 'i'},
		{"oids", no_argument, NULL, 'o'},
		{"port", required_argument, NULL, 'p'},
		{"password", no_argument, NULL, 'W'},
94
		{"schema-only", no_argument, NULL, 's'},
95 96
		{"username", required_argument, NULL, 'U'},
		{"verbose", no_argument, NULL, 'v'},
97 98
		{"no-privileges", no_argument, NULL, 'x'},
		{"no-acl", no_argument, NULL, 'x'},
99 100 101 102 103 104 105 106 107 108 109
		{NULL, 0, NULL, 0}
	};

	int			optindex;

#ifdef ENABLE_NLS
	setlocale(LC_ALL, "");
	bindtextdomain("pg_dump", LOCALEDIR);
	textdomain("pg_dump");
#endif

110
	progname = get_progname(argv[0]);
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

	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);
		}
	}

	pgdumploc = findPgDump(argv[0]);
	pgdumpopts = createPQExpBuffer();

129
	while ((c = getopt_long(argc, argv, "acdDgh:iop:sU:vWx", long_options, &optindex)) != -1)
130 131 132
	{
		switch (c)
		{
133 134 135 136 137
			case 'a':
				data_only = true;
				appendPQExpBuffer(pgdumpopts, " -a");
				break;

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
			case 'c':
				output_clean = true;
				break;

			case 'd':
			case 'D':
				appendPQExpBuffer(pgdumpopts, " -%c", c);
				break;

			case 'g':
				globals_only = true;
				break;

			case 'h':
				pghost = optarg;
				appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost);
				break;

			case 'i':
			case 'o':
				appendPQExpBuffer(pgdumpopts, " -%c", c);
				break;

			case 'p':
				pgport = optarg;
				appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport);
				break;

166 167 168 169 170
			case 's':
				schema_only = true;
				appendPQExpBuffer(pgdumpopts, " -s");
				break;

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
			case 'U':
				pguser = optarg;
				appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser);
				break;

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

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

186 187 188 189 190
			case 'x':
				skip_acls = true;
				appendPQExpBuffer(pgdumpopts, " -x");
				break;

Bruce Momjian's avatar
Bruce Momjian committed
191
			default:
192
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
Bruce Momjian's avatar
Bruce Momjian committed
193
				exit(1);
194 195 196
		}
	}

Bruce Momjian's avatar
Bruce Momjian committed
197 198
	if (optind < argc)
	{
199 200 201 202
		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
203 204
		exit(1);
	}
205 206 207 208 209 210 211 212 213


	conn = connectDatabase("template1", pghost, pgport, pguser, force_password);

	printf("--\n");
	printf("-- PostgreSQL database cluster dump\n");
	printf("--\n\n");
	printf("\\connect \"template1\"\n\n");

214 215 216 217 218
	if (!data_only)
	{
		dumpUsers(conn);
		dumpGroups(conn);
	}
219

220 221 222 223 224 225
	if (!globals_only)
	{
		if (!data_only)
			dumpCreateDB(conn);
		dumpDatabases(conn);
	}
226 227 228 229 230 231 232 233 234 235 236 237

	PQfinish(conn);
	exit(0);
}



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

240
	printf(_("\nOptions:\n"));
241
	printf(_("  -a, --data-only          dump only the data, not the schema\n"));
242
	printf(_("  -c, --clean              clean (drop) databases prior to create\n"));
243 244
	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"));
245
	printf(_("  -g, --globals-only       dump only global objects, no databases\n"));
246 247
	printf(_("  -i, --ignore-version     proceed even when server version mismatches\n"
			 "                           pg_dumpall version\n"));
248
	printf(_("  -s, --schema-only        dump only the schema, no data\n"));
249 250
	printf(_("  -o, --oids               include OIDs in dump\n"));
	printf(_("  -v, --verbose            verbose mode\n"));
251
	printf(_("  -x, --no-privileges      do not dump privileges (grant/revoke)\n"));
252 253 254 255
	printf(_("  --help                   show this help, then exit\n"));
	printf(_("  --version                output version information, then exit\n"));

	printf(_("\nConnection options:\n"));
256
	printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
257 258 259
	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"));
260 261 262 263 264 265 266 267 268 269 270 271 272

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



/*
 * Dump users (but not the user created by initdb).
 */
static void
dumpUsers(PGconn *conn)
{
Bruce Momjian's avatar
Bruce Momjian committed
273 274
	PGresult   *res;
	int			i;
275

276
	printf("--\n-- Users\n--\n\n");
277 278
	printf("DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');\n\n");

279 280 281
	if (server_version >= 70100)
		res = executeQuery(conn,
						   "SELECT usename, usesysid, passwd, usecreatedb, "
282
						   "usesuper, valuntil "
283 284 285 286 287
						   "FROM pg_shadow "
						   "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0')");
	else
		res = executeQuery(conn,
						   "SELECT usename, usesysid, passwd, usecreatedb, "
288
						   "usesuper, valuntil "
289 290
						   "FROM pg_shadow "
						   "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template1')");
291 292 293 294

	for (i = 0; i < PQntuples(res); i++)
	{
		PQExpBuffer buf = createPQExpBuffer();
295
		const char *username;
296

297
		username = PQgetvalue(res, i, 0);
298
		appendPQExpBuffer(buf, "CREATE USER %s WITH SYSID %s",
299
						  fmtId(username),
300 301 302 303 304 305 306 307
						  PQgetvalue(res, i, 1));

		if (!PQgetisnull(res, i, 2))
		{
			appendPQExpBuffer(buf, " PASSWORD ");
			appendStringLiteral(buf, PQgetvalue(res, i, 2), true);
		}

Bruce Momjian's avatar
Bruce Momjian committed
308
		if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
309 310 311 312
			appendPQExpBuffer(buf, " CREATEDB");
		else
			appendPQExpBuffer(buf, " NOCREATEDB");

Bruce Momjian's avatar
Bruce Momjian committed
313
		if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
314 315 316 317 318
			appendPQExpBuffer(buf, " CREATEUSER");
		else
			appendPQExpBuffer(buf, " NOCREATEUSER");

		if (!PQgetisnull(res, i, 5))
319 320
			appendPQExpBuffer(buf, " VALID UNTIL '%s'",
							  PQgetvalue(res, i, 5));
321 322 323 324 325

		appendPQExpBuffer(buf, ";\n");

		printf("%s", buf->data);
		destroyPQExpBuffer(buf);
326

327 328
		if (server_version >= 70300)
			dumpUserConfig(conn, username);
329 330 331 332 333 334 335 336 337 338 339 340 341 342
	}

	PQclear(res);
	printf("\n\n");
}



/*
 * Dump groups.
 */
static void
dumpGroups(PGconn *conn)
{
Bruce Momjian's avatar
Bruce Momjian committed
343 344
	PGresult   *res;
	int			i;
345

346
	printf("--\n-- Groups\n--\n\n");
347 348
	printf("DELETE FROM pg_group;\n\n");

349
	res = executeQuery(conn, "SELECT groname, grosysid, grolist FROM pg_group");
350 351 352 353

	for (i = 0; i < PQntuples(res); i++)
	{
		PQExpBuffer buf = createPQExpBuffer();
Bruce Momjian's avatar
Bruce Momjian committed
354 355
		char	   *val;
		char	   *tok;
356 357 358 359 360 361 362

		appendPQExpBuffer(buf, "CREATE GROUP %s WITH SYSID %s;\n",
						  fmtId(PQgetvalue(res, i, 0)),
						  PQgetvalue(res, i, 1));

		val = strdup(PQgetvalue(res, i, 2));
		tok = strtok(val, ",{}");
363
		while (tok)
364
		{
Bruce Momjian's avatar
Bruce Momjian committed
365
			PGresult   *res2;
366
			PQExpBuffer buf2 = createPQExpBuffer();
Bruce Momjian's avatar
Bruce Momjian committed
367
			int			j;
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382

			appendPQExpBuffer(buf2, "SELECT usename FROM pg_shadow WHERE usesysid = %s;", tok);
			res2 = executeQuery(conn, buf2->data);
			destroyPQExpBuffer(buf2);

			for (j = 0; j < PQntuples(res2); j++)
			{
				appendPQExpBuffer(buf, "ALTER GROUP %s ", fmtId(PQgetvalue(res, i, 0)));
				appendPQExpBuffer(buf, "ADD USER %s;\n", fmtId(PQgetvalue(res2, j, 0)));
			}

			PQclear(res2);

			tok = strtok(NULL, "{},");
		}
383
		free(val);
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408

		printf("%s", buf->data);
		destroyPQExpBuffer(buf);
	}

	PQclear(res);
	printf("\n\n");
}



/*
 * 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)
{
Bruce Momjian's avatar
Bruce Momjian committed
409 410
	PGresult   *res;
	int			i;
411

412 413
	printf("--\n-- Database creation\n--\n\n");

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
	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), "
						   "datistemplate, datpath, datacl "
						   "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
						   "WHERE datallowconn ORDER BY 1");
	else if (server_version >= 70100)
		res = executeQuery(conn,
						   "SELECT datname, "
						   "coalesce("
						   "(select usename from pg_shadow where usesysid=datdba), "
						   "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
						   "pg_encoding_to_char(d.encoding), "
						   "datistemplate, datpath, '' as datacl "
						   "FROM pg_database d "
						   "WHERE datallowconn ORDER BY 1");
	else
	{
		/*
		 * Note: 7.0 fails to cope with sub-select in COALESCE, so just
		 * deal with getting a NULL by not printing any OWNER clause.
		 */
		res = executeQuery(conn,
						   "SELECT datname, "
						   "(select usename from pg_shadow where usesysid=datdba), "
						   "pg_encoding_to_char(d.encoding), "
						   "'f' as datistemplate, datpath, '' as datacl "
						   "FROM pg_database d "
						   "ORDER BY 1");
	}
446 447 448

	for (i = 0; i < PQntuples(res); i++)
	{
449
		PQExpBuffer buf;
Bruce Momjian's avatar
Bruce Momjian committed
450 451 452 453 454
		char	   *dbname = PQgetvalue(res, i, 0);
		char	   *dbowner = PQgetvalue(res, i, 1);
		char	   *dbencoding = PQgetvalue(res, i, 2);
		char	   *dbistemplate = PQgetvalue(res, i, 3);
		char	   *dbpath = PQgetvalue(res, i, 4);
455 456
		char	   *dbacl = PQgetvalue(res, i, 5);
		char	   *fdbname;
457

Bruce Momjian's avatar
Bruce Momjian committed
458
		if (strcmp(dbname, "template1") == 0)
459 460
			continue;

461 462
		buf = createPQExpBuffer();

463 464 465
		/* needed for buildACLCommands() */
		fdbname = strdup(fmtId(dbname));

466
		if (output_clean)
467
			appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
468

469 470 471 472 473
		appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
		if (strlen(dbowner) != 0)
			appendPQExpBuffer(buf, " WITH OWNER = %s",
							  fmtId(dbowner));
		appendPQExpBuffer(buf, " TEMPLATE = template0");
474

475
		if (strlen(dbpath) != 0)
476 477 478 479 480 481 482 483 484 485
		{
			appendPQExpBuffer(buf, " LOCATION = ");
			appendStringLiteral(buf, dbpath, true);
		}

		appendPQExpBuffer(buf, " ENCODING = ");
		appendStringLiteral(buf, dbencoding, true);

		appendPQExpBuffer(buf, ";\n");

Bruce Momjian's avatar
Bruce Momjian committed
486
		if (strcmp(dbistemplate, "t") == 0)
487 488 489 490 491
		{
			appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
			appendStringLiteral(buf, dbname, true);
			appendPQExpBuffer(buf, ";\n");
		}
492

493 494
		if (!skip_acls &&
			!buildACLCommands(fdbname, "DATABASE", dbacl, dbowner,
495 496
							  server_version, buf))
		{
497
			fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
498 499 500 501 502
					progname, dbacl, fdbname);
			PQfinish(conn);
			exit(1);
		}

503 504
		printf("%s", buf->data);
		destroyPQExpBuffer(buf);
505
		free(fdbname);
506

507 508
		if (server_version >= 70300)
			dumpDatabaseConfig(conn, dbname);
509 510 511 512 513 514 515 516
	}

	PQclear(res);
	printf("\n\n");
}



517 518 519 520 521 522 523
/*
 * Dump database-specific configuration
 */
static void
dumpDatabaseConfig(PGconn *conn, const char *dbname)
{
	PQExpBuffer buf = createPQExpBuffer();
Bruce Momjian's avatar
Bruce Momjian committed
524
	int			count = 1;
525

Bruce Momjian's avatar
Bruce Momjian committed
526
	for (;;)
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
	{
		PGresult   *res;

		printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
		appendStringLiteral(buf, dbname, true);
		appendPQExpBuffer(buf, ";");

		res = executeQuery(conn, buf->data);
		if (!PQgetisnull(res, 0, 0))
		{
			makeAlterConfigCommand(PQgetvalue(res, 0, 0), "DATABASE", dbname);
			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
560
	int			count = 1;
561

Bruce Momjian's avatar
Bruce Momjian committed
562
	for (;;)
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
	{
		PGresult   *res;

		printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
		appendStringLiteral(buf, username, true);
		appendPQExpBuffer(buf, ";");

		res = executeQuery(conn, buf->data);
		if (!PQgetisnull(res, 0, 0))
		{
			makeAlterConfigCommand(PQgetvalue(res, 0, 0), "USER", username);
			PQclear(res);
			count++;
		}
		else
		{
			PQclear(res);
			break;
		}
	}

	destroyPQExpBuffer(buf);
}



/*
 * Helper function for dumpXXXConfig().
 */
static void
makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name)
{
Bruce Momjian's avatar
Bruce Momjian committed
595 596
	char	   *pos;
	char	   *mine;
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
	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));
	appendStringLiteral(buf, pos + 1, false);
	appendPQExpBuffer(buf, ";\n");

	printf("%s", buf->data);
	destroyPQExpBuffer(buf);
	free(mine);
}



617 618 619 620 621 622
/*
 * Dump contents of databases.
 */
static void
dumpDatabases(PGconn *conn)
{
Bruce Momjian's avatar
Bruce Momjian committed
623 624
	PGresult   *res;
	int			i;
625

626 627 628 629 630
	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");

631 632
	for (i = 0; i < PQntuples(res); i++)
	{
Bruce Momjian's avatar
Bruce Momjian committed
633 634 635
		int			ret;

		char	   *dbname = PQgetvalue(res, i, 0);
636 637 638 639

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

640
		printf("\\connect %s\n\n", fmtId(dbname));
641 642 643
		ret = runPgDump(dbname);
		if (ret != 0)
		{
644
			fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname);
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
			exit(1);
		}
	}

	PQclear(res);
}



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

664 665 666 667 668 669 670 671 672 673 674 675 676 677
	appendPQExpBuffer(cmd, "%s %s -X use-set-session-authorization -Fp '",
					  pgdumploc, pgdumpopts->data);

	/* Shell quoting is not quite like SQL quoting, so can't use fmtId */
	for (p = dbname; *p; p++)
	{
		if (*p == '\'')
			appendPQExpBuffer(cmd, "'\"'\"'");
		else
			appendPQExpBufferChar(cmd, *p);
	}

	appendPQExpBufferChar(cmd, '\'');

678
	if (verbose)
679
		fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
680

681 682 683
	fflush(stdout);
	fflush(stderr);

684
	ret = system(cmd->data);
685

686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
	destroyPQExpBuffer(cmd);

	return ret;
}



/*
 * Make a database connection with the given parameters.  An
 * interactive password prompt is automatically issued if required.
 */
static PGconn *
connectDatabase(const char *dbname, const char *pghost, const char *pgport,
				const char *pguser, bool require_password)
{
	PGconn	   *conn;
	char	   *password = NULL;
	bool		need_pass = false;
704
	const char *remoteversion_str;
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719

	if (require_password)
		password = simple_prompt("Password: ", 100, false);

	/*
	 * Start the connection.  Loop until we have a password if requested
	 * by backend.
	 */
	do
	{
		need_pass = false;
		conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);

		if (!conn)
		{
720
			fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
721
					progname, dbname);
722
			exit(1);
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
		}

		if (PQstatus(conn) == CONNECTION_BAD &&
			strcmp(PQerrorMessage(conn), "fe_sendauth: no password supplied\n") == 0 &&
			!feof(stdin))
		{
			PQfinish(conn);
			need_pass = true;
			free(password);
			password = NULL;
			password = simple_prompt("Password: ", 100, false);
		}
	} while (need_pass);

	if (password)
		free(password);

	/* check to see that the backend connection was successfully made */
	if (PQstatus(conn) == CONNECTION_BAD)
	{
743
		fprintf(stderr, _("%s: could not connect to database \"%s\": %s\n"),
Bruce Momjian's avatar
Bruce Momjian committed
744
				progname, dbname, PQerrorMessage(conn));
745 746 747
		exit(1);
	}

748 749
	remoteversion_str = PQparameterStatus(conn, "server_version");
	if (!remoteversion_str)
750 751 752 753
	{
		fprintf(stderr, _("%s: could not get server version\n"), progname);
		exit(1);
	}
754 755
	server_version = parse_version(remoteversion_str);
	if (server_version < 0)
756
	{
757 758 759
		fprintf(stderr, _("%s: could not parse server version \"%s\"\n"),
				progname, remoteversion_str);
		exit(1);
760 761 762 763 764 765 766 767 768 769 770 771 772
	}

	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
773
	PGresult   *res;
774

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

778 779 780 781 782
	res = PQexec(conn, query);
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		fprintf(stderr, _("%s: query failed: %s"), progname, PQerrorMessage(conn));
783
		fprintf(stderr, _("%s: query was: %s\n"), progname, query);
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
		PQfinish(conn);
		exit(1);
	}

	return res;
}



/*
 * Find location of pg_dump executable.
 */
static char *
findPgDump(const char *argv0)
{
	char	   *last;
	PQExpBuffer cmd;
	static char *result = NULL;

	if (result)
		return result;

	cmd = createPQExpBuffer();
807
	last = last_path_separator(argv0);
808 809 810 811 812

	if (!last)
		appendPQExpBuffer(cmd, "pg_dump");
	else
	{
Bruce Momjian's avatar
Bruce Momjian committed
813 814
		char	   *dir = strdup(argv0);

815 816 817 818 819 820 821
		*(dir + (last - argv0)) = '\0';
		appendPQExpBuffer(cmd, "%s/pg_dump", dir);
	}

	result = strdup(cmd->data);

	appendPQExpBuffer(cmd, " -V >/dev/null 2>&1");
Bruce Momjian's avatar
Bruce Momjian committed
822
	if (system(cmd->data) == 0)
823 824 825
		goto end;

	result = BINDIR "/pg_dump";
Bruce Momjian's avatar
Bruce Momjian committed
826
	if (system(BINDIR "/pg_dump -V >/dev/null 2>&1") == 0)
827 828 829
		goto end;

	fprintf(stderr, _("%s: could not find pg_dump\n"
Bruce Momjian's avatar
Bruce Momjian committed
830
		"Make sure it is in the path or in the same directory as %s.\n"),
831 832 833 834 835 836 837
			progname, progname);
	exit(1);

end:
	destroyPQExpBuffer(cmd);
	return result;
}