ignore-process-exit-status-after-close.patch
text/x-patch
Filename: ignore-process-exit-status-after-close.patch
Type: text/x-patch
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/commands/copy.c | 17 | 1 |
| src/backend/storage/file/fd.c | 11 | 3 |
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index b58a74f4e3..c7728f6d6e 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -219,6 +219,12 @@ typedef struct CopyStateData
char *raw_buf;
int raw_buf_index; /* next byte to process */
int raw_buf_len; /* total # of bytes stored */
+
+ /*
+ * We ignore errors signaled from called proram in ClosePipeToProgram()
+ * when we close our side of pipe before we receive EOF.
+ */
+ bool eof_reached;
} CopyStateData;
/* DestReceiver for COPY (query) TO */
@@ -1726,12 +1732,19 @@ ClosePipeToProgram(CopyState cstate)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not close pipe to external command: %m")));
- else if (pclose_rc != 0)
+ else if (cstate->eof_reached && pclose_rc != 0)
+ {
+ /*
+ * If the called program terminated on error after we closed the pipe
+ * on our reading end, assume it's OK; we must have chosen to stop
+ * reading its output early.
+ */
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
errmsg("program \"%s\" failed",
cstate->filename),
errdetail_internal("%s", wait_result_to_str(pclose_rc))));
+ }
}
/*
@@ -3525,7 +3538,10 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
/* read raw fields in the next line */
if (!NextCopyFromRawFields(cstate, &field_strings, &fldct))
+ {
+ cstate->eof_reached = true;
return false;
+ }
/* check for overflowing fields */
if (nfields > 0 && fldct > nfields)
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 8dd51f1767..6cec85e2c1 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -2430,11 +2430,16 @@ OpenTransientFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
* Routines that want to initiate a pipe stream should use OpenPipeStream
* rather than plain popen(). This lets fd.c deal with freeing FDs if
* necessary. When done, call ClosePipeStream rather than pclose.
+ *
+ * This function also ensures that the popen'd program is run with default
+ * SIGPIPE processing, rather than the SIG_IGN setting the backend normally
+ * uses. This ensures desirable response to, eg, closing a read pipe early.
*/
FILE *
OpenPipeStream(const char *command, const char *mode)
{
FILE *file;
+ int save_errno;
DO_DB(elog(LOG, "OpenPipeStream: Allocated %d (%s)",
numAllocatedDescs, command));
@@ -2452,8 +2457,13 @@ OpenPipeStream(const char *command, const char *mode)
TryAgain:
fflush(stdout);
fflush(stderr);
+ pqsignal(SIGPIPE, SIG_DFL);
errno = 0;
- if ((file = popen(command, mode)) != NULL)
+ file = popen(command, mode);
+ save_errno = errno;
+ pqsignal(SIGPIPE, SIG_IGN);
+ errno = save_errno;
+ if (file != NULL)
{
AllocateDesc *desc = &allocatedDescs[numAllocatedDescs];
@@ -2466,8 +2476,6 @@ TryAgain:
if (errno == EMFILE || errno == ENFILE)
{
- int save_errno = errno;
-
ereport(LOG,
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
errmsg("out of file descriptors: %m; release and retry")));