mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
Fix tracking of psql script line numbers during \copy from another place.
Commit 08146775acd8bfe0fcc509c71857abb928697171 changed do_copy() to temporarily scribble on pset.cur_cmd_source. That was a mighty ugly bit of code in any case, but in particular it broke handleCopyIn's ability to tell whether it was reading from the current script source file (in which case pset.lineno should be incremented for each line of COPY data), or from someplace else (in which case it shouldn't). The former case still worked, the latter not so much. The visible effect was that line numbers reported for errors in a script file would be wrong if there were an earlier \copy that was reading anything other than inline-in-the-script-file data. To fix, introduce another pset field that holds the file do_copy wants the COPY code to use. This is a little bit ugly, but less so than passing the file down explicitly through several layers that aren't COPY-specific. Extracted from a larger patch by Kumar Rajeev Rastogi; that patch also changes printing of COPY command tags, which is not a bug fix and shouldn't get back-patched. This particular idea was from a suggestion by Amit Khandekar, if I'm reading the thread correctly. Back-patch to 9.2 where the faulty code was introduced.
This commit is contained in:
parent
8722017bbc
commit
e85a5ffba8
@ -628,7 +628,7 @@ StoreQueryTuple(const PGresult *result)
|
|||||||
* command. In that event, we'll marshal data for the COPY and then cycle
|
* command. In that event, we'll marshal data for the COPY and then cycle
|
||||||
* through any subsequent PGresult objects.
|
* through any subsequent PGresult objects.
|
||||||
*
|
*
|
||||||
* When the command string contained no affected COPY command, this function
|
* When the command string contained no such COPY command, this function
|
||||||
* degenerates to an AcceptResult() call.
|
* degenerates to an AcceptResult() call.
|
||||||
*
|
*
|
||||||
* Changes its argument to point to the last PGresult of the command string,
|
* Changes its argument to point to the last PGresult of the command string,
|
||||||
@ -688,13 +688,28 @@ ProcessResult(PGresult **results)
|
|||||||
* Marshal the COPY data. Either subroutine will get the
|
* Marshal the COPY data. Either subroutine will get the
|
||||||
* connection out of its COPY state, then call PQresultStatus()
|
* connection out of its COPY state, then call PQresultStatus()
|
||||||
* once and report any error.
|
* once and report any error.
|
||||||
|
*
|
||||||
|
* If pset.copyStream is set, use that as data source/sink,
|
||||||
|
* otherwise use queryFout or cur_cmd_source as appropriate.
|
||||||
*/
|
*/
|
||||||
|
FILE *copystream = pset.copyStream;
|
||||||
|
|
||||||
SetCancelConn();
|
SetCancelConn();
|
||||||
if (result_status == PGRES_COPY_OUT)
|
if (result_status == PGRES_COPY_OUT)
|
||||||
success = handleCopyOut(pset.db, pset.queryFout) && success;
|
{
|
||||||
|
if (!copystream)
|
||||||
|
copystream = pset.queryFout;
|
||||||
|
success = handleCopyOut(pset.db,
|
||||||
|
copystream) && success;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
success = handleCopyIn(pset.db, pset.cur_cmd_source,
|
{
|
||||||
|
if (!copystream)
|
||||||
|
copystream = pset.cur_cmd_source;
|
||||||
|
success = handleCopyIn(pset.db,
|
||||||
|
copystream,
|
||||||
PQbinaryTuples(*results)) && success;
|
PQbinaryTuples(*results)) && success;
|
||||||
|
}
|
||||||
ResetCancelConn();
|
ResetCancelConn();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -269,11 +269,8 @@ do_copy(const char *args)
|
|||||||
{
|
{
|
||||||
PQExpBufferData query;
|
PQExpBufferData query;
|
||||||
FILE *copystream;
|
FILE *copystream;
|
||||||
FILE *save_file;
|
|
||||||
FILE **override_file;
|
|
||||||
struct copy_options *options;
|
struct copy_options *options;
|
||||||
bool success;
|
bool success;
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
/* parse options */
|
/* parse options */
|
||||||
options = parse_slash_copy(args);
|
options = parse_slash_copy(args);
|
||||||
@ -287,8 +284,6 @@ do_copy(const char *args)
|
|||||||
|
|
||||||
if (options->from)
|
if (options->from)
|
||||||
{
|
{
|
||||||
override_file = &pset.cur_cmd_source;
|
|
||||||
|
|
||||||
if (options->file)
|
if (options->file)
|
||||||
{
|
{
|
||||||
if (options->program)
|
if (options->program)
|
||||||
@ -308,8 +303,6 @@ do_copy(const char *args)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
override_file = &pset.queryFout;
|
|
||||||
|
|
||||||
if (options->file)
|
if (options->file)
|
||||||
{
|
{
|
||||||
if (options->program)
|
if (options->program)
|
||||||
@ -345,6 +338,7 @@ do_copy(const char *args)
|
|||||||
|
|
||||||
if (!options->program)
|
if (!options->program)
|
||||||
{
|
{
|
||||||
|
struct stat st;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* make sure the specified file is not a directory */
|
/* make sure the specified file is not a directory */
|
||||||
@ -375,11 +369,10 @@ do_copy(const char *args)
|
|||||||
if (options->after_tofrom)
|
if (options->after_tofrom)
|
||||||
appendPQExpBufferStr(&query, options->after_tofrom);
|
appendPQExpBufferStr(&query, options->after_tofrom);
|
||||||
|
|
||||||
/* Run it like a user command, interposing the data source or sink. */
|
/* run it like a user command, but with copystream as data source/sink */
|
||||||
save_file = *override_file;
|
pset.copyStream = copystream;
|
||||||
*override_file = copystream;
|
|
||||||
success = SendQuery(query.data);
|
success = SendQuery(query.data);
|
||||||
*override_file = save_file;
|
pset.copyStream = NULL;
|
||||||
termPQExpBuffer(&query);
|
termPQExpBuffer(&query);
|
||||||
|
|
||||||
if (options->file != NULL)
|
if (options->file != NULL)
|
||||||
|
@ -70,6 +70,8 @@ typedef struct _psqlSettings
|
|||||||
FILE *queryFout; /* where to send the query results */
|
FILE *queryFout; /* where to send the query results */
|
||||||
bool queryFoutPipe; /* queryFout is from a popen() */
|
bool queryFoutPipe; /* queryFout is from a popen() */
|
||||||
|
|
||||||
|
FILE *copyStream; /* Stream to read/write for \copy command */
|
||||||
|
|
||||||
printQueryOpt popt;
|
printQueryOpt popt;
|
||||||
|
|
||||||
char *gfname; /* one-shot file output argument for \g */
|
char *gfname; /* one-shot file output argument for \g */
|
||||||
|
@ -118,6 +118,7 @@ main(int argc, char *argv[])
|
|||||||
pset.encoding = PQenv2encoding();
|
pset.encoding = PQenv2encoding();
|
||||||
pset.queryFout = stdout;
|
pset.queryFout = stdout;
|
||||||
pset.queryFoutPipe = false;
|
pset.queryFoutPipe = false;
|
||||||
|
pset.copyStream = NULL;
|
||||||
pset.cur_cmd_source = stdin;
|
pset.cur_cmd_source = stdin;
|
||||||
pset.cur_cmd_interactive = false;
|
pset.cur_cmd_interactive = false;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user