提交 2aa64f79 编写于 作者: T Tom Lane

Plug several holes in backend's ability to cope with

unexpected loss of connection to frontend.
上级 991b82ee
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -54,15 +54,19 @@ static void GetIndexRelations(Oid main_relation_oid,
#ifdef COPY_PATCH #ifdef COPY_PATCH
static void CopyReadNewline(FILE *fp, int *newline); static void CopyReadNewline(FILE *fp, int *newline);
static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline); static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline);
#else #else
static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim); static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim);
#endif #endif
static void CopyAttributeOut(FILE *fp, char *string, char *delim, int is_array); static void CopyAttributeOut(FILE *fp, char *string, char *delim, int is_array);
static int CountTuples(Relation relation); static int CountTuples(Relation relation);
/*
* Static communication variables ... pretty grotty, but COPY has
* never been reentrant...
*/
static int lineno; static int lineno;
static bool fe_eof;
/* /*
* Internal communications functions * Internal communications functions
...@@ -90,7 +94,10 @@ static void ...@@ -90,7 +94,10 @@ static void
CopySendData(void *databuf, int datasize, FILE *fp) CopySendData(void *databuf, int datasize, FILE *fp)
{ {
if (!fp) if (!fp)
pq_putbytes((char *) databuf, datasize); {
if (pq_putbytes((char *) databuf, datasize))
fe_eof = true;
}
else else
fwrite(databuf, datasize, 1, fp); fwrite(databuf, datasize, 1, fp);
} }
...@@ -121,7 +128,10 @@ static void ...@@ -121,7 +128,10 @@ static void
CopyGetData(void *databuf, int datasize, FILE *fp) CopyGetData(void *databuf, int datasize, FILE *fp)
{ {
if (!fp) if (!fp)
pq_getbytes((char *) databuf, datasize); {
if (pq_getbytes((char *) databuf, datasize))
fe_eof = true;
}
else else
fread(databuf, datasize, 1, fp); fread(databuf, datasize, 1, fp);
} }
...@@ -134,7 +144,10 @@ CopyGetChar(FILE *fp) ...@@ -134,7 +144,10 @@ CopyGetChar(FILE *fp)
unsigned char ch; unsigned char ch;
if (pq_getbytes((char *) &ch, 1)) if (pq_getbytes((char *) &ch, 1))
{
fe_eof = true;
return EOF; return EOF;
}
return ch; return ch;
} }
else else
...@@ -145,8 +158,7 @@ static int ...@@ -145,8 +158,7 @@ static int
CopyGetEof(FILE *fp) CopyGetEof(FILE *fp)
{ {
if (!fp) if (!fp)
return 0; /* Never return EOF when talking to return fe_eof;
* frontend ? */
else else
return feof(fp); return feof(fp);
} }
...@@ -154,7 +166,7 @@ CopyGetEof(FILE *fp) ...@@ -154,7 +166,7 @@ CopyGetEof(FILE *fp)
/* /*
* CopyPeekChar reads a byte in "peekable" mode. * CopyPeekChar reads a byte in "peekable" mode.
* after each call to CopyPeekChar, a call to CopyDonePeek _must_ * 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 * CopyDonePeek will either take the peeked char off the steam
* (if pickup is != 0) or leave it on the stream (if pickup == 0) * (if pickup is != 0) or leave it on the stream (if pickup == 0)
*/ */
...@@ -162,7 +174,12 @@ static int ...@@ -162,7 +174,12 @@ static int
CopyPeekChar(FILE *fp) CopyPeekChar(FILE *fp)
{ {
if (!fp) if (!fp)
return pq_peekbyte(); {
int ch = pq_peekbyte();
if (ch == EOF)
fe_eof = true;
return ch;
}
else else
return getc(fp); return getc(fp);
} }
...@@ -668,6 +685,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim) ...@@ -668,6 +685,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
} }
lineno = 0; lineno = 0;
fe_eof = false;
while (!done) while (!done)
{ {
if (!binary) if (!binary)
...@@ -1193,10 +1212,7 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim) ...@@ -1193,10 +1212,7 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
else else
{ {
if (CopyGetEof(fp)) if (CopyGetEof(fp))
{
CopyDonePeek(fp, c, 1); /* pick up */
return NULL; return NULL;
}
CopyDonePeek(fp, c, 0); /* Return to stream! */ CopyDonePeek(fp, c, 0); /* Return to stream! */
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This cruft is the server side of PQfn. * This cruft is the server side of PQfn.
...@@ -265,8 +265,11 @@ update_fp_info(Oid func_id, struct fp_info * fip) ...@@ -265,8 +265,11 @@ update_fp_info(Oid func_id, struct fp_info * fip)
* This corresponds to the libpq protocol symbol "F". * This corresponds to the libpq protocol symbol "F".
* *
* RETURNS: * RETURNS:
* nothing of significance. * 0 if successful completion, EOF if frontend connection lost.
* All errors result in elog(ERROR,...). *
* 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 int
HandleFunctionRequest() HandleFunctionRequest()
...@@ -282,9 +285,11 @@ HandleFunctionRequest() ...@@ -282,9 +285,11 @@ HandleFunctionRequest()
char *p; char *p;
struct fp_info *fip; struct fp_info *fip;
pq_getint(&tmp, 4); /* function oid */ if (pq_getint(&tmp, 4)) /* function oid */
return EOF;
fid = (Oid) tmp; 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 * This is where the one-back caching is done. If you want to save
...@@ -294,6 +299,13 @@ HandleFunctionRequest() ...@@ -294,6 +299,13 @@ HandleFunctionRequest()
if (!valid_fp_info(fid, fip)) if (!valid_fp_info(fid, fip))
update_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) if (fip->nargs != nargs)
{ {
elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)", elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
...@@ -311,13 +323,15 @@ HandleFunctionRequest() ...@@ -311,13 +323,15 @@ HandleFunctionRequest()
arg[i] = (char *) NULL; arg[i] = (char *) NULL;
else else
{ {
pq_getint(&argsize, 4); if (pq_getint(&argsize, 4))
return EOF;
Assert(argsize > 0); Assert(argsize > 0);
if (fip->argbyval[i]) if (fip->argbyval[i])
{ /* by-value */ { /* by-value */
Assert(argsize <= 4); Assert(argsize <= 4);
pq_getint(&tmp, argsize); if (pq_getint(&tmp, argsize))
return EOF;
arg[i] = (char *) tmp; arg[i] = (char *) tmp;
} }
else else
...@@ -329,14 +343,16 @@ HandleFunctionRequest() ...@@ -329,14 +343,16 @@ HandleFunctionRequest()
* 98 Jan 6 */ * 98 Jan 6 */
elog(ERROR, "HandleFunctionRequest: palloc failed"); elog(ERROR, "HandleFunctionRequest: palloc failed");
VARSIZE(p) = argsize + VARHDRSZ; VARSIZE(p) = argsize + VARHDRSZ;
pq_getbytes(VARDATA(p), argsize); if (pq_getbytes(VARDATA(p), argsize))
return EOF;
} }
else else
{ /* ... fixed */ { /* ... fixed */
/* XXX cross our fingers and trust "argsize" */ /* XXX cross our fingers and trust "argsize" */
if (!(p = palloc(argsize + 1))) if (!(p = palloc(argsize + 1)))
elog(ERROR, "HandleFunctionRequest: palloc failed"); elog(ERROR, "HandleFunctionRequest: palloc failed");
pq_getbytes(p, argsize); if (pq_getbytes(p, argsize))
return EOF;
} }
palloced |= (1 << i); palloced |= (1 << i);
arg[i] = p; arg[i] = p;
...@@ -374,7 +390,5 @@ HandleFunctionRequest() ...@@ -374,7 +390,5 @@ HandleFunctionRequest()
if (!fip->retbyval) if (!fip->retbyval)
pfree(retval); pfree(retval);
return 0; return 0;
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -158,9 +158,9 @@ int _exec_repeat_ = 1; ...@@ -158,9 +158,9 @@ int _exec_repeat_ = 1;
* decls for routines only used in this file * decls for routines only used in this file
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static char InteractiveBackend(char *inBuf); static int InteractiveBackend(char *inBuf);
static char SocketBackend(char *inBuf); static int SocketBackend(char *inBuf);
static char ReadCommand(char *inBuf); static int ReadCommand(char *inBuf);
static void pg_exec_query(char *query_string); static void pg_exec_query(char *query_string);
...@@ -172,10 +172,12 @@ 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 * InteractiveBackend() is called for user interactive connections
* the string entered by the user is placed in its parameter inBuf. * 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) InteractiveBackend(char *inBuf)
{ {
char *stuff = inBuf; /* current place in input buffer */ char *stuff = inBuf; /* current place in input buffer */
...@@ -244,8 +246,7 @@ InteractiveBackend(char *inBuf) ...@@ -244,8 +246,7 @@ InteractiveBackend(char *inBuf)
{ {
if (Verbose) if (Verbose)
puts("EOF"); puts("EOF");
IsEmptyQuery = true; return EOF;
proc_exit(0);
} }
/* ---------------- /* ----------------
...@@ -274,11 +275,13 @@ InteractiveBackend(char *inBuf) ...@@ -274,11 +275,13 @@ InteractiveBackend(char *inBuf)
* *
* If the input is a fastpath function call (case 'F') then * If the input is a fastpath function call (case 'F') then
* the function call is processed in HandleFunctionRequest(). * 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) SocketBackend(char *inBuf)
{ {
char qtype; char qtype;
...@@ -290,13 +293,7 @@ SocketBackend(char *inBuf) ...@@ -290,13 +293,7 @@ SocketBackend(char *inBuf)
*/ */
qtype = '?'; qtype = '?';
if (pq_getbytes(&qtype, 1) == EOF) if (pq_getbytes(&qtype, 1) == EOF)
{ return EOF;
/* ------------
* when front-end applications quits/dies
* ------------
*/
proc_exit(0);
}
switch (qtype) switch (qtype)
{ {
...@@ -305,7 +302,8 @@ SocketBackend(char *inBuf) ...@@ -305,7 +302,8 @@ SocketBackend(char *inBuf)
* ---------------- * ----------------
*/ */
case 'Q': case 'Q':
pq_getstr(inBuf, MAX_PARSE_BUFFER); if (pq_getstr(inBuf, MAX_PARSE_BUFFER))
return EOF;
result = 'Q'; result = 'Q';
break; break;
...@@ -314,8 +312,8 @@ SocketBackend(char *inBuf) ...@@ -314,8 +312,8 @@ SocketBackend(char *inBuf)
* ---------------- * ----------------
*/ */
case 'F': case 'F':
pq_getstr(inBuf, MAX_PARSE_BUFFER); /* ignore the rest of the if (pq_getstr(inBuf, MAX_PARSE_BUFFER))
* line */ return EOF; /* ignore "string" at start of F message */
result = 'F'; result = 'F';
break; break;
...@@ -345,10 +343,10 @@ SocketBackend(char *inBuf) ...@@ -345,10 +343,10 @@ SocketBackend(char *inBuf)
* ReadCommand reads a command from either the frontend or * ReadCommand reads a command from either the frontend or
* standard input, places it in inBuf, and returns a char * standard input, places it in inBuf, and returns a char
* representing whether the string is a 'Q'uery or a 'F'astpath * 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) ReadCommand(char *inBuf)
{ {
if (IsUnderPostmaster) if (IsUnderPostmaster)
...@@ -890,7 +888,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -890,7 +888,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
bool secure = true; bool secure = true;
int errs = 0; int errs = 0;
char firstchar; int firstchar;
char parser_input[MAX_PARSE_BUFFER]; char parser_input[MAX_PARSE_BUFFER];
char *userName; char *userName;
...@@ -1494,7 +1492,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1494,7 +1492,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); 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[]) ...@@ -1581,7 +1579,12 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
TPRINTF(TRACE_VERBOSE, "StartTransactionCommand"); TPRINTF(TRACE_VERBOSE, "StartTransactionCommand");
StartTransactionCommand(); StartTransactionCommand();
HandleFunctionRequest(); if (HandleFunctionRequest() == EOF)
{
/* lost frontend connection during F message input */
pq_close();
proc_exit(0);
}
break; break;
/* ---------------- /* ----------------
...@@ -1621,10 +1624,13 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1621,10 +1624,13 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
break; 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 'X':
case EOF:
pq_close(); pq_close();
proc_exit(0); proc_exit(0);
break; break;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册