On Fri, 2018-04-06 at 23:24 +0000, Robert Haas wrote: > Allow insert and update tuple routing and COPY for foreign tables. > > Also enable this for postgres_fdw. > > Etsuro Fujita, based on an earlier patch by Amit Langote. The larger > patch series of which this is a part has been reviewed by Amit > Langote, David Fetter, Maksim Milyutin, Álvaro Herrera, Stephen Frost, > and me. Minor documentation changes to the final version by me. > > Discussion: > http://postgr.es/m/29906a26-da12-8c86-4fb9-d8f88442f...@lab.ntt.co.jp
This commit makes life hard for foreign data wrappers that support data modifications. If a FDW implements ExecForeignInsert, this commit automatically assumes that it also supports COPY FROM. It will call ExecForeignInsert without calling PlanForeignModify and BeginForeignModify, and a FDW that does not expect that will probably fail. So this commit silently turns a functioning FDW into a broken FDW. That is not nice. Probably not every FDW is aware of this change, and maybe there are FDWs that support INSERT but don't want to support COPY for some reason. I propose that PostgreSQL only allows COPY FROM on a foreign table if the FDW implements BeginForeignInsert. The attached patch implements that. I think this should be backpatched to v11. Yours, Laurenz Albe
From c4b0e871658c757124dad992578da0b60fccf962 Mon Sep 17 00:00:00 2001 From: Laurenz Albe <laurenz.a...@cybertec.at> Date: Sat, 20 Apr 2019 13:36:56 +0200 Subject: [PATCH] COPY FROM on foreign tables requires BeginForeignInsert Commit 3d956d956a introduced COPY FROM support for foreign tables. If a foreign data wrapper supports data modifications, but either has not adapted to this change yet or doesn't want to support COPY FROM for other reasons, it probably got broken by the above commit, because COPY will just call ExecForeignInsert anyway, which might not work because neither PlanForeignModify nor BeginForeignModify have been called. To avoid breaking third-party foreign data wrappers in that way, allow COPY FROM for foreign tables only if the foreign data wrapper implements BeginForeignInsert. --- doc/src/sgml/fdwhandler.sgml | 2 ++ src/backend/commands/copy.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml index 2c07a86637..8cd174a204 100644 --- a/doc/src/sgml/fdwhandler.sgml +++ b/doc/src/sgml/fdwhandler.sgml @@ -724,6 +724,8 @@ BeginForeignInsert(ModifyTableState *mtstate, perform any initialization needed prior to the actual insertion. Subsequently, <function>ExecForeignInsert</function> will be called for each tuple to be inserted into the foreign table. + All foreign data wrappers that support <command>COPY FROM</command> have + to provide this callback function. </para> <para> diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index c39218f8db..944d558cd4 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2857,6 +2857,11 @@ CopyFrom(CopyState cstate) resultRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL) resultRelInfo->ri_FdwRoutine->BeginForeignInsert(mtstate, resultRelInfo); + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE NOT SUPPORTED), + errmsg("cannot copy to foreign table \"%s\"", + RelationGetRelationName(cstate->rel)))); /* Prepare to catch AFTER triggers. */ AfterTriggerBeginQuery(); -- 2.20.1