OSDN Git Service

When closure of the backend connection is detected during pqFlush,
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 28 May 1999 01:54:53 +0000 (01:54 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 475a51b..446a70c 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 fd33052..a16b89e 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",