1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
9 * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.8 2002/09/22 20:57:20 petere Exp $
11 *-------------------------------------------------------------------------
14 #include "postgres_fe.h"
28 #include "dumputils.h"
30 #include "pg_backup.h"
31 #include "pqexpbuffer.h"
33 #define _(x) gettext((x))
36 static char *progname;
38 static void help(void);
40 static void dumpUsers(PGconn *conn);
41 static void dumpGroups(PGconn *conn);
42 static void dumpCreateDB(PGconn *conn);
43 static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
44 static void dumpUserConfig(PGconn *conn, const char *username);
45 static void makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name);
46 static void dumpDatabases(PGconn *conn);
48 static int runPgDump(const char *dbname);
49 static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
50 const char *pguser, bool require_password);
51 static PGresult *executeQuery(PGconn *conn, const char *query);
52 static char *findPgDump(const char *argv0);
56 PQExpBuffer pgdumpopts;
57 bool output_clean = false;
64 main(int argc, char *argv[])
69 bool force_password = false;
70 bool globals_only = false;
74 #ifdef HAVE_GETOPT_LONG
75 static struct option long_options[] = {
76 {"clean", no_argument, NULL, 'c'},
77 {"inserts", no_argument, NULL, 'd'},
78 {"attribute-inserts", no_argument, NULL, 'D'},
79 {"column-inserts", no_argument, NULL, 'D'},
80 {"host", required_argument, NULL, 'h'},
81 {"ignore-version", no_argument, NULL, 'i'},
82 {"oids", no_argument, NULL, 'o'},
83 {"port", required_argument, NULL, 'p'},
84 {"password", no_argument, NULL, 'W'},
85 {"username", required_argument, NULL, 'U'},
86 {"verbose", no_argument, NULL, 'v'},
94 setlocale(LC_ALL, "");
95 bindtextdomain("pg_dump", LOCALEDIR);
96 textdomain("pg_dump");
99 if (!strrchr(argv[0], '/'))
102 progname = strrchr(argv[0], '/') + 1;
106 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
111 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
113 puts("pg_dumpall (PostgreSQL) " PG_VERSION);
118 pgdumploc = findPgDump(argv[0]);
119 pgdumpopts = createPQExpBuffer();
121 #ifdef HAVE_GETOPT_LONG
122 while ((c = getopt_long(argc, argv, "cdDgh:iop:U:vW", long_options, &optindex)) != -1)
124 while ((c = getopt(argc, argv, "cdDgh:iop:U:vW")) != -1)
135 appendPQExpBuffer(pgdumpopts, " -%c", c);
144 appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost);
149 appendPQExpBuffer(pgdumpopts, " -%c", c);
154 appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport);
159 appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser);
164 appendPQExpBuffer(pgdumpopts, " -v");
168 force_password = true;
169 appendPQExpBuffer(pgdumpopts, " -W");
173 fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
181 _("%s: too many command line options (first is '%s')\n"
182 "Try '%s --help' for more information.\n"),
183 progname, argv[optind], progname);
188 conn = connectDatabase("template1", pghost, pgport, pguser, force_password);
191 printf("-- PostgreSQL database cluster dump\n");
193 printf("\\connect \"template1\"\n\n");
214 printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
215 printf(_("Usage:\n"));
216 printf(_(" %s [OPTIONS]\n\n"), progname);
218 printf(_("Options:\n"));
219 #ifdef HAVE_GETOPT_LONG
220 printf(_(" -c, --clean clean (drop) databases prior to create\n"));
221 printf(_(" -d, --inserts dump data as INSERT, rather than COPY, commands\n"));
222 printf(_(" -D, --column-inserts dump data as INSERT commands with column names\n"));
223 printf(_(" -g, --globals-only dump only global objects, no databases\n"));
224 printf(_(" -h, --host=HOSTNAME database server host name\n"));
225 printf(_(" -i, --ignore-version proceed even when server version mismatches\n"
226 " pg_dumpall version\n"));
227 printf(_(" -o, --oids include OIDs in dump\n"));
228 printf(_(" -p, --port=PORT database server port number\n"));
229 printf(_(" -U, --username=NAME connect as specified database user\n"));
230 printf(_(" -v, --verbose verbose mode\n"));
231 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
232 #else /* not HAVE_GETOPT_LONG */
233 printf(_(" -c clean (drop) databases prior to create\n"));
234 printf(_(" -d dump data as INSERT, rather than COPY, commands\n"));
235 printf(_(" -D dump data as INSERT commands with column names\n"));
236 printf(_(" -g dump only global objects, no databases\n"));
237 printf(_(" -h HOSTNAME database server host name\n"));
238 printf(_(" -i proceed even when server version mismatches\n"
239 " pg_dumpall version\n"));
240 printf(_(" -o include OIDs in dump\n"));
241 printf(_(" -p PORT database server port number\n"));
242 printf(_(" -U NAME connect as specified database user\n"));
243 printf(_(" -v verbose mode\n"));
244 printf(_(" -W force password prompt (should happen automatically)\n"));
245 #endif /* not HAVE_GETOPT_LONG */
247 printf(_("\nThe SQL script will be written to the standard output.\n\n"));
248 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
254 * Dump users (but not the user created by initdb).
257 dumpUsers(PGconn *conn)
262 printf("--\n-- Users\n--\n\n");
263 printf("DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');\n\n");
265 res = executeQuery(conn,
266 "SELECT usename, usesysid, passwd, usecreatedb, usesuper, CAST(valuntil AS timestamp) "
268 "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');");
270 for (i = 0; i < PQntuples(res); i++)
272 PQExpBuffer buf = createPQExpBuffer();
273 const char *username;
275 username = PQgetvalue(res, i, 0);
276 appendPQExpBuffer(buf, "CREATE USER %s WITH SYSID %s",
278 PQgetvalue(res, i, 1));
280 if (!PQgetisnull(res, i, 2))
282 appendPQExpBuffer(buf, " PASSWORD ");
283 appendStringLiteral(buf, PQgetvalue(res, i, 2), true);
286 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
287 appendPQExpBuffer(buf, " CREATEDB");
289 appendPQExpBuffer(buf, " NOCREATEDB");
291 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
292 appendPQExpBuffer(buf, " CREATEUSER");
294 appendPQExpBuffer(buf, " NOCREATEUSER");
296 if (!PQgetisnull(res, i, 5))
297 appendPQExpBuffer(buf, " VALID UNTIL '%s'", PQgetvalue(res, i, 5));
299 appendPQExpBuffer(buf, ";\n");
301 printf("%s", buf->data);
302 destroyPQExpBuffer(buf);
304 if (server_version >= 70300)
305 dumpUserConfig(conn, username);
318 dumpGroups(PGconn *conn)
323 printf("--\n-- Groups\n--\n\n");
324 printf("DELETE FROM pg_group;\n\n");
326 res = executeQuery(conn, "SELECT groname, grosysid, grolist FROM pg_group;");
328 for (i = 0; i < PQntuples(res); i++)
330 PQExpBuffer buf = createPQExpBuffer();
334 appendPQExpBuffer(buf, "CREATE GROUP %s WITH SYSID %s;\n",
335 fmtId(PQgetvalue(res, i, 0)),
336 PQgetvalue(res, i, 1));
338 val = strdup(PQgetvalue(res, i, 2));
339 tok = strtok(val, ",{}");
343 PQExpBuffer buf2 = createPQExpBuffer();
346 appendPQExpBuffer(buf2, "SELECT usename FROM pg_shadow WHERE usesysid = %s;", tok);
347 res2 = executeQuery(conn, buf2->data);
348 destroyPQExpBuffer(buf2);
350 for (j = 0; j < PQntuples(res2); j++)
352 appendPQExpBuffer(buf, "ALTER GROUP %s ", fmtId(PQgetvalue(res, i, 0)));
353 appendPQExpBuffer(buf, "ADD USER %s;\n", fmtId(PQgetvalue(res2, j, 0)));
358 tok = strtok(NULL, "{},");
362 printf("%s", buf->data);
363 destroyPQExpBuffer(buf);
373 * Dump commands to create each database.
375 * To minimize the number of reconnections (and possibly ensuing
376 * password prompts) required by the output script, we emit all CREATE
377 * DATABASE commands during the initial phase of the script, and then
378 * run pg_dump for each database to dump the contents of that
379 * database. We skip databases marked not datallowconn, since we'd be
380 * unable to connect to them anyway (and besides, we don't want to
384 dumpCreateDB(PGconn *conn)
389 printf("--\n-- Database creation\n--\n\n");
392 * Basically this query returns: dbname, dbowner, encoding,
395 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 FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) WHERE datallowconn ORDER BY 1;");
397 for (i = 0; i < PQntuples(res); i++)
399 PQExpBuffer buf = createPQExpBuffer();
400 char *dbname = PQgetvalue(res, i, 0);
401 char *dbowner = PQgetvalue(res, i, 1);
402 char *dbencoding = PQgetvalue(res, i, 2);
403 char *dbistemplate = PQgetvalue(res, i, 3);
404 char *dbpath = PQgetvalue(res, i, 4);
406 if (strcmp(dbname, "template1") == 0)
410 appendPQExpBuffer(buf, "DROP DATABASE %s\n;", fmtId(dbname));
412 appendPQExpBuffer(buf, "CREATE DATABASE %s", fmtId(dbname));
413 appendPQExpBuffer(buf, " WITH OWNER = %s TEMPLATE = template0", fmtId(dbowner));
415 if (strcmp(dbpath, "") != 0)
417 appendPQExpBuffer(buf, " LOCATION = ");
418 appendStringLiteral(buf, dbpath, true);
421 appendPQExpBuffer(buf, " ENCODING = ");
422 appendStringLiteral(buf, dbencoding, true);
424 appendPQExpBuffer(buf, ";\n");
426 if (strcmp(dbistemplate, "t") == 0)
428 appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
429 appendStringLiteral(buf, dbname, true);
430 appendPQExpBuffer(buf, ";\n");
432 printf("%s", buf->data);
433 destroyPQExpBuffer(buf);
435 if (server_version >= 70300)
436 dumpDatabaseConfig(conn, dbname);
446 * Dump database-specific configuration
449 dumpDatabaseConfig(PGconn *conn, const char *dbname)
451 PQExpBuffer buf = createPQExpBuffer();
458 printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
459 appendStringLiteral(buf, dbname, true);
460 appendPQExpBuffer(buf, ";");
462 res = executeQuery(conn, buf->data);
463 if (!PQgetisnull(res, 0, 0))
465 makeAlterConfigCommand(PQgetvalue(res, 0, 0), "DATABASE", dbname);
476 destroyPQExpBuffer(buf);
482 * Dump user-specific configuration
485 dumpUserConfig(PGconn *conn, const char *username)
487 PQExpBuffer buf = createPQExpBuffer();
494 printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
495 appendStringLiteral(buf, username, true);
496 appendPQExpBuffer(buf, ";");
498 res = executeQuery(conn, buf->data);
499 if (!PQgetisnull(res, 0, 0))
501 makeAlterConfigCommand(PQgetvalue(res, 0, 0), "USER", username);
512 destroyPQExpBuffer(buf);
518 * Helper function for dumpXXXConfig().
521 makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name)
525 PQExpBuffer buf = createPQExpBuffer();
527 mine = strdup(arrayitem);
528 pos = strchr(mine, '=');
533 appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
534 appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
535 appendStringLiteral(buf, pos + 1, false);
536 appendPQExpBuffer(buf, ";\n");
538 printf("%s", buf->data);
539 destroyPQExpBuffer(buf);
546 * Dump contents of databases.
549 dumpDatabases(PGconn *conn)
554 res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;");
555 for (i = 0; i < PQntuples(res); i++)
559 char *dbname = PQgetvalue(res, i, 0);
562 fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
564 printf("\\connect %s\n", fmtId(dbname));
565 ret = runPgDump(dbname);
568 fprintf(stderr, _("%s: pg_dump failed on %s, exiting\n"), progname, dbname);
579 * Run pg_dump on dbname.
582 runPgDump(const char *dbname)
584 PQExpBuffer cmd = createPQExpBuffer();
587 appendPQExpBuffer(cmd, "%s %s -X use-set-session-authorization -Fp %s",
588 pgdumploc, pgdumpopts->data, dbname);
590 fprintf(stderr, _("%s: running %s\n"), progname, cmd->data);
595 ret = system(cmd->data);
596 destroyPQExpBuffer(cmd);
604 * Make a database connection with the given parameters. An
605 * interactive password prompt is automatically issued if required.
608 connectDatabase(const char *dbname, const char *pghost, const char *pgport,
609 const char *pguser, bool require_password)
612 char *password = NULL;
613 bool need_pass = false;
616 if (require_password)
617 password = simple_prompt("Password: ", 100, false);
620 * Start the connection. Loop until we have a password if requested
626 conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);
630 fprintf(stderr, _("%s: could not connect to database %s\n"),
635 if (PQstatus(conn) == CONNECTION_BAD &&
636 strcmp(PQerrorMessage(conn), "fe_sendauth: no password supplied\n") == 0 &&
643 password = simple_prompt("Password: ", 100, false);
650 /* check to see that the backend connection was successfully made */
651 if (PQstatus(conn) == CONNECTION_BAD)
653 fprintf(stderr, _("%s: could not connect to database %s: %s\n"),
654 progname, dbname, PQerrorMessage(conn));
658 res = executeQuery(conn, "SELECT version();");
659 if (PQntuples(res) != 1)
661 fprintf(stderr, _("%s: could not get server version\n"), progname);
666 char *val = PQgetvalue(res, 0, 0);
667 server_version = parse_version(val + strcspn(val, "0123456789"));
668 if (server_version < 0)
670 fprintf(stderr, _("%s: could not parse server version \"%s\"\n"), progname, val);
681 * Run a query, return the results, exit program on failure.
684 executeQuery(PGconn *conn, const char *query)
688 res = PQexec(conn, query);
690 PQresultStatus(res) != PGRES_TUPLES_OK)
692 fprintf(stderr, _("%s: query failed: %s"), progname, PQerrorMessage(conn));
693 fprintf(stderr, _("%s: query was: %s\n"), progname, query);
704 * Find location of pg_dump executable.
707 findPgDump(const char *argv0)
711 static char *result = NULL;
716 cmd = createPQExpBuffer();
717 last = strrchr(argv0, '/');
720 appendPQExpBuffer(cmd, "pg_dump");
723 char *dir = strdup(argv0);
725 *(dir + (last - argv0)) = '\0';
726 appendPQExpBuffer(cmd, "%s/pg_dump", dir);
729 result = strdup(cmd->data);
731 appendPQExpBuffer(cmd, " -V >/dev/null 2>&1");
732 if (system(cmd->data) == 0)
735 result = BINDIR "/pg_dump";
736 if (system(BINDIR "/pg_dump -V >/dev/null 2>&1") == 0)
739 fprintf(stderr, _("%s: could not find pg_dump\n"
740 "Make sure it is in the path or in the same directory as %s.\n"),
745 destroyPQExpBuffer(cmd);