From: Tom Lane Date: Wed, 7 Sep 2016 03:55:55 +0000 (-0400) Subject: Add a HINT for client-vs-server COPY failure cases. X-Git-Tag: REL_10_BETA1~1761 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4f405c8ef4704b7fa7fd8ac14a66c5f5d13722c4;p=postgresql 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: --- 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,