summaryrefslogtreecommitdiff
path: root/src/port
diff options
context:
space:
mode:
authorHeikki Linnakangas2013-02-27 16:17:21 +0000
committerHeikki Linnakangas2013-02-27 16:22:31 +0000
commit3d009e45bde2a2681826ef549637ada76508b597 (patch)
tree6f429ba5f7bbfee65dfd14fcfacd19a2e0ddd053 /src/port
parent73dc003beef859e0b67da463c5e28f5468d3f17f (diff)
Add support for piping COPY to/from an external program.
This includes backend "COPY TO/FROM PROGRAM '...'" syntax, and corresponding psql \copy syntax. Like with reading/writing files, the backend version is superuser-only, and in the psql version, the program is run in the client. In the passing, the psql \copy STDIN/STDOUT syntax is subtly changed: if you the stdin/stdout is quoted, it's now interpreted as a filename. For example, "\copy foo from 'stdin'" now reads from a file called 'stdin', not from standard input. Before this, there was no way to specify a filename called stdin, stdout, pstdin or pstdout. This creates a new function in pgport, wait_result_to_str(), which can be used to convert the exit status of a process, as returned by wait(3), to a human-readable string. Etsuro Fujita, reviewed by Amit Kapila.
Diffstat (limited to 'src/port')
-rw-r--r--src/port/Makefile3
-rw-r--r--src/port/exec.c37
-rw-r--r--src/port/wait_error.c92
3 files changed, 104 insertions, 28 deletions
diff --git a/src/port/Makefile b/src/port/Makefile
index a3db615400e..0774e33f9fb 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -32,7 +32,8 @@ LIBS += $(PTHREAD_LIBS)
OBJS = $(LIBOBJS) chklocale.o dirmod.o erand48.o exec.o fls.o inet_net_ntop.o \
noblock.o path.o pgcheckdir.o pg_crc.o pgmkdirp.o pgsleep.o \
- pgstrcasecmp.o qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
+ pgstrcasecmp.o qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o \
+ wait_error.o
# foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
OBJS_SRV = $(OBJS:%.o=%_srv.o)
diff --git a/src/port/exec.c b/src/port/exec.c
index 18be1408f7a..01203c056cc 100644
--- a/src/port/exec.c
+++ b/src/port/exec.c
@@ -505,14 +505,12 @@ pipe_read_line(char *cmd, char *line, int maxsize)
/*
* pclose() plus useful error reporting
- * Is this necessary? bjm 2004-05-11
- * Originally this was stated to be here because pipe.c had backend linkage.
- * Perhaps that's no longer so now we have got rid of pipe.c amd 2012-03-28
*/
int
pclose_check(FILE *stream)
{
int exitstatus;
+ char *reason;
exitstatus = pclose(stream);
@@ -522,36 +520,21 @@ pclose_check(FILE *stream)
if (exitstatus == -1)
{
/* pclose() itself failed, and hopefully set errno */
- perror("pclose failed");
+ log_error(_("pclose failed: %s"), strerror(errno));
}
- else if (WIFEXITED(exitstatus))
- log_error(_("child process exited with exit code %d"),
- WEXITSTATUS(exitstatus));
- else if (WIFSIGNALED(exitstatus))
-#if defined(WIN32)
- log_error(_("child process was terminated by exception 0x%X"),
- WTERMSIG(exitstatus));
-#elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
+ else
{
- char str[256];
-
- snprintf(str, sizeof(str), "%d: %s", WTERMSIG(exitstatus),
- WTERMSIG(exitstatus) < NSIG ?
- sys_siglist[WTERMSIG(exitstatus)] : "(unknown)");
- log_error(_("child process was terminated by signal %s"), str);
- }
+ reason = wait_result_to_str(exitstatus);
+ log_error("%s", reason);
+#ifdef FRONTEND
+ free(reason);
#else
- log_error(_("child process was terminated by signal %d"),
- WTERMSIG(exitstatus));
+ pfree(reason);
#endif
- else
- log_error(_("child process exited with unrecognized status %d"),
- exitstatus);
-
- return -1;
+ }
+ return exitstatus;
}
-
/*
* set_pglocale_pgservice
*
diff --git a/src/port/wait_error.c b/src/port/wait_error.c
new file mode 100644
index 00000000000..ac9c52b3169
--- /dev/null
+++ b/src/port/wait_error.c
@@ -0,0 +1,92 @@
+/*-------------------------------------------------------------------------
+ *
+ * wait_error.c
+ * Convert a wait/waitpid(2) result code to a human-readable string
+ *
+ *
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/port/wait_error.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/wait.h>
+
+/*
+ * Return a human-readable string explaining the reason a child process
+ * terminated. The argument is a return code returned by wait(2) or
+ * waitpid(2). The result is a translated, palloc'd or malloc'd string.
+ */
+char *
+wait_result_to_str(int exitstatus)
+{
+ char str[512];
+ char *result;
+
+ if (WIFEXITED(exitstatus))
+ {
+ /*
+ * Give more specific error message for some common exit codes that
+ * have a special meaning in shells.
+ */
+ switch (WEXITSTATUS(exitstatus))
+ {
+ case 126:
+ snprintf(str, sizeof(str), _("command not executable"));
+ break;
+
+ case 127:
+ snprintf(str, sizeof(str), _("command not found"));
+ break;
+
+ default:
+ snprintf(str, sizeof(str),
+ _("child process exited with exit code %d"),
+ WEXITSTATUS(exitstatus));
+ }
+ }
+ else if (WIFSIGNALED(exitstatus))
+#if defined(WIN32)
+ snprintf(str, sizeof(str),
+ _("child process was terminated by exception 0x%X"),
+ WTERMSIG(exitstatus));
+#elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
+ {
+ char str2[256];
+
+ snprintf(str2, sizeof(str2), "%d: %s", WTERMSIG(exitstatus),
+ WTERMSIG(exitstatus) < NSIG ?
+ sys_siglist[WTERMSIG(exitstatus)] : "(unknown)");
+ snprintf(str, sizeof(str),
+ _("child process was terminated by signal %s"), str2);
+ }
+#else
+ snprintf(str, sizeof(str),
+ _("child process was terminated by signal %d"),
+ WTERMSIG(exitstatus));
+#endif
+ else
+ snprintf(str, sizeof(str),
+ _("child process exited with unrecognized status %d"),
+ exitstatus);
+
+#ifndef FRONTEND
+ result = pstrdup(str);
+#else
+ result = strdup(str);
+#endif
+ return result;
+}