I wrote: > Also, I'm thinking we should back-patch the aspects of the patch > needed to fix the wrong-line-number issue. That appears to have been > introduced in 9.2; older versions of PG get the above example right.
I've done that. For reference' sake, here's an updated patch against HEAD with just the uncommitted changes. regards, tom lane
diff -c new/common.c new-wholepatch/common.c *** new/common.c Mon Mar 10 14:55:49 2014 --- new-wholepatch/common.c Mon Mar 10 12:49:02 2014 *************** *** 631,638 **** * When the command string contained no such COPY command, this function * degenerates to an AcceptResult() call. * ! * Changes its argument to point to the last PGresult of the command string, ! * or NULL if that result was for a COPY FROM STDIN or COPY TO STDOUT. * * Returns true on complete success, false otherwise. Possible failure modes * include purely client-side problems; check the transaction status for the --- 631,637 ---- * When the command string contained no such COPY command, this function * degenerates to an AcceptResult() call. * ! * Changes its argument to point to the last PGresult of the command string. * * Returns true on complete success, false otherwise. Possible failure modes * include purely client-side problems; check the transaction status for the *************** *** 641,654 **** static bool ProcessResult(PGresult **results) { - PGresult *next_result; bool success = true; bool first_cycle = true; ! do { ExecStatusType result_status; bool is_copy; if (!AcceptResult(*results)) { --- 640,653 ---- static bool ProcessResult(PGresult **results) { bool success = true; bool first_cycle = true; ! for (;;) { ExecStatusType result_status; bool is_copy; + PGresult *next_result; if (!AcceptResult(*results)) { *************** *** 693,698 **** --- 692,698 ---- * otherwise use queryFout or cur_cmd_source as appropriate. */ FILE *copystream = pset.copyStream; + PGresult *copy_result; SetCancelConn(); if (result_status == PGRES_COPY_OUT) *************** *** 700,706 **** if (!copystream) copystream = pset.queryFout; success = handleCopyOut(pset.db, ! copystream) && success; } else { --- 700,707 ---- if (!copystream) copystream = pset.queryFout; success = handleCopyOut(pset.db, ! copystream, ! ©_result) && success; } else { *************** *** 708,737 **** copystream = pset.cur_cmd_source; success = handleCopyIn(pset.db, copystream, ! PQbinaryTuples(*results)) && success; } ResetCancelConn(); ! /* ! * Call PQgetResult() once more. In the typical case of a ! * single-command string, it will return NULL. Otherwise, we'll ! * have other results to process that may include other COPYs. ! */ PQclear(*results); ! *results = next_result = PQgetResult(pset.db); } else if (first_cycle) /* fast path: no COPY commands; PQexec visited all results */ break; - else if ((next_result = PQgetResult(pset.db))) - { - /* non-COPY command(s) after a COPY: keep the last one */ - PQclear(*results); - *results = next_result; } first_cycle = false; ! } while (next_result); /* may need this to recover from conn loss during COPY */ if (!first_cycle && !CheckConnection()) --- 709,742 ---- copystream = pset.cur_cmd_source; success = handleCopyIn(pset.db, copystream, ! PQbinaryTuples(*results), ! ©_result) && success; } ResetCancelConn(); ! /* replace the COPY_OUT/IN result with COPY command exit status */ PQclear(*results); ! *results = copy_result; } else if (first_cycle) + { /* fast path: no COPY commands; PQexec visited all results */ break; } + /* + * Check PQgetResult() again. In the typical case of a single-command + * string, it will return NULL. Otherwise, we'll have other results + * to process that may include other COPYs. We keep the last result. + */ + next_result = PQgetResult(pset.db); + if (!next_result) + break; + + PQclear(*results); + *results = next_result; first_cycle = false; ! } /* may need this to recover from conn loss during COPY */ if (!first_cycle && !CheckConnection()) diff -c new/copy.c new-wholepatch/copy.c *** new/copy.c Mon Mar 10 14:56:21 2014 --- new-wholepatch/copy.c Mon Mar 10 12:50:27 2014 *************** *** 429,444 **** * conn should be a database connection that you just issued COPY TO on * and got back a PGRES_COPY_OUT result. * copystream is the file stream for the data to go to. * * result is true if successful, false if not. */ bool ! handleCopyOut(PGconn *conn, FILE *copystream) { bool OK = true; char *buf; int ret; - PGresult *res; for (;;) { --- 429,445 ---- * conn should be a database connection that you just issued COPY TO on * and got back a PGRES_COPY_OUT result. * copystream is the file stream for the data to go to. + * The final status for the COPY is returned into *res (but note + * we already reported the error, if it's not a success result). * * result is true if successful, false if not. */ bool ! handleCopyOut(PGconn *conn, FILE *copystream, PGresult **res) { bool OK = true; char *buf; int ret; for (;;) { *************** *** 485,497 **** * but hasn't exited COPY_OUT state internally. So we ignore the * possibility here. */ ! res = PQgetResult(conn); ! if (PQresultStatus(res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } - PQclear(res); return OK; } --- 486,497 ---- * but hasn't exited COPY_OUT state internally. So we ignore the * possibility here. */ ! *res = PQgetResult(conn); ! if (PQresultStatus(*res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } return OK; } *************** *** 504,509 **** --- 504,511 ---- * and got back a PGRES_COPY_IN result. * copystream is the file stream to read the data from. * isbinary can be set from PQbinaryTuples(). + * The final status for the COPY is returned into *res (but note + * we already reported the error, if it's not a success result). * * result is true if successful, false if not. */ *************** *** 512,523 **** #define COPYBUFSIZ 8192 bool ! handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary) { bool OK; const char *prompt; char buf[COPYBUFSIZ]; - PGresult *res; /* * Establish longjmp destination for exiting from wait-for-input. (This is --- 514,524 ---- #define COPYBUFSIZ 8192 bool ! handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res) { bool OK; const char *prompt; char buf[COPYBUFSIZ]; /* * Establish longjmp destination for exiting from wait-for-input. (This is *************** *** 679,699 **** * connection is lost. But that's fine; it will get us out of COPY_IN * state, which is what we need.) */ ! while (res = PQgetResult(conn), PQresultStatus(res) == PGRES_COPY_IN) { OK = false; ! PQclear(res); /* We can't send an error message if we're using protocol version 2 */ PQputCopyEnd(conn, (PQprotocolVersion(conn) < 3) ? NULL : _("trying to exit copy mode")); } ! if (PQresultStatus(res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } - PQclear(res); return OK; } --- 680,699 ---- * connection is lost. But that's fine; it will get us out of COPY_IN * state, which is what we need.) */ ! while (*res = PQgetResult(conn), PQresultStatus(*res) == PGRES_COPY_IN) { OK = false; ! PQclear(*res); /* We can't send an error message if we're using protocol version 2 */ PQputCopyEnd(conn, (PQprotocolVersion(conn) < 3) ? NULL : _("trying to exit copy mode")); } ! if (PQresultStatus(*res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } return OK; } diff -c new/copy.h new-wholepatch/copy.h *** new/copy.h Mon Mar 10 14:55:49 2014 --- new-wholepatch/copy.h Mon Mar 10 12:49:03 2014 *************** *** 12,22 **** /* handler for \copy */ ! bool do_copy(const char *args); /* lower level processors for copy in/out streams */ ! bool handleCopyOut(PGconn *conn, FILE *copystream); ! bool handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary); #endif --- 12,24 ---- /* handler for \copy */ ! extern bool do_copy(const char *args); /* lower level processors for copy in/out streams */ ! extern bool handleCopyOut(PGconn *conn, FILE *copystream, ! PGresult **res); ! extern bool handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, ! PGresult **res); #endif
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers