Commit 1c2d9cb6 authored by Bruce Momjian's avatar Bruce Momjian

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
parent edbd5139
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.70 1998/04/07 22:36:38 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.71 1998/05/06 23:53:27 momjian Exp $
* *
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
* *
...@@ -230,7 +230,8 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids) ...@@ -230,7 +230,8 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids)
sprintf(query, "COPY %s TO stdout;\n", fmtId(classname)); sprintf(query, "COPY %s TO stdout;\n", fmtId(classname));
} }
res = PQexec(g_conn, query); res = PQexec(g_conn, query);
if (!res) if (!res ||
PQresultStatus(res) == PGRES_FATAL_ERROR)
{ {
fprintf(stderr, "SQL query to dump the contents of Table %s " fprintf(stderr, "SQL query to dump the contents of Table %s "
"did not execute. Explanation from backend: '%s'.\n" "did not execute. Explanation from backend: '%s'.\n"
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.9 1998/05/06 23:51:00 momjian Exp $ * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.10 1998/05/06 23:53:30 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -60,10 +60,6 @@ int PgInputProc(DRIVER_INPUT_PROTO) ...@@ -60,10 +60,6 @@ int PgInputProc(DRIVER_INPUT_PROTO)
return -1; return -1;
} }
if (connid->res_copyStatus == RES_COPY_FIN) {
return PgEndCopy(connid, errorCodePtr);
}
/* Try to load any newly arrived data */ /* Try to load any newly arrived data */
errno = 0; errno = 0;
...@@ -72,7 +68,13 @@ int PgInputProc(DRIVER_INPUT_PROTO) ...@@ -72,7 +68,13 @@ int PgInputProc(DRIVER_INPUT_PROTO)
return -1; return -1;
} }
/* Move data from libpq's buffer to tcl's */ /* Move data from libpq's buffer to Tcl's.
* We want to accept data only in units of whole lines,
* not partial lines. This ensures that we can recognize
* the terminator line "\\.\n". (Otherwise, if it happened
* to cross a packet/buffer boundary, we might hand the first
* one or two characters off to Tcl, which we shouldn't.)
*/
conn->inCursor = conn->inStart; conn->inCursor = conn->inStart;
...@@ -81,19 +83,33 @@ int PgInputProc(DRIVER_INPUT_PROTO) ...@@ -81,19 +83,33 @@ int PgInputProc(DRIVER_INPUT_PROTO)
pqGetc(&c, conn) == 0) { pqGetc(&c, conn) == 0) {
*buf++ = c; *buf++ = c;
--avail; --avail;
if (c == '\n' && bufSize-avail >= 3) { if (c == '\n') {
if ((bufSize-avail == 3 || buf[-4] == '\n') && /* Got a complete line; mark the data removed from libpq */
buf[-3] == '\\' && buf[-2] == '.') {
avail += 3;
connid->res_copyStatus = RES_COPY_FIN;
break;
}
}
}
/* Accept the data permanently */
conn->inStart = conn->inCursor; conn->inStart = conn->inCursor;
/* Is it the endmarker line? */
if (bufSize-avail == 3 && buf[-3] == '\\' && buf[-2] == '.') {
/* Yes, change state and return 0 */
return PgEndCopy(connid, errorCodePtr);
}
/* No, return the data to Tcl */
/* fprintf(stderr, "returning %d chars\n", bufSize - avail); */ /* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
return bufSize - avail; return bufSize - avail;
}
}
/* We don't have a complete line.
* We'd prefer to leave it in libpq's buffer until the rest arrives,
* but there is a special case: what if the line is longer than the
* buffer Tcl is offering us? In that case we'd better hand over
* a partial line, else we'd get into an infinite loop.
* Do this in a way that ensures we can't misrecognize a terminator
* line later: leave last 3 characters in libpq buffer.
*/
if (avail == 0 && bufSize > 3) {
conn->inStart = conn->inCursor - 3;
return bufSize - 3;
}
return 0;
} }
/* /*
...@@ -120,6 +136,9 @@ int PgOutputProc(DRIVER_OUTPUT_PROTO) ...@@ -120,6 +136,9 @@ int PgOutputProc(DRIVER_OUTPUT_PROTO)
return -1; return -1;
} }
/* This assumes Tcl script will write the terminator line
* in a single operation; maybe not such a good assumption?
*/
if (bufSize >= 3 && strncmp(&buf[bufSize-3], "\\.\n", 3) == 0) { if (bufSize >= 3 && strncmp(&buf[bufSize-3], "\\.\n", 3) == 0) {
(void) pqFlush(conn); (void) pqFlush(conn);
if (PgEndCopy(connid, errorCodePtr) == -1) if (PgEndCopy(connid, errorCodePtr) == -1)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.50 1998/05/06 23:51:13 momjian Exp $ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.51 1998/05/06 23:53:38 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -748,7 +748,8 @@ PQexec(PGconn *conn, const char *query) ...@@ -748,7 +748,8 @@ PQexec(PGconn *conn, const char *query)
return NULL; return NULL;
/* For backwards compatibility, return the last result if there are /* For backwards compatibility, return the last result if there are
* more than one. * more than one. We have to stop if we see copy in/out, however.
* We will resume parsing when application calls PQendcopy.
*/ */
lastResult = NULL; lastResult = NULL;
while ((result = PQgetResult(conn)) != NULL) while ((result = PQgetResult(conn)) != NULL)
...@@ -756,6 +757,9 @@ PQexec(PGconn *conn, const char *query) ...@@ -756,6 +757,9 @@ PQexec(PGconn *conn, const char *query)
if (lastResult) if (lastResult)
PQclear(lastResult); PQclear(lastResult);
lastResult = result; lastResult = result;
if (result->resultStatus == PGRES_COPY_IN ||
result->resultStatus == PGRES_COPY_OUT)
break;
} }
return lastResult; return lastResult;
} }
...@@ -950,7 +954,7 @@ PQputline(PGconn *conn, const char *s) ...@@ -950,7 +954,7 @@ PQputline(PGconn *conn, const char *s)
{ {
if (conn && conn->sock >= 0) if (conn && conn->sock >= 0)
{ {
(void) pqPuts(s, conn); (void) pqPutnchar(s, strlen(s), conn);
} }
} }
...@@ -988,7 +992,7 @@ PQendcopy(PGconn *conn) ...@@ -988,7 +992,7 @@ PQendcopy(PGconn *conn)
result = PQgetResult(conn); result = PQgetResult(conn);
/* Expecting a successful result */ /* Expecting a successful result */
if (result->resultStatus == PGRES_COMMAND_OK) if (result && result->resultStatus == PGRES_COMMAND_OK)
{ {
PQclear(result); PQclear(result);
return 0; return 0;
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.11 1998/05/06 23:51:14 momjian Exp $ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.12 1998/05/06 23:53:48 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -342,6 +342,15 @@ tryAgain: ...@@ -342,6 +342,15 @@ tryAgain:
{ {
if (errno == EINTR) if (errno == EINTR)
goto tryAgain; goto tryAgain;
/* Some systems return EAGAIN/EWOULDBLOCK for no data */
#ifdef EAGAIN
if (errno == EAGAIN)
return 0;
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
if (errno == EWOULDBLOCK)
return 0;
#endif
sprintf(conn->errorMessage, sprintf(conn->errorMessage,
"pqReadData() -- read() failed: errno=%d\n%s\n", "pqReadData() -- read() failed: errno=%d\n%s\n",
errno, strerror(errno)); errno, strerror(errno));
...@@ -374,6 +383,15 @@ tryAgain2: ...@@ -374,6 +383,15 @@ tryAgain2:
{ {
if (errno == EINTR) if (errno == EINTR)
goto tryAgain2; goto tryAgain2;
/* Some systems return EAGAIN/EWOULDBLOCK for no data */
#ifdef EAGAIN
if (errno == EAGAIN)
return 0;
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
if (errno == EWOULDBLOCK)
return 0;
#endif
sprintf(conn->errorMessage, sprintf(conn->errorMessage,
"pqReadData() -- read() failed: errno=%d\n%s\n", "pqReadData() -- read() failed: errno=%d\n%s\n",
errno, strerror(errno)); errno, strerror(errno));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment