@@ -35,6 +35,7 @@ char *const pgresStatus[] = {
3535"PGRES_TUPLES_OK" ,
3636"PGRES_COPY_OUT" ,
3737"PGRES_COPY_IN" ,
38+ "PGRES_COPY_BOTH" ,
3839"PGRES_BAD_RESPONSE" ,
3940"PGRES_NONFATAL_ERROR" ,
4041"PGRES_FATAL_ERROR"
@@ -174,6 +175,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
174175case PGRES_TUPLES_OK :
175176case PGRES_COPY_OUT :
176177case PGRES_COPY_IN :
178+ case PGRES_COPY_BOTH :
177179/* non-error cases */
178180break ;
179181default :
@@ -1591,6 +1593,12 @@ PQgetResult(PGconn *conn)
15911593else
15921594res = PQmakeEmptyPGresult (conn ,PGRES_COPY_OUT );
15931595break ;
1596+ case PGASYNC_COPY_BOTH :
1597+ if (conn -> result && conn -> result -> resultStatus == PGRES_COPY_BOTH )
1598+ res = pqPrepareAsyncResult (conn );
1599+ else
1600+ res = PQmakeEmptyPGresult (conn ,PGRES_COPY_BOTH );
1601+ break ;
15941602default :
15951603printfPQExpBuffer (& conn -> errorMessage ,
15961604libpq_gettext ("unexpected asyncStatus: %d\n" ),
@@ -1775,6 +1783,13 @@ PQexecStart(PGconn *conn)
17751783return false;
17761784}
17771785}
1786+ else if (resultStatus == PGRES_COPY_BOTH )
1787+ {
1788+ /* We don't allow PQexec during COPY BOTH */
1789+ printfPQExpBuffer (& conn -> errorMessage ,
1790+ libpq_gettext ("PQexec not allowed during COPY BOTH\n" ));
1791+ return false;
1792+ }
17781793/* check for loss of connection, too */
17791794if (conn -> status == CONNECTION_BAD )
17801795return false;
@@ -1798,7 +1813,7 @@ PQexecFinish(PGconn *conn)
17981813 * than one --- but merge error messages if we get more than one error
17991814 * result.
18001815 *
1801- * We have to stop if we see copy in/out, however. We will resume parsing
1816+ * We have to stop if we see copy in/out/both , however. We will resume parsing
18021817 * after application performs the data transfer.
18031818 *
18041819 * Also stop if the connection is lost (else we'll loop infinitely).
@@ -1827,6 +1842,7 @@ PQexecFinish(PGconn *conn)
18271842lastResult = result ;
18281843if (result -> resultStatus == PGRES_COPY_IN ||
18291844result -> resultStatus == PGRES_COPY_OUT ||
1845+ result -> resultStatus == PGRES_COPY_BOTH ||
18301846conn -> status == CONNECTION_BAD )
18311847break ;
18321848}
@@ -2000,7 +2016,7 @@ PQnotifies(PGconn *conn)
20002016}
20012017
20022018/*
2003- * PQputCopyData - send some data to the backend during COPY IN
2019+ * PQputCopyData - send some data to the backend during COPY IN or COPY BOTH
20042020 *
20052021 * Returns 1 if successful, 0 if data could not be sent (only possible
20062022 * in nonblock mode), or -1 if an error occurs.
@@ -2010,7 +2026,8 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
20102026{
20112027if (!conn )
20122028return -1 ;
2013- if (conn -> asyncStatus != PGASYNC_COPY_IN )
2029+ if (conn -> asyncStatus != PGASYNC_COPY_IN &&
2030+ conn -> asyncStatus != PGASYNC_COPY_BOTH )
20142031{
20152032printfPQExpBuffer (& conn -> errorMessage ,
20162033libpq_gettext ("no COPY in progress\n" ));
@@ -2148,6 +2165,7 @@ PQputCopyEnd(PGconn *conn, const char *errormsg)
21482165
21492166/*
21502167 * PQgetCopyData - read a row of data from the backend during COPY OUT
2168+ * or COPY BOTH
21512169 *
21522170 * If successful, sets *buffer to point to a malloc'd row of data, and
21532171 * returns row length (always > 0) as result.
@@ -2161,7 +2179,8 @@ PQgetCopyData(PGconn *conn, char **buffer, int async)
21612179* buffer = NULL ;/* for all failure cases */
21622180if (!conn )
21632181return -2 ;
2164- if (conn -> asyncStatus != PGASYNC_COPY_OUT )
2182+ if (conn -> asyncStatus != PGASYNC_COPY_OUT &&
2183+ conn -> asyncStatus != PGASYNC_COPY_BOTH )
21652184{
21662185printfPQExpBuffer (& conn -> errorMessage ,
21672186libpq_gettext ("no COPY in progress\n" ));