mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
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
This commit is contained in:
parent
edbd51395c
commit
1c2d9cb637
@ -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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,19 +60,21 @@ 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;
|
||||||
|
|
||||||
if (pqReadData(conn) < 0) {
|
if (pqReadData(conn) < 0) {
|
||||||
*errorCodePtr = errno ? errno : EIO;
|
*errorCodePtr = errno ? errno : EIO;
|
||||||
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)
|
|||||||
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] == '.') {
|
conn->inStart = conn->inCursor;
|
||||||
avail += 3;
|
/* Is it the endmarker line? */
|
||||||
connid->res_copyStatus = RES_COPY_FIN;
|
if (bufSize-avail == 3 && buf[-3] == '\\' && buf[-2] == '.') {
|
||||||
break;
|
/* 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;
|
/* We don't have a complete line.
|
||||||
/* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
|
* We'd prefer to leave it in libpq's buffer until the rest arrives,
|
||||||
return bufSize - avail;
|
* 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;
|
errno = 0;
|
||||||
|
|
||||||
if (pqPutnchar(buf, bufSize, conn)) {
|
if (pqPutnchar(buf, bufSize, conn)) {
|
||||||
*errorCodePtr = errno ? errno : EIO;
|
*errorCodePtr = errno ? errno : EIO;
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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:
|
|||||||
{
|
{
|
||||||
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:
|
|||||||
{
|
{
|
||||||
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));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user