1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-27 07:42:10 +03:00

Second round of FE/BE protocol changes. Frontend->backend messages now

have length counts, and COPY IN data is packetized into messages.
This commit is contained in:
Tom Lane
2003-04-19 00:02:30 +00:00
parent 54b38d293e
commit bd8d441775
24 changed files with 1337 additions and 982 deletions

View File

@@ -10,7 +10,7 @@
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.75 2003/04/17 22:26:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.76 2003/04/19 00:02:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -559,7 +559,7 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
default:
return STATUS_ERROR;
}
ret = pqPacketSend(conn, 0, crypt_pwd, strlen(crypt_pwd) + 1);
ret = pqPacketSend(conn, 'p', crypt_pwd, strlen(crypt_pwd) + 1);
if (areq == AUTH_REQ_MD5)
free(crypt_pwd);
return ret;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.232 2003/04/17 22:26:02 tgl Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.233 2003/04/19 00:02:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1820,11 +1820,11 @@ makeEmptyPGconn(void)
#endif
/*
* The output buffer size is set to 8K, which is the usual size of
* pipe buffers on Unix systems. That way, when we are sending a
* We try to send at least 8K at a time, which is the usual size
* of pipe buffers on Unix systems. That way, when we are sending a
* large amount of data, we avoid incurring extra kernel context swaps
* for partial bufferloads. Note that we currently don't ever enlarge
* the output buffer.
* for partial bufferloads. The output buffer is initially made 16K
* in size, and we try to dump it after accumulating 8K.
*
* With the same goal of minimizing context swaps, the input buffer will
* be enlarged anytime it has less than 8K free, so we initially
@@ -1832,7 +1832,7 @@ makeEmptyPGconn(void)
*/
conn->inBufSize = 16 * 1024;
conn->inBuffer = (char *) malloc(conn->inBufSize);
conn->outBufSize = 8 * 1024;
conn->outBufSize = 16 * 1024;
conn->outBuffer = (char *) malloc(conn->outBufSize);
conn->nonblocking = FALSE;
initPQExpBuffer(&conn->errorMessage);
@@ -1918,11 +1918,10 @@ closePGconn(PGconn *conn)
{
/*
* Try to send "close connection" message to backend. Ignore any
* error. Note: this routine used to go to substantial lengths to
* avoid getting SIGPIPE'd if the connection were already closed.
* Now we rely on pqFlush to avoid the signal.
* error.
*/
pqPutc('X', conn);
pqPutMsgStart('X', conn);
pqPutMsgEnd(conn);
pqFlush(conn);
}
@@ -2152,7 +2151,7 @@ cancel_errReturn:
/*
* pqPacketSend() -- send a single-packet message.
* pqPacketSend() -- convenience routine to send a message to server.
*
* pack_type: the single-byte message type code. (Pass zero for startup
* packets, which have no message type code.)
@@ -2167,19 +2166,18 @@ int
pqPacketSend(PGconn *conn, char pack_type,
const void *buf, size_t buf_len)
{
/* Send the message type. */
if (pack_type != 0)
if (pqPutc(pack_type, conn))
return STATUS_ERROR;
/* Send the (self-inclusive) message length word. */
if (pqPutInt(buf_len + 4, 4, conn))
/* Start the message. */
if (pqPutMsgStart(pack_type, conn))
return STATUS_ERROR;
/* Send the message body. */
if (pqPutnchar(buf, buf_len, conn))
return STATUS_ERROR;
/* Finish the message. */
if (pqPutMsgEnd(conn))
return STATUS_ERROR;
/* Flush to ensure backend gets it. */
if (pqFlush(conn))
return STATUS_ERROR;
@@ -2624,7 +2622,7 @@ build_startup_packet(const PGconn *conn, char *packet)
packet_len += sizeof(ProtocolVersion);
/* Add user name, database name, options */
if (conn->pguser)
if (conn->pguser && conn->pguser[0])
{
if (packet)
strcpy(packet + packet_len, "user");
@@ -2633,7 +2631,7 @@ build_startup_packet(const PGconn *conn, char *packet)
strcpy(packet + packet_len, conn->pguser);
packet_len += strlen(conn->pguser) + 1;
}
if (conn->dbName)
if (conn->dbName && conn->dbName[0])
{
if (packet)
strcpy(packet + packet_len, "database");
@@ -2642,7 +2640,7 @@ build_startup_packet(const PGconn *conn, char *packet)
strcpy(packet + packet_len, conn->dbName);
packet_len += strlen(conn->dbName) + 1;
}
if (conn->pgoptions)
if (conn->pgoptions && conn->pgoptions[0])
{
if (packet)
strcpy(packet + packet_len, "options");

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.128 2003/03/25 02:44:36 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.129 2003/04/19 00:02:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -734,7 +734,6 @@ addTuple(PGresult *res, PGresAttValue * tup)
* Returns: 1 if successfully submitted
* 0 if error (conn->errorMessage is set)
*/
int
PQsendQuery(PGconn *conn, const char *query)
{
@@ -770,51 +769,24 @@ PQsendQuery(PGconn *conn, const char *query)
conn->result = NULL;
conn->curTuple = NULL;
/* send the query to the backend; */
/* construct the outgoing Query message */
if (pqPutMsgStart('Q', conn) < 0 ||
pqPuts(query, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
{
handleSendFailure(conn);
return 0;
}
/*
* in order to guarantee that we don't send a partial query where we
* would become out of sync with the backend and/or block during a
* non-blocking connection we must first flush the send buffer before
* sending more data
*
* an alternative is to implement 'queue reservations' where we are able
* to roll up a transaction (the 'Q' along with our query) and make
* sure we have enough space for it all in the send buffer.
* Give the data a push. In nonblock mode, don't complain if we're
* unable to send it all; PQconsumeInput() will do any additional flushing
* needed.
*/
if (pqIsnonblocking(conn))
if (pqFlush(conn) < 0)
{
/*
* the buffer must have emptied completely before we allow a new
* query to be buffered
*/
if (pqFlush(conn))
return 0;
/* 'Q' == queries */
/* XXX: if we fail here we really ought to not block */
if (pqPutc('Q', conn) != 0 || pqPuts(query, conn) != 0)
{
handleSendFailure(conn);
return 0;
}
/*
* give the data a push, ignore the return value as ConsumeInput()
* will do any additional flushing if needed
*/
pqFlush(conn);
}
else
{
/*
* the frontend-backend protocol uses 'Q' to designate queries
*/
if (pqPutc('Q', conn) != 0 || pqPuts(query, conn) != 0 ||
pqFlush(conn) != 0)
{
handleSendFailure(conn);
return 0;
}
handleSendFailure(conn);
return 0;
}
/* OK, it's launched! */
@@ -830,7 +802,6 @@ PQsendQuery(PGconn *conn, const char *query)
*
* NOTE: this routine should only be called in PGASYNC_IDLE state.
*/
static void
handleSendFailure(PGconn *conn)
{
@@ -854,13 +825,23 @@ handleSendFailure(PGconn *conn)
* 0 return: some kind of trouble
* 1 return: no problem
*/
int
PQconsumeInput(PGconn *conn)
{
if (!conn)
return 0;
/*
* for non-blocking connections try to flush the send-queue,
* otherwise we may never get a response for something that may
* not have already been sent because it's in our write buffer!
*/
if (pqIsnonblocking(conn))
{
if (pqFlush(conn) < 0)
return 0;
}
/*
* Load more data, if available. We do this no matter what state we
* are in, since we are probably getting called because the
@@ -868,16 +849,8 @@ PQconsumeInput(PGconn *conn)
* we will NOT block waiting for more input.
*/
if (pqReadData(conn) < 0)
{
/*
* for non-blocking connections try to flush the send-queue
* otherwise we may never get a responce for something that may
* not have already been sent because it's in our write buffer!
*/
if (pqIsnonblocking(conn))
(void) pqFlush(conn);
return 0;
}
/* Parsing of the data waits till later. */
return 1;
}
@@ -1733,14 +1706,13 @@ PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)
* PQputline -- sends a string to the backend.
* Returns 0 if OK, EOF if not.
*
* Chiefly here so that applications can use "COPY <rel> from stdin".
* This exists to support "COPY <rel> from stdin". The backend will ignore
* the string if not doing COPY.
*/
int
PQputline(PGconn *conn, const char *s)
{
if (!conn || conn->sock < 0)
return EOF;
return pqPutnchar(s, strlen(s), conn);
return PQputnbytes(conn, s, strlen(s));
}
/*
@@ -1752,7 +1724,14 @@ PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
{
if (!conn || conn->sock < 0)
return EOF;
return pqPutnchar(buffer, nbytes, conn);
if (nbytes > 0)
{
if (pqPutMsgStart('d', conn) < 0 ||
pqPutnchar(buffer, nbytes, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return EOF;
}
return 0;
}
/*
@@ -1780,6 +1759,14 @@ PQendcopy(PGconn *conn)
return 1;
}
/* Send the CopyDone message if needed */
if (conn->asyncStatus == PGASYNC_COPY_IN)
{
if (pqPutMsgStart('c', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return 1;
}
/*
* make sure no data is waiting to be sent, abort if we are
* non-blocking and the flush fails
@@ -1884,9 +1871,10 @@ PQfn(PGconn *conn,
return NULL;
}
if (pqPuts("F ", conn) != 0 || /* function */
pqPutInt(fnid, 4, conn) != 0 || /* function id */
pqPutInt(nargs, 4, conn) != 0) /* # of args */
if (pqPutMsgStart('F', conn) < 0 || /* function call msg */
pqPuts("", conn) < 0 || /* useless string */
pqPutInt(fnid, 4, conn) < 0 || /* function id */
pqPutInt(nargs, 4, conn) < 0) /* # of args */
{
handleSendFailure(conn);
return NULL;
@@ -1917,7 +1905,9 @@ PQfn(PGconn *conn,
}
}
}
if (pqFlush(conn))
if (pqPutMsgEnd(conn) < 0 ||
pqFlush(conn))
{
handleSendFailure(conn);
return NULL;
@@ -2409,7 +2399,6 @@ PQgetisnull(const PGresult *res, int tup_num, int field_num)
int
PQsetnonblocking(PGconn *conn, int arg)
{
arg = (arg == TRUE) ? 1 : 0;
/* early out if the socket is already in the state requested */
if (arg == conn->nonblocking)
@@ -2437,7 +2426,6 @@ PQsetnonblocking(PGconn *conn, int arg)
int
PQisnonblocking(const PGconn *conn)
{
return (pqIsnonblocking(conn));
}
@@ -2445,18 +2433,9 @@ PQisnonblocking(const PGconn *conn)
int
PQflush(PGconn *conn)
{
return (pqFlush(conn));
}
/* try to force data out, really only useful for non-blocking users.
* This implementation actually works for non-blocking connections */
int
PQsendSome(PGconn *conn)
{
return pqSendSome(conn);
}
/*
* PQfreeNotify - free's the memory associated with a PGnotify
*
@@ -2473,5 +2452,3 @@ PQfreeNotify(PGnotify *notify)
{
PQfreemem(notify);
}

View File

@@ -16,16 +16,14 @@
* will cause repeat printouts.
*
* We must speak the same transmitted data representations as the backend
* routines. Note that this module supports *only* network byte order
* for transmitted ints, whereas the backend modules (as of this writing)
* still handle either network or little-endian byte order.
* routines.
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.88 2003/04/02 00:49:28 tgl Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.89 2003/04/19 00:02:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -63,15 +61,15 @@
#define DONOTICE(conn,message) \
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
static int pqPutMsgBytes(const void *buf, size_t len, PGconn *conn);
static int pqSendSome(PGconn *conn, int len);
static int pqSocketCheck(PGconn *conn, int forRead, int forWrite,
time_t end_time);
static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time);
static int pqPutBytes(const char *s, size_t nbytes, PGconn *conn);
/*
* pqGetc:
* get a character from the connection
* pqGetc: get 1 character from the connection
*
* All these routines return 0 on success, EOF on error.
* Note that for the Get routines, EOF only means there is not enough
@@ -93,12 +91,12 @@ pqGetc(char *result, PGconn *conn)
/*
* write 1 char to the connection
* pqPutc: write 1 char to the current message
*/
int
pqPutc(char c, PGconn *conn)
{
if (pqPutBytes(&c, 1, conn) == EOF)
if (pqPutMsgBytes(&c, 1, conn))
return EOF;
if (conn->Pfdebug)
@@ -108,93 +106,6 @@ pqPutc(char c, PGconn *conn)
}
/*
* pqPutBytes: local routine to write N bytes to the connection,
* with buffering
*/
static int
pqPutBytes(const char *s, size_t nbytes, PGconn *conn)
{
/*
* Strategy to handle blocking and non-blocking connections: Fill the
* output buffer and flush it repeatedly until either all data has
* been sent or is at least queued in the buffer.
*
* For non-blocking connections, grow the buffer if not all data fits
* into it and the buffer can't be sent because the socket would
* block.
*/
while (nbytes)
{
size_t avail,
remaining;
/* fill the output buffer */
avail = Max(conn->outBufSize - conn->outCount, 0);
remaining = Min(avail, nbytes);
memcpy(conn->outBuffer + conn->outCount, s, remaining);
conn->outCount += remaining;
s += remaining;
nbytes -= remaining;
/*
* if the data didn't fit completely into the buffer, try to flush
* the buffer
*/
if (nbytes)
{
int send_result = pqSendSome(conn);
/* if there were errors, report them */
if (send_result < 0)
return EOF;
/*
* if not all data could be sent, increase the output buffer,
* put the rest of s into it and return successfully. This
* case will only happen in a non-blocking connection
*/
if (send_result > 0)
{
/*
* try to grow the buffer. FIXME: The new size could be
* chosen more intelligently.
*/
size_t buflen = (size_t) conn->outCount + nbytes;
if (buflen > (size_t) conn->outBufSize)
{
char *newbuf = realloc(conn->outBuffer, buflen);
if (!newbuf)
{
/* realloc failed. Probably out of memory */
printfPQExpBuffer(&conn->errorMessage,
"cannot allocate memory for output buffer\n");
return EOF;
}
conn->outBuffer = newbuf;
conn->outBufSize = buflen;
}
/* put the data into it */
memcpy(conn->outBuffer + conn->outCount, s, nbytes);
conn->outCount += nbytes;
/* report success. */
return 0;
}
}
/*
* pqSendSome was able to send all data. Continue with the next
* chunk of s.
*/
} /* while */
return 0;
}
/*
* pqGets:
* get a null-terminated string from the connection,
@@ -232,14 +143,17 @@ pqGets(PQExpBuffer buf, PGconn *conn)
}
/*
* pqPuts: write a null-terminated string to the current message
*/
int
pqPuts(const char *s, PGconn *conn)
{
if (pqPutBytes(s, strlen(s) + 1, conn))
if (pqPutMsgBytes(s, strlen(s) + 1, conn))
return EOF;
if (conn->Pfdebug)
fprintf(conn->Pfdebug, "To backend> %s\n", s);
fprintf(conn->Pfdebug, "To backend> '%s'\n", s);
return 0;
}
@@ -267,12 +181,12 @@ pqGetnchar(char *s, size_t len, PGconn *conn)
/*
* pqPutnchar:
* send a string of exactly len bytes, no null termination needed
* write exactly len bytes to the current message
*/
int
pqPutnchar(const char *s, size_t len, PGconn *conn)
{
if (pqPutBytes(s, len, conn))
if (pqPutMsgBytes(s, len, conn))
return EOF;
if (conn->Pfdebug)
@@ -325,7 +239,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
/*
* pgPutInt
* send an integer of 2 or 4 bytes, converting from host byte order
* write an integer of 2 or 4 bytes, converting from host byte order
* to network byte order.
*/
int
@@ -339,12 +253,12 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
{
case 2:
tmp2 = htons((uint16) value);
if (pqPutBytes((const char *) &tmp2, 2, conn))
if (pqPutMsgBytes((const char *) &tmp2, 2, conn))
return EOF;
break;
case 4:
tmp4 = htonl((uint32) value);
if (pqPutBytes((const char *) &tmp4, 4, conn))
if (pqPutMsgBytes((const char *) &tmp4, 4, conn))
return EOF;
break;
default:
@@ -362,24 +276,162 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
}
/*
* pqReadReady: is select() saying the file is ready to read?
* JAB: -or- if SSL is enabled and used, is it buffering bytes?
* Returns -1 on failure, 0 if not ready, 1 if ready.
* Make sure conn's output buffer can hold bytes_needed bytes (caller must
* include existing outCount into the value!)
*
* Returns 0 on success, EOF on error
*/
int
pqReadReady(PGconn *conn)
static int
checkOutBufferSpace(int bytes_needed, PGconn *conn)
{
return pqSocketCheck(conn, 1, 0, (time_t) 0);
int newsize = conn->outBufSize;
char *newbuf;
if (bytes_needed <= newsize)
return 0;
/*
* If we need to enlarge the buffer, we first try to double it in size;
* if that doesn't work, enlarge in multiples of 8K. This avoids
* thrashing the malloc pool by repeated small enlargements.
*
* Note: tests for newsize > 0 are to catch integer overflow.
*/
do {
newsize *= 2;
} while (bytes_needed > newsize && newsize > 0);
if (bytes_needed <= newsize)
{
newbuf = realloc(conn->outBuffer, newsize);
if (newbuf)
{
/* realloc succeeded */
conn->outBuffer = newbuf;
conn->outBufSize = newsize;
return 0;
}
}
newsize = conn->outBufSize;
do {
newsize += 8192;
} while (bytes_needed > newsize && newsize > 0);
if (bytes_needed <= newsize)
{
newbuf = realloc(conn->outBuffer, newsize);
if (newbuf)
{
/* realloc succeeded */
conn->outBuffer = newbuf;
conn->outBufSize = newsize;
return 0;
}
}
/* realloc failed. Probably out of memory */
printfPQExpBuffer(&conn->errorMessage,
"cannot allocate memory for output buffer\n");
return EOF;
}
/*
* pqWriteReady: is select() saying the file is ready to write?
* Returns -1 on failure, 0 if not ready, 1 if ready.
* pqPutMsgStart: begin construction of a message to the server
*
* msg_type is the message type byte, or 0 for a message without type byte
* (only startup messages have no type byte)
*
* Returns 0 on success, EOF on error
*
* The idea here is that we construct the message in conn->outBuffer,
* beginning just past any data already in outBuffer (ie, at
* outBuffer+outCount). We enlarge the buffer as needed to hold the message.
* When the message is complete, we fill in the length word and then advance
* outCount past the message, making it eligible to send. The state
* variable conn->outMsgStart points to the incomplete message's length word
* (it is either outCount or outCount+1 depending on whether there is a
* type byte). The state variable conn->outMsgEnd is the end of the data
* collected so far.
*/
int
pqWriteReady(PGconn *conn)
pqPutMsgStart(char msg_type, PGconn *conn)
{
return pqSocketCheck(conn, 0, 1, (time_t) 0);
int lenPos;
/* where the message length word will go */
if (msg_type)
lenPos = conn->outCount + 1;
else
lenPos = conn->outCount;
/* make sure there is room for it */
if (checkOutBufferSpace(lenPos + 4, conn))
return EOF;
/* okay, save the message type byte if any */
if (msg_type)
conn->outBuffer[conn->outCount] = msg_type;
/* set up the message pointers */
conn->outMsgStart = lenPos;
conn->outMsgEnd = lenPos + 4;
/* length word will be filled in by pqPutMsgEnd */
if (conn->Pfdebug)
fprintf(conn->Pfdebug, "To backend> Msg %c\n",
msg_type ? msg_type : ' ');
return 0;
}
/*
* pqPutMsgBytes: add bytes to a partially-constructed message
*
* Returns 0 on success, EOF on error
*/
static int
pqPutMsgBytes(const void *buf, size_t len, PGconn *conn)
{
/* make sure there is room for it */
if (checkOutBufferSpace(conn->outMsgEnd + len, conn))
return EOF;
/* okay, save the data */
memcpy(conn->outBuffer + conn->outMsgEnd, buf, len);
conn->outMsgEnd += len;
/* no Pfdebug call here, caller should do it */
return 0;
}
/*
* pqPutMsgEnd: finish constructing a message and possibly send it
*
* Returns 0 on success, EOF on error
*
* We don't actually send anything here unless we've accumulated at least
* 8K worth of data (the typical size of a pipe buffer on Unix systems).
* This avoids sending small partial packets. The caller must use pqFlush
* when it's important to flush all the data out to the server.
*/
int
pqPutMsgEnd(PGconn *conn)
{
uint32 msgLen = conn->outMsgEnd - conn->outMsgStart;
if (conn->Pfdebug)
fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n",
msgLen);
msgLen = htonl(msgLen);
memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4);
conn->outCount = conn->outMsgEnd;
if (conn->outCount >= 8192)
{
int toSend = conn->outCount - (conn->outCount % 8192);
if (pqSendSome(conn, toSend) < 0)
return EOF;
/* in nonblock mode, don't complain if unable to send it all */
}
return 0;
}
/* ----------
@@ -580,16 +632,20 @@ definitelyFailed:
}
/*
* pqSendSome: send any data waiting in the output buffer.
* pqSendSome: send data waiting in the output buffer.
*
* Return 0 on sucess, -1 on failure and 1 when data remains because the
* socket would block and the connection is non-blocking.
* len is how much to try to send (typically equal to outCount, but may
* be less).
*
* Return 0 on success, -1 on failure and 1 when not all data could be sent
* because the socket would block and the connection is non-blocking.
*/
int
pqSendSome(PGconn *conn)
static int
pqSendSome(PGconn *conn, int len)
{
char *ptr = conn->outBuffer;
int len = conn->outCount;
int remaining = conn->outCount;
int result = 0;
if (conn->sock < 0)
{
@@ -598,13 +654,6 @@ pqSendSome(PGconn *conn)
return -1;
}
/*
* don't try to send zero data, allows us to use this function without
* too much worry about overhead
*/
if (len == 0)
return (0);
/* while there's still data to send */
while (len > 0)
{
@@ -648,8 +697,9 @@ pqSendSome(PGconn *conn)
* (typically, a NOTICE message from the backend
* telling us it's committing hara-kiri...). Leave
* the socket open until pqReadData finds no more data
* can be read.
* can be read. But abandon attempt to send data.
*/
conn->outCount = 0;
return -1;
default:
@@ -657,6 +707,7 @@ pqSendSome(PGconn *conn)
libpq_gettext("could not send data to server: %s\n"),
SOCK_STRERROR(SOCK_ERRNO));
/* We don't assume it's a fatal error... */
conn->outCount = 0;
return -1;
}
}
@@ -664,6 +715,7 @@ pqSendSome(PGconn *conn)
{
ptr += sent;
len -= sent;
remaining -= sent;
}
if (len > 0)
@@ -681,46 +733,49 @@ pqSendSome(PGconn *conn)
#endif
if (pqIsnonblocking(conn))
{
/* shift the contents of the buffer */
memmove(conn->outBuffer, ptr, len);
conn->outCount = len;
return 1;
result = 1;
break;
}
#ifdef USE_SSL
}
#endif
if (pqWait(FALSE, TRUE, conn))
return -1;
{
result = -1;
break;
}
}
}
conn->outCount = 0;
/* shift the remaining contents of the buffer */
if (remaining > 0)
memmove(conn->outBuffer, ptr, remaining);
conn->outCount = remaining;
if (conn->Pfdebug)
fflush(conn->Pfdebug);
return 0;
return result;
}
/*
* pqFlush: send any data waiting in the output buffer
*
* Implemented in terms of pqSendSome to recreate the old behavior which
* returned 0 if all data was sent or EOF. EOF was sent regardless of
* whether an error occurred or not all data was sent on a non-blocking
* socket.
* Return 0 on success, -1 on failure and 1 when not all data could be sent
* because the socket would block and the connection is non-blocking.
*/
int
pqFlush(PGconn *conn)
{
if (pqSendSome(conn))
return EOF;
if (conn->Pfdebug)
fflush(conn->Pfdebug);
if (conn->outCount > 0)
return pqSendSome(conn, conn->outCount);
return 0;
}
/*
* pqWait: wait until we can read or write the connection socket
*
@@ -766,10 +821,31 @@ pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time)
return 0;
}
/*
* pqReadReady: is select() saying the file is ready to read?
* Returns -1 on failure, 0 if not ready, 1 if ready.
*/
int
pqReadReady(PGconn *conn)
{
return pqSocketCheck(conn, 1, 0, (time_t) 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)
{
return pqSocketCheck(conn, 0, 1, (time_t) 0);
}
/*
* Checks a socket, using poll or select, for data to be read, written,
* or both. Returns >0 if one or more conditions are met, 0 if it timed
* out, -1 if an error occurred.
*
* If SSL is in use, the SSL buffer is checked prior to checking the socket
* for read data directly.
*/
@@ -787,8 +863,8 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
return -1;
}
/* JAB: Check for SSL library buffering read bytes */
#ifdef USE_SSL
/* Check for SSL library buffering read bytes */
if (forRead && conn->ssl && SSL_pending(conn->ssl) > 0)
{
/* short-circuit the select */
@@ -819,6 +895,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
* If neither forRead nor forWrite are set, immediately return a timeout
* condition (without waiting). Return >0 if condition is met, 0
* if a timeout occurred, -1 if an error or interrupt occurred.
*
* Timeout is infinite if end_time is -1. Timeout is immediate (no blocking)
* if end_time is 0 (or indeed, any time before now).
*/
@@ -830,16 +907,17 @@ pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
struct pollfd input_fd;
int timeout_ms;
if (!forRead && !forWrite)
return 0;
input_fd.fd = sock;
input_fd.events = 0;
input_fd.events = POLLERR;
input_fd.revents = 0;
if (forRead)
input_fd.events |= POLLIN;
if (forWrite)
input_fd.events |= POLLOUT;
if (!input_fd.events)
return 0;
/* Compute appropriate timeout interval */
if (end_time == ((time_t) -1))

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq-fe.h,v 1.91 2003/03/25 02:44:36 momjian Exp $
* $Id: libpq-fe.h,v 1.92 2003/04/19 00:02:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -284,7 +284,6 @@ extern int PQisnonblocking(const PGconn *conn);
/* Force the write buffer to be written (or at least try) */
extern int PQflush(PGconn *conn);
extern int PQsendSome(PGconn *conn);
/*
* "Fast path" interface --- not really recommended for application

View File

@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq-int.h,v 1.61 2003/04/17 22:26:02 tgl Exp $
* $Id: libpq-int.h,v 1.62 2003/04/19 00:02:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
* pqcomm.h describe what the backend knows, not what libpq knows.
*/
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,100) /* XXX temporary value */
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,101) /* XXX temporary value */
/*
* POSTGRES backend dependent Constants.
@@ -266,6 +266,10 @@ struct pg_conn
int outBufSize; /* allocated size of buffer */
int outCount; /* number of chars waiting in buffer */
/* State for constructing messages in outBuffer */
int outMsgStart; /* offset to msg start (length word) */
int outMsgEnd; /* offset to msg end (so far) */
/* Status for asynchronous result construction */
PGresult *result; /* result being constructed */
PGresAttValue *curTuple; /* tuple currently being read */
@@ -334,9 +338,10 @@ extern int pqGetnchar(char *s, size_t len, PGconn *conn);
extern int pqPutnchar(const char *s, size_t len, PGconn *conn);
extern int pqGetInt(int *result, size_t bytes, PGconn *conn);
extern int pqPutInt(int value, size_t bytes, PGconn *conn);
extern int pqPutMsgStart(char msg_type, PGconn *conn);
extern int pqPutMsgEnd(PGconn *conn);
extern int pqReadData(PGconn *conn);
extern int pqFlush(PGconn *conn);
extern int pqSendSome(PGconn *conn);
extern int pqWait(int forRead, int forWrite, PGconn *conn);
extern int pqWaitTimed(int forRead, int forWrite, PGconn *conn,
time_t finish_time);