aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2016-09-06 23:55:55 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2016-09-06 23:55:55 -0400
commit4f405c8ef4704b7fa7fd8ac14a66c5f5d13722c4 (patch)
tree8191c0e40a4d86f330c05d9da2478ac8690d56ee /src
parent49eb0fd0972d14014dd3533b1f1bf8c94c899883 (diff)
downloadpostgresql-4f405c8ef4704b7fa7fd8ac14a66c5f5d13722c4.tar.gz
postgresql-4f405c8ef4704b7fa7fd8ac14a66c5f5d13722c4.zip
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>
Diffstat (limited to 'src')
-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 e393c0b39ea..432b0ca67ba 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,