Commit f0ae1e8d authored by Tom Lane's avatar Tom Lane

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.
parent 615e77ed
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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[] = { ...@@ -47,6 +47,7 @@ const char *const pgresStatus[] = {
static int addTuple(PGresult *res, PGresAttValue *tup); static int addTuple(PGresult *res, PGresAttValue *tup);
static void parseInput(PGconn *conn); static void parseInput(PGconn *conn);
static void handleSendFailure(PGconn *conn);
static int getRowDescriptions(PGconn *conn); static int getRowDescriptions(PGconn *conn);
static int getAnotherTuple(PGconn *conn, int binary); static int getAnotherTuple(PGconn *conn, int binary);
static int getNotify(PGconn *conn); static int getNotify(PGconn *conn);
...@@ -433,18 +434,53 @@ PQsendQuery(PGconn *conn, const char *query) ...@@ -433,18 +434,53 @@ PQsendQuery(PGconn *conn, const char *query)
/* send the query to the backend; */ /* send the query to the backend; */
/* the frontend-backend protocol uses 'Q' to designate queries */ /* the frontend-backend protocol uses 'Q' to designate queries */
if (pqPutnchar("Q", 1, conn)) if (pqPutnchar("Q", 1, conn) ||
return 0; pqPuts(query, conn) ||
if (pqPuts(query, conn)) pqFlush(conn))
return 0; {
if (pqFlush(conn)) handleSendFailure(conn);
return 0; return 0;
}
/* OK, it's launched! */ /* OK, it's launched! */
conn->asyncStatus = PGASYNC_BUSY; conn->asyncStatus = PGASYNC_BUSY;
return 1; 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 * Consume any available input from the backend
...@@ -1399,31 +1435,44 @@ PQfn(PGconn *conn, ...@@ -1399,31 +1435,44 @@ PQfn(PGconn *conn,
/* clear the error string */ /* clear the error string */
conn->errorMessage[0] = '\0'; conn->errorMessage[0] = '\0';
if (pqPuts("F ", conn)) /* function */ if (pqPuts("F ", conn) || /* function */
return NULL; pqPutInt(fnid, 4, conn) || /* function id */
if (pqPutInt(fnid, 4, conn))/* function id */ pqPutInt(nargs, 4, conn)) /* # of args */
return NULL; {
if (pqPutInt(nargs, 4, conn)) /* # of args */ handleSendFailure(conn);
return NULL; return NULL;
}
for (i = 0; i < nargs; ++i) for (i = 0; i < nargs; ++i)
{ /* len.int4 + contents */ { /* len.int4 + contents */
if (pqPutInt(args[i].len, 4, conn)) if (pqPutInt(args[i].len, 4, conn))
{
handleSendFailure(conn);
return NULL; return NULL;
}
if (args[i].isint) if (args[i].isint)
{ {
if (pqPutInt(args[i].u.integer, 4, conn)) if (pqPutInt(args[i].u.integer, 4, conn))
{
handleSendFailure(conn);
return NULL; return NULL;
}
} }
else else
{ {
if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn)) if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn))
{
handleSendFailure(conn);
return NULL; return NULL;
}
} }
} }
if (pqFlush(conn)) if (pqFlush(conn))
{
handleSendFailure(conn);
return NULL; return NULL;
}
for (;;) for (;;)
{ {
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -471,7 +471,6 @@ pqFlush(PGconn *conn)
/* Prevent being SIGPIPEd if backend has closed the connection. */ /* Prevent being SIGPIPEd if backend has closed the connection. */
#ifndef WIN32 #ifndef WIN32
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN); pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
#endif #endif
int sent = send(conn->sock, ptr, len, 0); int sent = send(conn->sock, ptr, len, 0);
...@@ -498,6 +497,7 @@ pqFlush(PGconn *conn) ...@@ -498,6 +497,7 @@ pqFlush(PGconn *conn)
case EWOULDBLOCK: case EWOULDBLOCK:
break; break;
#endif #endif
case EPIPE: case EPIPE:
#ifdef ECONNRESET #ifdef ECONNRESET
case ECONNRESET: case ECONNRESET:
...@@ -506,14 +506,15 @@ pqFlush(PGconn *conn) ...@@ -506,14 +506,15 @@ pqFlush(PGconn *conn)
"pqFlush() -- backend closed the channel unexpectedly.\n" "pqFlush() -- backend closed the channel unexpectedly.\n"
"\tThis probably means the backend terminated abnormally" "\tThis probably means the backend terminated abnormally"
" before or while processing the request.\n"); " before or while processing the request.\n");
conn->status = CONNECTION_BAD; /* No more connection */ /*
#ifdef WIN32 * We used to close the socket here, but that's a bad
closesocket(conn->sock); * idea since there might be unread data waiting
#else * (typically, a NOTICE message from the backend telling
close(conn->sock); * us it's committing hara-kiri...). Leave the socket
#endif * open until pqReadData finds no more data can be read.
conn->sock = -1; */
return EOF; return EOF;
default: default:
sprintf(conn->errorMessage, sprintf(conn->errorMessage,
"pqFlush() -- couldn't send data: errno=%d\n%s\n", "pqFlush() -- couldn't send data: errno=%d\n%s\n",
......
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