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

Commitb8f00a4

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 parent801c2dc commitb8f00a4

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
@@ -445,15 +445,15 @@ handleCopyOut(PGconn *conn, FILE *copystream)
445445
ret=PQgetCopyData(conn,&buf,0);
446446

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

450450
if (buf)
451451
{
452-
if (fwrite(buf,1,ret,copystream)!=ret)
452+
if (OK&&fwrite(buf,1,ret,copystream)!=ret)
453453
{
454-
if (OK)/* complain only once, keep readingdata */
455-
psql_error("could not write COPY data: %s\n",
456-
strerror(errno));
454+
psql_error("could not write COPYdata: %s\n",
455+
strerror(errno));
456+
/* complain only once, keep reading data from server */
457457
OK= false;
458458
}
459459
PQfreemem(buf);
@@ -474,29 +474,18 @@ handleCopyOut(PGconn *conn, FILE *copystream)
474474
}
475475

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

541530
/* Terminate data transfer */
542-
PQputCopyEnd(conn,_("canceled by user"));
531+
PQputCopyEnd(conn,
532+
(PQprotocolVersion(conn)<3) ?NULL :
533+
_("canceled by user"));
543534

544535
OK= false;
545536
gotocopyin_cleanup;
@@ -665,29 +656,37 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary)
665656
if (ferror(copystream))
666657
OK= false;
667658

668-
/* Terminate data transfer */
659+
/*
660+
* Terminate data transfer. We can't send an error message if we're using
661+
* protocol version 2.
662+
*/
669663
if (PQputCopyEnd(conn,
670-
OK ?NULL :_("aborted because of read failure")) <=0)
664+
(OK||PQprotocolVersion(conn)<3) ?NULL :
665+
_("aborted because of read failure")) <=0)
671666
OK= false;
672667

673668
copyin_cleanup:
674669

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp