]> granicus.if.org Git - postgresql/commitdiff
Add -d option to pg_dumpall, for specifying a connection string.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 25 Feb 2013 17:39:10 +0000 (19:39 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 25 Feb 2013 17:39:10 +0000 (19:39 +0200)
Like with pg_basebackup and pg_receivexlog, it's a bit strange to call the
option -d/--dbname, when in fact you cannot pass a database name in it.

Original patch by Amit Kapila, heavily modified by me.

doc/src/sgml/ref/pg_dumpall.sgml
src/bin/pg_dump/pg_dumpall.c

index 253ee01c0e4c9ce75f1027f072ddc0036e5a5ef7..5c6a101333fe5622e46eb4e457377b81c0af49e5 100644 (file)
@@ -405,6 +405,25 @@ PostgreSQL documentation
    The following command-line options control the database connection parameters.
 
    <variablelist>
+     <varlistentry>
+      <term><option>-d <replaceable class="parameter">connstr</replaceable></option></term>
+      <term><option>--dbname=<replaceable class="parameter">connstr</replaceable></option></term>
+      <listitem>
+       <para>
+        Specifies parameters used to connect to the server, as a connection
+        string. See <xref linkend="libpq-connstring"> for more information.
+       </para>
+       <para>
+        The option is called <literal>--dbname</> for consistency with other
+        client applications, but because <application>pg_dumpall</application>
+        needs to connect to many databases, database name in the connection
+        string will be ignored. Use <literal>-l</literal> option to specify
+        the name of the database used to dump global objects and to discover
+        what other databases should be dumped.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>-h <replaceable>host</replaceable></option></term>
       <term><option>--host=<replaceable>host</replaceable></option></term>
index a6e6a0fa9aad4adb43d6749083d69fe8b65b15f9..ac3f57e5fe1ed627f465f141591856a987116b47 100644 (file)
@@ -56,13 +56,15 @@ static int  runPgDump(const char *dbname);
 static void buildShSecLabels(PGconn *conn, const char *catalog_name,
                                 uint32 objectId, PQExpBuffer buffer,
                                 const char *target, const char *objname);
-static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
+static PGconn *connectDatabase(const char *dbname, const char *connstr, const char *pghost, const char *pgport,
          const char *pguser, enum trivalue prompt_password, bool fail_on_error);
+static char *constructConnStr(const char **keywords, const char **values);
 static PGresult *executeQuery(PGconn *conn, const char *query);
 static void executeCommand(PGconn *conn, const char *query);
 
 static char pg_dump_bin[MAXPGPATH];
 static PQExpBuffer pgdumpopts;
+static char *connstr = "";
 static bool skip_acls = false;
 static bool verbose = false;
 
@@ -91,6 +93,7 @@ main(int argc, char *argv[])
                {"globals-only", no_argument, NULL, 'g'},
                {"host", required_argument, NULL, 'h'},
                {"ignore-version", no_argument, NULL, 'i'},
+               {"dbname", required_argument, NULL, 'd'},
                {"database", required_argument, NULL, 'l'},
                {"oids", no_argument, NULL, 'o'},
                {"no-owner", no_argument, NULL, 'O'},
@@ -188,7 +191,7 @@ main(int argc, char *argv[])
 
        pgdumpopts = createPQExpBuffer();
 
-       while ((c = getopt_long(argc, argv, "acf:gh:il:oOp:rsS:tU:vwWx", long_options, &optindex)) != -1)
+       while ((c = getopt_long(argc, argv, "acd:f:gh:i:l:oOp:rsS:tU:vwWx", long_options, &optindex)) != -1)
        {
                switch (c)
                {
@@ -201,6 +204,10 @@ main(int argc, char *argv[])
                                output_clean = true;
                                break;
 
+                       case 'd':
+                               connstr = pg_strdup(optarg);
+                               break;
+
                        case 'f':
                                filename = pg_strdup(optarg);
                                appendPQExpBuffer(pgdumpopts, " -f ");
@@ -213,8 +220,6 @@ main(int argc, char *argv[])
 
                        case 'h':
                                pghost = pg_strdup(optarg);
-                               appendPQExpBuffer(pgdumpopts, " -h ");
-                               doShellQuoting(pgdumpopts, pghost);
                                break;
 
                        case 'i':
@@ -235,8 +240,6 @@ main(int argc, char *argv[])
 
                        case 'p':
                                pgport = pg_strdup(optarg);
-                               appendPQExpBuffer(pgdumpopts, " -p ");
-                               doShellQuoting(pgdumpopts, pgport);
                                break;
 
                        case 'r':
@@ -258,8 +261,6 @@ main(int argc, char *argv[])
 
                        case 'U':
                                pguser = pg_strdup(optarg);
-                               appendPQExpBuffer(pgdumpopts, " -U ");
-                               doShellQuoting(pgdumpopts, pguser);
                                break;
 
                        case 'v':
@@ -370,7 +371,7 @@ main(int argc, char *argv[])
         */
        if (pgdb)
        {
-               conn = connectDatabase(pgdb, pghost, pgport, pguser,
+               conn = connectDatabase(pgdb, connstr, pghost, pgport, pguser,
                                                           prompt_password, false);
 
                if (!conn)
@@ -382,10 +383,10 @@ main(int argc, char *argv[])
        }
        else
        {
-               conn = connectDatabase("postgres", pghost, pgport, pguser,
+               conn = connectDatabase("postgres", connstr, pghost, pgport, pguser,
                                                           prompt_password, false);
                if (!conn)
-                       conn = connectDatabase("template1", pghost, pgport, pguser,
+                       conn = connectDatabase("template1", connstr, pghost, pgport, pguser,
                                                                   prompt_password, true);
 
                if (!conn)
@@ -568,6 +569,7 @@ help(void)
                         "                               ALTER OWNER commands to set ownership\n"));
 
        printf(_("\nConnection options:\n"));
+       printf(_("  -d, --dbname=CONNSTR     connect using connection string\n"));
        printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
        printf(_("  -l, --database=DBNAME    alternative default database\n"));
        printf(_("  -p, --port=PORT          database server port number\n"));
@@ -1630,7 +1632,7 @@ dumpDatabases(PGconn *conn)
 static int
 runPgDump(const char *dbname)
 {
-       PQExpBuffer connstr = createPQExpBuffer();
+       PQExpBuffer connstrbuf = createPQExpBuffer();
        PQExpBuffer cmd = createPQExpBuffer();
        int                     ret;
 
@@ -1647,16 +1649,13 @@ runPgDump(const char *dbname)
                appendPQExpBuffer(cmd, " -Fp ");
 
        /*
-        * Construct a connection string from the database name, like
-        * dbname='<database name>'. pg_dump would usually also accept the
-        * database name as is, but if it contains any = characters, it would
-        * incorrectly treat it as a connection string.
+        * Append the database name to the already-constructed stem of connection
+        * string.
         */
-       appendPQExpBuffer(connstr, "dbname='");
-       doConnStrQuoting(connstr, dbname);
-       appendPQExpBuffer(connstr, "'");
+       appendPQExpBuffer(connstrbuf, "%s dbname=", connstr);
+       doConnStrQuoting(connstrbuf, dbname);
 
-       doShellQuoting(cmd, connstr->data);
+       doShellQuoting(cmd, connstrbuf->data);
 
        appendPQExpBuffer(cmd, "%s", SYSTEMQUOTE);
 
@@ -1669,7 +1668,7 @@ runPgDump(const char *dbname)
        ret = system(cmd->data);
 
        destroyPQExpBuffer(cmd);
-       destroyPQExpBuffer(connstr);
+       destroyPQExpBuffer(connstrbuf);
 
        return ret;
 }
@@ -1703,16 +1702,23 @@ buildShSecLabels(PGconn *conn, const char *catalog_name, uint32 objectId,
  *
  * If fail_on_error is false, we return NULL without printing any message
  * on failure, but preserve any prompted password for the next try.
+ *
+ * On success, the global variable 'connstr' is set to a connection string
+ * containing the options used.
  */
 static PGconn *
-connectDatabase(const char *dbname, const char *pghost, const char *pgport,
-          const char *pguser, enum trivalue prompt_password, bool fail_on_error)
+connectDatabase(const char *dbname, const char *connection_string,
+                               const char *pghost, const char *pgport, const char *pguser,
+                               enum trivalue prompt_password, bool fail_on_error)
 {
        PGconn     *conn;
        bool            new_pass;
        const char *remoteversion_str;
        int                     my_version;
        static char *password = NULL;
+       const char **keywords = NULL;
+       const char **values = NULL;
+       PQconninfoOption *conn_opts = NULL;
 
        if (prompt_password == TRI_YES && !password)
                password = simple_prompt("Password: ", 100, false);
@@ -1723,31 +1729,93 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
         */
        do
        {
-#define PARAMS_ARRAY_SIZE      7
-               const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
-               const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
-
-               keywords[0] = "host";
-               values[0] = pghost;
-               keywords[1] = "port";
-               values[1] = pgport;
-               keywords[2] = "user";
-               values[2] = pguser;
-               keywords[3] = "password";
-               values[3] = password;
-               keywords[4] = "dbname";
-               values[4] = dbname;
-               keywords[5] = "fallback_application_name";
-               values[5] = progname;
-               keywords[6] = NULL;
-               values[6] = NULL;
+               int                     argcount = 6;
+               PQconninfoOption *conn_opt;
+               char       *err_msg = NULL;
+               int                     i = 0;
+
+               if (keywords)
+                       free(keywords);
+               if (values)
+                       free(values);
+               if (conn_opts)
+                       PQconninfoFree(conn_opts);
+
+               /*
+                * Merge the connection info inputs given in form of connection string
+                * and other options.
+                */
+               if (connection_string)
+               {
+                       conn_opts = PQconninfoParse(connection_string, &err_msg);
+                       if (conn_opts == NULL)
+                       {
+                               fprintf(stderr, "%s: %s\n", progname, err_msg);
+                               exit_nicely(1);
+                       }
+
+                       for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
+                       {
+                               if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
+                                       argcount++;
+                       }
+
+                       keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
+                       values = pg_malloc0((argcount + 1) * sizeof(*values));
+
+                       for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
+                       {
+                               if (conn_opt->val != NULL && conn_opt->val[0] != '\0')
+                               {
+                                       keywords[i] = conn_opt->keyword;
+                                       values[i] = conn_opt->val;
+                                       i++;
+                               }
+                       }
+               }
+               else
+               {
+                       keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
+                       values = pg_malloc0((argcount + 1) * sizeof(*values));
+               }
+
+               if (pghost)
+               {
+                       keywords[i] = "host";
+                       values[i] = pghost;
+                       i++;
+               }
+               if (pgport)
+               {
+                       keywords[i] = "port";
+                       values[i] = pgport;
+                       i++;
+               }
+               if (pguser)
+               {
+                       keywords[i] = "user";
+                       values[i] = pguser;
+                       i++;
+               }
+               if (password)
+               {
+                       keywords[i] = "password";
+                       values[i] = password;
+                       i++;
+               }
+               if (dbname)
+               {
+                       keywords[i] = "dbname";
+                       values[i] = dbname;
+                       i++;
+               }
+               keywords[i] = "fallback_application_name";
+               values[i] = progname;
+               i++;
 
                new_pass = false;
                conn = PQconnectdbParams(keywords, values, true);
 
-               free(keywords);
-               free(values);
-
                if (!conn)
                {
                        fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
@@ -1779,10 +1847,26 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
                else
                {
                        PQfinish(conn);
+
+                       free(keywords);
+                       free(values);
+                       PQconninfoFree(conn_opts);
+
                        return NULL;
                }
        }
 
+       /*
+        * Ok, connected successfully. Remember the options used, in the form of
+        * a connection string.
+        */
+       connstr = constructConnStr(keywords, values);
+
+       free(keywords);
+       free(values);
+       PQconninfoFree(conn_opts);
+
+       /* Check version */
        remoteversion_str = PQparameterStatus(conn, "server_version");
        if (!remoteversion_str)
        {
@@ -1829,6 +1913,43 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
        return conn;
 }
 
+/* ----------
+ * Construct a connection string from the given keyword/value pairs. It is
+ * used to pass the connection options to the pg_dump subprocess.
+ *
+ * The following parameters are excluded:
+ *     dbname          - varies in each pg_dump invocation
+ *     password        - it's not secure to pass a password on the command line
+ *     fallback_application_name - we'll let pg_dump set it
+ * ----------
+ */
+static char *
+constructConnStr(const char **keywords, const char **values)
+{
+       PQExpBuffer buf = createPQExpBuffer();
+       char       *connstr;
+       int                     i;
+       bool            firstkeyword = true;
+
+       /* Construct a new connection string in key='value' format. */
+       for (i = 0; keywords[i] != NULL; i++)
+       {
+               if (strcmp(keywords[i], "dbname") == 0 ||
+                       strcmp(keywords[i], "password") == 0 ||
+                       strcmp(keywords[i], "fallback_application_name") == 0)
+                       continue;
+
+               if (!firstkeyword)
+                       appendPQExpBufferChar(buf, ' ');
+               firstkeyword = false;
+               appendPQExpBuffer(buf, "%s=", keywords[i]);
+               doConnStrQuoting(buf, values[i]);
+       }
+
+       connstr = pg_strdup(buf->data);
+       destroyPQExpBuffer(buf);
+       return connstr;
+}
 
 /*
  * Run a query, return the results, exit program on failure.