When closure of the backend connection is detected during pqFlush,
authorTom Lane
Fri, 28 May 1999 01:54:53 +0000 (01:54 +0000)
committerTom Lane
Fri, 28 May 1999 01:54:53 +0000 (01:54 +0000)
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.

src/interfaces/libpq/fe-exec.c
src/interfaces/libpq/fe-misc.c

index 475a51bc4ac8080def7bd08b9f86162a2ac38e71..446a70c821a0d2c048d6f4680f0914f0aaadb79d 100644 (file)
@@ -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 (;;)
    {
index fd33052f7cf59c21d65f8567e71c19041878ec88..a16b89e5c3a36bbd2895ea172f9605712dc27709 100644 (file)
@@ -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",