mirror of
https://github.com/postgres/postgres.git
synced 2025-05-01 01:04:50 +03:00
Plug several holes in backend's ability to cope with
unexpected loss of connection to frontend.
This commit is contained in:
parent
991b82ee13
commit
2aa64f79f5
@ -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,
|
|||||||
#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
|
|||||||
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
|
|||||||
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)
|
|||||||
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
|
|||||||
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)
|
|||||||
/*
|
/*
|
||||||
* 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
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
* 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()
|
|||||||
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()
|
|||||||
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()
|
|||||||
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()
|
|||||||
* 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()
|
|||||||
if (!fip->retbyval)
|
if (!fip->retbyval)
|
||||||
pfree(retval);
|
pfree(retval);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|||||||
* 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);
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* 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)
|
|||||||
{
|
{
|
||||||
if (Verbose)
|
if (Verbose)
|
||||||
puts("EOF");
|
puts("EOF");
|
||||||
IsEmptyQuery = true;
|
return EOF;
|
||||||
proc_exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
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)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
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)
|
|||||||
* 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[])
|
|||||||
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[])
|
|||||||
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[])
|
|||||||
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[])
|
|||||||
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user