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.10 2002/11/22 03:09:43 tgl 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 [OPTION]...\n"), progname);
218 printf(_("\nOptions:\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(_(" -i, --ignore-version proceed even when server version mismatches\n"
225 " pg_dumpall version\n"));
226 printf(_(" -o, --oids include OIDs in dump\n"));
227 printf(_(" -v, --verbose verbose mode\n"));
228 #else /* not HAVE_GETOPT_LONG */
229 printf(_(" -c clean (drop) databases prior to create\n"));
230 printf(_(" -d dump data as INSERT, rather than COPY, commands\n"));
231 printf(_(" -D dump data as INSERT commands with column names\n"));
232 printf(_(" -g dump only global objects, no databases\n"));
233 printf(_(" -i proceed even when server version mismatches\n"
234 " pg_dumpall version\n"));
235 printf(_(" -o include OIDs in dump\n"));
236 printf(_(" -v verbose mode\n"));
237 #endif /* not HAVE_GETOPT_LONG */
238 printf(_(" --help show this help, then exit\n"));
239 printf(_(" --version output version information, then exit\n"));
241 printf(_("\nConnection options:\n"));
242 #ifdef HAVE_GETOPT_LONG
243 printf(_(" -h, --host=HOSTNAME database server host name\n"));
244 printf(_(" -p, --port=PORT database server port number\n"));
245 printf(_(" -U, --username=NAME connect as specified database user\n"));
246 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
247 #else /* not HAVE_GETOPT_LONG */
248 printf(_(" -h HOSTNAME database server host name\n"));
249 printf(_(" -p PORT database server port number\n"));
250 printf(_(" -U NAME connect as specified database user\n"));
251 printf(_(" -W force password prompt (should happen automatically)\n"));
252 #endif /* not HAVE_GETOPT_LONG */
254 printf(_("\nThe SQL script will be written to the standard output.\n\n"));
255 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
261 * Dump users (but not the user created by initdb).
264 dumpUsers(PGconn *conn)
269 printf("--\n-- Users\n--\n\n");
270 printf("DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');\n\n");
272 res = executeQuery(conn,
273 "SELECT usename, usesysid, passwd, usecreatedb, usesuper, CAST(valuntil AS timestamp) "
275 "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');");
277 for (i = 0; i < PQntuples(res); i++)
279 PQExpBuffer buf = createPQExpBuffer();
280 const char *username;
282 username = PQgetvalue(res, i, 0);
283 appendPQExpBuffer(buf, "CREATE USER %s WITH SYSID %s",
285 PQgetvalue(res, i, 1));
287 if (!PQgetisnull(res, i, 2))
289 appendPQExpBuffer(buf, " PASSWORD ");
290 appendStringLiteral(buf, PQgetvalue(res, i, 2), true);
293 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
294 appendPQExpBuffer(buf, " CREATEDB");
296 appendPQExpBuffer(buf, " NOCREATEDB");
298 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
299 appendPQExpBuffer(buf, " CREATEUSER");
301 appendPQExpBuffer(buf, " NOCREATEUSER");
303 if (!PQgetisnull(res, i, 5))
304 appendPQExpBuffer(buf, " VALID UNTIL '%s'", PQgetvalue(res, i, 5));
306 appendPQExpBuffer(buf, ";\n");
308 printf("%s", buf->data);
309 destroyPQExpBuffer(buf);
311 if (server_version >= 70300)
312 dumpUserConfig(conn, username);
325 dumpGroups(PGconn *conn)
330 printf("--\n-- Groups\n--\n\n");
331 printf("DELETE FROM pg_group;\n\n");
333 res = executeQuery(conn, "SELECT groname, grosysid, grolist FROM pg_group;");
335 for (i = 0; i < PQntuples(res); i++)
337 PQExpBuffer buf = createPQExpBuffer();
341 appendPQExpBuffer(buf, "CREATE GROUP %s WITH SYSID %s;\n",
342 fmtId(PQgetvalue(res, i, 0)),
343 PQgetvalue(res, i, 1));
345 val = strdup(PQgetvalue(res, i, 2));
346 tok = strtok(val, ",{}");
350 PQExpBuffer buf2 = createPQExpBuffer();
353 appendPQExpBuffer(buf2, "SELECT usename FROM pg_shadow WHERE usesysid = %s;", tok);
354 res2 = executeQuery(conn, buf2->data);
355 destroyPQExpBuffer(buf2);
357 for (j = 0; j < PQntuples(res2); j++)
359 appendPQExpBuffer(buf, "ALTER GROUP %s ", fmtId(PQgetvalue(res, i, 0)));
360 appendPQExpBuffer(buf, "ADD USER %s;\n", fmtId(PQgetvalue(res2, j, 0)));
365 tok = strtok(NULL, "{},");
369 printf("%s", buf->data);
370 destroyPQExpBuffer(buf);
380 * Dump commands to create each database.
382 * To minimize the number of reconnections (and possibly ensuing
383 * password prompts) required by the output script, we emit all CREATE
384 * DATABASE commands during the initial phase of the script, and then
385 * run pg_dump for each database to dump the contents of that
386 * database. We skip databases marked not datallowconn, since we'd be
387 * unable to connect to them anyway (and besides, we don't want to
391 dumpCreateDB(PGconn *conn)
396 printf("--\n-- Database creation\n--\n\n");
399 * Basically this query returns: dbname, dbowner, encoding,
402 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;");
404 for (i = 0; i < PQntuples(res); i++)
406 PQExpBuffer buf = createPQExpBuffer();
407 char *dbname = PQgetvalue(res, i, 0);
408 char *dbowner = PQgetvalue(res, i, 1);
409 char *dbencoding = PQgetvalue(res, i, 2);
410 char *dbistemplate = PQgetvalue(res, i, 3);
411 char *dbpath = PQgetvalue(res, i, 4);
413 if (strcmp(dbname, "template1") == 0)
417 appendPQExpBuffer(buf, "DROP DATABASE %s\n;", fmtId(dbname));
419 appendPQExpBuffer(buf, "CREATE DATABASE %s", fmtId(dbname));
420 appendPQExpBuffer(buf, " WITH OWNER = %s TEMPLATE = template0", fmtId(dbowner));
422 if (strcmp(dbpath, "") != 0)
424 appendPQExpBuffer(buf, " LOCATION = ");
425 appendStringLiteral(buf, dbpath, true);
428 appendPQExpBuffer(buf, " ENCODING = ");
429 appendStringLiteral(buf, dbencoding, true);
431 appendPQExpBuffer(buf, ";\n");
433 if (strcmp(dbistemplate, "t") == 0)
435 appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
436 appendStringLiteral(buf, dbname, true);
437 appendPQExpBuffer(buf, ";\n");
439 printf("%s", buf->data);
440 destroyPQExpBuffer(buf);
442 if (server_version >= 70300)
443 dumpDatabaseConfig(conn, dbname);
453 * Dump database-specific configuration
456 dumpDatabaseConfig(PGconn *conn, const char *dbname)
458 PQExpBuffer buf = createPQExpBuffer();
465 printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
466 appendStringLiteral(buf, dbname, true);
467 appendPQExpBuffer(buf, ";");
469 res = executeQuery(conn, buf->data);
470 if (!PQgetisnull(res, 0, 0))
472 makeAlterConfigCommand(PQgetvalue(res, 0, 0), "DATABASE", dbname);
483 destroyPQExpBuffer(buf);
489 * Dump user-specific configuration
492 dumpUserConfig(PGconn *conn, const char *username)
494 PQExpBuffer buf = createPQExpBuffer();
501 printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
502 appendStringLiteral(buf, username, true);
503 appendPQExpBuffer(buf, ";");
505 res = executeQuery(conn, buf->data);
506 if (!PQgetisnull(res, 0, 0))
508 makeAlterConfigCommand(PQgetvalue(res, 0, 0), "USER", username);
519 destroyPQExpBuffer(buf);
525 * Helper function for dumpXXXConfig().
528 makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name)
532 PQExpBuffer buf = createPQExpBuffer();
534 mine = strdup(arrayitem);
535 pos = strchr(mine, '=');
540 appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
541 appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
542 appendStringLiteral(buf, pos + 1, false);
543 appendPQExpBuffer(buf, ";\n");
545 printf("%s", buf->data);
546 destroyPQExpBuffer(buf);
553 * Dump contents of databases.
556 dumpDatabases(PGconn *conn)
561 res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;");
562 for (i = 0; i < PQntuples(res); i++)
566 char *dbname = PQgetvalue(res, i, 0);
569 fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
571 printf("\\connect %s\n", fmtId(dbname));
572 ret = runPgDump(dbname);
575 fprintf(stderr, _("%s: pg_dump failed on %s, exiting\n"), progname, dbname);
586 * Run pg_dump on dbname.
589 runPgDump(const char *dbname)
591 PQExpBuffer cmd = createPQExpBuffer();
595 appendPQExpBuffer(cmd, "%s %s -X use-set-session-authorization -Fp '",
596 pgdumploc, pgdumpopts->data);
598 /* Shell quoting is not quite like SQL quoting, so can't use fmtId */
599 for (p = dbname; *p; p++)
602 appendPQExpBuffer(cmd, "'\"'\"'");
604 appendPQExpBufferChar(cmd, *p);
607 appendPQExpBufferChar(cmd, '\'');
610 fprintf(stderr, _("%s: running %s\n"), progname, cmd->data);
615 ret = system(cmd->data);
617 destroyPQExpBuffer(cmd);
625 * Make a database connection with the given parameters. An
626 * interactive password prompt is automatically issued if required.
629 connectDatabase(const char *dbname, const char *pghost, const char *pgport,
630 const char *pguser, bool require_password)
633 char *password = NULL;
634 bool need_pass = false;
637 if (require_password)
638 password = simple_prompt("Password: ", 100, false);
641 * Start the connection. Loop until we have a password if requested
647 conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);
651 fprintf(stderr, _("%s: could not connect to database %s\n"),
656 if (PQstatus(conn) == CONNECTION_BAD &&
657 strcmp(PQerrorMessage(conn), "fe_sendauth: no password supplied\n") == 0 &&
664 password = simple_prompt("Password: ", 100, false);
671 /* check to see that the backend connection was successfully made */
672 if (PQstatus(conn) == CONNECTION_BAD)
674 fprintf(stderr, _("%s: could not connect to database %s: %s\n"),
675 progname, dbname, PQerrorMessage(conn));
679 res = executeQuery(conn, "SELECT version();");
680 if (PQntuples(res) != 1)
682 fprintf(stderr, _("%s: could not get server version\n"), progname);
687 char *val = PQgetvalue(res, 0, 0);
688 server_version = parse_version(val + strcspn(val, "0123456789"));
689 if (server_version < 0)
691 fprintf(stderr, _("%s: could not parse server version \"%s\"\n"), progname, val);
702 * Run a query, return the results, exit program on failure.
705 executeQuery(PGconn *conn, const char *query)
709 res = PQexec(conn, query);
711 PQresultStatus(res) != PGRES_TUPLES_OK)
713 fprintf(stderr, _("%s: query failed: %s"), progname, PQerrorMessage(conn));
714 fprintf(stderr, _("%s: query was: %s\n"), progname, query);
725 * Find location of pg_dump executable.
728 findPgDump(const char *argv0)
732 static char *result = NULL;
737 cmd = createPQExpBuffer();
738 last = strrchr(argv0, '/');
741 appendPQExpBuffer(cmd, "pg_dump");
744 char *dir = strdup(argv0);
746 *(dir + (last - argv0)) = '\0';
747 appendPQExpBuffer(cmd, "%s/pg_dump", dir);
750 result = strdup(cmd->data);
752 appendPQExpBuffer(cmd, " -V >/dev/null 2>&1");
753 if (system(cmd->data) == 0)
756 result = BINDIR "/pg_dump";
757 if (system(BINDIR "/pg_dump -V >/dev/null 2>&1") == 0)
760 fprintf(stderr, _("%s: could not find pg_dump\n"
761 "Make sure it is in the path or in the same directory as %s.\n"),
766 destroyPQExpBuffer(cmd);