Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2aa64f7

Browse files
committed
Plug several holes in backend's ability to cope with
unexpected loss of connection to frontend.
1 parent 991b82e commit 2aa64f7

File tree

3 files changed

+84
-48
lines changed

3 files changed

+84
-48
lines changed

src/backend/commands/copy.c

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
*
88
* IDENTIFICATION
9-
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.85 1999/07/17 20:16:51 momjian Exp $
9+
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.86 1999/07/22 02:40:06 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -54,15 +54,19 @@ static void GetIndexRelations(Oid main_relation_oid,
5454
#ifdef COPY_PATCH
5555
static void CopyReadNewline(FILE *fp, int *newline);
5656
static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline);
57-
5857
#else
5958
static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim);
60-
6159
#endif
60+
6261
static void CopyAttributeOut(FILE *fp, char *string, char *delim, int is_array);
6362
static int CountTuples(Relation relation);
6463

64+
/*
65+
* Static communication variables ... pretty grotty, but COPY has
66+
* never been reentrant...
67+
*/
6568
static int lineno;
69+
static bool fe_eof;
6670

6771
/*
6872
* Internal communications functions
@@ -90,7 +94,10 @@ static void
9094
CopySendData(void *databuf, int datasize, FILE *fp)
9195
{
9296
if (!fp)
93-
pq_putbytes((char *) databuf, datasize);
97+
{
98+
if (pq_putbytes((char *) databuf, datasize))
99+
fe_eof = true;
100+
}
94101
else
95102
fwrite(databuf, datasize, 1, fp);
96103
}
@@ -121,7 +128,10 @@ static void
121128
CopyGetData(void *databuf, int datasize, FILE *fp)
122129
{
123130
if (!fp)
124-
pq_getbytes((char *) databuf, datasize);
131+
{
132+
if (pq_getbytes((char *) databuf, datasize))
133+
fe_eof = true;
134+
}
125135
else
126136
fread(databuf, datasize, 1, fp);
127137
}
@@ -134,7 +144,10 @@ CopyGetChar(FILE *fp)
134144
unsigned char ch;
135145

136146
if (pq_getbytes((char *) &ch, 1))
147+
{
148+
fe_eof = true;
137149
return EOF;
150+
}
138151
return ch;
139152
}
140153
else
@@ -145,24 +158,28 @@ static int
145158
CopyGetEof(FILE *fp)
146159
{
147160
if (!fp)
148-
return 0; /* Never return EOF when talking to
149-
* frontend ? */
161+
return fe_eof;
150162
else
151163
return feof(fp);
152164
}
153165

154166
/*
155167
* CopyPeekChar reads a byte in "peekable" mode.
156168
* after each call to CopyPeekChar, a call to CopyDonePeek _must_
157-
* follow.
169+
* follow, unless EOF was returned.
158170
* CopyDonePeek will either take the peeked char off the steam
159171
* (if pickup is != 0) or leave it on the stream (if pickup == 0)
160172
*/
161173
static int
162174
CopyPeekChar(FILE *fp)
163175
{
164176
if (!fp)
165-
return pq_peekbyte();
177+
{
178+
int ch = pq_peekbyte();
179+
if (ch == EOF)
180+
fe_eof = true;
181+
return ch;
182+
}
166183
else
167184
return getc(fp);
168185
}
@@ -668,6 +685,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
668685
}
669686

670687
lineno = 0;
688+
fe_eof = false;
689+
671690
while (!done)
672691
{
673692
if (!binary)
@@ -1193,10 +1212,7 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
11931212
else
11941213
{
11951214
if (CopyGetEof(fp))
1196-
{
1197-
CopyDonePeek(fp, c, 1); /* pick up */
11981215
return NULL;
1199-
}
12001216
CopyDonePeek(fp, c, 0); /* Return to stream! */
12011217
}
12021218
}

src/backend/tcop/fastpath.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.29 1999/07/17 20:17:50 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.30 1999/07/22 02:40:07 tgl Exp $
1111
*
1212
* NOTES
1313
* This cruft is the server side of PQfn.
@@ -265,8 +265,11 @@ update_fp_info(Oid func_id, struct fp_info * fip)
265265
* This corresponds to the libpq protocol symbol "F".
266266
*
267267
* RETURNS:
268-
* nothing of significance.
269-
* All errors result in elog(ERROR,...).
268+
* 0 if successful completion, EOF if frontend connection lost.
269+
*
270+
* Note: All ordinary errors result in elog(ERROR,...). However,
271+
* if we lose the frontend connection there is no one to elog to,
272+
* and no use in proceeding...
270273
*/
271274
int
272275
HandleFunctionRequest()
@@ -282,9 +285,11 @@ HandleFunctionRequest()
282285
char *p;
283286
struct fp_info *fip;
284287

285-
pq_getint(&tmp, 4); /* function oid */
288+
if (pq_getint(&tmp, 4)) /* function oid */
289+
return EOF;
286290
fid = (Oid) tmp;
287-
pq_getint(&nargs, 4); /* # of arguments */
291+
if (pq_getint(&nargs, 4)) /* # of arguments */
292+
return EOF;
288293

289294
/*
290295
* This is where the one-back caching is done. If you want to save
@@ -294,6 +299,13 @@ HandleFunctionRequest()
294299
if (!valid_fp_info(fid, fip))
295300
update_fp_info(fid, fip);
296301

302+
/*
303+
* XXX FIXME: elog() here means we lose sync with the frontend,
304+
* since we have not swallowed all of its input message. What
305+
* should happen is we absorb all of the input message per protocol
306+
* syntax, and *then* do error checking and elog if appropriate.
307+
*/
308+
297309
if (fip->nargs != nargs)
298310
{
299311
elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
@@ -311,13 +323,15 @@ HandleFunctionRequest()
311323
arg[i] = (char *) NULL;
312324
else
313325
{
314-
pq_getint(&argsize, 4);
326+
if (pq_getint(&argsize, 4))
327+
return EOF;
315328

316329
Assert(argsize > 0);
317330
if (fip->argbyval[i])
318331
{ /* by-value */
319332
Assert(argsize <= 4);
320-
pq_getint(&tmp, argsize);
333+
if (pq_getint(&tmp, argsize))
334+
return EOF;
321335
arg[i] = (char *) tmp;
322336
}
323337
else
@@ -329,14 +343,16 @@ HandleFunctionRequest()
329343
* 98 Jan 6 */
330344
elog(ERROR, "HandleFunctionRequest: palloc failed");
331345
VARSIZE(p) = argsize + VARHDRSZ;
332-
pq_getbytes(VARDATA(p), argsize);
346+
if (pq_getbytes(VARDATA(p), argsize))
347+
return EOF;
333348
}
334349
else
335350
{ /* ... fixed */
336351
/* XXX cross our fingers and trust "argsize" */
337352
if (!(p = palloc(argsize + 1)))
338353
elog(ERROR, "HandleFunctionRequest: palloc failed");
339-
pq_getbytes(p, argsize);
354+
if (pq_getbytes(p, argsize))
355+
return EOF;
340356
}
341357
palloced |= (1 << i);
342358
arg[i] = p;
@@ -374,7 +390,5 @@ HandleFunctionRequest()
374390
if (!fip->retbyval)
375391
pfree(retval);
376392

377-
378-
379393
return 0;
380394
}

src/backend/tcop/postgres.c

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.126 1999/07/19 02:27:06 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.127 1999/07/22 02:40:07 tgl Exp $
1111
*
1212
* NOTES
1313
* this is the "main" module of the postgres backend and
@@ -158,9 +158,9 @@ int _exec_repeat_ = 1;
158158
* decls for routines only used in this file
159159
* ----------------------------------------------------------------
160160
*/
161-
static char InteractiveBackend(char *inBuf);
162-
static char SocketBackend(char *inBuf);
163-
static char ReadCommand(char *inBuf);
161+
static int InteractiveBackend(char *inBuf);
162+
static int SocketBackend(char *inBuf);
163+
static int ReadCommand(char *inBuf);
164164
static void pg_exec_query(char *query_string);
165165

166166

@@ -172,10 +172,12 @@ static void pg_exec_query(char *query_string);
172172
/* ----------------
173173
* InteractiveBackend() is called for user interactive connections
174174
* the string entered by the user is placed in its parameter inBuf.
175+
*
176+
* EOF is returned if end-of-file input is seen; time to shut down.
175177
* ----------------
176178
*/
177179

178-
static char
180+
static int
179181
InteractiveBackend(char *inBuf)
180182
{
181183
char *stuff = inBuf; /* current place in input buffer */
@@ -244,8 +246,7 @@ InteractiveBackend(char *inBuf)
244246
{
245247
if (Verbose)
246248
puts("EOF");
247-
IsEmptyQuery = true;
248-
proc_exit(0);
249+
return EOF;
249250
}
250251

251252
/* ----------------
@@ -274,11 +275,13 @@ InteractiveBackend(char *inBuf)
274275
*
275276
* If the input is a fastpath function call (case 'F') then
276277
* the function call is processed in HandleFunctionRequest().
277-
* (now called from PostgresMain())
278+
* (now called from PostgresMain()).
279+
*
280+
* EOF is returned if the connection is lost.
278281
* ----------------
279282
*/
280283

281-
static char
284+
static int
282285
SocketBackend(char *inBuf)
283286
{
284287
char qtype;
@@ -290,13 +293,7 @@ SocketBackend(char *inBuf)
290293
*/
291294
qtype = '?';
292295
if (pq_getbytes(&qtype, 1) == EOF)
293-
{
294-
/* ------------
295-
* when front-end applications quits/dies
296-
* ------------
297-
*/
298-
proc_exit(0);
299-
}
296+
return EOF;
300297

301298
switch (qtype)
302299
{
@@ -305,7 +302,8 @@ SocketBackend(char *inBuf)
305302
* ----------------
306303
*/
307304
case 'Q':
308-
pq_getstr(inBuf, MAX_PARSE_BUFFER);
305+
if (pq_getstr(inBuf, MAX_PARSE_BUFFER))
306+
return EOF;
309307
result = 'Q';
310308
break;
311309

@@ -314,8 +312,8 @@ SocketBackend(char *inBuf)
314312
* ----------------
315313
*/
316314
case 'F':
317-
pq_getstr(inBuf, MAX_PARSE_BUFFER); /* ignore the rest of the
318-
* line */
315+
if (pq_getstr(inBuf, MAX_PARSE_BUFFER))
316+
return EOF; /* ignore "string" at start of F message */
319317
result = 'F';
320318
break;
321319

@@ -345,10 +343,10 @@ SocketBackend(char *inBuf)
345343
* ReadCommand reads a command from either the frontend or
346344
* standard input, places it in inBuf, and returns a char
347345
* representing whether the string is a 'Q'uery or a 'F'astpath
348-
* call.
346+
* call. EOF is returned if end of file.
349347
* ----------------
350348
*/
351-
static char
349+
static int
352350
ReadCommand(char *inBuf)
353351
{
354352
if (IsUnderPostmaster)
@@ -890,7 +888,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
890888
bool secure = true;
891889
int errs = 0;
892890

893-
char firstchar;
891+
int firstchar;
894892
char parser_input[MAX_PARSE_BUFFER];
895893
char *userName;
896894

@@ -1494,7 +1492,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
14941492
if (!IsUnderPostmaster)
14951493
{
14961494
puts("\nPOSTGRES backend interactive interface ");
1497-
puts("$Revision: 1.126 $ $Date: 1999/07/19 02:27:06 $\n");
1495+
puts("$Revision: 1.127 $ $Date: 1999/07/22 02:40:07 $\n");
14981496
}
14991497

15001498
/* ----------------
@@ -1581,7 +1579,12 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
15811579
TPRINTF(TRACE_VERBOSE, "StartTransactionCommand");
15821580
StartTransactionCommand();
15831581

1584-
HandleFunctionRequest();
1582+
if (HandleFunctionRequest() == EOF)
1583+
{
1584+
/* lost frontend connection during F message input */
1585+
pq_close();
1586+
proc_exit(0);
1587+
}
15851588
break;
15861589

15871590
/* ----------------
@@ -1621,10 +1624,13 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
16211624
break;
16221625

16231626
/* ----------------
1624-
* 'X' means that the frontend is closing down the socket
1627+
* 'X' means that the frontend is closing down the socket.
1628+
* EOF means unexpected loss of frontend connection.
1629+
* Either way, perform normal shutdown.
16251630
* ----------------
16261631
*/
16271632
case 'X':
1633+
case EOF:
16281634
pq_close();
16291635
proc_exit(0);
16301636
break;

0 commit comments

Comments
 (0)