When closure of the backend connection is detected during pqFlush,
do the right thing: look for a NOTICE message from the backend before we close our side of the socket. 6.4 libpq did not reliably print the backend's hara-kiri message, 'The Postmaster has informed me ...', because it only did the right thing if connection closure was detected during a read attempt instead of a write attempt.
This commit is contained in:
parent
615e77ede2
commit
f0ae1e8d10
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.80 1999/05/25 16:15:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.81 1999/05/28 01:54:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -47,6 +47,7 @@ const char *const pgresStatus[] = {
|
|||
|
||||
static int addTuple(PGresult *res, PGresAttValue *tup);
|
||||
static void parseInput(PGconn *conn);
|
||||
static void handleSendFailure(PGconn *conn);
|
||||
static int getRowDescriptions(PGconn *conn);
|
||||
static int getAnotherTuple(PGconn *conn, int binary);
|
||||
static int getNotify(PGconn *conn);
|
||||
|
@ -433,18 +434,53 @@ PQsendQuery(PGconn *conn, const char *query)
|
|||
|
||||
/* send the query to the backend; */
|
||||
/* the frontend-backend protocol uses 'Q' to designate queries */
|
||||
if (pqPutnchar("Q", 1, conn))
|
||||
return 0;
|
||||
if (pqPuts(query, conn))
|
||||
return 0;
|
||||
if (pqFlush(conn))
|
||||
if (pqPutnchar("Q", 1, conn) ||
|
||||
pqPuts(query, conn) ||
|
||||
pqFlush(conn))
|
||||
{
|
||||
handleSendFailure(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* OK, it's launched! */
|
||||
conn->asyncStatus = PGASYNC_BUSY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* handleSendFailure: try to clean up after failure to send command.
|
||||
*
|
||||
* Primarily, what we want to accomplish here is to process an async
|
||||
* NOTICE message that the backend might have sent just before it died.
|
||||
*
|
||||
* NOTE: this routine should only be called in PGASYNC_IDLE state.
|
||||
*/
|
||||
|
||||
static void
|
||||
handleSendFailure(PGconn *conn)
|
||||
{
|
||||
/* Preserve the error message emitted by the failing output routine */
|
||||
char * svErrMsg = strdup(conn->errorMessage);
|
||||
|
||||
/*
|
||||
* Accept any available input data, ignoring errors. Note that if
|
||||
* pqReadData decides the backend has closed the channel, it will
|
||||
* close our side of the socket --- that's just what we want here.
|
||||
*/
|
||||
while (pqReadData(conn) > 0)
|
||||
/* loop until no more data readable */ ;
|
||||
|
||||
/*
|
||||
* Parse any available input messages. Since we are in PGASYNC_IDLE
|
||||
* state, only NOTICE and NOTIFY messages will be eaten.
|
||||
*/
|
||||
parseInput(conn);
|
||||
|
||||
/* Restore error message generated by output routine, if any. */
|
||||
if (*svErrMsg != '\0')
|
||||
strcpy(conn->errorMessage, svErrMsg);
|
||||
free(svErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Consume any available input from the backend
|
||||
|
@ -1399,31 +1435,44 @@ PQfn(PGconn *conn,
|
|||
/* clear the error string */
|
||||
conn->errorMessage[0] = '\0';
|
||||
|
||||
if (pqPuts("F ", conn)) /* function */
|
||||
return NULL;
|
||||
if (pqPutInt(fnid, 4, conn))/* function id */
|
||||
return NULL;
|
||||
if (pqPutInt(nargs, 4, conn)) /* # of args */
|
||||
if (pqPuts("F ", conn) || /* function */
|
||||
pqPutInt(fnid, 4, conn) || /* function id */
|
||||
pqPutInt(nargs, 4, conn)) /* # of args */
|
||||
{
|
||||
handleSendFailure(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < nargs; ++i)
|
||||
{ /* len.int4 + contents */
|
||||
if (pqPutInt(args[i].len, 4, conn))
|
||||
{
|
||||
handleSendFailure(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (args[i].isint)
|
||||
{
|
||||
if (pqPutInt(args[i].u.integer, 4, conn))
|
||||
{
|
||||
handleSendFailure(conn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn))
|
||||
{
|
||||
handleSendFailure(conn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pqFlush(conn))
|
||||
{
|
||||
handleSendFailure(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.24 1999/05/25 16:15:13 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.25 1999/05/28 01:54:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -471,7 +471,6 @@ pqFlush(PGconn *conn)
|
|||
/* Prevent being SIGPIPEd if backend has closed the connection. */
|
||||
#ifndef WIN32
|
||||
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
|
||||
|
||||
#endif
|
||||
|
||||
int sent = send(conn->sock, ptr, len, 0);
|
||||
|
@ -498,6 +497,7 @@ pqFlush(PGconn *conn)
|
|||
case EWOULDBLOCK:
|
||||
break;
|
||||
#endif
|
||||
|
||||
case EPIPE:
|
||||
#ifdef ECONNRESET
|
||||
case ECONNRESET:
|
||||
|
@ -506,14 +506,15 @@ pqFlush(PGconn *conn)
|
|||
"pqFlush() -- backend closed the channel unexpectedly.\n"
|
||||
"\tThis probably means the backend terminated abnormally"
|
||||
" before or while processing the request.\n");
|
||||
conn->status = CONNECTION_BAD; /* No more connection */
|
||||
#ifdef WIN32
|
||||
closesocket(conn->sock);
|
||||
#else
|
||||
close(conn->sock);
|
||||
#endif
|
||||
conn->sock = -1;
|
||||
/*
|
||||
* We used to close the socket here, but that's a bad
|
||||
* idea since there might be unread data waiting
|
||||
* (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.
|
||||
*/
|
||||
return EOF;
|
||||
|
||||
default:
|
||||
sprintf(conn->errorMessage,
|
||||
"pqFlush() -- couldn't send data: errno=%d\n%s\n",
|
||||
|
|
Loading…
Reference in New Issue