summaryrefslogtreecommitdiff
path: root/src/interfaces
diff options
context:
space:
mode:
authorTom Lane1999-05-28 01:54:53 +0000
committerTom Lane1999-05-28 01:54:53 +0000
commitf0ae1e8d10d7a38029cd0009063fa5131dce7937 (patch)
tree956a7576fd28cf549772139240a5157085b35c7c /src/interfaces
parent615e77ede2f3cd25cac7725112e31fb38753e270 (diff)
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.
Diffstat (limited to 'src/interfaces')
-rw-r--r--src/interfaces/libpq/fe-exec.c71
-rw-r--r--src/interfaces/libpq/fe-misc.c19
2 files changed, 70 insertions, 20 deletions
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 475a51bc4ac..446a70c821a 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -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 (;;)
{
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index fd33052f7cf..a16b89e5c3a 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -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",