related to http://www.postgresql.org/message-id/bf2827dcce55594c8d7a8f7ffd3ab7713ddb1...@szxeml508-mbx.china.huawei.com
Hello 1. I had to rebase this patch - actualised version is attached - I merged two patches to one 2. The psql code is compiled without issues after patching 3. All regress tests are passed without errors 5. We like this feature - it shows interesting info without any slowdown - psql copy command is more consistent with server side copy statement from psql perspective. This patch is ready for commit Regards Pavel
*** ./src/bin/psql/common.c.orig 2014-01-29 21:09:07.108862537 +0100 --- ./src/bin/psql/common.c 2014-01-29 21:09:42.810920907 +0100 *************** *** 631,638 **** * When the command string contained no affected 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 affected 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 *************** *** 689,709 **** * connection out of its COPY state, then call PQresultStatus() * once and report any error. */ SetCancelConn(); if (result_status == PGRES_COPY_OUT) ! success = handleCopyOut(pset.db, pset.queryFout) && success; else ! success = handleCopyIn(pset.db, pset.cur_cmd_source, ! 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 */ --- 688,723 ---- * connection out of its COPY state, then call PQresultStatus() * once and report any error. */ + + /* + * If this is second copy; then it will be definately not \copy, + * and also it can not be from any user given file. So pass the + * value of copystream as NULL, so that read/wrie happens on + * already set cur_cmd_source/queryFout. + */ SetCancelConn(); if (result_status == PGRES_COPY_OUT) ! success = handleCopyOut(pset.db, ! (first_cycle ? pset.copyStream : NULL), ! results) && success; else ! success = handleCopyIn(pset.db, ! (first_cycle ? pset.copyStream : NULL), ! PQbinaryTuples(*results), ! 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. + * It keeps last result. */ ! if ((next_result = PQgetResult(pset.db))) ! { ! PQclear(*results); ! *results = next_result; ! } } else if (first_cycle) /* fast path: no COPY commands; PQexec visited all results */ *** ./src/bin/psql/copy.c.orig 2014-01-29 21:09:15.131875660 +0100 --- ./src/bin/psql/copy.c 2014-01-29 21:09:42.811920909 +0100 *************** *** 269,276 **** { PQExpBufferData query; FILE *copystream; - FILE *save_file; - FILE **override_file; struct copy_options *options; bool success; struct stat st; --- 269,274 ---- *************** *** 287,294 **** if (options->from) { - override_file = &pset.cur_cmd_source; - if (options->file) { if (options->program) --- 285,290 ---- *************** *** 308,315 **** } else { - override_file = &pset.queryFout; - if (options->file) { if (options->program) --- 304,309 ---- *************** *** 369,378 **** appendPQExpBufferStr(&query, options->after_tofrom); /* Run it like a user command, interposing the data source or sink. */ ! save_file = *override_file; ! *override_file = copystream; success = SendQuery(query.data); ! *override_file = save_file; termPQExpBuffer(&query); if (options->file != NULL) --- 363,371 ---- appendPQExpBufferStr(&query, options->after_tofrom); /* Run it like a user command, interposing the data source or sink. */ ! pset.copyStream = copystream; success = SendQuery(query.data); ! pset.copyStream = NULL; termPQExpBuffer(&query); if (options->file != NULL) *************** *** 433,444 **** * result is true if successful, false if not. */ bool ! handleCopyOut(PGconn *conn, FILE *copystream) { bool OK = true; char *buf; int ret; ! PGresult *res; for (;;) { --- 426,439 ---- * result is true if successful, false if not. */ bool ! handleCopyOut(PGconn *conn, FILE *copystream, PGresult **res) { bool OK = true; char *buf; int ret; ! ! if (!copystream) ! copystream = pset.queryFout; for (;;) { *************** *** 490,508 **** * TO STDOUT commands. We trust that no condition can make PQexec() fail * indefinitely while retaining status PGRES_COPY_OUT. */ ! while (res = PQgetResult(conn), PQresultStatus(res) == PGRES_COPY_OUT) { OK = false; ! PQclear(res); PQexec(conn, "-- clear PGRES_COPY_OUT state"); } ! if (PQresultStatus(res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } - PQclear(res); return OK; } --- 485,502 ---- * TO STDOUT commands. We trust that no condition can make PQexec() fail * indefinitely while retaining status PGRES_COPY_OUT. */ ! while (*res = PQgetResult(conn), PQresultStatus(*res) == PGRES_COPY_OUT) { OK = false; ! PQclear(*res); PQexec(conn, "-- clear PGRES_COPY_OUT state"); } ! if (PQresultStatus(*res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } return OK; } *************** *** 523,534 **** #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 --- 517,530 ---- #define COPYBUFSIZ 8192 bool ! handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res) { bool OK; const char *prompt; char buf[COPYBUFSIZ]; ! ! if (!copystream) ! copystream = pset.cur_cmd_source; /* * Establish longjmp destination for exiting from wait-for-input. (This is *************** *** 656,663 **** } } ! if (copystream == pset.cur_cmd_source) ! pset.lineno++; } } --- 652,658 ---- } } ! pset.lineno++; } } *************** *** 682,700 **** * indefinitely while retaining status PGRES_COPY_IN, we get an infinite * loop. This is more realistic than handleCopyOut()'s counterpart risk. */ ! while (res = PQgetResult(conn), PQresultStatus(res) == PGRES_COPY_IN) { OK = false; ! PQclear(res); PQputCopyEnd(pset.db, _("trying to exit copy mode")); } ! if (PQresultStatus(res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } - PQclear(res); return OK; } --- 677,694 ---- * indefinitely while retaining status PGRES_COPY_IN, we get an infinite * loop. This is more realistic than handleCopyOut()'s counterpart risk. */ ! while (*res = PQgetResult(conn), PQresultStatus(*res) == PGRES_COPY_IN) { OK = false; ! PQclear(*res); PQputCopyEnd(pset.db, _("trying to exit copy mode")); } ! if (PQresultStatus(*res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } return OK; } *** ./src/bin/psql/copy.h.orig 2014-01-29 21:09:21.264885699 +0100 --- ./src/bin/psql/copy.h 2014-01-29 21:09:42.811920909 +0100 *************** *** 16,22 **** /* lower level processors for copy in/out streams */ ! bool handleCopyOut(PGconn *conn, FILE *copystream); ! bool handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary); #endif --- 16,22 ---- /* lower level processors for copy in/out streams */ ! bool handleCopyOut(PGconn *conn, FILE *copystream, PGresult **res); ! bool handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res); #endif *** ./src/bin/psql/settings.h.orig 2014-01-29 21:09:28.060896814 +0100 --- ./src/bin/psql/settings.h 2014-01-29 21:09:42.811920909 +0100 *************** *** 70,75 **** --- 70,77 ---- FILE *queryFout; /* where to send the query results */ bool queryFoutPipe; /* queryFout is from a popen() */ + FILE *copyStream; /* Stream to read/write for copy command */ + printQueryOpt popt; char *gfname; /* one-shot file output argument for \g */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers