Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1c2d9cb

Browse files
committed
It seems the regression tests don't cover copy in/out at all, so
code that I had assumed was working had not been tested. Naturally, it was broken ... Tom Lane
1 parent edbd513 commit 1c2d9cb

File tree

4 files changed

+69
-27
lines changed

4 files changed

+69
-27
lines changed

src/bin/pg_dump/pg_dump.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
*
2222
*
2323
* IDENTIFICATION
24-
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.70 1998/04/07 22:36:38 momjian Exp $
24+
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.71 1998/05/06 23:53:27 momjian Exp $
2525
*
2626
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
2727
*
@@ -230,7 +230,8 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids)
230230
sprintf(query, "COPY %s TO stdout;\n", fmtId(classname));
231231
}
232232
res = PQexec(g_conn, query);
233-
if (!res)
233+
if (!res ||
234+
PQresultStatus(res) == PGRES_FATAL_ERROR)
234235
{
235236
fprintf(stderr, "SQL query to dump the contents of Table %s "
236237
"did not execute. Explanation from backend: '%s'.\n"

src/interfaces/libpgtcl/pgtclId.c

+39-20
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*
1313
*
1414
* IDENTIFICATION
15-
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.9 1998/05/06 23:51:00 momjian Exp $
15+
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.10 1998/05/06 23:53:30 momjian Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -60,19 +60,21 @@ int PgInputProc(DRIVER_INPUT_PROTO)
6060
return -1;
6161
}
6262

63-
if (connid->res_copyStatus == RES_COPY_FIN) {
64-
return PgEndCopy(connid, errorCodePtr);
65-
}
66-
6763
/* Try to load any newly arrived data */
6864
errno = 0;
6965

7066
if (pqReadData(conn) < 0) {
71-
*errorCodePtr = errno ? errno : EIO;
72-
return -1;
67+
*errorCodePtr = errno ? errno : EIO;
68+
return -1;
7369
}
7470

75-
/* Move data from libpq's buffer to tcl's */
71+
/* Move data from libpq's buffer to Tcl's.
72+
* We want to accept data only in units of whole lines,
73+
* not partial lines. This ensures that we can recognize
74+
* the terminator line "\\.\n". (Otherwise, if it happened
75+
* to cross a packet/buffer boundary, we might hand the first
76+
* one or two characters off to Tcl, which we shouldn't.)
77+
*/
7678

7779
conn->inCursor = conn->inStart;
7880

@@ -81,19 +83,33 @@ int PgInputProc(DRIVER_INPUT_PROTO)
8183
pqGetc(&c, conn) == 0) {
8284
*buf++ = c;
8385
--avail;
84-
if (c == '\n' && bufSize-avail >= 3) {
85-
if ((bufSize-avail == 3 || buf[-4] == '\n') &&
86-
buf[-3] == '\\' && buf[-2] == '.') {
87-
avail += 3;
88-
connid->res_copyStatus = RES_COPY_FIN;
89-
break;
86+
if (c == '\n') {
87+
/* Got a complete line; mark the data removed from libpq */
88+
conn->inStart = conn->inCursor;
89+
/* Is it the endmarker line? */
90+
if (bufSize-avail == 3 && buf[-3] == '\\' && buf[-2] == '.') {
91+
/* Yes, change state and return 0 */
92+
return PgEndCopy(connid, errorCodePtr);
9093
}
94+
/* No, return the data to Tcl */
95+
/* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
96+
return bufSize - avail;
9197
}
9298
}
93-
/* Accept the data permanently */
94-
conn->inStart = conn->inCursor;
95-
/* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
96-
return bufSize - avail;
99+
100+
/* We don't have a complete line.
101+
* We'd prefer to leave it in libpq's buffer until the rest arrives,
102+
* but there is a special case: what if the line is longer than the
103+
* buffer Tcl is offering us? In that case we'd better hand over
104+
* a partial line, else we'd get into an infinite loop.
105+
* Do this in a way that ensures we can't misrecognize a terminator
106+
* line later: leave last 3 characters in libpq buffer.
107+
*/
108+
if (avail == 0 && bufSize > 3) {
109+
conn->inStart = conn->inCursor - 3;
110+
return bufSize - 3;
111+
}
112+
return 0;
97113
}
98114

99115
/*
@@ -116,10 +132,13 @@ int PgOutputProc(DRIVER_OUTPUT_PROTO)
116132
errno = 0;
117133

118134
if (pqPutnchar(buf, bufSize, conn)) {
119-
*errorCodePtr = errno ? errno : EIO;
120-
return -1;
135+
*errorCodePtr = errno ? errno : EIO;
136+
return -1;
121137
}
122138

139+
/* This assumes Tcl script will write the terminator line
140+
* in a single operation; maybe not such a good assumption?
141+
*/
123142
if (bufSize >= 3 && strncmp(&buf[bufSize-3], "\\.\n", 3) == 0) {
124143
(void) pqFlush(conn);
125144
if (PgEndCopy(connid, errorCodePtr) == -1)

src/interfaces/libpq/fe-exec.c

+8-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.50 1998/05/06 23:51:13 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.51 1998/05/06 23:53:38 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -748,14 +748,18 @@ PQexec(PGconn *conn, const char *query)
748748
return NULL;
749749

750750
/* For backwards compatibility, return the last result if there are
751-
* more than one.
751+
* more than one. We have to stop if we see copy in/out, however.
752+
* We will resume parsing when application calls PQendcopy.
752753
*/
753754
lastResult = NULL;
754755
while ((result = PQgetResult(conn)) != NULL)
755756
{
756757
if (lastResult)
757758
PQclear(lastResult);
758759
lastResult = result;
760+
if (result->resultStatus == PGRES_COPY_IN ||
761+
result->resultStatus == PGRES_COPY_OUT)
762+
break;
759763
}
760764
return lastResult;
761765
}
@@ -950,7 +954,7 @@ PQputline(PGconn *conn, const char *s)
950954
{
951955
if (conn && conn->sock >= 0)
952956
{
953-
(void) pqPuts(s, conn);
957+
(void) pqPutnchar(s, strlen(s), conn);
954958
}
955959
}
956960

@@ -988,7 +992,7 @@ PQendcopy(PGconn *conn)
988992
result = PQgetResult(conn);
989993

990994
/* Expecting a successful result */
991-
if (result->resultStatus == PGRES_COMMAND_OK)
995+
if (result && result->resultStatus == PGRES_COMMAND_OK)
992996
{
993997
PQclear(result);
994998
return 0;

src/interfaces/libpq/fe-misc.c

+19-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*
2525
*
2626
* IDENTIFICATION
27-
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.11 1998/05/06 23:51:14 momjian Exp $
27+
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.12 1998/05/06 23:53:48 momjian Exp $
2828
*
2929
*-------------------------------------------------------------------------
3030
*/
@@ -342,6 +342,15 @@ pqReadData(PGconn *conn)
342342
{
343343
if (errno == EINTR)
344344
goto tryAgain;
345+
/* Some systems return EAGAIN/EWOULDBLOCK for no data */
346+
#ifdef EAGAIN
347+
if (errno == EAGAIN)
348+
return 0;
349+
#endif
350+
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
351+
if (errno == EWOULDBLOCK)
352+
return 0;
353+
#endif
345354
sprintf(conn->errorMessage,
346355
"pqReadData() -- read() failed: errno=%d\n%s\n",
347356
errno, strerror(errno));
@@ -374,6 +383,15 @@ pqReadData(PGconn *conn)
374383
{
375384
if (errno == EINTR)
376385
goto tryAgain2;
386+
/* Some systems return EAGAIN/EWOULDBLOCK for no data */
387+
#ifdef EAGAIN
388+
if (errno == EAGAIN)
389+
return 0;
390+
#endif
391+
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
392+
if (errno == EWOULDBLOCK)
393+
return 0;
394+
#endif
377395
sprintf(conn->errorMessage,
378396
"pqReadData() -- read() failed: errno=%d\n%s\n",
379397
errno, strerror(errno));

0 commit comments

Comments
 (0)