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