Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf208fb4

Browse files
committed
Clean up error cases in psql's COPY TO STDOUT/FROM STDIN code.
Adjust handleCopyOut() to stop trying to write data once it's failedone time. For typical cases such as out-of-disk-space or broken-pipe,additional attempts aren't going to do anything but waste time, andin any case clean truncation of the output seems like a better behaviorthan randomly dropping blocks in the middle.Also remove dubious (and misleadingly documented) attempt to force our wayout of COPY_OUT state if libpq didn't do that. If we did have a situationlike that, it'd be a bug in libpq and would be better fixed there, IMO.We can hope that commitfa4440f took careof any such problems, anyway.Also fix longstanding bug in handleCopyIn(): PQputCopyEnd() only supportsa non-null errormsg parameter in protocol version 3, and will activelyfail if one is passed in version 2. This would've made our attemptsto get out of COPY_IN state after a failure into infinite loops whentalking to pre-7.4 servers.Back-patch the COPY_OUT state change business back to 9.2 where it wasintroduced, and the other two fixes into all supported branches.
1 parentfb47de2 commitf208fb4

File tree

1 file changed

+37
-38
lines changed

1 file changed

+37
-38
lines changed

‎src/bin/psql/copy.c

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -447,15 +447,15 @@ handleCopyOut(PGconn *conn, FILE *copystream)
447447
ret=PQgetCopyData(conn,&buf,0);
448448

449449
if (ret<0)
450-
break;/* done or error */
450+
break;/* done orserver/connectionerror */
451451

452452
if (buf)
453453
{
454-
if (fwrite(buf,1,ret,copystream)!=ret)
454+
if (OK&&fwrite(buf,1,ret,copystream)!=ret)
455455
{
456-
if (OK)/* complain only once, keep readingdata */
457-
psql_error("could not write COPY data: %s\n",
458-
strerror(errno));
456+
psql_error("could not write COPYdata: %s\n",
457+
strerror(errno));
458+
/* complain only once, keep reading data from server */
459459
OK= false;
460460
}
461461
PQfreemem(buf);
@@ -476,29 +476,18 @@ handleCopyOut(PGconn *conn, FILE *copystream)
476476
}
477477

478478
/*
479-
* Check command status and return to normal libpq state. After a
480-
* client-side error, the server will remain ready to deliver data. The
481-
* cleanest thing is to fully drain and discard that data.If the
482-
* client-side error happened early in a large file, this takes a long
483-
* time. Instead, take advantage of the fact that PQexec() will silently
484-
* end any ongoing PGRES_COPY_OUT state. This does cause us to lose the
485-
* results of any commands following the COPY in a single command string.
486-
* It also only works for protocol version 3. XXX should we clean up
487-
* using the slow way when the connection is using protocol version 2?
479+
* Check command status and return to normal libpq state.
488480
*
489-
* We must not ever return with the status still PGRES_COPY_OUT. Our
490-
* caller is unable to distinguish that situation from reaching the next
491-
* COPY in a command string that happened to contain two consecutive COPY
492-
* TO STDOUT commands.We trust that no condition can make PQexec() fail
493-
* indefinitely while retaining status PGRES_COPY_OUT.
481+
* If for some reason libpq is still reporting PGRES_COPY_OUT state, we
482+
* would like to forcibly exit that state, since our caller would be
483+
* unable to distinguish that situation from reaching the next COPY in a
484+
* command string that happened to contain two consecutive COPY TO STDOUT
485+
* commands. However, libpq provides no API for doing that, and in
486+
* principle it's a libpq bug anyway if PQgetCopyData() returns -1 or -2
487+
* but hasn't exited COPY_OUT state internally. So we ignore the
488+
* possibility here.
494489
*/
495-
while (res=PQgetResult(conn),PQresultStatus(res)==PGRES_COPY_OUT)
496-
{
497-
OK= false;
498-
PQclear(res);
499-
500-
PQexec(conn,"-- clear PGRES_COPY_OUT state");
501-
}
490+
res=PQgetResult(conn);
502491
if (PQresultStatus(res)!=PGRES_COMMAND_OK)
503492
{
504493
psql_error("%s",PQerrorMessage(conn));
@@ -541,7 +530,9 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary)
541530
/* got here with longjmp */
542531

543532
/* Terminate data transfer */
544-
PQputCopyEnd(conn,_("canceled by user"));
533+
PQputCopyEnd(conn,
534+
(PQprotocolVersion(conn)<3) ?NULL :
535+
_("canceled by user"));
545536

546537
OK= false;
547538
gotocopyin_cleanup;
@@ -662,29 +653,37 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary)
662653
if (ferror(copystream))
663654
OK= false;
664655

665-
/* Terminate data transfer */
656+
/*
657+
* Terminate data transfer. We can't send an error message if we're using
658+
* protocol version 2.
659+
*/
666660
if (PQputCopyEnd(conn,
667-
OK ?NULL :_("aborted because of read failure")) <=0)
661+
(OK||PQprotocolVersion(conn)<3) ?NULL :
662+
_("aborted because of read failure")) <=0)
668663
OK= false;
669664

670665
copyin_cleanup:
671666

672667
/*
673-
* Check command status and return to normal libpq state
668+
* Check command status and return to normal libpq state.
674669
*
675-
* We must not ever return with the status still PGRES_COPY_IN. Our
676-
* caller is unable to distinguish that situation from reaching the next
677-
* COPY in a command string that happened to contain two consecutive COPY
678-
* FROM STDIN commands. XXX if something makes PQputCopyEnd() fail
679-
* indefinitely while retaining status PGRES_COPY_IN, we get an infinite
680-
* loop. This is more realistic than handleCopyOut()'s counterpart risk.
670+
* We do not want to return with the status still PGRES_COPY_IN: our
671+
* caller would be unable to distinguish that situation from reaching the
672+
* next COPY in a command string that happened to contain two consecutive
673+
* COPY FROM STDIN commands. We keep trying PQputCopyEnd() in the hope
674+
* it'll work eventually. (What's actually likely to happen is that in
675+
* attempting to flush the data, libpq will eventually realize that the
676+
* connection is lost.But that's fine; it will get us out of COPY_IN
677+
* state, which is what we need.)
681678
*/
682679
while (res=PQgetResult(conn),PQresultStatus(res)==PGRES_COPY_IN)
683680
{
684681
OK= false;
685682
PQclear(res);
686-
687-
PQputCopyEnd(pset.db,_("trying to exit copy mode"));
683+
/* We can't send an error message if we're using protocol version 2 */
684+
PQputCopyEnd(conn,
685+
(PQprotocolVersion(conn)<3) ?NULL :
686+
_("trying to exit copy mode"));
688687
}
689688
if (PQresultStatus(res)!=PGRES_COMMAND_OK)
690689
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp