]> granicus.if.org Git - postgresql/blobdiff - src/bin/pg_dump/pg_dumpall.c
Fix HAVE_OPTRESET to be HAVE_INT_OPTRESET. Typos spotted by Lorne Sunley.
[postgresql] / src / bin / pg_dump / pg_dumpall.c
index 1ff698ef5b97c4b4137c44edbd0c2d6ed67c4af4..d666d53376bf97b02e11825b0605b2f362a4254f 100644 (file)
@@ -2,11 +2,11 @@
  *
  * pg_dumpall
  *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.6 2002/09/04 20:31:35 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.55 2004/11/27 18:51:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #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>
+#include <time.h>
+
+#include "getopt_long.h"
+
+#ifndef HAVE_INT_OPTRESET
+int                    optreset;
+#endif
 
 #include "dumputils.h"
 #include "libpq-fe.h"
 
 #define _(x) gettext((x))
 
+/* version string we expect back from postgres */
+#define PG_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
+
 
-static char *progname;
+static const char *progname;
 
 static void help(void);
 
-static void dumpUsers(PGconn *conn);
+static void dumpUsers(PGconn *conn, bool initdbonly);
 static void dumpGroups(PGconn *conn);
+static void dumpTablespaces(PGconn *conn);
 static void dumpCreateDB(PGconn *conn);
 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);
 static void dumpDatabases(PGconn *conn);
+static void dumpTimestamp(char *msg);
 
 static int     runPgDump(const char *dbname);
 static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
                                const char *pguser, bool require_password);
 static PGresult *executeQuery(PGconn *conn, const char *query);
-static char *findPgDump(const char *argv0);
-
 
-char      *pgdumploc;
+char           pg_dump_bin[MAXPGPATH];
 PQExpBuffer pgdumpopts;
 bool           output_clean = false;
+bool           skip_acls = false;
 bool           verbose = false;
+int                    server_version;
 
-
+/* flags for -X long options */
+int                    disable_dollar_quoting = 0;
+int                    disable_triggers = 0;
+int                    use_setsessauth = 0;
 
 int
 main(int argc, char *argv[])
@@ -66,39 +78,49 @@ main(int argc, char *argv[])
        char       *pgport = NULL;
        char       *pguser = NULL;
        bool            force_password = false;
+       bool            data_only = false;
        bool            globals_only = false;
+       bool            schema_only = false;
        PGconn     *conn;
-       int                     c;
+       int                     c,
+                               ret;
 
-#ifdef HAVE_GETOPT_LONG
        static struct option long_options[] = {
+               {"data-only", no_argument, NULL, 'a'},
                {"clean", no_argument, NULL, 'c'},
                {"inserts", no_argument, NULL, 'd'},
                {"attribute-inserts", no_argument, NULL, 'D'},
                {"column-inserts", no_argument, NULL, 'D'},
+               {"globals-only", no_argument, NULL, 'g'},
                {"host", required_argument, NULL, 'h'},
                {"ignore-version", no_argument, NULL, 'i'},
                {"oids", no_argument, NULL, 'o'},
+               {"no-owner", no_argument, NULL, 'O'},
                {"port", required_argument, NULL, 'p'},
                {"password", no_argument, NULL, 'W'},
+               {"schema-only", no_argument, NULL, 's'},
+               {"superuser", required_argument, NULL, 'S'},
                {"username", required_argument, NULL, 'U'},
                {"verbose", no_argument, NULL, 'v'},
+               {"no-privileges", no_argument, NULL, 'x'},
+               {"no-acl", no_argument, NULL, 'x'},
+
+               /*
+                * the following options don't have an equivalent short option
+                * letter, but are available as '-X long-name'
+                */
+               {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
+               {"disable-triggers", no_argument, &disable_triggers, 1},
+               {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
+
                {NULL, 0, NULL, 0}
        };
 
        int                     optindex;
-#endif
 
-#ifdef ENABLE_NLS
-       setlocale(LC_ALL, "");
-       bindtextdomain("pg_dump", LOCALEDIR);
-       textdomain("pg_dump");
-#endif
+       set_pglocale_pgservice(argv[0], "pg_dump");
 
-       if (!strrchr(argv[0], '/'))
-               progname = argv[0];
-       else
-               progname = strrchr(argv[0], '/') + 1;
+       progname = get_progname(argv[0]);
 
        if (argc > 1)
        {
@@ -114,20 +136,43 @@ main(int argc, char *argv[])
                }
        }
 
-       pgdumploc = findPgDump(argv[0]);
+       if ((ret = find_other_exec(argv[0], "pg_dump", PG_VERSIONSTR,
+                                                          pg_dump_bin)) < 0)
+       {
+               char full_path[MAXPGPATH];
+
+               if (find_my_exec(argv[0], full_path) < 0)
+                       StrNCpy(full_path, progname, MAXPGPATH);
+
+               if (ret == -1)
+                       fprintf(stderr,
+                                       _("The program \"pg_dump\" is needed by %s "
+                                         "but was not found in the\n"
+                                         "same directory as \"%s\".\n"
+                                         "Check your installation.\n"),
+                                       progname, full_path);
+               else
+                       fprintf(stderr,
+                                       _("The program \"pg_dump\" was found by \"%s\"\n"
+                                         "but was not the same version as %s.\n"
+                                         "Check your installation.\n"),
+                                       full_path, progname);
+               exit(1);
+       }
+
        pgdumpopts = createPQExpBuffer();
 
-#ifdef HAVE_GETOPT_LONG
-       while ((c = getopt_long(argc, argv, "cdDgh:iop:U:vW", long_options, &optindex)) != -1)
-#else
-       while ((c = getopt(argc, argv, "cdDgh:iop:U:vW")) != -1)
-#endif
+       while ((c = getopt_long(argc, argv, "acdDgh:ioOp:sS:U:vWxX:", long_options, &optindex)) != -1)
        {
                switch (c)
                {
+                       case 'a':
+                               data_only = true;
+                               appendPQExpBuffer(pgdumpopts, " -a");
+                               break;
+
                        case 'c':
                                output_clean = true;
-                               appendPQExpBuffer(pgdumpopts, " -c");
                                break;
 
                        case 'd':
@@ -141,22 +186,54 @@ main(int argc, char *argv[])
 
                        case 'h':
                                pghost = optarg;
+#ifndef WIN32
                                appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost);
+#else
+                                appendPQExpBuffer(pgdumpopts, " -h \"%s\"", pghost);
+#endif
+
                                break;
 
+
+
                        case 'i':
                        case 'o':
                                appendPQExpBuffer(pgdumpopts, " -%c", c);
                                break;
 
+                       case 'O':
+                               appendPQExpBuffer(pgdumpopts, " -O");
+                               break;
+
                        case 'p':
                                pgport = optarg;
+#ifndef WIN32
                                appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport);
+#else
+                                appendPQExpBuffer(pgdumpopts, " -p \"%s\"", pgport);
+#endif
+                               break;
+
+                       case 's':
+                               schema_only = true;
+                               appendPQExpBuffer(pgdumpopts, " -s");
+                               break;
+
+                       case 'S':
+#ifndef WIN32
+                               appendPQExpBuffer(pgdumpopts, " -S '%s'", optarg);
+#else
+                                appendPQExpBuffer(pgdumpopts, " -S \"%s\"", optarg);
+#endif
                                break;
 
                        case 'U':
                                pguser = optarg;
+#ifndef WIN32
                                appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser);
+#else
+                                appendPQExpBuffer(pgdumpopts, " -U \"%s\"", pguser);
+#endif
                                break;
 
                        case 'v':
@@ -169,40 +246,85 @@ main(int argc, char *argv[])
                                appendPQExpBuffer(pgdumpopts, " -W");
                                break;
 
+                       case 'x':
+                               skip_acls = true;
+                               appendPQExpBuffer(pgdumpopts, " -x");
+                               break;
+
+                       case 'X':
+                               if (strcmp(optarg, "disable-dollar-quoting") == 0)
+                                       appendPQExpBuffer(pgdumpopts, " -X disable-dollar-quoting");
+                               else if (strcmp(optarg, "disable-triggers") == 0)
+                                       appendPQExpBuffer(pgdumpopts, " -X disable-triggers");
+                               else if (strcmp(optarg, "use-set-session-authorization") == 0)
+                                        /* no-op, still allowed for compatibility */ ;
+                               else
+                               {
+                                       fprintf(stderr,
+                                                       _("%s: invalid -X option -- %s\n"),
+                                                       progname, optarg);
+                                       fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
+                                       exit(1);
+                               }
+                               break;
+
+                       case 0:
+                               break;
+
                        default:
-                               fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
+                               fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                                exit(1);
                }
        }
 
+       /* Add long options to the pg_dump argument list */
+       if (disable_dollar_quoting)
+               appendPQExpBuffer(pgdumpopts, " -X disable-dollar-quoting");
+       if (disable_triggers)
+               appendPQExpBuffer(pgdumpopts, " -X disable-triggers");
+       if (use_setsessauth)
+               appendPQExpBuffer(pgdumpopts, " -X use-set-session-authorization");
+
        if (optind < argc)
        {
-               fprintf(stderr,
-                               _("%s: too many command line options (first is '%s')\n"
-                                 "Try '%s --help' for more information.\n"),
-                               progname, argv[optind], progname);
+               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);
                exit(1);
        }
 
 
        conn = connectDatabase("template1", pghost, pgport, pguser, force_password);
 
-       printf("--\n");
-       printf("-- PostgreSQL database cluster dump\n");
-       printf("--\n\n");
-       printf("\\connect \"template1\"\n\n");
+       printf("--\n-- PostgreSQL database cluster dump\n--\n\n");
+       if (verbose)
+               dumpTimestamp("Started on");
 
-       dumpUsers(conn);
-       dumpGroups(conn);
+       printf("\\connect \"template1\"\n\n");
 
-       if (globals_only)
-               goto end;
+       if (!data_only)
+       {
+               /* Dump all users excluding the initdb user */
+               dumpUsers(conn, false);
+               dumpGroups(conn);
+               if (server_version >= 80000)
+                       dumpTablespaces(conn);
+               if (!globals_only)
+                       dumpCreateDB(conn);
+               /* Dump alter command for initdb user */
+               dumpUsers(conn, true);
+       }
 
-       dumpCreateDB(conn);
-       dumpDatabases(conn);
+       if (!globals_only)
+               dumpDatabases(conn);
 
-end:
        PQfinish(conn);
+
+       if (verbose)
+               dumpTimestamp("Completed on");
+       printf("--\n-- PostgreSQL database cluster dump complete\n--\n\n");
+
        exit(0);
 }
 
@@ -213,36 +335,37 @@ help(void)
 {
        printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
        printf(_("Usage:\n"));
-       printf(_("  %s [OPTIONS]\n\n"), progname);
+       printf(_("  %s [OPTION]...\n"), progname);
 
-       printf(_("Options:\n"));
-#ifdef HAVE_GETOPT_LONG
-       printf(_("  -c, --clean              clean (drop) schema prior to create\n"));
-       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"));
-       printf(_("  -g, --globals-only       only dump global objects, no databases\n"));
-       printf(_("  -h, --host=HOSTNAME      database server host name\n"));
+       printf(_("\nGeneral options:\n"));
        printf(_("  -i, --ignore-version     proceed even when server version mismatches\n"
                         "                           pg_dumpall version\n"));
+       printf(_("  --help                   show this help, then exit\n"));
+       printf(_("  --version                output version information, then exit\n"));
+       printf(_("\nOptions controlling the output content:\n"));
+       printf(_("  -a, --data-only          dump only the data, not the schema\n"));
+       printf(_("  -c, --clean              clean (drop) databases prior to create\n"));
+       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"));
+       printf(_("  -g, --globals-only       dump only global objects, no databases\n"));
        printf(_("  -o, --oids               include OIDs in dump\n"));
+       printf(_("  -O, --no-owner           do not output commands to set object ownership\n"));
+       printf(_("  -s, --schema-only        dump only the schema, no data\n"));
+       printf(_("  -S, --superuser=NAME     specify the superuser user name to use in the dump\n"));
+       printf(_("  -x, --no-privileges      do not dump privileges (grant/revoke)\n"));
+       printf(_("  -X disable-dollar-quoting, --disable-dollar-quoting\n"
+                        "                           disable dollar quoting, use SQL standard quoting\n"));
+       printf(_("  -X disable-triggers, --disable-triggers\n"
+                        "                           disable triggers during data-only restore\n"));
+       printf(_("  -X use-set-session-authorization, --use-set-session-authorization\n"
+                        "                           use SESSION AUTHORIZATION commands instead of\n"
+                        "                           OWNER TO commands\n"));
+
+       printf(_("\nConnection options:\n"));
+       printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
        printf(_("  -p, --port=PORT          database server port number\n"));
        printf(_("  -U, --username=NAME      connect as specified database user\n"));
-       printf(_("  -v, --verbose            verbose mode\n"));
        printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
-#else                                                  /* not HAVE_GETOPT_LONG */
-       printf(_("  -c                       clean (drop) schema prior to create\n"));
-       printf(_("  -d                       dump data as INSERT, rather than COPY, commands\n"));
-       printf(_("  -D                       dump data as INSERT commands with column names\n"));
-       printf(_("  -g                       only dump global objects, no databases\n"));
-       printf(_("  -h HOSTNAME              database server host name\n"));
-       printf(_("  -i                       proceed even when server version mismatches\n"
-                        "                           pg_dumpall version\n"));
-       printf(_("  -o                       include OIDs in dump\n"));
-       printf(_("  -p PORT                  database server port number\n"));
-       printf(_("  -U NAME                  connect as specified database user\n"));
-       printf(_("  -v                       verbose mode\n"));
-       printf(_("  -W                       force password prompt (should happen automatically)\n"));
-#endif   /* not HAVE_GETOPT_LONG */
 
        printf(_("\nThe SQL script will be written to the standard output.\n\n"));
        printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
@@ -251,31 +374,57 @@ help(void)
 
 
 /*
- * Dump users (but not the user created by initdb).
+ * Dump users
+ * Is able to dump all non initdb users or just the initdb user.
  */
 static void
-dumpUsers(PGconn *conn)
+dumpUsers(PGconn *conn, bool initdbonly)
 {
        PGresult   *res;
        int                     i;
 
-       printf("--\n-- Users\n--\n\n");
-       printf("DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');\n\n");
+       if (server_version >= 70100)
+               res = executeQuery(conn,
+                                               "SELECT usename, usesysid, passwd, usecreatedb, "
+                                                  "usesuper, valuntil, "
+                                                  "(usesysid = (SELECT datdba FROM pg_database WHERE datname = 'template0')) AS clusterowner "
+                                                  "FROM pg_shadow");
+       else
+               res = executeQuery(conn,
+                                               "SELECT usename, usesysid, passwd, usecreatedb, "
+                                                  "usesuper, valuntil, "
+                                                  "(usesysid = (SELECT datdba FROM pg_database WHERE datname = 'template1')) AS clusterowner "
+                                                  "FROM pg_shadow");
 
-       res = executeQuery(conn,
-                                          "SELECT usename, usesysid, passwd, usecreatedb, usesuper, CAST(valuntil AS timestamp) "
-                                          "FROM pg_shadow "
-                                          "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');");
+       if (PQntuples(res) > 0 || (!initdbonly && output_clean))
+               printf("--\n-- Users\n--\n\n");
+       if (!initdbonly && output_clean)
+               printf("DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');\n\n");
 
        for (i = 0; i < PQntuples(res); i++)
        {
-               PQExpBuffer buf = createPQExpBuffer();
                const char *username;
+               bool            clusterowner;
+               PQExpBuffer buf = createPQExpBuffer();
 
                username = PQgetvalue(res, i, 0);
-               appendPQExpBuffer(buf, "CREATE USER %s WITH SYSID %s",
-                                                 fmtId(username),
-                                                 PQgetvalue(res, i, 1));
+               clusterowner = (strcmp(PQgetvalue(res, i, 6), "t") == 0);
+
+               /* Check which pass we're on */
+               if ((initdbonly && !clusterowner) || (!initdbonly && clusterowner))
+                       continue;
+
+               /*
+                * Dump ALTER USER for the cluster owner and CREATE USER for all
+                * other users
+                */
+               if (!clusterowner)
+                       appendPQExpBuffer(buf, "CREATE USER %s WITH SYSID %s",
+                                                         fmtId(username),
+                                                         PQgetvalue(res, i, 1));
+               else
+                       appendPQExpBuffer(buf, "ALTER USER %s WITH",
+                                                         fmtId(username));
 
                if (!PQgetisnull(res, i, 2))
                {
@@ -294,14 +443,16 @@ dumpUsers(PGconn *conn)
                        appendPQExpBuffer(buf, " NOCREATEUSER");
 
                if (!PQgetisnull(res, i, 5))
-                       appendPQExpBuffer(buf, " VALID UNTIL '%s'", PQgetvalue(res, i, 5));
+                       appendPQExpBuffer(buf, " VALID UNTIL '%s'",
+                                                         PQgetvalue(res, i, 5));
 
                appendPQExpBuffer(buf, ";\n");
 
                printf("%s", buf->data);
                destroyPQExpBuffer(buf);
 
-               dumpUserConfig(conn, username);
+               if (server_version >= 70300)
+                       dumpUserConfig(conn, username);
        }
 
        PQclear(res);
@@ -319,10 +470,12 @@ dumpGroups(PGconn *conn)
        PGresult   *res;
        int                     i;
 
-       printf("--\n-- Groups\n--\n\n");
-       printf("DELETE FROM pg_group;\n\n");
+       res = executeQuery(conn, "SELECT groname, grosysid, grolist FROM pg_group");
 
-       res = executeQuery(conn, "SELECT groname, grosysid, grolist FROM pg_group;");
+       if (PQntuples(res) > 0 || output_clean)
+               printf("--\n-- Groups\n--\n\n");
+       if (output_clean)
+               printf("DELETE FROM pg_group;\n\n");
 
        for (i = 0; i < PQntuples(res); i++)
        {
@@ -336,7 +489,7 @@ dumpGroups(PGconn *conn)
 
                val = strdup(PQgetvalue(res, i, 2));
                tok = strtok(val, ",{}");
-               do
+               while (tok)
                {
                        PGresult   *res2;
                        PQExpBuffer buf2 = createPQExpBuffer();
@@ -356,7 +509,7 @@ dumpGroups(PGconn *conn)
 
                        tok = strtok(NULL, "{},");
                }
-               while (tok);
+               free(val);
 
                printf("%s", buf->data);
                destroyPQExpBuffer(buf);
@@ -366,7 +519,69 @@ dumpGroups(PGconn *conn)
        printf("\n\n");
 }
 
+/*
+ * Dump tablespaces.
+ */
+static void
+dumpTablespaces(PGconn *conn)
+{
+       PGresult   *res;
+       int                     i;
+
+       /*
+        * Get all tablespaces except built-in ones (which we assume are named
+        * pg_xxx)
+        */
+       res = executeQuery(conn, "SELECT spcname, "
+                                        "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
+                                          "spclocation, spcacl "
+                                          "FROM pg_catalog.pg_tablespace "
+                                          "WHERE spcname NOT LIKE 'pg\\_%'");
+
+       if (PQntuples(res) > 0)
+               printf("--\n-- Tablespaces\n--\n\n");
+
+       for (i = 0; i < PQntuples(res); i++)
+       {
+               PQExpBuffer buf = createPQExpBuffer();
+               char       *spcname = PQgetvalue(res, i, 0);
+               char       *spcowner = PQgetvalue(res, i, 1);
+               char       *spclocation = PQgetvalue(res, i, 2);
+               char       *spcacl = PQgetvalue(res, i, 3);
+               char       *fspcname;
+
+               /* needed for buildACLCommands() */
+               fspcname = strdup(fmtId(spcname));
+
+               if (output_clean)
+                       appendPQExpBuffer(buf, "DROP TABLESPACE %s;\n", fspcname);
+
+               appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
+               appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
 
+               appendPQExpBuffer(buf, " LOCATION ");
+               appendStringLiteral(buf, spclocation, true);
+               appendPQExpBuffer(buf, ";\n");
+
+               if (!skip_acls &&
+                       !buildACLCommands(fspcname, "TABLESPACE", spcacl, spcowner,
+                                                         server_version, buf))
+               {
+                       fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
+                                       progname, spcacl, fspcname);
+                       PQfinish(conn);
+                       exit(1);
+               }
+
+               printf("%s", buf->data);
+
+               free(fspcname);
+               destroyPQExpBuffer(buf);
+       }
+
+       PQclear(res);
+       printf("\n\n");
+}
 
 /*
  * Dump commands to create each database.
@@ -387,39 +602,90 @@ dumpCreateDB(PGconn *conn)
 
        printf("--\n-- Database creation\n--\n\n");
 
-       /*
-        * Basically this query returns: dbname, dbowner, encoding,
-        * istemplate, dbpath
-        */
-       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;");
+       if (server_version >= 80000)
+               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, datacl, "
+                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
+               "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
+                                                  "WHERE datallowconn ORDER BY 1");
+       else 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, datacl, "
+                                                  "'pg_default' AS dattablespace "
+               "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, '' as datacl, "
+                                                  "'pg_default' AS dattablespace "
+                                                  "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, "
+                                                  "'' as datacl, "
+                                                  "'pg_default' AS dattablespace "
+                                                  "FROM pg_database d "
+                                                  "ORDER BY 1");
+       }
 
        for (i = 0; i < PQntuples(res); i++)
        {
-               PQExpBuffer buf = createPQExpBuffer();
+               PQExpBuffer buf;
                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);
+               char       *dbacl = PQgetvalue(res, i, 4);
+               char       *dbtablespace = PQgetvalue(res, i, 5);
+               char       *fdbname;
 
                if (strcmp(dbname, "template1") == 0)
                        continue;
 
+               buf = createPQExpBuffer();
+
+               /* needed for buildACLCommands() */
+               fdbname = strdup(fmtId(dbname));
+
                if (output_clean)
-                       appendPQExpBuffer(buf, "DROP DATABASE %s\n;", fmtId(dbname));
+                       appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
 
-               appendPQExpBuffer(buf, "CREATE DATABASE %s", fmtId(dbname));
-               appendPQExpBuffer(buf, " WITH OWNER = %s TEMPLATE = template0", fmtId(dbowner));
+               appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
 
-               if (strcmp(dbpath, "") != 0)
-               {
-                       appendPQExpBuffer(buf, " LOCATION = ");
-                       appendStringLiteral(buf, dbpath, true);
-               }
+               appendPQExpBuffer(buf, " WITH TEMPLATE = template0");
+
+               if (strlen(dbowner) != 0)
+                       appendPQExpBuffer(buf, " OWNER = %s",
+                                                         fmtId(dbowner));
 
                appendPQExpBuffer(buf, " ENCODING = ");
                appendStringLiteral(buf, dbencoding, true);
 
+               /* Output tablespace if it isn't default */
+               if (strcmp(dbtablespace, "pg_default") != 0)
+                       appendPQExpBuffer(buf, " TABLESPACE = %s",
+                                                         fmtId(dbtablespace));
+
                appendPQExpBuffer(buf, ";\n");
 
                if (strcmp(dbistemplate, "t") == 0)
@@ -428,10 +694,23 @@ dumpCreateDB(PGconn *conn)
                        appendStringLiteral(buf, dbname, true);
                        appendPQExpBuffer(buf, ";\n");
                }
+
+               if (!skip_acls &&
+                       !buildACLCommands(fdbname, "DATABASE", dbacl, dbowner,
+                                                         server_version, buf))
+               {
+                       fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
+                                       progname, dbacl, fdbname);
+                       PQfinish(conn);
+                       exit(1);
+               }
+
                printf("%s", buf->data);
                destroyPQExpBuffer(buf);
+               free(fdbname);
 
-               dumpDatabaseConfig(conn, dbname);
+               if (server_version >= 70300)
+                       dumpDatabaseConfig(conn, dbname);
        }
 
        PQclear(res);
@@ -530,7 +809,16 @@ makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name
        *pos = 0;
        appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
        appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
-       appendStringLiteral(buf, pos + 1, false);
+
+       /*
+        * Some GUC variable names are 'LIST' type and hence must not be
+        * quoted.
+        */
+       if (strcasecmp(mine, "DateStyle") == 0
+               || strcasecmp(mine, "search_path") == 0)
+               appendPQExpBuffer(buf, "%s", pos + 1);
+       else
+               appendStringLiteral(buf, pos + 1, false);
        appendPQExpBuffer(buf, ";\n");
 
        printf("%s", buf->data);
@@ -549,7 +837,11 @@ dumpDatabases(PGconn *conn)
        PGresult   *res;
        int                     i;
 
-       res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;");
+       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");
+
        for (i = 0; i < PQntuples(res); i++)
        {
                int                     ret;
@@ -559,11 +851,11 @@ dumpDatabases(PGconn *conn)
                if (verbose)
                        fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
 
-               printf("\\connect %s\n", fmtId(dbname));
+               printf("\\connect %s\n\n", fmtId(dbname));
                ret = runPgDump(dbname);
                if (ret != 0)
                {
-                       fprintf(stderr, _("%s: pg_dump failed on %s, exiting\n"), progname, dbname);
+                       fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname);
                        exit(1);
                }
        }
@@ -580,17 +872,51 @@ static int
 runPgDump(const char *dbname)
 {
        PQExpBuffer cmd = createPQExpBuffer();
+       const char *p;
        int                     ret;
 
-       appendPQExpBuffer(cmd, "%s %s -X use-set-session-authorization -Fp %s",
-                                         pgdumploc, pgdumpopts->data, dbname);
+       /*
+        * Win32 has to use double-quotes for args, rather than single quotes.
+        * Strangely enough, this is the only place we pass a database name on
+        * the command line, except template1 that doesn't need quoting.
+        */
+#ifndef WIN32
+       appendPQExpBuffer(cmd, "%s\"%s\" %s -Fp '", SYSTEMQUOTE, pg_dump_bin,
+#else
+       appendPQExpBuffer(cmd, "%s\"%s\" %s -Fp \"", SYSTEMQUOTE, pg_dump_bin,
+#endif
+                                         pgdumpopts->data);
+
+       /* Shell quoting is not quite like SQL quoting, so can't use fmtId */
+       for (p = dbname; *p; p++)
+       {
+#ifndef WIN32
+               if (*p == '\'')
+                       appendPQExpBuffer(cmd, "'\"'\"'");
+#else
+               if (*p == '"')
+                       appendPQExpBuffer(cmd, "\\\"");
+#endif
+               else
+                       appendPQExpBufferChar(cmd, *p);
+       }
+
+#ifndef WIN32
+       appendPQExpBufferChar(cmd, '\'');
+#else
+       appendPQExpBufferChar(cmd, '"');
+#endif
+
+       appendPQExpBuffer(cmd, "%s", SYSTEMQUOTE);
+
        if (verbose)
-               fprintf(stderr, _("%s: running %s\n"), progname, cmd->data);
+               fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
 
        fflush(stdout);
        fflush(stderr);
 
        ret = system(cmd->data);
+
        destroyPQExpBuffer(cmd);
 
        return ret;
@@ -609,6 +935,7 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
        PGconn     *conn;
        char       *password = NULL;
        bool            need_pass = false;
+       const char *remoteversion_str;
 
        if (require_password)
                password = simple_prompt("Password: ", 100, false);
@@ -624,13 +951,13 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
 
                if (!conn)
                {
-                       fprintf(stderr, _("%s: could not connect to database %s\n"),
+                       fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
                                        progname, dbname);
-                       exit(0);
+                       exit(1);
                }
 
                if (PQstatus(conn) == CONNECTION_BAD &&
-                       strcmp(PQerrorMessage(conn), "fe_sendauth: no password supplied\n") == 0 &&
+                       strcmp(PQerrorMessage(conn), PQnoPasswordSupplied) == 0 &&
                        !feof(stdin))
                {
                        PQfinish(conn);
@@ -647,9 +974,23 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
        /* check to see that the backend connection was successfully made */
        if (PQstatus(conn) == CONNECTION_BAD)
        {
-               fprintf(stderr, _("%s: could not connect to database %s: %s\n"),
+               fprintf(stderr, _("%s: could not connect to database \"%s\": %s\n"),
                                progname, dbname, PQerrorMessage(conn));
-               exit(0);
+               exit(1);
+       }
+
+       remoteversion_str = PQparameterStatus(conn, "server_version");
+       if (!remoteversion_str)
+       {
+               fprintf(stderr, _("%s: could not get server version\n"), progname);
+               exit(1);
+       }
+       server_version = parse_version(remoteversion_str);
+       if (server_version < 0)
+       {
+               fprintf(stderr, _("%s: could not parse server version \"%s\"\n"),
+                               progname, remoteversion_str);
+               exit(1);
        }
 
        return conn;
@@ -665,12 +1006,15 @@ executeQuery(PGconn *conn, const char *query)
 {
        PGresult   *res;
 
+       if (verbose)
+               fprintf(stderr, _("%s: executing %s\n"), progname, query);
+
        res = PQexec(conn, query);
        if (!res ||
                PQresultStatus(res) != PGRES_TUPLES_OK)
        {
                fprintf(stderr, _("%s: query failed: %s"), progname, PQerrorMessage(conn));
-               fprintf(stderr, _("%s: query was: %s"), progname, query);
+               fprintf(stderr, _("%s: query was: %s\n"), progname, query);
                PQfinish(conn);
                exit(1);
        }
@@ -679,49 +1023,15 @@ executeQuery(PGconn *conn, const char *query)
 }
 
 
-
 /*
- * Find location of pg_dump executable.
+ * dumpTimestamp
  */
-static char *
-findPgDump(const char *argv0)
+static void
+dumpTimestamp(char *msg)
 {
-       char       *last;
-       PQExpBuffer cmd;
-       static char *result = NULL;
-
-       if (result)
-               return result;
-
-       cmd = createPQExpBuffer();
-       last = strrchr(argv0, '/');
+       char            buf[256];
+       time_t          now = time(NULL);
 
-       if (!last)
-               appendPQExpBuffer(cmd, "pg_dump");
-       else
-       {
-               char       *dir = strdup(argv0);
-
-               *(dir + (last - argv0)) = '\0';
-               appendPQExpBuffer(cmd, "%s/pg_dump", dir);
-       }
-
-       result = strdup(cmd->data);
-
-       appendPQExpBuffer(cmd, " -V >/dev/null 2>&1");
-       if (system(cmd->data) == 0)
-               goto end;
-
-       result = BINDIR "/pg_dump";
-       if (system(BINDIR "/pg_dump -V >/dev/null 2>&1") == 0)
-               goto end;
-
-       fprintf(stderr, _("%s: could not find pg_dump\n"
-               "Make sure it is in the path or in the same directory as %s.\n"),
-                       progname, progname);
-       exit(1);
-
-end:
-       destroyPQExpBuffer(cmd);
-       return result;
+       if (strftime(buf, 256, "%Y-%m-%d %H:%M:%S %Z", localtime(&now)) != 0)
+               printf("-- %s %s\n\n", msg, buf);
 }