]> granicus.if.org Git - postgresql/commitdiff
Modify recently added PQconnectdbParams() with new argument, expand_dbname.
authorJoe Conway <mail@joeconway.com>
Fri, 5 Feb 2010 03:09:05 +0000 (03:09 +0000)
committerJoe Conway <mail@joeconway.com>
Fri, 5 Feb 2010 03:09:05 +0000 (03:09 +0000)
If expand_dbname is non-zero and dbname contains an = sign, it is taken as
a conninfo string in exactly the same way as if it had been passed to
PQconnectdb. This is equivalent to the way PQsetdbLogin() works, allowing
PQconnectdbParams() to be a complete alternative.

Also improve the way the new function is called from psql and replace a
previously missed call to PQsetdbLogin() in psql. Additionally use
PQconnectdbParams() for pg_dump and friends, and the bin/scripts
command line utilities such as vacuumdb, createdb, etc.

Finally, update the documentation for the new parameter, as well as the
nuances of precedence in cases where key words are repeated or duplicated
in the conninfo string.

doc/src/sgml/libpq.sgml
src/bin/pg_dump/pg_backup_db.c
src/bin/pg_dump/pg_dumpall.c
src/bin/psql/command.c
src/bin/psql/startup.c
src/bin/scripts/common.c
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/libpq-fe.h

index a698ab1958dd89ccf53c136d13691c76f915bcb1..c7131fea4c44cdf241d3c4f3bd08ec2097bd8f6f 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.296 2010/01/28 06:28:26 joe Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.297 2010/02/05 03:09:04 joe Exp $ -->
 
 <chapter id="libpq">
  <title><application>libpq</application> - C Library</title>
@@ -98,7 +98,7 @@
        Makes a new connection to the database server.
 
        <synopsis>
-        PGconn *PQconnectdbParams(const char **keywords, const char **values);
+        PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand_dbname);
        </synopsis>
       </para>
 
        programming.
       </para>
 
+      <para>
+       When <literal>expand_dbname</literal> is non-zero, the
+       <parameter>dbname</parameter> key word value is allowed to be recognized
+       as a <parameter>conninfo</parameter> string. See below for details.
+      </para>
+
       <para>
        The passed arrays can be empty to use all default parameters, or can
        contain one or more parameter settings. They should be matched in length.
        is checked. If the  environment  variable is not set either,
        then the indicated built-in defaults are used.
       </para>
+
+      <para>
+        If <literal>expand_dbname</literal> is non-zero and 
+        <parameter>dbname</parameter> contains an <symbol>=</symbol> sign, it
+        is taken as a <parameter>conninfo</parameter> string in exactly the same way as
+        if it had been passed to <function>PQconnectdb</function>(see below). Previously
+        processed key words will be overridden by key words in the
+        <parameter>conninfo</parameter> string.
+      </para>
+
+      <para>
+        In general key words are processed from the beginning of these arrays in index
+        order. The effect of this is that when key words are repeated, the last processed
+        value is retained. Therefore, through careful placement of the
+        <parameter>dbname</parameter> key word, it is possible to determine what may
+        be overridden by a <parameter>conninfo</parameter> string, and what may not.
+      </para>
+
      </listitem>
     </varlistentry>
 
@@ -573,7 +597,7 @@ PGconn *PQsetdb(char *pghost,
        Make a connection to the database server in a nonblocking manner.
 
        <synopsis>
-        PGconn *PQconnectStartParams(const char **keywords, const char **values);
+        PGconn *PQconnectStartParams(const char **keywords, const char **values, int expand_dbname);
        </synopsis>
 
        <synopsis>
@@ -597,8 +621,8 @@ PGconn *PQsetdb(char *pghost,
       <para>
        With <function>PQconnectStartParams</function>, the database connection is made
        using the parameters taken from the <literal>keywords</literal> and
-       <literal>values</literal> arrays, as described above for
-       <function>PQconnectdbParams</function>.
+       <literal>values</literal> arrays, and controlled by <literal>expand_dbname</literal>,
+       as described above for <function>PQconnectdbParams</function>.
       </para>
 
       <para>
index 1d72d6dd7e2470e8aa1f66b66c6f512cc21a08bd..4aa10135bb06ea7e64a08164b9205cb390aa6328 100644 (file)
@@ -5,7 +5,7 @@
  *     Implements the basic DB functions used by the archiver.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.85 2009/12/14 00:39:11 itagaki Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.86 2010/02/05 03:09:05 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -154,10 +154,34 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
 
        do
        {
+#define PARAMS_ARRAY_SIZE      7
+               const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
+               const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
+
+               if (!keywords || !values)
+                       die_horribly(AH, modulename, "out of memory\n");
+
+               keywords[0]     = "host";
+               values[0]       = PQhost(AH->connection);
+               keywords[1]     = "port";
+               values[1]       = PQport(AH->connection);
+               keywords[2]     = "user";
+               values[2]       = newuser;
+               keywords[3]     = "password";
+               values[3]       = password;
+               keywords[4]     = "dbname";
+               values[4]       = newdb;
+               keywords[5]     = "fallback_application_name";
+               values[5]       = progname;
+               keywords[6]     = NULL;
+               values[6]       = NULL;
+
                new_pass = false;
-               newConn = PQsetdbLogin(PQhost(AH->connection), PQport(AH->connection),
-                                                          NULL, NULL, newdb,
-                                                          newuser, password);
+               newConn = PQconnectdbParams(keywords, values, true);
+
+               free(keywords);
+               free(values);
+
                if (!newConn)
                        die_horribly(AH, modulename, "failed to reconnect to database\n");
 
@@ -237,9 +261,33 @@ ConnectDatabase(Archive *AHX,
         */
        do
        {
+#define PARAMS_ARRAY_SIZE      7
+               const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
+               const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
+
+               if (!keywords || !values)
+                       die_horribly(AH, modulename, "out of memory\n");
+
+               keywords[0]     = "host";
+               values[0]       = pghost;
+               keywords[1]     = "port";
+               values[1]       = pgport;
+               keywords[2]     = "user";
+               values[2]       = username;
+               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;
+
                new_pass = false;
-               AH->connection = PQsetdbLogin(pghost, pgport, NULL, NULL,
-                                                                         dbname, username, password);
+               AH->connection = PQconnectdbParams(keywords, values, true);
+
+               free(keywords);
+               free(values);
 
                if (!AH->connection)
                        die_horribly(AH, modulename, "failed to connect to database\n");
@@ -697,3 +745,4 @@ _isDQChar(unsigned char c, bool atStart)
        else
                return false;
 }
+
index 48084db12f880813943981b9975deb901979531a..f1d74574313c94c8a8e2cedbc9a27accf21df8b4 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.131 2010/01/06 03:34:41 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.132 2010/02/05 03:09:05 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1618,8 +1618,36 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
         */
        do
        {
+#define PARAMS_ARRAY_SIZE      7
+               const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
+               const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
+
+               if (!keywords || !values)
+               {
+                       fprintf(stderr, _("%s: out of memory\n"), progname);
+                       exit(1);
+               }
+
+               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;
+
                new_pass = false;
-               conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);
+               conn = PQconnectdbParams(keywords, values, true);
+
+               free(keywords);
+               free(values);
 
                if (!conn)
                {
index 10f36dc22d451ebc332986eb946451e83947751e..74119fd29f0c927ba132c7502c6c2ba6f8c15abe 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2010, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.213 2010/01/02 16:57:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.214 2010/02/05 03:09:05 joe Exp $
  */
 #include "postgres_fe.h"
 #include "command.h"
@@ -1213,7 +1213,7 @@ param_is_newly_set(const char *old_val, const char *new_val)
  * Connects to a database with given parameters. If there exists an
  * established connection, NULL values will be replaced with the ones
  * in the current connection. Otherwise NULL will be passed for that
- * parameter to PQsetdbLogin(), so the libpq defaults will be used.
+ * parameter to PQconnectdbParams(), so the libpq defaults will be used.
  *
  * In interactive mode, if connection fails with the given parameters,
  * the old connection will be kept.
@@ -1255,8 +1255,29 @@ do_connect(char *dbname, char *user, char *host, char *port)
 
        while (true)
        {
-               n_conn = PQsetdbLogin(host, port, NULL, NULL,
-                                                         dbname, user, password);
+#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]       = host;
+               keywords[1]     = "port";
+               values[1]       = port;
+               keywords[2]     = "user";
+               values[2]       = user;
+               keywords[3]     = "password";
+               values[3]       = password;
+               keywords[4]     = "dbname";
+               values[4]       = dbname;
+               keywords[5]     = "fallback_application_name";
+               values[5]       = pset.progname;
+               keywords[6]     = NULL;
+               values[6]       = NULL;
+
+               n_conn = PQconnectdbParams(keywords, values, true);
+
+               free(keywords);
+               free(values);
 
                /* We can immediately discard the password -- no longer needed */
                if (password)
index b29c84fdaec26f697f38a18f08da280a19c86541..c45a869d92cd0f72f070319ea216b5be3e92224f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2010, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.159 2010/01/28 06:28:26 joe Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.160 2010/02/05 03:09:05 joe Exp $
  */
 #include "postgres_fe.h"
 
@@ -90,8 +90,6 @@ main(int argc, char *argv[])
        char       *password = NULL;
        char       *password_prompt = NULL;
        bool            new_pass;
-       const char *keywords[] = {"host","port","dbname","user",
-                                                         "password","application_name",NULL};
 
        set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
 
@@ -173,20 +171,31 @@ main(int argc, char *argv[])
        /* loop until we have a password if requested by backend */
        do
        {
-        const char *values[] = {
-                  options.host,
-                  options.port,
-                  (options.action == ACT_LIST_DB && 
-                               options.dbname == NULL) ? "postgres" : options.dbname,
-                  options.username,
-                  password,
-                  pset.progname,
-                  NULL
-              };
-        
-        new_pass = false;
-
-        pset.db = PQconnectdbParams(keywords, values);
+#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]       = options.host;
+               keywords[1]     = "port";
+               values[1]       = options.port;
+               keywords[2]     = "user";
+               values[2]       = options.username;
+               keywords[3]     = "password";
+               values[3]       = password;
+               keywords[4]     = "dbname";
+               values[4]       = (options.action == ACT_LIST_DB &&
+                                               options.dbname == NULL) ?
+                                               "postgres" : options.dbname;
+               keywords[5]     = "fallback_application_name";
+               values[5]       = pset.progname;
+               keywords[6]     = NULL;
+               values[6]       = NULL;
+
+               new_pass = false;
+               pset.db = PQconnectdbParams(keywords, values, true);
+               free(keywords);
+               free(values);
 
                if (PQstatus(pset.db) == CONNECTION_BAD &&
                        PQconnectionNeedsPassword(pset.db) &&
index 27aafa102c404f92ee54c9c0969d6f840856966a..026eb80a025fd941ca3a7a451d8393af5ad7287b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.38 2010/01/02 16:58:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.39 2010/02/05 03:09:05 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -108,8 +108,36 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
         */
        do
        {
+#define PARAMS_ARRAY_SIZE      7
+               const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
+               const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
+
+               if (!keywords || !values)
+               {
+                       fprintf(stderr, _("%s: out of memory\n"), progname);
+                       exit(1);
+               }
+
+               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;
+
                new_pass = false;
-               conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);
+               conn = PQconnectdbParams(keywords, values, true);
+
+               free(keywords);
+               free(values);
 
                if (!conn)
                {
index 048c438527b81492dd726d2d0affd5ad776f0b9f..994b70b190487888b88af7b8775faf1d962ddc08 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.385 2010/01/28 06:28:26 joe Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.386 2010/02/05 03:09:05 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -269,7 +269,7 @@ static PQconninfoOption *conninfo_parse(const char *conninfo,
                           PQExpBuffer errorMessage, bool use_defaults);
 static PQconninfoOption *conninfo_array_parse(const char **keywords,
                                const char **values, PQExpBuffer errorMessage,
-                               bool use_defaults);
+                               bool use_defaults, int expand_dbname);
 static char *conninfo_getval(PQconninfoOption *connOptions,
                                const char *keyword);
 static void defaultNoticeReceiver(void *arg, const PGresult *res);
@@ -336,9 +336,11 @@ pgthreadlock_t pg_g_threadlock = default_threadlock;
  * call succeeded.
  */
 PGconn *
-PQconnectdbParams(const char **keywords, const char **values)
+PQconnectdbParams(const char **keywords,
+                                 const char **values,
+                                 int expand_dbname)
 {
-       PGconn     *conn = PQconnectStartParams(keywords, values);
+       PGconn     *conn = PQconnectStartParams(keywords, values, expand_dbname);
 
        if (conn && conn->status != CONNECTION_BAD)
                (void) connectDBComplete(conn);
@@ -400,7 +402,9 @@ PQconnectdb(const char *conninfo)
  * See PQconnectPoll for more info.
  */
 PGconn *
-PQconnectStartParams(const char **keywords, const char **values)
+PQconnectStartParams(const char **keywords,
+                                        const char **values,
+                                        int expand_dbname)
 {
        PGconn                     *conn;
        PQconninfoOption   *connOptions;
@@ -416,7 +420,8 @@ PQconnectStartParams(const char **keywords, const char **values)
         * Parse the conninfo arrays
         */
        connOptions = conninfo_array_parse(keywords, values,
-                                                                          &conn->errorMessage, true);
+                                                                          &conn->errorMessage,
+                                                                          true, expand_dbname);
        if (connOptions == NULL)
        {
                conn->status = CONNECTION_BAD;
@@ -3729,16 +3734,53 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
  * left in errorMessage.
  * Defaults are supplied (from a service file, environment variables, etc)
  * for unspecified options, but only if use_defaults is TRUE.
+ *
+ * If expand_dbname is non-zero, and the value passed for keyword "dbname"
+ * contains an "=", assume it is a conninfo string and process it,
+ * overriding any previously processed conflicting keywords. Subsequent
+ * keywords will take precedence, however.
  */
 static PQconninfoOption *
 conninfo_array_parse(const char **keywords, const char **values,
-                                        PQExpBuffer errorMessage, bool use_defaults)
+                                        PQExpBuffer errorMessage, bool use_defaults,
+                                        int expand_dbname)
 {
        char                       *tmp;
        PQconninfoOption   *options;
+       PQconninfoOption   *str_options = NULL;
        PQconninfoOption   *option;
        int                                     i = 0;
 
+       /*
+        * If expand_dbname is non-zero, check keyword "dbname"
+        * to see if val is actually a conninfo string
+        */
+       while(expand_dbname && keywords[i])
+       {
+               const char *pname = keywords[i];
+               const char *pvalue  = values[i];
+
+               /* first find "dbname" if any */
+               if (strcmp(pname, "dbname") == 0)
+               {
+                       /* next look for "=" in the value */
+                       if (pvalue && strchr(pvalue, '='))
+                       {
+                               /*
+                                * Must be a conninfo string, so parse it, but do not
+                                * use defaults here -- those get picked up later.
+                                * We only want to override for those parameters actually
+                                * passed.
+                                */
+                               str_options = conninfo_parse(pvalue, errorMessage, false);
+                               if (str_options == NULL)
+                                       return NULL;
+                       }
+                       break;
+               }
+               ++i;
+       }
+
        /* Make a working copy of PQconninfoOptions */
        options = malloc(sizeof(PQconninfoOptions));
        if (options == NULL)
@@ -3749,6 +3791,7 @@ conninfo_array_parse(const char **keywords, const char **values,
        }
        memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions));
 
+       i = 0;
        /* Parse the keywords/values arrays */
        while(keywords[i])
        {
@@ -3774,22 +3817,54 @@ conninfo_array_parse(const char **keywords, const char **values,
                                return NULL;
                        }
 
-                   /*
-                    * Store the value
-                    */
-                   if (option->val)
-                       free(option->val);
-                   option->val = strdup(pvalue);
-                   if (!option->val)
-                   {
-                       printfPQExpBuffer(errorMessage,
-                                                         libpq_gettext("out of memory\n"));
-                       PQconninfoFree(options);
-                       return NULL;
-                   }
+                       /*
+                        * If we are on the dbname parameter, and we have a parsed
+                        * conninfo string, copy those parameters across, overriding
+                        * any existing previous settings
+                        */
+                       if (strcmp(pname, "dbname") == 0 && str_options)
+                       {
+                               PQconninfoOption *str_option;
+
+                               for (str_option = str_options; str_option->keyword != NULL; str_option++)
+                               {
+                                       if (str_option->val != NULL)
+                                       {
+                                               int                     k;
+
+                                               for (k = 0; options[k].keyword; k++)
+                                               {
+                                                       if (strcmp(options[k].keyword, str_option->keyword) == 0)
+                                                       {
+                                                               if (options[k].val)
+                                                                       free(options[k].val);
+                                                               options[k].val = strdup(str_option->val);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               /*
+                                * Store the value, overriding previous settings
+                                */
+                               if (option->val)
+                                       free(option->val);
+                               option->val = strdup(pvalue);
+                               if (!option->val)
+                               {
+                                       printfPQExpBuffer(errorMessage,
+                                                                         libpq_gettext("out of memory\n"));
+                                       PQconninfoFree(options);
+                                       return NULL;
+                               }
+                       }
                }
                ++i;
        }
+       PQconninfoFree(str_options);
 
        /*
         * Stop here if caller doesn't want defaults filled in.
index 5f59da0f753bc76c0cc8e2b4b0269b159b660976..c2698fe257e1c2667c31cecf44b3cd24a1cf2fe1 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.150 2010/01/28 06:28:26 joe Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.151 2010/02/05 03:09:05 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -226,12 +226,14 @@ typedef struct pgresAttDesc
 /* make a new client connection to the backend */
 /* Asynchronous (non-blocking) */
 extern PGconn *PQconnectStart(const char *conninfo);
-extern PGconn *PQconnectStartParams(const char **keywords, const char **values);
+extern PGconn *PQconnectStartParams(const char **keywords,
+                        const char **values, int expand_dbname);
 extern PostgresPollingStatusType PQconnectPoll(PGconn *conn);
 
 /* Synchronous (blocking) */
 extern PGconn *PQconnectdb(const char *conninfo);
-extern PGconn *PQconnectdbParams(const char **keywords, const char **values);
+extern PGconn *PQconnectdbParams(const char **keywords,
+                        const char **values, int expand_dbname);
 extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport,
                         const char *pgoptions, const char *pgtty,
                         const char *dbName,