Commit 4f405c8e authored by Tom Lane's avatar Tom Lane

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>
parent 49eb0fd0
...@@ -280,7 +280,7 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0"; ...@@ -280,7 +280,7 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
/* non-export function prototypes */ /* non-export function prototypes */
static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel, Node *raw_query, 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); List *options);
static void EndCopy(CopyState cstate); static void EndCopy(CopyState cstate);
static void ClosePipeToProgram(CopyState cstate); static void ClosePipeToProgram(CopyState cstate);
...@@ -1175,7 +1175,7 @@ ProcessCopyOptions(ParseState *pstate, ...@@ -1175,7 +1175,7 @@ ProcessCopyOptions(ParseState *pstate,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("option \"%s\" not recognized", errmsg("option \"%s\" not recognized",
defel->defname), defel->defname),
parser_errposition(pstate, defel->location))); parser_errposition(pstate, defel->location)));
} }
/* /*
...@@ -1785,10 +1785,18 @@ BeginCopyTo(ParseState *pstate, ...@@ -1785,10 +1785,18 @@ BeginCopyTo(ParseState *pstate,
cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_W); cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_W);
umask(oumask); umask(oumask);
if (cstate->copy_file == NULL) if (cstate->copy_file == NULL)
{
/* copy errno because ereport subfunctions might change it */
int save_errno = errno;
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file \"%s\" for writing: %m", 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)) if (fstat(fileno(cstate->copy_file), &st))
ereport(ERROR, ereport(ERROR,
...@@ -2810,10 +2818,18 @@ BeginCopyFrom(ParseState *pstate, ...@@ -2810,10 +2818,18 @@ BeginCopyFrom(ParseState *pstate,
cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_R); cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_R);
if (cstate->copy_file == NULL) if (cstate->copy_file == NULL)
{
/* copy errno because ereport subfunctions might change it */
int save_errno = errno;
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file \"%s\" for reading: %m", 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)) if (fstat(fileno(cstate->copy_file), &st))
ereport(ERROR, ereport(ERROR,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment