1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* fe-connect.c--
|
1997-09-07 07:04:48 +02:00
|
|
|
* functions related to setting up a connection to the backend
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
1998-07-09 05:32:10 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.74 1998/07/09 03:32:10 scrappy Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
1998-07-03 06:29:04 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
#include "win32.h"
|
|
|
|
#else
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <netdb.h>
|
1998-07-03 06:29:04 +02:00
|
|
|
#include <sys/un.h>
|
1998-01-26 02:42:53 +01:00
|
|
|
#include <netinet/in.h>
|
1997-04-16 08:29:19 +02:00
|
|
|
#include <netinet/tcp.h>
|
1998-07-03 06:29:04 +02:00
|
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <errno.h>
|
1996-10-10 10:20:11 +02:00
|
|
|
#include <signal.h>
|
1997-09-07 07:04:48 +02:00
|
|
|
#include <ctype.h> /* for isspace() */
|
1996-11-03 08:14:32 +01:00
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "fe-auth.h"
|
1997-03-12 22:23:16 +01:00
|
|
|
#include "fe-connect.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "libpq-fe.h"
|
|
|
|
|
1997-02-13 09:32:20 +01:00
|
|
|
#ifndef HAVE_STRDUP
|
1996-11-26 08:39:11 +01:00
|
|
|
#include "strdup.h"
|
|
|
|
#endif
|
1997-12-04 01:28:15 +01:00
|
|
|
#ifdef HAVE_CRYPT_H
|
|
|
|
#include <crypt.h>
|
|
|
|
#endif
|
1996-11-26 04:20:35 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-08 23:56:23 +02:00
|
|
|
static ConnStatusType connectDB(PGconn *conn);
|
1998-05-07 01:51:16 +02:00
|
|
|
static PGconn *makeEmptyPGconn(void);
|
1997-09-08 23:56:23 +02:00
|
|
|
static void freePGconn(PGconn *conn);
|
|
|
|
static void closePGconn(PGconn *conn);
|
1997-09-08 04:41:22 +02:00
|
|
|
static int conninfo_parse(const char *conninfo, char *errorMessage);
|
|
|
|
static char *conninfo_getval(char *keyword);
|
|
|
|
static void conninfo_free(void);
|
1998-05-07 01:51:16 +02:00
|
|
|
/* XXX Why is this not static? */
|
1998-02-26 05:46:47 +01:00
|
|
|
void PQsetenv(PGconn *conn);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
#define NOTIFYLIST_INITIAL_SIZE 10
|
|
|
|
#define NOTIFYLIST_GROWBY 10
|
|
|
|
|
1996-11-09 11:39:54 +01:00
|
|
|
|
|
|
|
/* ----------
|
1996-11-14 11:25:54 +01:00
|
|
|
* Definition of the conninfo parameters and their fallback resources.
|
1996-11-09 11:39:54 +01:00
|
|
|
* If Environment-Var and Compiled-in are specified as NULL, no
|
|
|
|
* fallback is available. If after all no value can be determined
|
|
|
|
* for an option, an error is returned.
|
|
|
|
*
|
|
|
|
* The values for dbname and user are treated special in conninfo_parse.
|
|
|
|
* If the Compiled-in resource is specified as a NULL value, the
|
|
|
|
* user is determined by fe_getauthname() and for dbname the user
|
|
|
|
* name is copied.
|
|
|
|
*
|
|
|
|
* The Label and Disp-Char entries are provided for applications that
|
|
|
|
* want to use PQconndefaults() to create a generic database connection
|
|
|
|
* dialog. Disp-Char is defined as follows:
|
1997-09-07 07:04:48 +02:00
|
|
|
* "" Normal input field
|
1996-11-09 11:39:54 +01:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static PQconninfoOption PQconninfoOptions[] = {
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------------------------------------------------------- */
|
|
|
|
/* Option-name Environment-Var Compiled-in Current value */
|
|
|
|
/* Label Disp-Char */
|
|
|
|
/* ----------------- --------------- --------------- --------------- */
|
1998-01-26 02:42:53 +01:00
|
|
|
/* "authtype" is ignored as it is no longer used. */
|
1997-09-07 07:04:48 +02:00
|
|
|
{"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL,
|
|
|
|
"Database-Authtype", "", 20},
|
1997-03-12 22:23:16 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
{"user", "PGUSER", NULL, NULL,
|
|
|
|
"Database-User", "", 20},
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
{"password", "PGPASSWORD", DefaultPassword, NULL,
|
|
|
|
"Database-Password", "", 20},
|
1997-03-12 22:23:16 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
{"dbname", "PGDATABASE", NULL, NULL,
|
|
|
|
"Database-Name", "", 20},
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-11-07 21:52:15 +01:00
|
|
|
{"host", "PGHOST", NULL, NULL,
|
1997-09-07 07:04:48 +02:00
|
|
|
"Database-Host", "", 40},
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
{"port", "PGPORT", DEF_PGPORT, NULL,
|
|
|
|
"Database-Port", "", 6},
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
{"tty", "PGTTY", DefaultTty, NULL,
|
|
|
|
"Backend-Debug-TTY", "D", 40},
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
{"options", "PGOPTIONS", DefaultOption, NULL,
|
|
|
|
"Backend-Debug-Options", "D", 40},
|
|
|
|
/* ----------------- --------------- --------------- --------------- */
|
|
|
|
{NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, 0}
|
1996-11-09 11:39:54 +01:00
|
|
|
};
|
|
|
|
|
1997-03-18 21:15:39 +01:00
|
|
|
struct EnvironmentOptions
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
const char *envName,
|
|
|
|
*pgName;
|
|
|
|
} EnvironmentOptions[] =
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
{
|
1997-11-14 16:38:31 +01:00
|
|
|
/* common user-interface settings */
|
1998-02-26 05:46:47 +01:00
|
|
|
{
|
|
|
|
"PGDATESTYLE", "datestyle"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"PGTZ", "timezone"
|
|
|
|
},
|
1998-06-16 09:29:54 +02:00
|
|
|
#ifdef MB
|
|
|
|
{
|
|
|
|
"PGCLIENTENCODING", "client_encoding"
|
|
|
|
},
|
|
|
|
#endif
|
1997-11-14 16:38:31 +01:00
|
|
|
/* internal performance-related settings */
|
1998-02-26 05:46:47 +01:00
|
|
|
{
|
|
|
|
"PGCOSTHEAP", "cost_heap"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"PGCOSTINDEX", "cost_index"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"PGRPLANS", "r_plans"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"PGGEQO", "geqo"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
NULL
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
};
|
|
|
|
|
1996-11-09 11:39:54 +01:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* PQconnectdb
|
|
|
|
*
|
1997-11-10 16:41:58 +01:00
|
|
|
* establishes a connection to a postgres backend through the postmaster
|
1996-11-09 11:39:54 +01:00
|
|
|
* using connection information in a string.
|
|
|
|
*
|
|
|
|
* The conninfo string is a list of
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* option = value
|
1996-11-09 11:39:54 +01:00
|
|
|
*
|
|
|
|
* definitions. Value might be a single value containing no whitespaces
|
|
|
|
* or a single quoted string. If a single quote should appear everywhere
|
|
|
|
* in the value, it must be escaped with a backslash like \'
|
|
|
|
*
|
|
|
|
* Returns a PGconn* which is needed for all subsequent libpq calls
|
|
|
|
* if the status field of the connection returned is CONNECTION_BAD,
|
1997-09-07 07:04:48 +02:00
|
|
|
* then some fields may be null'ed out instead of having valid values
|
1996-11-09 11:39:54 +01:00
|
|
|
* ----------------
|
|
|
|
*/
|
1997-11-10 16:41:58 +01:00
|
|
|
PGconn *
|
1996-11-09 11:39:54 +01:00
|
|
|
PQconnectdb(const char *conninfo)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
PGconn *conn;
|
1998-02-26 05:46:47 +01:00
|
|
|
char *tmp;
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------
|
|
|
|
* Allocate memory for the conn structure
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-05-07 01:51:16 +02:00
|
|
|
conn = makeEmptyPGconn();
|
1997-09-07 07:04:48 +02:00
|
|
|
if (conn == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
1998-05-07 01:51:16 +02:00
|
|
|
"FATAL: PQconnectdb() -- unable to allocate memory for a PGconn");
|
1997-09-07 07:04:48 +02:00
|
|
|
return (PGconn *) NULL;
|
|
|
|
}
|
1996-11-09 11:39:54 +01:00
|
|
|
|
|
|
|
/* ----------
|
1998-05-07 01:51:16 +02:00
|
|
|
* Parse the conninfo string and save settings in conn structure
|
1996-11-09 11:39:54 +01:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-05-07 01:51:16 +02:00
|
|
|
if (conninfo_parse(conninfo, conn->errorMessage) < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
conn->status = CONNECTION_BAD;
|
|
|
|
conninfo_free();
|
|
|
|
return conn;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
1998-01-13 05:24:10 +01:00
|
|
|
tmp = conninfo_getval("host");
|
|
|
|
conn->pghost = tmp ? strdup(tmp) : NULL;
|
|
|
|
tmp = conninfo_getval("port");
|
|
|
|
conn->pgport = tmp ? strdup(tmp) : NULL;
|
|
|
|
tmp = conninfo_getval("tty");
|
1998-02-26 05:46:47 +01:00
|
|
|
conn->pgtty = tmp ? strdup(tmp) : NULL;
|
1998-01-13 05:24:10 +01:00
|
|
|
tmp = conninfo_getval("options");
|
|
|
|
conn->pgoptions = tmp ? strdup(tmp) : NULL;
|
1998-05-07 01:51:16 +02:00
|
|
|
tmp = conninfo_getval("dbname");
|
|
|
|
conn->dbName = tmp ? strdup(tmp) : NULL;
|
1998-01-13 05:24:10 +01:00
|
|
|
tmp = conninfo_getval("user");
|
|
|
|
conn->pguser = tmp ? strdup(tmp) : NULL;
|
|
|
|
tmp = conninfo_getval("password");
|
|
|
|
conn->pgpass = tmp ? strdup(tmp) : NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* Free the connection info - all is in conn now
|
|
|
|
* ----------
|
|
|
|
*/
|
1996-11-09 11:39:54 +01:00
|
|
|
conninfo_free();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* Connect to the database
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
conn->status = connectDB(conn);
|
1997-11-10 16:41:58 +01:00
|
|
|
|
1996-11-09 11:39:54 +01:00
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* PQconndefaults
|
|
|
|
*
|
1996-11-09 11:39:54 +01:00
|
|
|
* Parse an empty string like PQconnectdb() would do and return the
|
|
|
|
* address of the connection options structure. Using this function
|
|
|
|
* an application might determine all possible options and their
|
|
|
|
* current default values.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
PQconninfoOption *
|
1996-11-10 04:06:38 +01:00
|
|
|
PQconndefaults(void)
|
1996-11-09 11:39:54 +01:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
char errorMessage[ERROR_MSG_LENGTH];
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
conninfo_parse("", errorMessage);
|
|
|
|
return PQconninfoOptions;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-12-04 01:28:15 +01:00
|
|
|
* PQsetdbLogin
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
1996-10-10 10:20:11 +02:00
|
|
|
* establishes a connection to a postgres backend through the postmaster
|
1996-07-09 08:22:35 +02:00
|
|
|
* 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,
|
1997-09-07 07:04:48 +02:00
|
|
|
* then some fields may be null'ed out instead of having valid values
|
1996-10-10 10:20:11 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Uses these environment variables:
|
1996-10-10 10:20:11 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* PGHOST identifies host to which to connect if <pghost> argument
|
|
|
|
* is NULL or a null string.
|
1996-10-10 10:20:11 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* PGPORT identifies TCP port to which to connect if <pgport> argument
|
|
|
|
* is NULL or a null string.
|
1996-10-10 10:20:11 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* PGTTY identifies tty to which to send messages if <pgtty> argument
|
|
|
|
* is NULL or a null string.
|
1996-10-10 10:20:11 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* PGOPTIONS identifies connection options if <pgoptions> argument is
|
|
|
|
* NULL or a null string.
|
1996-10-10 10:20:11 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* PGUSER Postgres username to associate with the connection.
|
1996-10-10 10:20:11 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* PGPASSWORD The user's password.
|
1997-03-12 22:23:16 +01:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* PGDATABASE name of database to which to connect if <pgdatabase>
|
|
|
|
* argument is NULL or a null string
|
1996-10-10 10:20:11 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* None of the above need be defined. There are defaults for all of them.
|
1996-10-10 10:20:11 +02:00
|
|
|
*
|
1997-11-10 16:41:58 +01:00
|
|
|
* 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
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1998-02-26 05:46:47 +01:00
|
|
|
PGconn *
|
1997-12-04 01:28:15 +01:00
|
|
|
PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName, const char *login, const char *pwd)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
PGconn *conn;
|
|
|
|
char *tmp;
|
1997-09-07 07:04:48 +02:00
|
|
|
/* An error message from some service we call. */
|
1998-05-07 01:51:16 +02:00
|
|
|
bool error = FALSE;
|
1997-09-07 07:04:48 +02:00
|
|
|
/* We encountered an error that prevents successful completion */
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
conn = makeEmptyPGconn();
|
1997-09-07 07:04:48 +02:00
|
|
|
if (conn == NULL)
|
1998-05-07 01:51:16 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
fprintf(stderr,
|
1998-05-07 01:51:16 +02:00
|
|
|
"FATAL: PQsetdbLogin() -- unable to allocate memory for a PGconn");
|
|
|
|
return (PGconn *) NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((pghost == NULL) || pghost[0] == '\0')
|
|
|
|
{
|
|
|
|
if ((tmp = getenv("PGHOST")) != NULL)
|
|
|
|
conn->pghost = strdup(tmp);
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
1998-05-07 01:51:16 +02:00
|
|
|
conn->pghost = strdup(pghost);
|
|
|
|
|
|
|
|
if ((pgport == NULL) || pgport[0] == '\0')
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-05-07 01:51:16 +02:00
|
|
|
if ((tmp = getenv("PGPORT")) == NULL)
|
|
|
|
tmp = DEF_PGPORT;
|
|
|
|
conn->pgport = strdup(tmp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
conn->pgport = strdup(pgport);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if ((pgtty == NULL) || pgtty[0] == '\0')
|
|
|
|
{
|
|
|
|
if ((tmp = getenv("PGTTY")) == NULL)
|
|
|
|
tmp = DefaultTty;
|
|
|
|
conn->pgtty = strdup(tmp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
conn->pgtty = strdup(pgtty);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if ((pgoptions == NULL) || pgoptions[0] == '\0')
|
|
|
|
{
|
|
|
|
if ((tmp = getenv("PGOPTIONS")) == NULL)
|
|
|
|
tmp = DefaultOption;
|
|
|
|
conn->pgoptions = strdup(tmp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
conn->pgoptions = strdup(pgoptions);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if (login)
|
|
|
|
conn->pguser = strdup(login);
|
|
|
|
else if ((tmp = getenv("PGUSER")) != NULL)
|
|
|
|
conn->pguser = strdup(tmp);
|
|
|
|
else
|
|
|
|
conn->pguser = fe_getauthname(conn->errorMessage);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if (conn->pguser == NULL)
|
|
|
|
{
|
|
|
|
error = TRUE;
|
|
|
|
sprintf(conn->errorMessage,
|
|
|
|
"FATAL: PQsetdbLogin(): Unable to determine a Postgres username!\n");
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if (pwd)
|
|
|
|
conn->pgpass = strdup(pwd);
|
|
|
|
else if ((tmp = getenv("PGPASSWORD")) != NULL)
|
|
|
|
conn->pgpass = strdup(tmp);
|
|
|
|
else
|
|
|
|
conn->pgpass = strdup(DefaultPassword);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if ((dbName == NULL) || dbName[0] == '\0')
|
|
|
|
{
|
|
|
|
if ((tmp = getenv("PGDATABASE")) != NULL)
|
|
|
|
conn->dbName = strdup(tmp);
|
|
|
|
else if (conn->pguser)
|
|
|
|
conn->dbName = strdup(conn->pguser);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
conn->dbName = strdup(dbName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if (conn->dbName)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* if the database name is surrounded by double-quotes, then
|
|
|
|
* don't convert case
|
|
|
|
*/
|
|
|
|
if (*conn->dbName == '"')
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-05-07 01:51:16 +02:00
|
|
|
strcpy(conn->dbName, conn->dbName + 1);
|
|
|
|
conn->dbName[strlen(conn->dbName) - 1] = '\0';
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
1998-05-07 01:51:16 +02:00
|
|
|
for (i = 0; conn->dbName[i]; i++)
|
1998-06-16 09:29:54 +02:00
|
|
|
if (isascii((unsigned char)conn->dbName[i]) &&
|
|
|
|
isupper(conn->dbName[i]))
|
1998-05-07 01:51:16 +02:00
|
|
|
conn->dbName[i] = tolower(conn->dbName[i]);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-05-07 01:51:16 +02:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
conn->status = CONNECTION_BAD;
|
|
|
|
else
|
|
|
|
conn->status = connectDB(conn);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return conn;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-07-07 20:00:09 +02:00
|
|
|
/*
|
|
|
|
* update_db_info -
|
|
|
|
* get all additional infos out of dbName
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
update_db_info(PGconn *conn)
|
|
|
|
{
|
|
|
|
char *tmp, *old = conn->dbName;
|
|
|
|
|
|
|
|
if (strchr(conn->dbName, '@') != NULL)
|
|
|
|
{
|
|
|
|
/* old style: dbname[@server][:port] */
|
|
|
|
tmp = strrchr(conn->dbName, ':');
|
|
|
|
if (tmp != NULL) /* port number given */
|
|
|
|
{
|
|
|
|
conn->pgport = strdup(tmp + 1);
|
|
|
|
*tmp = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = strrchr(conn->dbName, '@');
|
|
|
|
if (tmp != NULL) /* host name given */
|
|
|
|
{
|
|
|
|
conn->pghost = strdup(tmp + 1);
|
|
|
|
*tmp = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->dbName = strdup(old);
|
|
|
|
free(old);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* only allow protocols tcp and unix
|
|
|
|
*/
|
|
|
|
if (strncmp(conn->dbName, "tcp:", 4) == 0)
|
|
|
|
offset = 4;
|
|
|
|
else if (strncmp(conn->dbName, "unix:", 5) == 0)
|
|
|
|
offset = 5;
|
|
|
|
else return 0;
|
|
|
|
|
|
|
|
if (strncmp(conn->dbName + offset, "postgresql://", strlen("postgresql://")) == 0)
|
|
|
|
{
|
|
|
|
/* new style: <tcp|unix>:postgresql://server[:port][/dbname][?options] */
|
|
|
|
offset += strlen("postgresql://");
|
|
|
|
|
|
|
|
tmp = strrchr(conn->dbName + offset, '?');
|
|
|
|
if (tmp != NULL) /* options given */
|
|
|
|
{
|
|
|
|
conn->pgoptions = strdup(tmp + 1);
|
|
|
|
*tmp = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = strrchr(conn->dbName + offset, '/');
|
|
|
|
if (tmp != NULL) /* database name given */
|
|
|
|
{
|
|
|
|
conn->dbName = strdup(tmp + 1);
|
|
|
|
*tmp = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((tmp = getenv("PGDATABASE")) != NULL)
|
|
|
|
conn->dbName = strdup(tmp);
|
|
|
|
else if (conn->pguser)
|
|
|
|
conn->dbName = strdup(conn->pguser);
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = strrchr(old + offset, ':');
|
|
|
|
if (tmp != NULL) /* port number given */
|
|
|
|
{
|
|
|
|
conn->pgport = strdup(tmp + 1);
|
|
|
|
*tmp = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strncmp(old, "unix:", 5) == 0)
|
|
|
|
{
|
|
|
|
conn->pghost = NULL;
|
|
|
|
if (strcmp(old + offset, "localhost") != 0)
|
|
|
|
{
|
|
|
|
(void) sprintf(conn->errorMessage,
|
|
|
|
"connectDB() -- non-tcp access only possible on localhost\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else conn->pghost = strdup(old + offset);
|
|
|
|
|
|
|
|
free(old);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* connectDB -
|
1997-09-07 07:04:48 +02:00
|
|
|
* make a connection to the backend so it is ready to receive queries.
|
1996-08-19 15:25:40 +02:00
|
|
|
* return CONNECTION_OK if successful, CONNECTION_BAD if not.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static ConnStatusType
|
1997-09-08 23:56:23 +02:00
|
|
|
connectDB(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-05-07 01:51:16 +02:00
|
|
|
PGresult *res;
|
1997-09-07 07:04:48 +02:00
|
|
|
struct hostent *hp;
|
1998-02-26 05:46:47 +01:00
|
|
|
StartupPacket sp;
|
|
|
|
AuthRequest areq;
|
1998-01-26 02:42:53 +01:00
|
|
|
int laddrlen = sizeof(SockAddr);
|
1997-11-10 06:10:50 +01:00
|
|
|
int portno,
|
1998-07-09 05:29:11 +02:00
|
|
|
family;
|
1998-05-07 01:51:16 +02:00
|
|
|
char beresp;
|
1998-07-03 06:24:16 +02:00
|
|
|
int on = 1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-07-07 20:00:09 +02:00
|
|
|
/*
|
|
|
|
* parse dbName to get all additional info in it, if any
|
|
|
|
*/
|
|
|
|
if (update_db_info(conn) != 0)
|
|
|
|
goto connect_errReturn;
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* Initialize the startup packet.
|
|
|
|
*/
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
MemSet((char *) &sp, 0, sizeof(StartupPacket));
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LATEST);
|
1998-01-26 02:42:53 +01:00
|
|
|
|
|
|
|
strncpy(sp.user, conn->pguser, SM_USER);
|
|
|
|
strncpy(sp.database, conn->dbName, SM_DATABASE);
|
|
|
|
strncpy(sp.tty, conn->pgtty, SM_TTY);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (conn->pgoptions)
|
1998-01-26 02:42:53 +01:00
|
|
|
strncpy(sp.options, conn->pgoptions, SM_OPTIONS);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Open a connection to postmaster/backend.
|
|
|
|
*/
|
|
|
|
|
1997-11-17 17:42:39 +01:00
|
|
|
if (conn->pghost != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1997-11-17 17:42:39 +01:00
|
|
|
hp = gethostbyname(conn->pghost);
|
|
|
|
if ((hp == NULL) || (hp->h_addrtype != AF_INET))
|
|
|
|
{
|
|
|
|
(void) sprintf(conn->errorMessage,
|
|
|
|
"connectDB() -- unknown hostname: %s\n",
|
|
|
|
conn->pghost);
|
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
1998-05-07 01:51:16 +02:00
|
|
|
family = AF_INET;
|
1998-02-26 05:46:47 +01:00
|
|
|
}
|
1998-05-07 01:51:16 +02:00
|
|
|
else {
|
1997-11-17 17:42:39 +01:00
|
|
|
hp = NULL;
|
1998-05-07 01:51:16 +02:00
|
|
|
family = AF_UNIX;
|
|
|
|
}
|
1997-11-17 17:42:39 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
|
1998-01-26 02:42:53 +01:00
|
|
|
conn->raddr.sa.sa_family = family;
|
1998-05-07 01:51:16 +02:00
|
|
|
|
|
|
|
portno = atoi(conn->pgport);
|
1997-11-07 21:52:15 +01:00
|
|
|
if (family == AF_INET)
|
1997-11-10 06:10:50 +01:00
|
|
|
{
|
1998-01-26 02:42:53 +01:00
|
|
|
memmove((char *) &(conn->raddr.in.sin_addr),
|
1997-11-10 06:10:50 +01:00
|
|
|
(char *) hp->h_addr,
|
|
|
|
hp->h_length);
|
1998-01-26 02:42:53 +01:00
|
|
|
conn->raddr.in.sin_port = htons((unsigned short) (portno));
|
1998-07-09 05:29:11 +02:00
|
|
|
conn->raddr_len = sizeof(struct sockaddr_in);
|
1997-11-10 06:10:50 +01:00
|
|
|
}
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifndef WIN32
|
1997-11-07 21:52:15 +01:00
|
|
|
else
|
1998-07-09 05:29:11 +02:00
|
|
|
conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
|
1998-07-03 06:24:16 +02:00
|
|
|
#endif
|
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
|
|
|
|
/* Connect to the server */
|
1998-01-26 02:42:53 +01:00
|
|
|
if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
(void) sprintf(conn->errorMessage,
|
|
|
|
"connectDB() -- socket() failed: errno=%d\n%s\n",
|
|
|
|
errno, strerror(errno));
|
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
1998-07-09 05:29:11 +02:00
|
|
|
if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
(void) sprintf(conn->errorMessage,
|
1997-12-04 21:32:35 +01:00
|
|
|
"connectDB() failed: Is the postmaster running and accepting%s connections at '%s' on port '%s'?\n",
|
1997-12-04 21:26:37 +01:00
|
|
|
conn->pghost ? " TCP/IP(with -i)" : "",
|
1997-11-10 06:10:50 +01:00
|
|
|
conn->pghost ? conn->pghost : "UNIX Socket",
|
|
|
|
conn->pgport);
|
1997-09-07 07:04:48 +02:00
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
1998-05-07 01:51:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the right options.
|
|
|
|
* We need nonblocking I/O, and we don't want delay of outgoing data.
|
|
|
|
*/
|
|
|
|
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifndef WIN32
|
1998-05-07 01:51:16 +02:00
|
|
|
if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) < 0)
|
1998-07-03 06:24:16 +02:00
|
|
|
#else
|
|
|
|
if (ioctlsocket(conn->sock,FIONBIO, &on) != 0)
|
|
|
|
#endif
|
1998-05-07 01:51:16 +02:00
|
|
|
{
|
|
|
|
(void) sprintf(conn->errorMessage,
|
|
|
|
"connectDB() -- fcntl() failed: errno=%d\n%s\n",
|
|
|
|
errno, strerror(errno));
|
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
|
|
|
|
1997-11-07 21:52:15 +01:00
|
|
|
if (family == AF_INET)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
struct protoent *pe;
|
|
|
|
|
|
|
|
pe = getprotobyname("TCP");
|
|
|
|
if (pe == NULL)
|
|
|
|
{
|
|
|
|
(void) sprintf(conn->errorMessage,
|
|
|
|
"connectDB(): getprotobyname failed\n");
|
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
if (setsockopt(conn->sock, pe->p_proto, TCP_NODELAY,
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
(char *)
|
|
|
|
#endif
|
|
|
|
&on,
|
|
|
|
sizeof(on)) < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
(void) sprintf(conn->errorMessage,
|
1998-05-07 01:51:16 +02:00
|
|
|
"connectDB() -- setsockopt failed: errno=%d\n%s\n",
|
|
|
|
errno, strerror(errno));
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
printf("Winsock error: %i\n",WSAGetLastError());
|
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Fill in the client address */
|
1998-01-26 02:42:53 +01:00
|
|
|
if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
(void) sprintf(conn->errorMessage,
|
1998-05-07 01:51:16 +02:00
|
|
|
"connectDB() -- getsockname() failed: errno=%d\n%s\n",
|
1997-09-07 07:04:48 +02:00
|
|
|
errno, strerror(errno));
|
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Ensure our buffers are empty */
|
|
|
|
conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
|
conn->outCount = 0;
|
1998-01-26 02:42:53 +01:00
|
|
|
|
|
|
|
/* Send the startup packet. */
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
if (packetSend(conn, (char *) &sp, sizeof(StartupPacket)) != STATUS_OK)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
sprintf(conn->errorMessage,
|
1998-05-07 01:51:16 +02:00
|
|
|
"connectDB() -- couldn't send startup packet: errno=%d\n%s\n",
|
|
|
|
errno, strerror(errno));
|
1997-09-07 07:04:48 +02:00
|
|
|
goto connect_errReturn;
|
1997-04-16 08:29:19 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
/*
|
1998-05-07 01:51:16 +02:00
|
|
|
* Perform the authentication exchange:
|
|
|
|
* wait for backend messages and respond as necessary.
|
|
|
|
* We fall out of this loop when done talking to the postmaster.
|
1998-01-26 02:42:53 +01:00
|
|
|
*/
|
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
for (;;)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Wait for some data to arrive (or for the channel to close) */
|
|
|
|
if (pqWait(TRUE, FALSE, conn))
|
1998-01-26 02:42:53 +01:00
|
|
|
goto connect_errReturn;
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Load data, or detect EOF */
|
|
|
|
if (pqReadData(conn) < 0)
|
|
|
|
goto connect_errReturn;
|
|
|
|
/* Scan the message.
|
|
|
|
* If we run out of data, loop around to try again.
|
|
|
|
*/
|
|
|
|
conn->inCursor = conn->inStart;
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if (pqGetc(&beresp, conn))
|
|
|
|
continue; /* no data yet */
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Handle errors. */
|
1998-01-26 02:42:53 +01:00
|
|
|
if (beresp == 'E')
|
|
|
|
{
|
1998-05-07 01:51:16 +02:00
|
|
|
if (pqGets(conn->errorMessage, sizeof(conn->errorMessage), conn))
|
|
|
|
continue;
|
1998-01-26 02:42:53 +01:00
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Otherwise it should be an authentication request. */
|
1998-01-26 02:42:53 +01:00
|
|
|
if (beresp != 'R')
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
(void) sprintf(conn->errorMessage,
|
1998-05-07 01:51:16 +02:00
|
|
|
"connectDB() -- expected authentication request\n");
|
1998-01-26 02:42:53 +01:00
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the type of request. */
|
1998-05-07 01:51:16 +02:00
|
|
|
if (pqGetInt((int *) &areq, 4, conn))
|
|
|
|
continue;
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Get the password salt if there is one. */
|
|
|
|
if (areq == AUTH_REQ_CRYPT)
|
1998-01-26 02:42:53 +01:00
|
|
|
{
|
1998-05-07 01:51:16 +02:00
|
|
|
if (pqGetnchar(conn->salt, sizeof(conn->salt), conn))
|
|
|
|
continue;
|
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/* OK, we successfully read the message; mark data consumed */
|
|
|
|
conn->inStart = conn->inCursor;
|
|
|
|
|
|
|
|
/* Respond to the request if necessary. */
|
|
|
|
if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
|
|
|
|
conn->errorMessage) != STATUS_OK)
|
|
|
|
goto connect_errReturn;
|
|
|
|
if (pqFlush(conn))
|
1998-01-26 02:42:53 +01:00
|
|
|
goto connect_errReturn;
|
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Are we done? */
|
|
|
|
if (areq == AUTH_REQ_OK)
|
|
|
|
break;
|
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/*
|
|
|
|
* Now we expect to hear from the backend.
|
|
|
|
* A ReadyForQuery message indicates that startup is successful,
|
|
|
|
* but we might also get an Error message indicating failure.
|
|
|
|
* (Notice messages indicating nonfatal warnings are also allowed
|
1998-07-09 05:29:11 +02:00
|
|
|
* by the protocol, as is a BackendKeyData message.)
|
1998-05-07 01:51:16 +02:00
|
|
|
* Easiest way to handle this is to let PQgetResult() read the messages.
|
|
|
|
* We just have to fake it out about the state of the connection.
|
|
|
|
*/
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
conn->status = CONNECTION_OK;
|
|
|
|
conn->asyncStatus = PGASYNC_BUSY;
|
|
|
|
res = PQgetResult(conn);
|
|
|
|
/* NULL return indicating we have gone to IDLE state is expected */
|
|
|
|
if (res) {
|
|
|
|
if (res->resultStatus != PGRES_FATAL_ERROR)
|
|
|
|
sprintf(conn->errorMessage,
|
|
|
|
"connectDB() -- unexpected message during startup\n");
|
|
|
|
PQclear(res);
|
|
|
|
goto connect_errReturn;
|
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Given the new protocol that sends a ReadyForQuery message
|
|
|
|
* after successful backend startup, it should no longer be
|
|
|
|
* necessary to send an empty query to test for startup.
|
|
|
|
*/
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
#if 0
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/*
|
|
|
|
* Send a blank query to make sure everything works; in
|
|
|
|
* particular, that the database exists.
|
|
|
|
*/
|
|
|
|
res = PQexec(conn, " ");
|
|
|
|
if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY)
|
|
|
|
{
|
|
|
|
/* PQexec has put error message in conn->errorMessage */
|
|
|
|
closePGconn(conn);
|
|
|
|
PQclear(res);
|
|
|
|
goto connect_errReturn;
|
1997-04-16 08:29:19 +02:00
|
|
|
}
|
1998-05-07 01:51:16 +02:00
|
|
|
PQclear(res);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Post-connection housekeeping.
|
|
|
|
* Send environment variables to server
|
|
|
|
*/
|
|
|
|
|
|
|
|
PQsetenv(conn);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return CONNECTION_OK;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
connect_errReturn:
|
1998-05-07 01:51:16 +02:00
|
|
|
if (conn->sock >= 0)
|
|
|
|
{
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
closesocket(conn->sock);
|
|
|
|
#else
|
1998-05-07 01:51:16 +02:00
|
|
|
close(conn->sock);
|
1998-07-03 06:24:16 +02:00
|
|
|
#endif
|
1998-05-07 01:51:16 +02:00
|
|
|
conn->sock = -1;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
return CONNECTION_BAD;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
1997-11-10 16:41:58 +01:00
|
|
|
void
|
|
|
|
PQsetenv(PGconn *conn)
|
|
|
|
{
|
|
|
|
struct EnvironmentOptions *eo;
|
1998-02-26 05:46:47 +01:00
|
|
|
char setQuery[80]; /* mjl: size okay? XXX */
|
1997-11-10 16:41:58 +01:00
|
|
|
|
|
|
|
for (eo = EnvironmentOptions; eo->envName; eo++)
|
|
|
|
{
|
|
|
|
const char *val;
|
|
|
|
|
|
|
|
if ((val = getenv(eo->envName)))
|
|
|
|
{
|
|
|
|
PGresult *res;
|
|
|
|
|
1997-11-14 16:38:31 +01:00
|
|
|
if (strcasecmp(val, "default") == 0)
|
|
|
|
sprintf(setQuery, "SET %s = %.60s", eo->pgName, val);
|
|
|
|
else
|
|
|
|
sprintf(setQuery, "SET %s = '%.60s'", eo->pgName, val);
|
1997-11-10 16:41:58 +01:00
|
|
|
#ifdef CONNECTDEBUG
|
1998-02-26 05:46:47 +01:00
|
|
|
printf("Use environment variable %s to send %s\n", eo->envName, setQuery);
|
1997-11-10 16:41:58 +01:00
|
|
|
#endif
|
|
|
|
res = PQexec(conn, setQuery);
|
1998-02-26 05:46:47 +01:00
|
|
|
PQclear(res); /* Don't care? */
|
1997-11-10 16:41:58 +01:00
|
|
|
}
|
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
} /* PQsetenv() */
|
1997-11-10 16:41:58 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
/*
|
|
|
|
* makeEmptyPGconn
|
|
|
|
* - create a PGconn data structure with (as yet) no interesting data
|
|
|
|
*/
|
|
|
|
static PGconn *
|
|
|
|
makeEmptyPGconn(void)
|
|
|
|
{
|
|
|
|
PGconn *conn = (PGconn *) malloc(sizeof(PGconn));
|
|
|
|
if (conn == NULL)
|
|
|
|
return conn;
|
|
|
|
|
|
|
|
/* Zero all pointers */
|
|
|
|
MemSet((char *) conn, 0, sizeof(PGconn));
|
|
|
|
|
|
|
|
conn->status = CONNECTION_BAD;
|
|
|
|
conn->asyncStatus = PGASYNC_IDLE;
|
|
|
|
conn->notifyList = DLNewList();
|
|
|
|
conn->sock = -1;
|
|
|
|
conn->inBufSize = 8192;
|
|
|
|
conn->inBuffer = (char *) malloc(conn->inBufSize);
|
|
|
|
conn->outBufSize = 8192;
|
|
|
|
conn->outBuffer = (char *) malloc(conn->outBufSize);
|
|
|
|
if (conn->inBuffer == NULL || conn->outBuffer == NULL)
|
|
|
|
{
|
|
|
|
freePGconn(conn);
|
|
|
|
conn = NULL;
|
|
|
|
}
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* freePGconn
|
1997-09-07 07:04:48 +02:00
|
|
|
* - free the PGconn data structure
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
static void
|
1997-09-08 23:56:23 +02:00
|
|
|
freePGconn(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
return;
|
1998-05-07 01:51:16 +02:00
|
|
|
PQclearAsyncResult(conn); /* deallocate result and curTuple */
|
|
|
|
if (conn->sock >= 0)
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
closesocket(conn->sock);
|
|
|
|
#else
|
|
|
|
close(conn->sock);
|
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
if (conn->pghost)
|
|
|
|
free(conn->pghost);
|
1998-05-07 01:51:16 +02:00
|
|
|
if (conn->pgport)
|
|
|
|
free(conn->pgport);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (conn->pgtty)
|
|
|
|
free(conn->pgtty);
|
|
|
|
if (conn->pgoptions)
|
|
|
|
free(conn->pgoptions);
|
|
|
|
if (conn->dbName)
|
|
|
|
free(conn->dbName);
|
|
|
|
if (conn->pguser)
|
|
|
|
free(conn->pguser);
|
1998-04-21 06:00:06 +02:00
|
|
|
if (conn->pgpass)
|
|
|
|
free(conn->pgpass);
|
1998-05-07 01:51:16 +02:00
|
|
|
/* Note that conn->Pfdebug is not ours to close or free */
|
1997-09-07 07:04:48 +02:00
|
|
|
if (conn->notifyList)
|
|
|
|
DLFreeList(conn->notifyList);
|
1998-05-07 01:51:16 +02:00
|
|
|
if (conn->lobjfuncs)
|
|
|
|
free(conn->lobjfuncs);
|
|
|
|
if (conn->inBuffer)
|
|
|
|
free(conn->inBuffer);
|
|
|
|
if (conn->outBuffer)
|
|
|
|
free(conn->outBuffer);
|
1997-09-07 07:04:48 +02:00
|
|
|
free(conn);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
closePGconn
|
1997-09-07 07:04:48 +02:00
|
|
|
- properly close a connection to the backend
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
static void
|
1997-09-08 23:56:23 +02:00
|
|
|
closePGconn(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-05-07 01:51:16 +02:00
|
|
|
if (conn->sock >= 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Try to send close message.
|
|
|
|
* If connection is already gone, that's cool. No reason for kernel
|
|
|
|
* to kill us when we try to write to it. So ignore SIGPIPE signals.
|
|
|
|
*/
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifndef WIN32
|
1997-02-13 09:32:20 +01:00
|
|
|
#if defined(USE_POSIX_SIGNALS)
|
1998-05-07 01:51:16 +02:00
|
|
|
struct sigaction ignore_action;
|
|
|
|
struct sigaction oldaction;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
ignore_action.sa_handler = SIG_IGN;
|
|
|
|
sigemptyset(&ignore_action.sa_mask);
|
|
|
|
ignore_action.sa_flags = 0;
|
|
|
|
sigaction(SIGPIPE, (struct sigaction *) & ignore_action, &oldaction);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
(void) pqPuts("X", conn);
|
|
|
|
(void) pqFlush(conn);
|
|
|
|
|
|
|
|
sigaction(SIGPIPE, &oldaction, NULL);
|
1997-02-13 09:32:20 +01:00
|
|
|
#else
|
1998-05-07 01:51:16 +02:00
|
|
|
void (*oldsignal)(int);
|
|
|
|
|
|
|
|
oldsignal = signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
|
|
|
(void) pqPuts("X", conn);
|
|
|
|
(void) pqFlush(conn);
|
|
|
|
|
|
|
|
signal(SIGPIPE, oldsignal);
|
1997-02-13 09:32:20 +01:00
|
|
|
#endif
|
1998-07-03 06:24:16 +02:00
|
|
|
#endif /* Win32 uses no signals at all */
|
1998-05-07 01:51:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Close the connection, reset all transient state, flush I/O buffers.
|
|
|
|
*/
|
|
|
|
if (conn->sock >= 0)
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
closesocket(conn->sock);
|
|
|
|
#else
|
1998-05-07 01:51:16 +02:00
|
|
|
close(conn->sock);
|
1998-07-03 06:24:16 +02:00
|
|
|
#endif
|
1998-05-07 01:51:16 +02:00
|
|
|
conn->sock = -1;
|
1997-09-07 07:04:48 +02:00
|
|
|
conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just
|
|
|
|
* absent */
|
1998-05-07 01:51:16 +02:00
|
|
|
conn->asyncStatus = PGASYNC_IDLE;
|
|
|
|
PQclearAsyncResult(conn); /* deallocate result and curTuple */
|
|
|
|
if (conn->lobjfuncs)
|
|
|
|
free(conn->lobjfuncs);
|
|
|
|
conn->lobjfuncs = NULL;
|
|
|
|
conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
|
conn->outCount = 0;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
PQfinish:
|
1997-09-07 07:04:48 +02:00
|
|
|
properly close a connection to the backend
|
|
|
|
also frees the PGconn data structure so it shouldn't be re-used
|
|
|
|
after this
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
PQfinish(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
fprintf(stderr, "PQfinish() -- pointer to PGconn is null\n");
|
|
|
|
else
|
|
|
|
{
|
1998-05-07 01:51:16 +02:00
|
|
|
closePGconn(conn);
|
1997-09-07 07:04:48 +02:00
|
|
|
freePGconn(conn);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* PQreset :
|
|
|
|
resets the connection to the backend
|
1997-09-07 07:04:48 +02:00
|
|
|
closes the existing connection and makes a new one
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
PQreset(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
fprintf(stderr, "PQreset() -- pointer to PGconn is null\n");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
closePGconn(conn);
|
|
|
|
conn->status = connectDB(conn);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-07-09 05:29:11 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* PQrequestCancel: attempt to request cancellation of the current operation.
|
|
|
|
*
|
|
|
|
* The return value is TRUE if the cancel request was successfully
|
|
|
|
* dispatched, FALSE if not (in which case errorMessage is set).
|
|
|
|
* Note: successful dispatch is no guarantee that there will be any effect at
|
|
|
|
* the backend. The application must read the operation result as usual.
|
|
|
|
*
|
|
|
|
* CAUTION: we want this routine to be safely callable from a signal handler
|
|
|
|
* (for example, an application might want to call it in a SIGINT handler).
|
|
|
|
* This means we cannot use any C library routine that might be non-reentrant.
|
|
|
|
* malloc/free are often non-reentrant, and anything that might call them is
|
|
|
|
* just as dangerous. We avoid sprintf here for that reason. Building up
|
|
|
|
* error messages with strcpy/strcat is tedious but should be quite safe.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
PQrequestCancel(PGconn *conn)
|
|
|
|
{
|
|
|
|
int tmpsock = -1;
|
|
|
|
struct {
|
|
|
|
uint32 packetlen;
|
|
|
|
CancelRequestPacket cp;
|
|
|
|
} crp;
|
|
|
|
|
|
|
|
/* Check we have an open connection */
|
|
|
|
if (!conn)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (conn->sock < 0)
|
|
|
|
{
|
|
|
|
strcpy(conn->errorMessage,
|
|
|
|
"PQrequestCancel() -- connection is not open\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to open a temporary connection to the postmaster.
|
|
|
|
* Use the information saved by connectDB to do this with
|
|
|
|
* only kernel calls.
|
|
|
|
*/
|
|
|
|
if ((tmpsock = socket(conn->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
|
|
|
|
{
|
|
|
|
strcpy(conn->errorMessage, "PQrequestCancel() -- socket() failed: ");
|
|
|
|
goto cancel_errReturn;
|
|
|
|
}
|
|
|
|
if (connect(tmpsock, &conn->raddr.sa, conn->raddr_len) < 0)
|
|
|
|
{
|
|
|
|
strcpy(conn->errorMessage, "PQrequestCancel() -- connect() failed: ");
|
|
|
|
goto cancel_errReturn;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We needn't set nonblocking I/O or NODELAY options here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Create and send the cancel request packet. */
|
|
|
|
|
|
|
|
crp.packetlen = htonl((uint32) sizeof(crp));
|
|
|
|
crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);
|
|
|
|
crp.cp.backendPID = htonl(conn->be_pid);
|
|
|
|
crp.cp.cancelAuthCode = htonl(conn->be_key);
|
|
|
|
|
|
|
|
if (send(tmpsock, (char*) &crp, sizeof(crp), 0) != (int) sizeof(crp))
|
|
|
|
{
|
|
|
|
strcpy(conn->errorMessage, "PQrequestCancel() -- send() failed: ");
|
|
|
|
goto cancel_errReturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sent it, done */
|
|
|
|
#ifdef WIN32
|
|
|
|
closesocket(tmpsock);
|
|
|
|
#else
|
|
|
|
close(tmpsock);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
cancel_errReturn:
|
|
|
|
strcat(conn->errorMessage, strerror(errno));
|
|
|
|
strcat(conn->errorMessage, "\n");
|
|
|
|
if (tmpsock >= 0)
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
closesocket(tmpsock);
|
|
|
|
#else
|
|
|
|
close(tmpsock);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1998-05-07 01:51:16 +02:00
|
|
|
* PacketSend() -- send a single-packet message.
|
|
|
|
* this is like PacketSend(), defined in backend/libpq/pqpacket.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
|
|
|
|
* SIDE_EFFECTS: may block.
|
|
|
|
*/
|
1997-03-12 22:23:16 +01:00
|
|
|
int
|
1998-01-29 04:24:36 +01:00
|
|
|
packetSend(PGconn *conn, const char *buf, size_t len)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-01-26 02:42:53 +01:00
|
|
|
/* Send the total packet size. */
|
1997-11-10 06:10:50 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if (pqPutInt(4 + len, 4, conn))
|
1998-01-26 02:42:53 +01:00
|
|
|
return STATUS_ERROR;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
/* Send the packet itself. */
|
1997-12-04 01:28:15 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if (pqPutnchar(buf, len, conn))
|
1998-01-26 02:42:53 +01:00
|
|
|
return STATUS_ERROR;
|
1997-12-04 01:28:15 +01:00
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
if (pqFlush(conn))
|
|
|
|
return STATUS_ERROR;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
return STATUS_OK;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1996-11-09 11:39:54 +01:00
|
|
|
/* ----------------
|
|
|
|
* Conninfo parser routine
|
|
|
|
* ----------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
static int
|
|
|
|
conninfo_parse(const char *conninfo, char *errorMessage)
|
1996-11-09 11:39:54 +01:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
char *pname;
|
|
|
|
char *pval;
|
|
|
|
char *buf;
|
|
|
|
char *tmp;
|
|
|
|
char *cp;
|
|
|
|
char *cp2;
|
1997-09-07 07:04:48 +02:00
|
|
|
PQconninfoOption *option;
|
1997-09-08 04:41:22 +02:00
|
|
|
char errortmp[ERROR_MSG_LENGTH];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
conninfo_free();
|
|
|
|
|
|
|
|
if ((buf = strdup(conninfo)) == NULL)
|
|
|
|
{
|
|
|
|
strcpy(errorMessage,
|
|
|
|
"FATAL: cannot allocate memory for copy of conninfo string\n");
|
|
|
|
return -1;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
cp = buf;
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
while (*cp)
|
|
|
|
{
|
|
|
|
/* Skip blanks before the parameter name */
|
|
|
|
if (isspace(*cp))
|
|
|
|
{
|
|
|
|
cp++;
|
|
|
|
continue;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* Get the parameter name */
|
|
|
|
pname = cp;
|
|
|
|
while (*cp)
|
|
|
|
{
|
|
|
|
if (*cp == '=')
|
|
|
|
break;
|
|
|
|
if (isspace(*cp))
|
|
|
|
{
|
|
|
|
*cp++ = '\0';
|
|
|
|
while (*cp)
|
|
|
|
{
|
|
|
|
if (!isspace(*cp))
|
|
|
|
break;
|
|
|
|
cp++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cp++;
|
|
|
|
}
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* Check that there is a following '=' */
|
|
|
|
if (*cp != '=')
|
|
|
|
{
|
|
|
|
sprintf(errorMessage,
|
|
|
|
"ERROR: PQconnectdb() - Missing '=' after '%s' in conninfo\n",
|
|
|
|
pname);
|
|
|
|
free(buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*cp++ = '\0';
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* Skip blanks after the '=' */
|
|
|
|
while (*cp)
|
|
|
|
{
|
|
|
|
if (!isspace(*cp))
|
|
|
|
break;
|
|
|
|
cp++;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
pval = cp;
|
|
|
|
|
|
|
|
if (*cp != '\'')
|
|
|
|
{
|
|
|
|
cp2 = pval;
|
|
|
|
while (*cp)
|
|
|
|
{
|
|
|
|
if (isspace(*cp))
|
|
|
|
{
|
|
|
|
*cp++ = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*cp == '\\')
|
|
|
|
{
|
|
|
|
cp++;
|
|
|
|
if (*cp != '\0')
|
|
|
|
*cp2++ = *cp++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*cp2++ = *cp++;
|
|
|
|
}
|
|
|
|
*cp2 = '\0';
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
cp2 = pval;
|
|
|
|
cp++;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (*cp == '\0')
|
|
|
|
{
|
|
|
|
sprintf(errorMessage,
|
|
|
|
"ERROR: PQconnectdb() - unterminated quoted string in conninfo\n");
|
|
|
|
free(buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (*cp == '\\')
|
|
|
|
{
|
|
|
|
cp++;
|
|
|
|
if (*cp != '\0')
|
|
|
|
*cp2++ = *cp++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*cp == '\'')
|
|
|
|
{
|
|
|
|
*cp2 = '\0';
|
|
|
|
cp++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*cp2++ = *cp++;
|
|
|
|
}
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* Now we have the name and the value. Search
|
|
|
|
* for the param record.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
for (option = PQconninfoOptions; option->keyword != NULL; option++)
|
|
|
|
{
|
|
|
|
if (!strcmp(option->keyword, pname))
|
|
|
|
break;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
if (option->keyword == NULL)
|
|
|
|
{
|
|
|
|
sprintf(errorMessage,
|
|
|
|
"ERROR: PQconnectdb() - unknown option '%s'\n",
|
|
|
|
pname);
|
|
|
|
free(buf);
|
|
|
|
return -1;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------
|
|
|
|
* Store the value
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
option->val = strdup(pval);
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
free(buf);
|
1996-11-09 11:39:54 +01:00
|
|
|
|
|
|
|
/* ----------
|
1997-09-07 07:04:48 +02:00
|
|
|
* Get the fallback resources for parameters not specified
|
|
|
|
* in the conninfo string.
|
1996-11-09 11:39:54 +01:00
|
|
|
* ----------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
for (option = PQconninfoOptions; option->keyword != NULL; option++)
|
|
|
|
{
|
|
|
|
if (option->val != NULL)
|
|
|
|
continue; /* Value was in conninfo */
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* Try to get the environment variable fallback
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
if (option->environ != NULL)
|
|
|
|
{
|
|
|
|
if ((tmp = getenv(option->environ)) != NULL)
|
|
|
|
{
|
|
|
|
option->val = strdup(tmp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------
|
|
|
|
* No environment variable specified or this one isn't set -
|
|
|
|
* try compiled in
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
if (option->compiled != NULL)
|
|
|
|
{
|
|
|
|
option->val = strdup(option->compiled);
|
|
|
|
continue;
|
|
|
|
}
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------
|
|
|
|
* Special handling for user
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
if (!strcmp(option->keyword, "user"))
|
|
|
|
{
|
|
|
|
tmp = fe_getauthname(errortmp);
|
|
|
|
if (tmp)
|
|
|
|
option->val = strdup(tmp);
|
|
|
|
}
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------
|
|
|
|
* Special handling for dbname
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
if (!strcmp(option->keyword, "dbname"))
|
|
|
|
{
|
|
|
|
tmp = conninfo_getval("user");
|
|
|
|
if (tmp)
|
|
|
|
option->val = strdup(tmp);
|
|
|
|
}
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return 0;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static char *
|
1996-11-09 11:39:54 +01:00
|
|
|
conninfo_getval(char *keyword)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
PQconninfoOption *option;
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
for (option = PQconninfoOptions; option->keyword != NULL; option++)
|
|
|
|
{
|
|
|
|
if (!strcmp(option->keyword, keyword))
|
|
|
|
return option->val;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return NULL;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
conninfo_free()
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
PQconninfoOption *option;
|
1996-11-09 11:39:54 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
for (option = PQconninfoOptions; option->keyword != NULL; option++)
|
|
|
|
{
|
|
|
|
if (option->val != NULL)
|
|
|
|
{
|
|
|
|
free(option->val);
|
|
|
|
option->val = NULL;
|
|
|
|
}
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* =========== accessor functions for PGconn ========= */
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
1997-09-08 23:56:23 +02:00
|
|
|
PQdb(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "PQdb() -- pointer to PGconn is null\n");
|
|
|
|
return (char *) NULL;
|
|
|
|
}
|
|
|
|
return conn->dbName;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
1997-09-08 23:56:23 +02:00
|
|
|
PQuser(PGconn *conn)
|
1996-11-09 11:39:54 +01:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "PQuser() -- pointer to PGconn is null\n");
|
|
|
|
return (char *) NULL;
|
|
|
|
}
|
|
|
|
return conn->pguser;
|
1996-11-09 11:39:54 +01:00
|
|
|
}
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
1997-09-08 23:56:23 +02:00
|
|
|
PQhost(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "PQhost() -- pointer to PGconn is null\n");
|
|
|
|
return (char *) NULL;
|
|
|
|
}
|
1996-07-12 06:53:59 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return conn->pghost;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
1997-09-08 23:56:23 +02:00
|
|
|
PQoptions(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "PQoptions() -- pointer to PGconn is null\n");
|
|
|
|
return (char *) NULL;
|
|
|
|
}
|
|
|
|
return conn->pgoptions;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
1997-09-08 23:56:23 +02:00
|
|
|
PQtty(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "PQtty() -- pointer to PGconn is null\n");
|
|
|
|
return (char *) NULL;
|
|
|
|
}
|
|
|
|
return conn->pgtty;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
1997-09-08 23:56:23 +02:00
|
|
|
PQport(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "PQport() -- pointer to PGconn is null\n");
|
|
|
|
return (char *) NULL;
|
|
|
|
}
|
|
|
|
return conn->pgport;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ConnStatusType
|
1997-09-08 23:56:23 +02:00
|
|
|
PQstatus(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "PQstatus() -- pointer to PGconn is null\n");
|
|
|
|
return CONNECTION_BAD;
|
|
|
|
}
|
|
|
|
return conn->status;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
1997-09-08 23:56:23 +02:00
|
|
|
PQerrorMessage(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "PQerrorMessage() -- pointer to PGconn is null\n");
|
|
|
|
return (char *) NULL;
|
|
|
|
}
|
|
|
|
return conn->errorMessage;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-05-07 01:51:16 +02:00
|
|
|
int
|
|
|
|
PQsocket(PGconn *conn)
|
|
|
|
{
|
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "PQsocket() -- pointer to PGconn is null\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return conn->sock;
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
PQtrace(PGconn *conn, FILE *debug_port)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (conn == NULL ||
|
|
|
|
conn->status == CONNECTION_BAD)
|
|
|
|
return;
|
|
|
|
PQuntrace(conn);
|
|
|
|
conn->Pfdebug = debug_port;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
void
|
1997-09-08 23:56:23 +02:00
|
|
|
PQuntrace(PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-05-07 01:51:16 +02:00
|
|
|
/* note: better allow untrace even when connection bad */
|
|
|
|
if (conn == NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
return;
|
|
|
|
if (conn->Pfdebug)
|
|
|
|
{
|
|
|
|
fflush(conn->Pfdebug);
|
|
|
|
conn->Pfdebug = NULL;
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|