OSDN Git Service

Plug several holes in backend's ability to cope with
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 22 Jul 1999 02:40:07 +0000 (02:40 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 98a0fb9..a25dc0b 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 8bc5b28..aed201e 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 ea357ba..a667fa7 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;