OSDN Git Service

Okay, I've had it with PQsetdbLogin having slightly different defaults
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 28 Apr 2003 04:29:12 +0000 (04:29 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 28 Apr 2003 04:29:12 +0000 (04:29 +0000)
than PQconnectdb.  Reimplement the former to use the same code as the
latter.  Fix documentation omissions while at it.

doc/src/sgml/libpq.sgml
src/interfaces/libpq/fe-connect.c
src/test/regress/pg_regress.sh

index 5ba7e64..b8499f0 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.120 2003/04/22 00:08:06 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.121 2003/04/28 04:29:11 tgl Exp $
 -->
 
  <chapter id="libpq">
@@ -114,21 +114,26 @@ PGconn *PQconnectdb(const char *conninfo);
       used.
      </para>
      <para>
-      Using <literal>hostaddr</> instead of <literal>host</> allows the application to avoid a host
-      name look-up, which may be important in applications with time
-      constraints. However, Kerberos authentication requires the host
-      name. The following therefore applies: If <literal>host</> is specified without
-      <literal>hostaddr</>, a host name lookup is forced. If <literal>hostaddr</> is specified without
-      <literal>host</>, the value for <literal>hostaddr</> gives the remote address; if Kerberos is
-      used, this causes a reverse name query. If both <literal>host</> and <literal>hostaddr</> are
-      specified, the value for <literal>hostaddr</> gives the remote address; the value
-      for <literal>host</> is ignored, unless Kerberos is used, in which case that value
-      is used for Kerberos authentication. Note that authentication is likely
-      to fail if <application>libpq</application> is passed a host name that is not the name of the
-      machine at <literal>hostaddr</>.
+      Using <literal>hostaddr</> instead of <literal>host</> allows the
+      application to avoid a host name look-up, which may be important in
+      applications with time constraints. However, Kerberos authentication
+      requires the host name. The following therefore applies: If
+      <literal>host</> is specified without <literal>hostaddr</>, a host name
+      lookup is forced. If <literal>hostaddr</> is specified without
+      <literal>host</>, the value for <literal>hostaddr</> gives the remote
+      address; if Kerberos is used, this causes a reverse name query. If both
+      <literal>host</> and <literal>hostaddr</> are specified, the value for
+      <literal>hostaddr</> gives the remote address; the value for
+      <literal>host</> is ignored, unless Kerberos is used, in which case that
+      value is used for Kerberos authentication. (Note that authentication is
+      likely to fail if <application>libpq</application> is passed a host name
+      that is not the name of the machine at <literal>hostaddr</>.)  Also,
+      <literal>host</> rather than <literal>hostaddr</> is used to identify
+      the connection in <filename>$HOME/.pgpass</>.
      </para>
      <para>
-      Without either a host name or host address, <application>libpq</application> will connect using a
+      Without either a host name or host address,
+      <application>libpq</application> will connect using a
       local Unix domain socket.
      </para>
      </listitem>
@@ -176,7 +181,8 @@ PGconn *PQconnectdb(const char *conninfo);
      <listitem>
      <para>
       Maximum wait for connection, in seconds (write as a decimal integer
-      string). Zero or not specified means infinite.
+      string). Zero or not specified means wait indefinitely.  It is not
+      recommended to set the timeout to less than 2 seconds.
      </para>
      </listitem>
     </varlistentry>
@@ -2321,7 +2327,7 @@ information into simple client applications, for example.
 <indexterm>
  <primary><envar>PGHOST</envar></primary>
 </indexterm>
-<envar>PGHOST</envar> sets the default server name.
+<envar>PGHOST</envar> sets the database server name.
 If this begins with a slash, it specifies Unix-domain communication
 rather than TCP/IP communication; the value is the name of the
 directory in which the socket file is stored (default <filename>/tmp</filename>).
@@ -2330,9 +2336,21 @@ directory in which the socket file is stored (default <filename>/tmp</filename>)
 <listitem>
 <para>
 <indexterm>
+ <primary><envar>PGHOSTADDR</envar></primary>
+</indexterm>
+<envar>PGHOSTADDR</envar> specifies the numeric IP address of the database
+server.  This can be set instead of <envar>PGHOST</envar> to avoid DNS
+lookup overhead. See the documentation of
+these parameters, under <function>PQconnectdb</function> above, for details
+on their interaction.
+</para>
+</listitem>
+<listitem>
+<para>
+<indexterm>
  <primary><envar>PGPORT</envar></primary>
 </indexterm>
-<envar>PGPORT</envar> sets the default TCP port number or Unix-domain
+<envar>PGPORT</envar> sets the TCP port number or Unix-domain
 socket file extension for communicating with the
 <productname>PostgreSQL</productname> server.
 </para>
@@ -2342,7 +2360,7 @@ socket file extension for communicating with the
 <indexterm>
  <primary><envar>PGDATABASE</envar></primary>
 </indexterm>
-<envar>PGDATABASE</envar>  sets the default 
+<envar>PGDATABASE</envar>  sets the 
 <productname>PostgreSQL</productname> database name.
 </para>
 </listitem>
@@ -2369,6 +2387,19 @@ file (see <xref linkend="libpq-pgpass">).
 </listitem>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGSERVICE</envar></primary>
+</indexterm>
+<envar>PGSERVICE</envar>
+sets the service name to be looked up in <filename>pg_service.conf</filename>.
+This offers a shorthand way of setting all the parameters.
+</para>
+</listitem>
+<listitem>
+<para>
+<indexterm>
+ <primary><envar>PGREALM</envar></primary>
+</indexterm>
 <envar>PGREALM</envar> sets the Kerberos realm to  use  with  
 <productname>PostgreSQL</productname>, if  it is different from the local realm.
 If <envar>PGREALM</envar> is set, <application>libpq</application>
@@ -2380,12 +2411,18 @@ used if Kerberos authentication is selected by the server.
 </listitem>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGOPTIONS</envar></primary>
+</indexterm>
 <envar>PGOPTIONS</envar> sets additional run-time  options  for  
 the <productname>PostgreSQL</productname> server.
 </para>
 </listitem>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGREQUIRESSL</envar></primary>
+</indexterm>
 <envar>PGREQUIRESSL</envar> sets whether or not the connection must be
 made over <acronym>SSL</acronym>. If set to
 <quote>1</quote>, <application>libpq</>
@@ -2397,10 +2434,14 @@ This option is only available if
 </listitem>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGCONNECT_TIMEOUT</envar></primary>
+</indexterm>
 <envar>PGCONNECT_TIMEOUT</envar> sets the maximum number of seconds
 that <application>libpq</application> will wait when attempting to
-connect to the <productname>PostgreSQL</productname> server. This
-option should be set to at least 2 seconds.
+connect to the <productname>PostgreSQL</productname> server.  If unset
+or set to zero, <application>libpq</application> will wait indefinitely.
+It is not recommended to set the timeout to less than 2 seconds.
 </para>
 </listitem>
 </itemizedlist>
@@ -2413,6 +2454,9 @@ behavior for every <productname>PostgreSQL</productname> session.
 <itemizedlist>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGDATESTYLE</envar></primary>
+</indexterm>
 <envar>PGDATESTYLE</envar>
 sets the default style of date/time representation.
 (Equivalent to <literal>SET datestyle TO ...</literal>.)
@@ -2420,6 +2464,9 @@ sets the default style of date/time representation.
 </listitem>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGTZ</envar></primary>
+</indexterm>
 <envar>PGTZ</envar>
 sets the default time zone.
 (Equivalent to <literal>SET timezone TO ...</literal>.)
@@ -2427,6 +2474,9 @@ sets the default time zone.
 </listitem>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGCLIENTENCODING</envar></primary>
+</indexterm>
 <envar>PGCLIENTENCODING</envar>
 sets the default client character set encoding.
 (Equivalent to <literal>SET client_encoding TO ...</literal>.)
@@ -2434,6 +2484,9 @@ sets the default client character set encoding.
 </listitem>
 <listitem>
 <para>
+<indexterm>
+ <primary><envar>PGGEQO</envar></primary>
+</indexterm>
 <envar>PGGEQO</envar>
 sets the default mode for the genetic query optimizer.
 (Equivalent to <literal>SET geqo TO ...</literal>.)
index e2df4de..704935e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.237 2003/04/25 19:45:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.238 2003/04/28 04:29:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -172,6 +172,8 @@ static const struct EnvironmentOptions
 };
 
 
+static bool connectOptions1(PGconn *conn, const char *conninfo);
+static bool connectOptions2(PGconn *conn);
 static int     connectDBStart(PGconn *conn);
 static int     connectDBComplete(PGconn *conn);
 static PGconn *makeEmptyPGconn(void);
@@ -264,13 +266,10 @@ PGconn *
 PQconnectStart(const char *conninfo)
 {
        PGconn     *conn;
-       PQconninfoOption *connOptions;
-       char       *tmp;
 
        /*
         * Allocate memory for the conn structure
         */
-
        conn = makeEmptyPGconn();
        if (conn == NULL)
                return (PGconn *) NULL;
@@ -278,16 +277,60 @@ PQconnectStart(const char *conninfo)
        /*
         * Parse the conninfo string
         */
+       if (!connectOptions1(conn, conninfo))
+               return conn;
+
+       /*
+        * Compute derived options
+        */
+       if (!connectOptions2(conn))
+               return conn;
+
+       /*
+        * Connect to the database
+        */
+       if (!connectDBStart(conn))
+       {
+               /* Just in case we failed to set it in connectDBStart */
+               conn->status = CONNECTION_BAD;
+       }
+
+       return conn;
+}
+
+/*
+ *             connectOptions1
+ *
+ * Internal subroutine to set up connection parameters given an already-
+ * created PGconn and a conninfo string.  Derived settings should be
+ * processed by calling connectOptions2 next.  (We split them because
+ * PQsetdbLogin overrides defaults in between.)
+ *
+ * Returns true if OK, false if trouble (in which case errorMessage is set
+ * and so is conn->status).
+ */
+static bool
+connectOptions1(PGconn *conn, const char *conninfo)
+{
+       PQconninfoOption *connOptions;
+       char       *tmp;
+
+       /*
+        * Parse the conninfo string
+        */
        connOptions = conninfo_parse(conninfo, &conn->errorMessage);
        if (connOptions == NULL)
        {
                conn->status = CONNECTION_BAD;
                /* errorMessage is already set */
-               return conn;
+               return false;
        }
 
        /*
         * Move option values into conn structure
+        *
+        * Don't put anything cute here --- intelligence should be in
+        * connectOptions2 ...
         */
        tmp = conninfo_getval(connOptions, "hostaddr");
        conn->pghostaddr = tmp ? strdup(tmp) : NULL;
@@ -305,15 +348,6 @@ PQconnectStart(const char *conninfo)
        conn->pguser = tmp ? strdup(tmp) : NULL;
        tmp = conninfo_getval(connOptions, "password");
        conn->pgpass = tmp ? strdup(tmp) : NULL;
-       if (conn->pgpass == NULL || conn->pgpass[0] == '\0')
-       {
-               if (conn->pgpass)
-                       free(conn->pgpass);
-               conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport,
-                                                                               conn->dbName, conn->pguser);
-               if (conn->pgpass == NULL)
-                       conn->pgpass = strdup(DefaultPassword);
-       }
        tmp = conninfo_getval(connOptions, "connect_timeout");
        conn->connect_timeout = tmp ? strdup(tmp) : NULL;
 #ifdef USE_SSL
@@ -327,6 +361,33 @@ PQconnectStart(const char *conninfo)
         */
        PQconninfoFree(connOptions);
 
+       return true;
+}
+
+/*
+ *             connectOptions2
+ *
+ * Compute derived connection options after absorbing all user-supplied info.
+ *
+ * Returns true if OK, false if trouble (in which case errorMessage is set
+ * and so is conn->status).
+ */
+static bool
+connectOptions2(PGconn *conn)
+{
+       /*
+        * Supply default password if none given
+        */
+       if (conn->pgpass == NULL || conn->pgpass[0] == '\0')
+       {
+               if (conn->pgpass)
+                       free(conn->pgpass);
+               conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport,
+                                                                               conn->dbName, conn->pguser);
+               if (conn->pgpass == NULL)
+                       conn->pgpass = strdup(DefaultPassword);
+       }
+
        /*
         * Allow unix socket specification in the host name
         */
@@ -338,16 +399,19 @@ PQconnectStart(const char *conninfo)
                conn->pghost = NULL;
        }
 
+#ifdef NOT_USED
        /*
-        * Connect to the database
+        * parse dbName to get all additional info in it, if any
         */
-       if (!connectDBStart(conn))
+       if (update_db_info(conn) != 0)
        {
-               /* Just in case we failed to set it in connectDBStart */
                conn->status = CONNECTION_BAD;
+               /* errorMessage is already set */
+               return false;
        }
+#endif
 
-       return conn;
+       return true;
 }
 
 /*
@@ -384,36 +448,9 @@ PQconndefaults(void)
  * at the specified host and port.
  *
  * returns a PGconn* which is needed for all subsequent libpq calls
- * if the status field of the connection returned is CONNECTION_BAD,
- * then some fields may be null'ed out instead of having valid values
- *
- *     Uses these environment variables:
- *
- *       PGHOST           identifies host to which to connect if <pghost> argument
- *                                is NULL or a null string.
- *
- *       PGPORT           identifies TCP port to which to connect if <pgport> argument
- *                                is NULL or a null string.
- *
- *       PGTTY            identifies tty to which to send messages if <pgtty> argument
- *                                is NULL or a null string.  (No longer used by backend.)
- *
- *       PGOPTIONS    identifies connection options if <pgoptions> argument is
- *                                NULL or a null string.
- *
- *       PGUSER           Postgres username to associate with the connection.
- *
- *       PGPASSWORD   The user's password.
  *
- *       PGDATABASE   name of database to which to connect if <pgdatabase>
- *                                argument is NULL or a null string
- *
- *       None of the above need be defined.  There are defaults for all of them.
- *
- * To support "delimited identifiers" for database names, only convert
- * the database name to lower case if it is not surrounded by double quotes.
- * Otherwise, strip the double quotes but leave the reset of the string intact.
- * - thomas 1997-11-08
+ * if the status field of the connection returned is CONNECTION_BAD,
+ * then only the errorMessage is likely to be useful.
  * ----------------
  */
 PGconn *
@@ -422,112 +459,84 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
                         const char *pwd)
 {
        PGconn     *conn;
-       char       *tmp;                        /* An error message from some service we
-                                                                * call. */
-       bool            error = FALSE;  /* We encountered an error. */
 
+       /*
+        * Allocate memory for the conn structure
+        */
        conn = makeEmptyPGconn();
        if (conn == NULL)
                return (PGconn *) NULL;
 
-       if (pghost)
-               conn->pghost = strdup(pghost);
-       else if ((tmp = getenv("PGHOST")) != NULL)
-               conn->pghost = strdup(tmp);
-
-       if (pgport == NULL || pgport[0] == '\0')
-       {
-               tmp = getenv("PGPORT");
-               if (tmp == NULL || tmp[0] == '\0')
-                       tmp = DEF_PGPORT_STR;
-               conn->pgport = strdup(tmp);
-       }
-       else
-               conn->pgport = strdup(pgport);
+       /*
+        * Parse an empty conninfo string in order to set up the same defaults
+        * that PQconnectdb() would use.
+        */
+       if (!connectOptions1(conn, ""))
+               return conn;
 
        /*
-        * We don't allow unix socket path as a function parameter. This
-        * allows unix socket specification in the host name.
+        * Absorb specified options into conn structure, overriding defaults
         */
-       if (conn->pghost && is_absolute_path(conn->pghost))
+       if (pghost && pghost[0] != '\0')
        {
-               if (conn->pgunixsocket)
-                       free(conn->pgunixsocket);
-               conn->pgunixsocket = conn->pghost;
-               conn->pghost = NULL;
+               if (conn->pghost)
+                       free(conn->pghost);
+               conn->pghost = strdup(pghost);
        }
 
-       if (pgtty == NULL)
+       if (pgport && pgport[0] != '\0')
        {
-               if ((tmp = getenv("PGTTY")) == NULL)
-                       tmp = DefaultTty;
-               conn->pgtty = strdup(tmp);
+               if (conn->pgport)
+                       free(conn->pgport);
+               conn->pgport = strdup(pgport);
        }
-       else
-               conn->pgtty = strdup(pgtty);
 
-       if (pgoptions == NULL)
+       if (pgoptions && pgoptions[0] != '\0')
        {
-               if ((tmp = getenv("PGOPTIONS")) == NULL)
-                       tmp = DefaultOption;
-               conn->pgoptions = strdup(tmp);
-       }
-       else
+               if (conn->pgoptions)
+                       free(conn->pgoptions);
                conn->pgoptions = strdup(pgoptions);
+       }
 
-       if (login)
-               conn->pguser = strdup(login);
-       else if ((tmp = getenv("PGUSER")) != NULL)
-               conn->pguser = strdup(tmp);
-       else
+       if (pgtty && pgtty[0] != '\0')
        {
-               /* fe-auth.c has not been fixed to support PQExpBuffers, so: */
-               conn->pguser = fe_getauthname(conn->errorMessage.data);
-               conn->errorMessage.len = strlen(conn->errorMessage.data);
+               if (conn->pgtty)
+                       free(conn->pgtty);
+               conn->pgtty = strdup(pgtty);
        }
 
-       if (conn->pguser == NULL)
+       if (dbName && dbName[0] != '\0')
        {
-               error = TRUE;
-               printfPQExpBuffer(&conn->errorMessage,
-                                                 libpq_gettext("could not determine the PostgreSQL user name to use\n"));
+               if (conn->dbName)
+                       free(conn->dbName);
+               conn->dbName = strdup(dbName);
        }
 
-       if (dbName == NULL)
+       if (login && login[0] != '\0')
        {
-               if ((tmp = getenv("PGDATABASE")) != NULL)
-                       conn->dbName = strdup(tmp);
-               else if (conn->pguser)
-                       conn->dbName = strdup(conn->pguser);
+               if (conn->pguser)
+                       free(conn->pguser);
+               conn->pguser = strdup(login);
        }
-       else
-               conn->dbName = strdup(dbName);
 
-       if (pwd)
+       if (pwd && pwd[0] != '\0')
+       {
+               if (conn->pgpass)
+                       free(conn->pgpass);
                conn->pgpass = strdup(pwd);
-       else if ((tmp = getenv("PGPASSWORD")) != NULL)
-               conn->pgpass = strdup(tmp);
-       else if ((tmp = PasswordFromFile(conn->pghost, conn->pgport,
-                                                                        conn->dbName, conn->pguser)) != NULL)
-               conn->pgpass = tmp;
-       else
-               conn->pgpass = strdup(DefaultPassword);
-
-       if ((tmp = getenv("PGCONNECT_TIMEOUT")) != NULL)
-               conn->connect_timeout = strdup(tmp);
+       }
 
-#ifdef USE_SSL
-       if ((tmp = getenv("PGREQUIRESSL")) != NULL)
-               conn->require_ssl = (tmp[0] == '1') ? true : false;
-#endif
+       /*
+        * Compute derived options
+        */
+       if (!connectOptions2(conn))
+               return conn;
 
-       if (error)
-               conn->status = CONNECTION_BAD;
-       else
-       {
-               if (connectDBStart(conn))
-                       (void) connectDBComplete(conn);
-       }
+       /*
+        * Connect to the database
+        */
+       if (connectDBStart(conn))
+               (void) connectDBComplete(conn);
 
        return conn;
 }
@@ -537,7 +546,6 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
 /*
  * update_db_info -
  * get all additional info out of dbName
- *
  */
 static int
 update_db_info(PGconn *conn)
@@ -771,10 +779,10 @@ connectFailureMessage(PGconn *conn, int errorno)
                                                                         "\tTCP/IP connections on port %s?\n"
                                                                                ),
                                                  SOCK_STRERROR(errorno),
-                                                 conn->pghost
-                                                 ? conn->pghost
-                                                 : (conn->pghostaddr
-                                                        ? conn->pghostaddr
+                                                 conn->pghostaddr
+                                                 ? conn->pghostaddr
+                                                 : (conn->pghost
+                                                        ? conn->pghost
                                                         : "???"),
                                                  conn->pgport);
 }
@@ -799,20 +807,12 @@ connectDBStart(PGconn *conn)
        const char *unix_node = "unix";
        int                     ret;
 
-       /* Initialize hint structure */
-       MemSet(&hint, 0, sizeof(hint));
-       hint.ai_socktype = SOCK_STREAM;
-
        if (!conn)
                return 0;
 
-#ifdef NOT_USED
-       /*
-        * parse dbName to get all additional info in it, if any
-        */
-       if (update_db_info(conn) != 0)
-               goto connect_errReturn;
-#endif
+       /* Initialize hint structure */
+       MemSet(&hint, 0, sizeof(hint));
+       hint.ai_socktype = SOCK_STREAM;
 
        /* Ensure our buffers are empty */
        conn->inStart = conn->inCursor = conn->inEnd = 0;
@@ -2116,7 +2116,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
        char       *cp2;
        PQconninfoOption *options;
        PQconninfoOption *option;
-       char            errortmp[INITIAL_EXPBUFFER_SIZE];
+       char            errortmp[PQERRORMSG_LENGTH];
 
        /* Make a working copy of PQconninfoOptions */
        options = malloc(sizeof(PQconninfoOptions));
@@ -2270,17 +2270,16 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
 
        }
 
+       /* Done with the modifiable input string */
+       free(buf);
+
        /* Now check for service info */
        if (parseServiceInfo(options, errorMessage))
        {
                PQconninfoFree(options);
-               free(buf);
                return NULL;
        }
 
-       /* Done with the modifiable input string */
-       free(buf);
-
        /*
         * Get the fallback resources for parameters not specified in the
         * conninfo string.
index d5291a1..63991ad 100644 (file)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $Header: /cvsroot/pgsql/src/test/regress/Attic/pg_regress.sh,v 1.29 2002/11/13 16:40:23 tgl Exp $
+# $Header: /cvsroot/pgsql/src/test/regress/Attic/pg_regress.sh,v 1.30 2003/04/28 04:29:12 tgl Exp $
 
 me=`basename $0`
 : ${TMPDIR=/tmp}
@@ -137,6 +137,7 @@ do
         --host=*)
                 PGHOST=`expr "x$1" : "x--host=\(.*\)"`
                 export PGHOST
+                unset PGHOSTADDR
                 shift;;
         --port=*)
                 PGPORT=`expr "x$1" : "x--port=\(.*\)"`
@@ -279,8 +280,10 @@ then
     if [ "$unix_sockets" = no ]; then
         PGHOST=$hostname
         export PGHOST
+        unset PGHOSTADDR
     else
         unset PGHOST
+        unset PGHOSTADDR
     fi
     PGPORT=65432
     export PGPORT
@@ -397,6 +400,7 @@ else # not temp-install
     if [ "$unix_sockets" = no ]; then
         PGHOST=$hostname
         export PGHOST
+        unset PGHOSTADDR
     fi
 
     if [ -n "$PGPORT" ]; then