From 1c2d9cb63774f46f70f20ca8daa70f451886da1f Mon Sep 17 00:00:00 2001 From: Bruce Momjian <bruce@momjian.us> Date: Wed, 6 May 1998 23:53:48 +0000 Subject: [PATCH] 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 --- src/bin/pg_dump/pg_dump.c | 5 +-- src/interfaces/libpgtcl/pgtclId.c | 59 ++++++++++++++++++++----------- src/interfaces/libpq/fe-exec.c | 12 ++++--- src/interfaces/libpq/fe-misc.c | 20 ++++++++++- 4 files changed, 69 insertions(+), 27 deletions(-) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 50b4b99514b..f386231d14e 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -21,7 +21,7 @@ * * * 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 * @@ -230,7 +230,8 @@ dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids) sprintf(query, "COPY %s TO stdout;\n", fmtId(classname)); } 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 " "did not execute. Explanation from backend: '%s'.\n" diff --git a/src/interfaces/libpgtcl/pgtclId.c b/src/interfaces/libpgtcl/pgtclId.c index 1707e9b7750..b3985f73216 100644 --- a/src/interfaces/libpgtcl/pgtclId.c +++ b/src/interfaces/libpgtcl/pgtclId.c @@ -12,7 +12,7 @@ * * * 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,19 +60,21 @@ int PgInputProc(DRIVER_INPUT_PROTO) return -1; } - if (connid->res_copyStatus == RES_COPY_FIN) { - return PgEndCopy(connid, errorCodePtr); - } - /* Try to load any newly arrived data */ errno = 0; if (pqReadData(conn) < 0) { - *errorCodePtr = errno ? errno : EIO; - return -1; + *errorCodePtr = errno ? errno : EIO; + 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; @@ -81,19 +83,33 @@ int PgInputProc(DRIVER_INPUT_PROTO) pqGetc(&c, conn) == 0) { *buf++ = c; --avail; - if (c == '\n' && bufSize-avail >= 3) { - if ((bufSize-avail == 3 || buf[-4] == '\n') && - buf[-3] == '\\' && buf[-2] == '.') { - avail += 3; - connid->res_copyStatus = RES_COPY_FIN; - break; + if (c == '\n') { + /* Got a complete line; mark the data removed from libpq */ + 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); */ + return bufSize - avail; } } - /* Accept the data permanently */ - conn->inStart = conn->inCursor; - /* fprintf(stderr, "returning %d chars\n", 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; } /* @@ -116,10 +132,13 @@ int PgOutputProc(DRIVER_OUTPUT_PROTO) errno = 0; if (pqPutnchar(buf, bufSize, conn)) { - *errorCodePtr = errno ? errno : EIO; - return -1; + *errorCodePtr = errno ? errno : EIO; + 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) { (void) pqFlush(conn); if (PgEndCopy(connid, errorCodePtr) == -1) diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index aac0ea0e97b..ae770e197aa 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -7,7 +7,7 @@ * * * 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) return NULL; /* 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; while ((result = PQgetResult(conn)) != NULL) @@ -756,6 +757,9 @@ PQexec(PGconn *conn, const char *query) if (lastResult) PQclear(lastResult); lastResult = result; + if (result->resultStatus == PGRES_COPY_IN || + result->resultStatus == PGRES_COPY_OUT) + break; } return lastResult; } @@ -950,7 +954,7 @@ PQputline(PGconn *conn, const char *s) { if (conn && conn->sock >= 0) { - (void) pqPuts(s, conn); + (void) pqPutnchar(s, strlen(s), conn); } } @@ -988,7 +992,7 @@ PQendcopy(PGconn *conn) result = PQgetResult(conn); /* Expecting a successful result */ - if (result->resultStatus == PGRES_COMMAND_OK) + if (result && result->resultStatus == PGRES_COMMAND_OK) { PQclear(result); return 0; diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index d7fc71dd134..3d3cf2a7197 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -24,7 +24,7 @@ * * * 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: { if (errno == EINTR) 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, "pqReadData() -- read() failed: errno=%d\n%s\n", errno, strerror(errno)); @@ -374,6 +383,15 @@ tryAgain2: { if (errno == EINTR) 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, "pqReadData() -- read() failed: errno=%d\n%s\n", errno, strerror(errno)); -- GitLab