aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-protocol3.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2013-04-29 06:29:32 -0400
committerRobert Haas <rhaas@postgresql.org>2013-04-29 06:29:32 -0400
commit91fa8532f4053468acc08534a6aac516ccde47b7 (patch)
treedee028ed0f9f985691ca80fc00ce5d978b21ee56 /src/interfaces/libpq/fe-protocol3.c
parent43e7a668499b8a69a62cc539a0fbe6983384339c (diff)
downloadpostgresql-91fa8532f4053468acc08534a6aac516ccde47b7.tar.gz
postgresql-91fa8532f4053468acc08534a6aac516ccde47b7.zip
Attempt to fix error recovery in COPY BOTH mode.
Previously, libpq and the backend had opposite ideas about whether it was necessary for the client to send a CopyDone message after receiving an ErrorResponse, making it impossible to cleanly exit COPY BOTH mode. Fix libpq so that works correctly, adopting the backend's notion that an ErrorResponse kills the copy in both directions. Adjust receivelog.c to avoid a degradation in the quality of the resulting error messages. libpqwalreceiver.c is already doing the right thing, so no adjustment needed there. Add an explicit statement to the documentation explaining how this part of the protocol is supposed to work, in the hopes of avoiding future confusion in this area. Since the consequences of all this confusion are very limited, especially in the back-branches where no client ever attempts to exit COPY BOTH mode without closing the connection entirely, no back-patch.
Diffstat (limited to 'src/interfaces/libpq/fe-protocol3.c')
-rw-r--r--src/interfaces/libpq/fe-protocol3.c31
1 files changed, 16 insertions, 15 deletions
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 7fa090adf35..a7d4f40d38a 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -1466,7 +1466,23 @@ getCopyDataMessage(PGconn *conn)
break;
case 'd': /* Copy Data, pass it back to caller */
return msgLength;
+ case 'c':
+ /*
+ * If this is a CopyDone message, exit COPY_OUT mode and let
+ * caller read status with PQgetResult(). If we're in
+ * COPY_BOTH mode, return to COPY_IN mode.
+ */
+ if (conn->asyncStatus == PGASYNC_COPY_BOTH)
+ conn->asyncStatus = PGASYNC_COPY_IN;
+ else
+ conn->asyncStatus = PGASYNC_BUSY;
+ return -1;
default: /* treat as end of copy */
+ /*
+ * Any other message terminates either COPY_IN or COPY_BOTH
+ * mode.
+ */
+ conn->asyncStatus = PGASYNC_BUSY;
return -1;
}
@@ -1499,22 +1515,7 @@ pqGetCopyData3(PGconn *conn, char **buffer, int async)
*/
msgLength = getCopyDataMessage(conn);
if (msgLength < 0)
- {
- /*
- * On end-of-copy, exit COPY_OUT or COPY_BOTH mode and let caller
- * read status with PQgetResult(). The normal case is that it's
- * Copy Done, but we let parseInput read that. If error, we
- * expect the state was already changed.
- */
- if (msgLength == -1)
- {
- if (conn->asyncStatus == PGASYNC_COPY_BOTH)
- conn->asyncStatus = PGASYNC_COPY_IN;
- else
- conn->asyncStatus = PGASYNC_BUSY;
- }
return msgLength; /* end-of-copy or error */
- }
if (msgLength == 0)
{
/* Don't block if async read requested */