mirror of
https://github.com/postgres/postgres.git
synced 2025-08-09 17:03:00 +03:00
This patch (against the current CVS sources) adds to libpq the functions
PQconnectStart PQconnectPoll PQresetStart PQresetPoll PQsetenvStart PQsetenvPoll PQsetenvAbort and brings into the published interface PQsetenv. The first four are asynchronous analogues of PQconnectdb and PQreset - they allow an application to connect to the DB without blocking on remote I/O. The PQsetenv functions perform an environment negotiation with the server. Internal to libpq, pqReadReady and pqWriteReady have been made available across the library (they were previously static functions inside fe-misc.c). A lot of internal rearrangement has been necessary to support these changes. The API documentation has been updated also. Caveats: o The Windows code does not default to using non-blocking sockets, since I have no documentation: Define WIN32_NON_BLOCKING_CONNECTIONS to do that. o The SSL code still blocks. Ewan Mellor.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.32 1999/11/11 00:10:14 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.33 1999/11/30 03:08:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -269,29 +269,69 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* pqReadReady: is select() saying the file is ready to read?
|
||||
* Returns -1 on failure, 0 if not ready, 1 if ready.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
pqReadReady(PGconn *conn)
|
||||
{
|
||||
fd_set input_mask;
|
||||
struct timeval timeout;
|
||||
|
||||
if (conn->sock < 0)
|
||||
return 0;
|
||||
if (!conn || conn->sock < 0)
|
||||
return -1;
|
||||
|
||||
FD_ZERO(&input_mask);
|
||||
FD_SET(conn->sock, &input_mask);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
retry:
|
||||
if (select(conn->sock + 1, &input_mask, (fd_set *) NULL, (fd_set *) NULL,
|
||||
&timeout) < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
/* Interrupted system call - we'll just try again */
|
||||
goto retry;
|
||||
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
"pqReadReady() -- select() failed: errno=%d\n%s\n",
|
||||
errno, strerror(errno));
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
return FD_ISSET(conn->sock, &input_mask);
|
||||
|
||||
return FD_ISSET(conn->sock, &input_mask) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* pqWriteReady: is select() saying the file is ready to write?
|
||||
* Returns -1 on failure, 0 if not ready, 1 if ready.
|
||||
*/
|
||||
int
|
||||
pqWriteReady(PGconn *conn)
|
||||
{
|
||||
fd_set input_mask;
|
||||
struct timeval timeout;
|
||||
|
||||
if (!conn || conn->sock < 0)
|
||||
return -1;
|
||||
|
||||
FD_ZERO(&input_mask);
|
||||
FD_SET(conn->sock, &input_mask);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
retry:
|
||||
if (select(conn->sock + 1, (fd_set *) NULL, &input_mask, (fd_set *) NULL,
|
||||
&timeout) < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
/* Interrupted system call - we'll just try again */
|
||||
goto retry;
|
||||
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
"pqWriteReady() -- select() failed: errno=%d\n%s\n",
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return FD_ISSET(conn->sock, &input_mask) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
@@ -418,8 +458,17 @@ tryAgain:
|
||||
* be taken much, since in normal practice we should not be trying to
|
||||
* read data unless the file selected for reading already.
|
||||
*/
|
||||
if (!pqReadReady(conn))
|
||||
return 0; /* definitely no data available */
|
||||
switch (pqReadReady(conn))
|
||||
{
|
||||
case 0:
|
||||
/* definitely no data available */
|
||||
return 0;
|
||||
case 1:
|
||||
/* ready for read */
|
||||
break;
|
||||
default:
|
||||
goto definitelyFailed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Still not sure that it's EOF, because some data could have just
|
||||
@@ -570,6 +619,10 @@ pqFlush(PGconn *conn)
|
||||
if (len > 0)
|
||||
{
|
||||
/* We didn't send it all, wait till we can send more */
|
||||
|
||||
/* At first glance this looks as though it should block. I think
|
||||
* that it will be OK though, as long as the socket is
|
||||
* non-blocking. */
|
||||
if (pqWait(FALSE, TRUE, conn))
|
||||
return EOF;
|
||||
}
|
||||
@@ -599,9 +652,9 @@ pqWait(int forRead, int forWrite, PGconn *conn)
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* loop in case select returns EINTR */
|
||||
for (;;)
|
||||
if (forRead || forWrite)
|
||||
{
|
||||
retry:
|
||||
FD_ZERO(&input_mask);
|
||||
FD_ZERO(&output_mask);
|
||||
if (forRead)
|
||||
@@ -612,14 +665,12 @@ pqWait(int forRead, int forWrite, PGconn *conn)
|
||||
(struct timeval *) NULL) < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
goto retry;
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
"pqWait() -- select() failed: errno=%d\n%s\n",
|
||||
errno, strerror(errno));
|
||||
return EOF;
|
||||
}
|
||||
/* On nonerror return, assume we're done */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -6,7 +6,7 @@
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq-fe.h,v 1.52 1999/11/11 00:10:14 momjian Exp $
|
||||
* $Id: libpq-fe.h,v 1.53 1999/11/30 03:08:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -29,10 +29,40 @@ extern "C"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* Although you may decide to change this list in some way,
|
||||
values which become unused should never be removed, nor
|
||||
should constants be redefined - that would break
|
||||
compatibility with existing code. */
|
||||
CONNECTION_OK,
|
||||
CONNECTION_BAD
|
||||
CONNECTION_BAD,
|
||||
/* Non-blocking mode only below here */
|
||||
/* The existence of these should never be relied upon - they
|
||||
should only be used for user feedback or similar purposes. */
|
||||
CONNECTION_STARTED, /* Waiting for connection to be made. */
|
||||
CONNECTION_MADE, /* Connection OK; waiting to send. */
|
||||
CONNECTION_AWAITING_RESPONSE, /* Waiting for a response
|
||||
from the backend. */
|
||||
CONNECTION_AUTH_RESPONSE, /* Got an authentication
|
||||
response; about to deal
|
||||
with it. */
|
||||
CONNECTION_ERROR_RESPONSE, /* Got an error
|
||||
response; about to deal
|
||||
with it. */
|
||||
CONNECTION_AUTH_OK, /* Received authentication;
|
||||
waiting for ReadyForQuery
|
||||
etc. */
|
||||
CONNECTION_SETENV /* Negotiating environment. */
|
||||
} ConnStatusType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PGRES_POLLING_FAILED = 0,
|
||||
PGRES_POLLING_READING, /* These two indicate that one may */
|
||||
PGRES_POLLING_WRITING, /* use select before polling again. */
|
||||
PGRES_POLLING_OK,
|
||||
PGRES_POLLING_ACTIVE /* Can call poll function immediately.*/
|
||||
} PostgresPollingStatusType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PGRES_EMPTY_QUERY = 0,
|
||||
@@ -67,6 +97,12 @@ extern "C"
|
||||
*/
|
||||
typedef struct pg_result PGresult;
|
||||
|
||||
/* PGsetenvHandle is an opaque handle which is returned by PQsetenvStart and
|
||||
* which should be passed to PQsetenvPoll or PQsetenvAbort in order to refer
|
||||
* to the particular process being performed.
|
||||
*/
|
||||
typedef struct pg_setenv_state *PGsetenvHandle;
|
||||
|
||||
/* PGnotify represents the occurrence of a NOTIFY message.
|
||||
* Ideally this would be an opaque typedef, but it's so simple that it's
|
||||
* unlikely to change.
|
||||
@@ -152,11 +188,15 @@ extern "C"
|
||||
/* === in fe-connect.c === */
|
||||
|
||||
/* make a new client connection to the backend */
|
||||
/* Asynchronous (non-blocking) */
|
||||
extern PGconn *PQconnectStart(const char *conninfo);
|
||||
extern PostgresPollingStatusType PQconnectPoll(PGconn *conn);
|
||||
/* Synchronous (blocking) */
|
||||
extern PGconn *PQconnectdb(const char *conninfo);
|
||||
extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport,
|
||||
const char *pgoptions, const char *pgtty,
|
||||
const char *dbName,
|
||||
const char *login, const char *pwd);
|
||||
const char *dbName,
|
||||
const char *login, const char *pwd);
|
||||
#define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME) \
|
||||
PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL)
|
||||
|
||||
@@ -170,6 +210,10 @@ extern "C"
|
||||
* close the current connection and restablish a new one with the same
|
||||
* parameters
|
||||
*/
|
||||
/* Asynchronous (non-blocking) */
|
||||
extern int PQresetStart(PGconn *conn);
|
||||
extern PostgresPollingStatusType PQresetPoll(PGconn *conn);
|
||||
/* Synchronous (blocking) */
|
||||
extern void PQreset(PGconn *conn);
|
||||
|
||||
/* issue a cancel request */
|
||||
@@ -195,6 +239,15 @@ extern "C"
|
||||
/* Override default notice processor */
|
||||
extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg);
|
||||
|
||||
/* Passing of environment variables */
|
||||
/* Asynchronous (non-blocking) */
|
||||
extern PGsetenvHandle PQsetenvStart(PGconn *conn);
|
||||
extern PostgresPollingStatusType PQsetenvPoll(PGsetenvHandle handle);
|
||||
extern void PQsetenvAbort(PGsetenvHandle handle);
|
||||
|
||||
/* Synchronous (blocking) */
|
||||
extern int PQsetenv(PGconn *conn);
|
||||
|
||||
/* === in fe-exec.c === */
|
||||
|
||||
/* Simple synchronous query */
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq-int.h,v 1.13 1999/11/11 00:10:14 momjian Exp $
|
||||
* $Id: libpq-int.h,v 1.14 1999/11/30 03:08:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -168,6 +168,10 @@ struct pg_conn
|
||||
/* Saved values of connection options */
|
||||
char *pghost; /* the machine on which the server is
|
||||
* running */
|
||||
char *pghostaddr; /* the IPv4 address of the machine on
|
||||
* which the server is running, in
|
||||
* IPv4 numbers-and-dots notation. Takes
|
||||
* precedence over above. */
|
||||
char *pgport; /* the server's communication port */
|
||||
char *pgtty; /* tty on which the backend messages is
|
||||
* displayed (NOT ACTUALLY USED???) */
|
||||
@@ -220,6 +224,9 @@ struct pg_conn
|
||||
PGresult *result; /* result being constructed */
|
||||
PGresAttValue *curTuple; /* tuple currently being read */
|
||||
|
||||
/* Handle for setenv request. Used during connection only. */
|
||||
PGsetenvHandle setenv_handle;
|
||||
|
||||
#ifdef USE_SSL
|
||||
SSL *ssl;
|
||||
#endif
|
||||
@@ -268,6 +275,8 @@ extern int pqPutInt(int value, size_t bytes, PGconn *conn);
|
||||
extern int pqReadData(PGconn *conn);
|
||||
extern int pqFlush(PGconn *conn);
|
||||
extern int pqWait(int forRead, int forWrite, PGconn *conn);
|
||||
extern int pqReadReady(PGconn *conn);
|
||||
extern int pqWriteReady(PGconn *conn);
|
||||
|
||||
/* bits in a byte */
|
||||
#define BYTELEN 8
|
||||
|
Reference in New Issue
Block a user