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.25 2003/08/04 00:43:28 momjian Exp $
11 *-------------------------------------------------------------------------
14 #include "postgres_fe.h"
28 #ifndef HAVE_GETOPT_LONG
29 #include "getopt_long.h"
33 #include "dumputils.h"
35 #include "pg_backup.h"
36 #include "pqexpbuffer.h"
38 #define _(x) gettext((x))
41 static char *progname;
43 static void help(void);
45 static void dumpUsers(PGconn *conn);
46 static void dumpGroups(PGconn *conn);
47 static void dumpCreateDB(PGconn *conn);
48 static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
49 static void dumpUserConfig(PGconn *conn, const char *username);
50 static void makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name);
51 static void dumpDatabases(PGconn *conn);
53 static int runPgDump(const char *dbname);
54 static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
55 const char *pguser, bool require_password);
56 static PGresult *executeQuery(PGconn *conn, const char *query);
57 static char *findPgDump(const char *argv0);
61 PQExpBuffer pgdumpopts;
62 bool output_clean = false;
63 bool skip_acls = false;
70 main(int argc, char *argv[])
75 bool force_password = false;
76 bool data_only = false;
77 bool globals_only = false;
78 bool schema_only = false;
82 static struct option long_options[] = {
83 {"data-only", no_argument, NULL, 'a'},
84 {"clean", no_argument, NULL, 'c'},
85 {"inserts", no_argument, NULL, 'd'},
86 {"attribute-inserts", no_argument, NULL, 'D'},
87 {"column-inserts", no_argument, NULL, 'D'},
88 {"globals-only", no_argument, NULL, 'g'},
89 {"host", required_argument, NULL, 'h'},
90 {"ignore-version", no_argument, NULL, 'i'},
91 {"oids", no_argument, NULL, 'o'},
92 {"port", required_argument, NULL, 'p'},
93 {"password", no_argument, NULL, 'W'},
94 {"schema-only", no_argument, NULL, 's'},
95 {"username", required_argument, NULL, 'U'},
96 {"verbose", no_argument, NULL, 'v'},
97 {"no-privileges", no_argument, NULL, 'x'},
98 {"no-acl", no_argument, NULL, 'x'},
105 setlocale(LC_ALL, "");
106 bindtextdomain("pg_dump", LOCALEDIR);
107 textdomain("pg_dump");
110 progname = get_progname(argv[0]);
114 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
119 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
121 puts("pg_dumpall (PostgreSQL) " PG_VERSION);
126 pgdumploc = findPgDump(argv[0]);
127 pgdumpopts = createPQExpBuffer();
129 while ((c = getopt_long(argc, argv, "acdDgh:iop:sU:vWx", long_options, &optindex)) != -1)
135 appendPQExpBuffer(pgdumpopts, " -a");
144 appendPQExpBuffer(pgdumpopts, " -%c", c);
153 appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost);
158 appendPQExpBuffer(pgdumpopts, " -%c", c);
163 appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport);
168 appendPQExpBuffer(pgdumpopts, " -s");
173 appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser);
178 appendPQExpBuffer(pgdumpopts, " -v");
182 force_password = true;
183 appendPQExpBuffer(pgdumpopts, " -W");
188 appendPQExpBuffer(pgdumpopts, " -x");
192 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
199 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
200 progname, argv[optind]);
201 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
207 conn = connectDatabase("template1", pghost, pgport, pguser, force_password);
210 printf("-- PostgreSQL database cluster dump\n");
212 printf("\\connect \"template1\"\n\n");
236 printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
237 printf(_("Usage:\n"));
238 printf(_(" %s [OPTION]...\n"), progname);
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 printf(_(" -d, --inserts dump data as INSERT, rather than COPY, commands\n"));
244 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 printf(_(" -i, --ignore-version proceed even when server version mismatches\n"
247 " pg_dumpall version\n"));
248 printf(_(" -s, --schema-only dump only the schema, no data\n"));
249 printf(_(" -o, --oids include OIDs in dump\n"));
250 printf(_(" -v, --verbose verbose mode\n"));
251 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
252 printf(_(" --help show this help, then exit\n"));
253 printf(_(" --version output version information, then exit\n"));
255 printf(_("\nConnection options:\n"));
256 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
257 printf(_(" -p, --port=PORT database server port number\n"));
258 printf(_(" -U, --username=NAME connect as specified database user\n"));
259 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
261 printf(_("\nThe SQL script will be written to the standard output.\n\n"));
262 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
268 * Dump users (but not the user created by initdb).
271 dumpUsers(PGconn *conn)
276 printf("--\n-- Users\n--\n\n");
277 printf("DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');\n\n");
279 if (server_version >= 70100)
280 res = executeQuery(conn,
281 "SELECT usename, usesysid, passwd, usecreatedb, "
282 "usesuper, valuntil "
284 "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0')");
286 res = executeQuery(conn,
287 "SELECT usename, usesysid, passwd, usecreatedb, "
288 "usesuper, valuntil "
290 "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template1')");
292 for (i = 0; i < PQntuples(res); i++)
294 PQExpBuffer buf = createPQExpBuffer();
295 const char *username;
297 username = PQgetvalue(res, i, 0);
298 appendPQExpBuffer(buf, "CREATE USER %s WITH SYSID %s",
300 PQgetvalue(res, i, 1));
302 if (!PQgetisnull(res, i, 2))
304 appendPQExpBuffer(buf, " PASSWORD ");
305 appendStringLiteral(buf, PQgetvalue(res, i, 2), true);
308 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
309 appendPQExpBuffer(buf, " CREATEDB");
311 appendPQExpBuffer(buf, " NOCREATEDB");
313 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
314 appendPQExpBuffer(buf, " CREATEUSER");
316 appendPQExpBuffer(buf, " NOCREATEUSER");
318 if (!PQgetisnull(res, i, 5))
319 appendPQExpBuffer(buf, " VALID UNTIL '%s'",
320 PQgetvalue(res, i, 5));
322 appendPQExpBuffer(buf, ";\n");
324 printf("%s", buf->data);
325 destroyPQExpBuffer(buf);
327 if (server_version >= 70300)
328 dumpUserConfig(conn, username);
341 dumpGroups(PGconn *conn)
346 printf("--\n-- Groups\n--\n\n");
347 printf("DELETE FROM pg_group;\n\n");
349 res = executeQuery(conn, "SELECT groname, grosysid, grolist FROM pg_group");
351 for (i = 0; i < PQntuples(res); i++)
353 PQExpBuffer buf = createPQExpBuffer();
357 appendPQExpBuffer(buf, "CREATE GROUP %s WITH SYSID %s;\n",
358 fmtId(PQgetvalue(res, i, 0)),
359 PQgetvalue(res, i, 1));
361 val = strdup(PQgetvalue(res, i, 2));
362 tok = strtok(val, ",{}");
366 PQExpBuffer buf2 = createPQExpBuffer();
369 appendPQExpBuffer(buf2, "SELECT usename FROM pg_shadow WHERE usesysid = %s;", tok);
370 res2 = executeQuery(conn, buf2->data);
371 destroyPQExpBuffer(buf2);
373 for (j = 0; j < PQntuples(res2); j++)
375 appendPQExpBuffer(buf, "ALTER GROUP %s ", fmtId(PQgetvalue(res, i, 0)));
376 appendPQExpBuffer(buf, "ADD USER %s;\n", fmtId(PQgetvalue(res2, j, 0)));
381 tok = strtok(NULL, "{},");
385 printf("%s", buf->data);
386 destroyPQExpBuffer(buf);
396 * Dump commands to create each database.
398 * To minimize the number of reconnections (and possibly ensuing
399 * password prompts) required by the output script, we emit all CREATE
400 * DATABASE commands during the initial phase of the script, and then
401 * run pg_dump for each database to dump the contents of that
402 * database. We skip databases marked not datallowconn, since we'd be
403 * unable to connect to them anyway (and besides, we don't want to
407 dumpCreateDB(PGconn *conn)
412 printf("--\n-- Database creation\n--\n\n");
414 if (server_version >= 70300)
415 res = executeQuery(conn,
417 "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
418 "pg_encoding_to_char(d.encoding), "
419 "datistemplate, datpath, datacl "
420 "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
421 "WHERE datallowconn ORDER BY 1");
422 else if (server_version >= 70100)
423 res = executeQuery(conn,
426 "(select usename from pg_shadow where usesysid=datdba), "
427 "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
428 "pg_encoding_to_char(d.encoding), "
429 "datistemplate, datpath, '' as datacl "
430 "FROM pg_database d "
431 "WHERE datallowconn ORDER BY 1");
435 * Note: 7.0 fails to cope with sub-select in COALESCE, so just
436 * deal with getting a NULL by not printing any OWNER clause.
438 res = executeQuery(conn,
440 "(select usename from pg_shadow where usesysid=datdba), "
441 "pg_encoding_to_char(d.encoding), "
442 "'f' as datistemplate, datpath, '' as datacl "
443 "FROM pg_database d "
447 for (i = 0; i < PQntuples(res); i++)
450 char *dbname = PQgetvalue(res, i, 0);
451 char *dbowner = PQgetvalue(res, i, 1);
452 char *dbencoding = PQgetvalue(res, i, 2);
453 char *dbistemplate = PQgetvalue(res, i, 3);
454 char *dbpath = PQgetvalue(res, i, 4);
455 char *dbacl = PQgetvalue(res, i, 5);
458 if (strcmp(dbname, "template1") == 0)
461 buf = createPQExpBuffer();
463 /* needed for buildACLCommands() */
464 fdbname = strdup(fmtId(dbname));
467 appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
469 appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
470 if (strlen(dbowner) != 0)
471 appendPQExpBuffer(buf, " WITH OWNER = %s",
473 appendPQExpBuffer(buf, " TEMPLATE = template0");
475 if (strlen(dbpath) != 0)
477 appendPQExpBuffer(buf, " LOCATION = ");
478 appendStringLiteral(buf, dbpath, true);
481 appendPQExpBuffer(buf, " ENCODING = ");
482 appendStringLiteral(buf, dbencoding, true);
484 appendPQExpBuffer(buf, ";\n");
486 if (strcmp(dbistemplate, "t") == 0)
488 appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
489 appendStringLiteral(buf, dbname, true);
490 appendPQExpBuffer(buf, ";\n");
494 !buildACLCommands(fdbname, "DATABASE", dbacl, dbowner,
495 server_version, buf))
497 fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
498 progname, dbacl, fdbname);
503 printf("%s", buf->data);
504 destroyPQExpBuffer(buf);
507 if (server_version >= 70300)
508 dumpDatabaseConfig(conn, dbname);
518 * Dump database-specific configuration
521 dumpDatabaseConfig(PGconn *conn, const char *dbname)
523 PQExpBuffer buf = createPQExpBuffer();
530 printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
531 appendStringLiteral(buf, dbname, true);
532 appendPQExpBuffer(buf, ";");
534 res = executeQuery(conn, buf->data);
535 if (!PQgetisnull(res, 0, 0))
537 makeAlterConfigCommand(PQgetvalue(res, 0, 0), "DATABASE", dbname);
548 destroyPQExpBuffer(buf);
554 * Dump user-specific configuration
557 dumpUserConfig(PGconn *conn, const char *username)
559 PQExpBuffer buf = createPQExpBuffer();
566 printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
567 appendStringLiteral(buf, username, true);
568 appendPQExpBuffer(buf, ";");
570 res = executeQuery(conn, buf->data);
571 if (!PQgetisnull(res, 0, 0))
573 makeAlterConfigCommand(PQgetvalue(res, 0, 0), "USER", username);
584 destroyPQExpBuffer(buf);
590 * Helper function for dumpXXXConfig().
593 makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name)
597 PQExpBuffer buf = createPQExpBuffer();
599 mine = strdup(arrayitem);
600 pos = strchr(mine, '=');
605 appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
606 appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
607 appendStringLiteral(buf, pos + 1, false);
608 appendPQExpBuffer(buf, ";\n");
610 printf("%s", buf->data);
611 destroyPQExpBuffer(buf);
618 * Dump contents of databases.
621 dumpDatabases(PGconn *conn)
626 if (server_version >= 70100)
627 res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1");
629 res = executeQuery(conn, "SELECT datname FROM pg_database ORDER BY 1");
631 for (i = 0; i < PQntuples(res); i++)
635 char *dbname = PQgetvalue(res, i, 0);
638 fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
640 printf("\\connect %s\n\n", fmtId(dbname));
641 ret = runPgDump(dbname);
644 fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname);
655 * Run pg_dump on dbname.
658 runPgDump(const char *dbname)
660 PQExpBuffer cmd = createPQExpBuffer();
664 appendPQExpBuffer(cmd, "%s %s -X use-set-session-authorization -Fp '",
665 pgdumploc, pgdumpopts->data);
667 /* Shell quoting is not quite like SQL quoting, so can't use fmtId */
668 for (p = dbname; *p; p++)
671 appendPQExpBuffer(cmd, "'\"'\"'");
673 appendPQExpBufferChar(cmd, *p);
676 appendPQExpBufferChar(cmd, '\'');
679 fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
684 ret = system(cmd->data);
686 destroyPQExpBuffer(cmd);
694 * Make a database connection with the given parameters. An
695 * interactive password prompt is automatically issued if required.
698 connectDatabase(const char *dbname, const char *pghost, const char *pgport,
699 const char *pguser, bool require_password)
702 char *password = NULL;
703 bool need_pass = false;
704 const char *remoteversion_str;
706 if (require_password)
707 password = simple_prompt("Password: ", 100, false);
710 * Start the connection. Loop until we have a password if requested
716 conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);
720 fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
725 if (PQstatus(conn) == CONNECTION_BAD &&
726 strcmp(PQerrorMessage(conn), "fe_sendauth: no password supplied\n") == 0 &&
733 password = simple_prompt("Password: ", 100, false);
740 /* check to see that the backend connection was successfully made */
741 if (PQstatus(conn) == CONNECTION_BAD)
743 fprintf(stderr, _("%s: could not connect to database \"%s\": %s\n"),
744 progname, dbname, PQerrorMessage(conn));
748 remoteversion_str = PQparameterStatus(conn, "server_version");
749 if (!remoteversion_str)
751 fprintf(stderr, _("%s: could not get server version\n"), progname);
754 server_version = parse_version(remoteversion_str);
755 if (server_version < 0)
757 fprintf(stderr, _("%s: could not parse server version \"%s\"\n"),
758 progname, remoteversion_str);
768 * Run a query, return the results, exit program on failure.
771 executeQuery(PGconn *conn, const char *query)
776 fprintf(stderr, _("%s: executing %s\n"), progname, query);
778 res = PQexec(conn, query);
780 PQresultStatus(res) != PGRES_TUPLES_OK)
782 fprintf(stderr, _("%s: query failed: %s"), progname, PQerrorMessage(conn));
783 fprintf(stderr, _("%s: query was: %s\n"), progname, query);
794 * Find location of pg_dump executable.
797 findPgDump(const char *argv0)
801 static char *result = NULL;
806 cmd = createPQExpBuffer();
807 last = last_path_separator(argv0);
810 appendPQExpBuffer(cmd, "pg_dump");
813 char *dir = strdup(argv0);
815 *(dir + (last - argv0)) = '\0';
816 appendPQExpBuffer(cmd, "%s/pg_dump", dir);
819 result = strdup(cmd->data);
821 appendPQExpBuffer(cmd, " -V >/dev/null 2>&1");
822 if (system(cmd->data) == 0)
825 result = BINDIR "/pg_dump";
826 if (system(BINDIR "/pg_dump -V >/dev/null 2>&1") == 0)
829 fprintf(stderr, _("%s: could not find pg_dump\n"
830 "Make sure it is in the path or in the same directory as %s.\n"),
835 destroyPQExpBuffer(cmd);