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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers