summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2016-09-07 03:55:55 +0000
committerTom Lane2016-09-07 03:55:55 +0000
commit4f405c8ef4704b7fa7fd8ac14a66c5f5d13722c4 (patch)
tree8191c0e40a4d86f330c05d9da2478ac8690d56ee
parent49eb0fd0972d14014dd3533b1f1bf8c94c899883 (diff)
Add a HINT for client-vs-server COPY failure cases.
Users often get confused between COPY and \copy and try to use client-side paths with COPY. The server then cannot find the file (if remote), or sees a permissions problem (if local), or some variant of that. Emit a hint about this in the most common cases. In future we might want to expand the set of errnos for which the hint gets printed, but be conservative for now. Craig Ringer, reviewed by Christoph Berg and Tom Lane Discussion: <CAMsr+YEqtD97qPEzQDqrCt5QiqPbWP_X4hmvy2pQzWC0GWiyPA@mail.gmail.com>
-rw-r--r--src/backend/commands/copy.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index e393c0b39e..432b0ca67b 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -280,7 +280,7 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
/* non-export function prototypes */
static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel, Node *raw_query,
- const Oid queryRelId, List *attnamelist,
+ const Oid queryRelId, List *attnamelist,
List *options);
static void EndCopy(CopyState cstate);
static void ClosePipeToProgram(CopyState cstate);
@@ -1175,7 +1175,7 @@ ProcessCopyOptions(ParseState *pstate,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("option \"%s\" not recognized",
defel->defname),
- parser_errposition(pstate, defel->location)));
+ parser_errposition(pstate, defel->location)));
}
/*
@@ -1785,10 +1785,18 @@ BeginCopyTo(ParseState *pstate,
cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_W);
umask(oumask);
if (cstate->copy_file == NULL)
+ {
+ /* copy errno because ereport subfunctions might change it */
+ int save_errno = errno;
+
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open file \"%s\" for writing: %m",
- cstate->filename)));
+ cstate->filename),
+ (save_errno == ENOENT || save_errno == EACCES) ?
+ errhint("COPY TO instructs the PostgreSQL server process to write a file. "
+ "You may want a client-side facility such as psql's \\copy.") : 0));
+ }
if (fstat(fileno(cstate->copy_file), &st))
ereport(ERROR,
@@ -2810,10 +2818,18 @@ BeginCopyFrom(ParseState *pstate,
cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_R);
if (cstate->copy_file == NULL)
+ {
+ /* copy errno because ereport subfunctions might change it */
+ int save_errno = errno;
+
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open file \"%s\" for reading: %m",
- cstate->filename)));
+ cstate->filename),
+ (save_errno == ENOENT || save_errno == EACCES) ?
+ errhint("COPY FROM instructs the PostgreSQL server process to read a file. "
+ "You may want a client-side facility such as psql's \\copy.") : 0));
+ }
if (fstat(fileno(cstate->copy_file), &st))
ereport(ERROR,