Commit 3ab5b1f1 authored by Bruce Momjian's avatar Bruce Momjian

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.
parent d264b53d
This diff is collapsed.
This diff is collapsed.
......@@ -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) ? 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);
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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment