1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
9 * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.41 2004/06/10 16:35:17 momjian Exp $
11 *-------------------------------------------------------------------------
14 #include "postgres_fe.h"
26 #include "getopt_long.h"
32 #include "dumputils.h"
34 #include "pg_backup.h"
35 #include "pqexpbuffer.h"
37 #define _(x) gettext((x))
39 /* version string we expect back from postgres */
40 #define PG_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
43 static const char *progname;
45 static void help(void);
47 static void dumpUsers(PGconn *conn);
48 static void dumpGroups(PGconn *conn);
49 static void dumpCreateDB(PGconn *conn);
50 static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
51 static void dumpUserConfig(PGconn *conn, const char *username);
52 static void makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name);
53 static void dumpDatabases(PGconn *conn);
54 static void dumpTimestamp(char *msg);
56 static int runPgDump(const char *dbname);
57 static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
58 const char *pguser, bool require_password);
59 static PGresult *executeQuery(PGconn *conn, const char *query);
62 char pg_dump_bin[MAXPGPATH];
63 PQExpBuffer pgdumpopts;
64 bool output_clean = false;
65 bool skip_acls = false;
72 main(int argc, char *argv[])
77 bool force_password = false;
78 bool data_only = false;
79 bool globals_only = false;
80 bool schema_only = false;
84 static struct option long_options[] = {
85 {"data-only", no_argument, NULL, 'a'},
86 {"clean", no_argument, NULL, 'c'},
87 {"inserts", no_argument, NULL, 'd'},
88 {"attribute-inserts", no_argument, NULL, 'D'},
89 {"column-inserts", no_argument, NULL, 'D'},
90 {"globals-only", no_argument, NULL, 'g'},
91 {"host", required_argument, NULL, 'h'},
92 {"ignore-version", no_argument, NULL, 'i'},
93 {"oids", no_argument, NULL, 'o'},
94 {"port", required_argument, NULL, 'p'},
95 {"password", no_argument, NULL, 'W'},
96 {"schema-only", no_argument, NULL, 's'},
97 {"username", required_argument, NULL, 'U'},
98 {"verbose", no_argument, NULL, 'v'},
99 {"no-privileges", no_argument, NULL, 'x'},
100 {"no-acl", no_argument, NULL, 'x'},
106 set_pglocale_pgservice(argv[0], "pg_dump");
108 progname = get_progname(argv[0]);
112 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
117 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
119 puts("pg_dumpall (PostgreSQL) " PG_VERSION);
124 if ((ret = find_other_exec(argv[0], "pg_dump", PG_VERSIONSTR,
129 _("The program \"pg_dump\" is needed by %s "
130 "but was not found in the same directory as \"%s\".\n"
131 "Check your installation.\n"),
135 _("The program \"pg_dump\" was found by %s "
136 "but was not the same version as \"%s\".\n"
137 "Check your installation.\n"),
142 pgdumpopts = createPQExpBuffer();
144 while ((c = getopt_long(argc, argv, "acdDgh:iop:sU:vWx", long_options, &optindex)) != -1)
150 appendPQExpBuffer(pgdumpopts, " -a");
159 appendPQExpBuffer(pgdumpopts, " -%c", c);
168 appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost);
173 appendPQExpBuffer(pgdumpopts, " -%c", c);
178 appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport);
183 appendPQExpBuffer(pgdumpopts, " -s");
188 appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser);
193 appendPQExpBuffer(pgdumpopts, " -v");
197 force_password = true;
198 appendPQExpBuffer(pgdumpopts, " -W");
203 appendPQExpBuffer(pgdumpopts, " -x");
207 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
214 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
215 progname, argv[optind]);
216 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
222 conn = connectDatabase("template1", pghost, pgport, pguser, force_password);
224 printf("--\n-- PostgreSQL database cluster dump\n--\n\n");
226 dumpTimestamp("Started on");
228 printf("\\connect \"template1\"\n\n");
246 dumpTimestamp("Completed on");
247 printf("--\n-- PostgreSQL database cluster dump complete\n--\n\n");
257 printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
258 printf(_("Usage:\n"));
259 printf(_(" %s [OPTION]...\n"), progname);
261 printf(_("\nOptions:\n"));
262 printf(_(" -a, --data-only dump only the data, not the schema\n"));
263 printf(_(" -c, --clean clean (drop) databases prior to create\n"));
264 printf(_(" -d, --inserts dump data as INSERT, rather than COPY, commands\n"));
265 printf(_(" -D, --column-inserts dump data as INSERT commands with column names\n"));
266 printf(_(" -g, --globals-only dump only global objects, no databases\n"));
267 printf(_(" -i, --ignore-version proceed even when server version mismatches\n"
268 " pg_dumpall version\n"));
269 printf(_(" -s, --schema-only dump only the schema, no data\n"));
270 printf(_(" -o, --oids include OIDs in dump\n"));
271 printf(_(" -v, --verbose verbose mode\n"));
272 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
273 printf(_(" --help show this help, then exit\n"));
274 printf(_(" --version output version information, then exit\n"));
276 printf(_("\nConnection options:\n"));
277 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
278 printf(_(" -p, --port=PORT database server port number\n"));
279 printf(_(" -U, --username=NAME connect as specified database user\n"));
280 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
282 printf(_("\nThe SQL script will be written to the standard output.\n\n"));
283 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
289 * Dump users (but not the user created by initdb).
292 dumpUsers(PGconn *conn)
297 printf("--\n-- Users\n--\n\n");
298 printf("DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');\n\n");
300 if (server_version >= 70100)
301 res = executeQuery(conn,
302 "SELECT usename, usesysid, passwd, usecreatedb, "
303 "usesuper, valuntil "
305 "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0')");
307 res = executeQuery(conn,
308 "SELECT usename, usesysid, passwd, usecreatedb, "
309 "usesuper, valuntil "
311 "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template1')");
313 for (i = 0; i < PQntuples(res); i++)
315 PQExpBuffer buf = createPQExpBuffer();
316 const char *username;
318 username = PQgetvalue(res, i, 0);
319 appendPQExpBuffer(buf, "CREATE USER %s WITH SYSID %s",
321 PQgetvalue(res, i, 1));
323 if (!PQgetisnull(res, i, 2))
325 appendPQExpBuffer(buf, " PASSWORD ");
326 appendStringLiteral(buf, PQgetvalue(res, i, 2), true);
329 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
330 appendPQExpBuffer(buf, " CREATEDB");
332 appendPQExpBuffer(buf, " NOCREATEDB");
334 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
335 appendPQExpBuffer(buf, " CREATEUSER");
337 appendPQExpBuffer(buf, " NOCREATEUSER");
339 if (!PQgetisnull(res, i, 5))
340 appendPQExpBuffer(buf, " VALID UNTIL '%s'",
341 PQgetvalue(res, i, 5));
343 appendPQExpBuffer(buf, ";\n");
345 printf("%s", buf->data);
346 destroyPQExpBuffer(buf);
348 if (server_version >= 70300)
349 dumpUserConfig(conn, username);
362 dumpGroups(PGconn *conn)
367 printf("--\n-- Groups\n--\n\n");
368 printf("DELETE FROM pg_group;\n\n");
370 res = executeQuery(conn, "SELECT groname, grosysid, grolist FROM pg_group");
372 for (i = 0; i < PQntuples(res); i++)
374 PQExpBuffer buf = createPQExpBuffer();
378 appendPQExpBuffer(buf, "CREATE GROUP %s WITH SYSID %s;\n",
379 fmtId(PQgetvalue(res, i, 0)),
380 PQgetvalue(res, i, 1));
382 val = strdup(PQgetvalue(res, i, 2));
383 tok = strtok(val, ",{}");
387 PQExpBuffer buf2 = createPQExpBuffer();
390 appendPQExpBuffer(buf2, "SELECT usename FROM pg_shadow WHERE usesysid = %s;", tok);
391 res2 = executeQuery(conn, buf2->data);
392 destroyPQExpBuffer(buf2);
394 for (j = 0; j < PQntuples(res2); j++)
396 appendPQExpBuffer(buf, "ALTER GROUP %s ", fmtId(PQgetvalue(res, i, 0)));
397 appendPQExpBuffer(buf, "ADD USER %s;\n", fmtId(PQgetvalue(res2, j, 0)));
402 tok = strtok(NULL, "{},");
406 printf("%s", buf->data);
407 destroyPQExpBuffer(buf);
417 * Dump commands to create each database.
419 * To minimize the number of reconnections (and possibly ensuing
420 * password prompts) required by the output script, we emit all CREATE
421 * DATABASE commands during the initial phase of the script, and then
422 * run pg_dump for each database to dump the contents of that
423 * database. We skip databases marked not datallowconn, since we'd be
424 * unable to connect to them anyway (and besides, we don't want to
428 dumpCreateDB(PGconn *conn)
433 printf("--\n-- Database creation\n--\n\n");
435 if (server_version >= 70300)
436 res = executeQuery(conn,
438 "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
439 "pg_encoding_to_char(d.encoding), "
440 "datistemplate, datpath, datacl "
441 "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
442 "WHERE datallowconn ORDER BY 1");
443 else if (server_version >= 70100)
444 res = executeQuery(conn,
447 "(select usename from pg_shadow where usesysid=datdba), "
448 "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
449 "pg_encoding_to_char(d.encoding), "
450 "datistemplate, datpath, '' as datacl "
451 "FROM pg_database d "
452 "WHERE datallowconn ORDER BY 1");
456 * In 7.0, datpath is either the same as datname, or the user-given
457 * location with "/" and the datname appended. We must strip this
458 * junk off to produce a correct LOCATION value.
460 * Note: 7.0 fails to cope with sub-select in COALESCE, so just
461 * deal with getting a NULL by not printing any OWNER clause.
463 res = executeQuery(conn,
465 "(select usename from pg_shadow where usesysid=datdba), "
466 "pg_encoding_to_char(d.encoding), "
467 "'f' as datistemplate, "
468 "CASE WHEN length(datpath) > length(datname) THEN "
469 "substr(datpath,1,length(datpath)-length(datname)-1) "
470 "ELSE '' END as datpath, "
472 "FROM pg_database d "
476 for (i = 0; i < PQntuples(res); i++)
479 char *dbname = PQgetvalue(res, i, 0);
480 char *dbowner = PQgetvalue(res, i, 1);
481 char *dbencoding = PQgetvalue(res, i, 2);
482 char *dbistemplate = PQgetvalue(res, i, 3);
483 char *dbpath = PQgetvalue(res, i, 4);
484 char *dbacl = PQgetvalue(res, i, 5);
487 if (strcmp(dbname, "template1") == 0)
490 buf = createPQExpBuffer();
492 /* needed for buildACLCommands() */
493 fdbname = strdup(fmtId(dbname));
496 appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
498 appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
499 if (strlen(dbowner) != 0)
500 appendPQExpBuffer(buf, " WITH OWNER = %s",
502 appendPQExpBuffer(buf, " TEMPLATE = template0");
504 if (strlen(dbpath) != 0)
506 appendPQExpBuffer(buf, " LOCATION = ");
507 appendStringLiteral(buf, dbpath, true);
510 appendPQExpBuffer(buf, " ENCODING = ");
511 appendStringLiteral(buf, dbencoding, true);
513 appendPQExpBuffer(buf, ";\n");
515 if (strcmp(dbistemplate, "t") == 0)
517 appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
518 appendStringLiteral(buf, dbname, true);
519 appendPQExpBuffer(buf, ";\n");
523 !buildACLCommands(fdbname, "DATABASE", dbacl, dbowner,
524 server_version, buf))
526 fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
527 progname, dbacl, fdbname);
532 printf("%s", buf->data);
533 destroyPQExpBuffer(buf);
536 if (server_version >= 70300)
537 dumpDatabaseConfig(conn, dbname);
547 * Dump database-specific configuration
550 dumpDatabaseConfig(PGconn *conn, const char *dbname)
552 PQExpBuffer buf = createPQExpBuffer();
559 printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
560 appendStringLiteral(buf, dbname, true);
561 appendPQExpBuffer(buf, ";");
563 res = executeQuery(conn, buf->data);
564 if (!PQgetisnull(res, 0, 0))
566 makeAlterConfigCommand(PQgetvalue(res, 0, 0), "DATABASE", dbname);
577 destroyPQExpBuffer(buf);
583 * Dump user-specific configuration
586 dumpUserConfig(PGconn *conn, const char *username)
588 PQExpBuffer buf = createPQExpBuffer();
595 printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
596 appendStringLiteral(buf, username, true);
597 appendPQExpBuffer(buf, ";");
599 res = executeQuery(conn, buf->data);
600 if (!PQgetisnull(res, 0, 0))
602 makeAlterConfigCommand(PQgetvalue(res, 0, 0), "USER", username);
613 destroyPQExpBuffer(buf);
619 * Helper function for dumpXXXConfig().
622 makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name)
626 PQExpBuffer buf = createPQExpBuffer();
628 mine = strdup(arrayitem);
629 pos = strchr(mine, '=');
634 appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
635 appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
636 appendStringLiteral(buf, pos + 1, false);
637 appendPQExpBuffer(buf, ";\n");
639 printf("%s", buf->data);
640 destroyPQExpBuffer(buf);
647 * Dump contents of databases.
650 dumpDatabases(PGconn *conn)
655 if (server_version >= 70100)
656 res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1");
658 res = executeQuery(conn, "SELECT datname FROM pg_database ORDER BY 1");
660 for (i = 0; i < PQntuples(res); i++)
664 char *dbname = PQgetvalue(res, i, 0);
667 fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
669 printf("\\connect %s\n\n", fmtId(dbname));
670 ret = runPgDump(dbname);
673 fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname);
684 * Run pg_dump on dbname.
687 runPgDump(const char *dbname)
689 PQExpBuffer cmd = createPQExpBuffer();
693 appendPQExpBuffer(cmd, "%s\"%s\" %s -Fp '", SYSTEMQUOTE, pg_dump_bin,
696 /* Shell quoting is not quite like SQL quoting, so can't use fmtId */
697 for (p = dbname; *p; p++)
700 appendPQExpBuffer(cmd, "'\"'\"'");
702 appendPQExpBufferChar(cmd, *p);
705 appendPQExpBufferChar(cmd, '\'');
706 appendStringLiteral(cmd, SYSTEMQUOTE, false);
709 fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
714 ret = system(cmd->data);
716 destroyPQExpBuffer(cmd);
724 * Make a database connection with the given parameters. An
725 * interactive password prompt is automatically issued if required.
728 connectDatabase(const char *dbname, const char *pghost, const char *pgport,
729 const char *pguser, bool require_password)
732 char *password = NULL;
733 bool need_pass = false;
734 const char *remoteversion_str;
736 if (require_password)
737 password = simple_prompt("Password: ", 100, false);
740 * Start the connection. Loop until we have a password if requested
746 conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);
750 fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
755 if (PQstatus(conn) == CONNECTION_BAD &&
756 strcmp(PQerrorMessage(conn), "fe_sendauth: no password supplied\n") == 0 &&
763 password = simple_prompt("Password: ", 100, false);
770 /* check to see that the backend connection was successfully made */
771 if (PQstatus(conn) == CONNECTION_BAD)
773 fprintf(stderr, _("%s: could not connect to database \"%s\": %s\n"),
774 progname, dbname, PQerrorMessage(conn));
778 remoteversion_str = PQparameterStatus(conn, "server_version");
779 if (!remoteversion_str)
781 fprintf(stderr, _("%s: could not get server version\n"), progname);
784 server_version = parse_version(remoteversion_str);
785 if (server_version < 0)
787 fprintf(stderr, _("%s: could not parse server version \"%s\"\n"),
788 progname, remoteversion_str);
798 * Run a query, return the results, exit program on failure.
801 executeQuery(PGconn *conn, const char *query)
806 fprintf(stderr, _("%s: executing %s\n"), progname, query);
808 res = PQexec(conn, query);
810 PQresultStatus(res) != PGRES_TUPLES_OK)
812 fprintf(stderr, _("%s: query failed: %s"), progname, PQerrorMessage(conn));
813 fprintf(stderr, _("%s: query was: %s\n"), progname, query);
826 dumpTimestamp(char *msg)
829 time_t now = time(NULL);
831 if (strftime(buf, 256, "%Y-%m-%d %H:%M:%S %Z", localtime(&now)) != 0)
832 printf("-- %s %s\n\n", msg, buf);