Okay, I've had it with PQsetdbLogin having slightly different defaults

than PQconnectdb.  Reimplement the former to use the same code as the
latter.  Fix documentation omissions while at it.
This commit is contained in:
Tom Lane 2003-04-28 04:29:12 +00:00
parent d08007ae77
commit 092133beb3
3 changed files with 227 additions and 171 deletions

View 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>).
@ -2329,10 +2335,22 @@ directory in which the socket file is stored (default <filename>/tmp</filename>)
</listitem>
<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>.)

View 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,17 +266,55 @@ 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;
/*
* 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
*/
@ -283,11 +323,14 @@ PQconnectStart(const char *conninfo)
{
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
* then only the errorMessage is likely to be useful.
* ----------------
*/
PGconn *
@ -422,113 +459,85 @@ 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
{
/* 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->pguser == NULL)
if (pgtty && pgtty[0] != '\0')
{
error = TRUE;
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not determine the PostgreSQL user name to use\n"));
if (conn->pgtty)
free(conn->pgtty);
conn->pgtty = strdup(pgtty);
}
if (dbName == NULL)
if (dbName && dbName[0] != '\0')
{
if ((tmp = getenv("PGDATABASE")) != NULL)
conn->dbName = strdup(tmp);
else if (conn->pguser)
conn->dbName = strdup(conn->pguser);
}
else
if (conn->dbName)
free(conn->dbName);
conn->dbName = strdup(dbName);
if (pwd)
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
if (error)
conn->status = CONNECTION_BAD;
else
{
if (connectDBStart(conn))
(void) connectDBComplete(conn);
}
if (login && login[0] != '\0')
{
if (conn->pguser)
free(conn->pguser);
conn->pguser = strdup(login);
}
if (pwd && pwd[0] != '\0')
{
if (conn->pgpass)
free(conn->pgpass);
conn->pgpass = strdup(pwd);
}
/*
* Compute derived options
*/
if (!connectOptions2(conn))
return 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.

View 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