Plug several holes in backend's ability to cope with
authorTom Lane
Thu, 22 Jul 1999 02:40:07 +0000 (02:40 +0000)
committerTom Lane
Thu, 22 Jul 1999 02:40:07 +0000 (02:40 +0000)
unexpected loss of connection to frontend.

src/backend/commands/copy.c
src/backend/tcop/fastpath.c
src/backend/tcop/postgres.c

index 98a0fb924390f37398cc738375a6739cacdc3bf2..a25dc0b8a693654a493894d38d8f386ebcb19a7d 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.85 1999/07/17 20:16:51 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.86 1999/07/22 02:40:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -54,15 +54,19 @@ static void GetIndexRelations(Oid main_relation_oid,
 #ifdef COPY_PATCH
 static void CopyReadNewline(FILE *fp, int *newline);
 static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline);
-
 #else
 static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim);
-
 #endif
+
 static void CopyAttributeOut(FILE *fp, char *string, char *delim, int is_array);
 static int CountTuples(Relation relation);
 
+/*
+ * Static communication variables ... pretty grotty, but COPY has
+ * never been reentrant...
+ */
 static int lineno;
+static bool    fe_eof;
 
 /*
  * Internal communications functions
@@ -90,7 +94,10 @@ static void
 CopySendData(void *databuf, int datasize, FILE *fp)
 {
    if (!fp)
-       pq_putbytes((char *) databuf, datasize);
+   {
+       if (pq_putbytes((char *) databuf, datasize))
+           fe_eof = true;
+   }
    else
        fwrite(databuf, datasize, 1, fp);
 }
@@ -121,7 +128,10 @@ static void
 CopyGetData(void *databuf, int datasize, FILE *fp)
 {
    if (!fp)
-       pq_getbytes((char *) databuf, datasize);
+   {
+       if (pq_getbytes((char *) databuf, datasize))
+           fe_eof = true;
+   }
    else
        fread(databuf, datasize, 1, fp);
 }
@@ -134,7 +144,10 @@ CopyGetChar(FILE *fp)
        unsigned char ch;
 
        if (pq_getbytes((char *) &ch, 1))
+       {
+           fe_eof = true;
            return EOF;
+       }
        return ch;
    }
    else
@@ -145,8 +158,7 @@ static int
 CopyGetEof(FILE *fp)
 {
    if (!fp)
-       return 0;               /* Never return EOF when talking to
-                                * frontend ? */
+       return fe_eof;
    else
        return feof(fp);
 }
@@ -154,7 +166,7 @@ CopyGetEof(FILE *fp)
 /*
  * CopyPeekChar reads a byte in "peekable" mode.
  * after each call to CopyPeekChar, a call to CopyDonePeek _must_
- * follow.
+ * follow, unless EOF was returned.
  * CopyDonePeek will either take the peeked char off the steam
  * (if pickup is != 0) or leave it on the stream (if pickup == 0)
  */
@@ -162,7 +174,12 @@ static int
 CopyPeekChar(FILE *fp)
 {
    if (!fp)
-       return pq_peekbyte();
+   {
+       int ch = pq_peekbyte();
+       if (ch == EOF)
+           fe_eof = true;
+       return ch;
+   }
    else
        return getc(fp);
 }
@@ -668,6 +685,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
    }
 
    lineno = 0;
+   fe_eof = false;
+
    while (!done)
    {
        if (!binary)
@@ -1193,10 +1212,7 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
                            else
                            {
                                if (CopyGetEof(fp))
-                               {
-                                   CopyDonePeek(fp, c, 1);     /* pick up */
                                    return NULL;
-                               }
                                CopyDonePeek(fp, c, 0); /* Return to stream! */
                            }
                        }
index 8bc5b28ee9228365d49978ec405d4793c09d0540..aed201e36d6543e7495c4efa2e342ec28fce6200 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.29 1999/07/17 20:17:50 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.30 1999/07/22 02:40:07 tgl Exp $
  *
  * NOTES
  *   This cruft is the server side of PQfn.
@@ -265,8 +265,11 @@ update_fp_info(Oid func_id, struct fp_info * fip)
  * This corresponds to the libpq protocol symbol "F".
  *
  * RETURNS:
- *     nothing of significance.
- *     All errors result in elog(ERROR,...).
+ *     0 if successful completion, EOF if frontend connection lost.
+ *
+ * Note: All ordinary errors result in elog(ERROR,...).  However,
+ * if we lose the frontend connection there is no one to elog to,
+ * and no use in proceeding...
  */
 int
 HandleFunctionRequest()
@@ -282,9 +285,11 @@ HandleFunctionRequest()
    char       *p;
    struct fp_info *fip;
 
-   pq_getint(&tmp, 4);         /* function oid */
+   if (pq_getint(&tmp, 4))     /* function oid */
+       return EOF;
    fid = (Oid) tmp;
-   pq_getint(&nargs, 4);       /* # of arguments */
+   if (pq_getint(&nargs, 4))   /* # of arguments */
+       return EOF;
 
    /*
     * This is where the one-back caching is done. If you want to save
@@ -294,6 +299,13 @@ HandleFunctionRequest()
    if (!valid_fp_info(fid, fip))
        update_fp_info(fid, fip);
 
+   /*
+    * XXX FIXME: elog() here means we lose sync with the frontend,
+    * since we have not swallowed all of its input message.  What
+    * should happen is we absorb all of the input message per protocol
+    * syntax, and *then* do error checking and elog if appropriate.
+    */
+
    if (fip->nargs != nargs)
    {
        elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
@@ -311,13 +323,15 @@ HandleFunctionRequest()
            arg[i] = (char *) NULL;
        else
        {
-           pq_getint(&argsize, 4);
+           if (pq_getint(&argsize, 4))
+               return EOF;
 
            Assert(argsize > 0);
            if (fip->argbyval[i])
            {                   /* by-value */
                Assert(argsize <= 4);
-               pq_getint(&tmp, argsize);
+               if (pq_getint(&tmp, argsize))
+                   return EOF;
                arg[i] = (char *) tmp;
            }
            else
@@ -329,14 +343,16 @@ HandleFunctionRequest()
                                                                 * 98 Jan 6 */
                        elog(ERROR, "HandleFunctionRequest: palloc failed");
                    VARSIZE(p) = argsize + VARHDRSZ;
-                   pq_getbytes(VARDATA(p), argsize);
+                   if (pq_getbytes(VARDATA(p), argsize))
+                       return EOF;
                }
                else
                {               /* ... fixed */
                    /* XXX cross our fingers and trust "argsize" */
                    if (!(p = palloc(argsize + 1)))
                        elog(ERROR, "HandleFunctionRequest: palloc failed");
-                   pq_getbytes(p, argsize);
+                   if (pq_getbytes(p, argsize))
+                       return EOF;
                }
                palloced |= (1 << i);
                arg[i] = p;
@@ -374,7 +390,5 @@ HandleFunctionRequest()
    if (!fip->retbyval)
        pfree(retval);
 
-
-
    return 0;
 }
index ea357ba613a14a4f4e6da210ace00ac3b2a024ad..a667fa70c40f82893ba4957e7e8b2b992017c3fa 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.126 1999/07/19 02:27:06 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.127 1999/07/22 02:40:07 tgl Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -158,9 +158,9 @@ int         _exec_repeat_ = 1;
  *     decls for routines only used in this file
  * ----------------------------------------------------------------
  */
-static char InteractiveBackend(char *inBuf);
-static char SocketBackend(char *inBuf);
-static char ReadCommand(char *inBuf);
+static int InteractiveBackend(char *inBuf);
+static int SocketBackend(char *inBuf);
+static int ReadCommand(char *inBuf);
 static void pg_exec_query(char *query_string);
 
 
@@ -172,10 +172,12 @@ static void pg_exec_query(char *query_string);
 /* ----------------
  * InteractiveBackend() is called for user interactive connections
  * the string entered by the user is placed in its parameter inBuf.
+ *
+ *  EOF is returned if end-of-file input is seen; time to shut down.
  * ----------------
  */
 
-static char
+static int
 InteractiveBackend(char *inBuf)
 {
    char       *stuff = inBuf;  /* current place in input buffer */
@@ -244,8 +246,7 @@ InteractiveBackend(char *inBuf)
        {
            if (Verbose)
                puts("EOF");
-           IsEmptyQuery = true;
-           proc_exit(0);
+           return EOF;
        }
 
        /* ----------------
@@ -274,11 +275,13 @@ InteractiveBackend(char *inBuf)
  *
  * If the input is a fastpath function call (case 'F') then
  * the function call is processed in HandleFunctionRequest().
- * (now called from PostgresMain())
+ * (now called from PostgresMain()).
+ *
+ *  EOF is returned if the connection is lost.
  * ----------------
  */
 
-static char
+static int
 SocketBackend(char *inBuf)
 {
    char        qtype;
@@ -290,13 +293,7 @@ SocketBackend(char *inBuf)
     */
    qtype = '?';
    if (pq_getbytes(&qtype, 1) == EOF)
-   {
-       /* ------------
-        *  when front-end applications quits/dies
-        * ------------
-        */
-       proc_exit(0);
-   }
+       return EOF;
 
    switch (qtype)
    {
@@ -305,7 +302,8 @@ SocketBackend(char *inBuf)
             * ----------------
             */
        case 'Q':
-           pq_getstr(inBuf, MAX_PARSE_BUFFER);
+           if (pq_getstr(inBuf, MAX_PARSE_BUFFER))
+               return EOF;
            result = 'Q';
            break;
 
@@ -314,8 +312,8 @@ SocketBackend(char *inBuf)
             * ----------------
             */
        case 'F':
-           pq_getstr(inBuf, MAX_PARSE_BUFFER); /* ignore the rest of the
-                                                * line */
+           if (pq_getstr(inBuf, MAX_PARSE_BUFFER))
+               return EOF;     /* ignore "string" at start of F message */
            result = 'F';
            break;
 
@@ -345,10 +343,10 @@ SocketBackend(char *inBuf)
  *     ReadCommand reads a command from either the frontend or
  *     standard input, places it in inBuf, and returns a char
  *     representing whether the string is a 'Q'uery or a 'F'astpath
- *     call.
+ *     call.  EOF is returned if end of file.
  * ----------------
  */
-static char
+static int
 ReadCommand(char *inBuf)
 {
    if (IsUnderPostmaster)
@@ -890,7 +888,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
    bool        secure = true;
    int         errs = 0;
 
-   char        firstchar;
+   int         firstchar;
    char        parser_input[MAX_PARSE_BUFFER];
    char       *userName;
 
@@ -1494,7 +1492,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
    if (!IsUnderPostmaster)
    {
        puts("\nPOSTGRES backend interactive interface ");
-       puts("$Revision: 1.126 $ $Date: 1999/07/19 02:27:06 $\n");
+       puts("$Revision: 1.127 $ $Date: 1999/07/22 02:40:07 $\n");
    }
 
    /* ----------------
@@ -1581,7 +1579,12 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
                    TPRINTF(TRACE_VERBOSE, "StartTransactionCommand");
                StartTransactionCommand();
 
-               HandleFunctionRequest();
+               if (HandleFunctionRequest() == EOF)
+               {
+                   /* lost frontend connection during F message input */
+                   pq_close();
+                   proc_exit(0);
+               }
                break;
 
                /* ----------------
@@ -1621,10 +1624,13 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
                break;
 
                /* ----------------
-                *  'X' means that the frontend is closing down the socket
+                *  'X' means that the frontend is closing down the socket.
+                *  EOF means unexpected loss of frontend connection.
+                *  Either way, perform normal shutdown.
                 * ----------------
                 */
            case 'X':
+           case EOF:
                pq_close();
                proc_exit(0);
                break;