OSDN Git Service

It seems the regression tests don't cover copy in/out at all, so
authorBruce Momjian <bruce@momjian.us>
Wed, 6 May 1998 23:53:48 +0000 (23:53 +0000)
committerBruce Momjian <bruce@momjian.us>
Wed, 6 May 1998 23:53:48 +0000 (23:53 +0000)
code that I had assumed was working had not been tested.  Naturally,
it was broken ...

Tom Lane

src/bin/pg_dump/pg_dump.c
src/interfaces/libpgtcl/pgtclId.c
src/interfaces/libpq/fe-exec.c
src/interfaces/libpq/fe-misc.c

index 50b4b99..f386231 100644 (file)
@@ -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"
index 1707e9b..b3985f7 100644 (file)
@@ -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)
index aac0ea0..ae770e1 100644 (file)
@@ -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;
index d7fc71d..3d3cf2a 100644 (file)
@@ -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));