<function>GetForeignPlan</function>. The recommended place to generate
such paths is in the <function>GetForeignUpperPaths</function>
callback function, which is called for each upper relation (i.e., each
post-scan/join processing step), if all the base relations of the query
come from the same FDW.
</para>
<para>
<function>PlanForeignModify</function> and the other callbacks described in
<xref linkend="fdw-callbacks-update"/> are designed around the assumption
that the foreign relation will be scanned in the usual way and then
individual row updates will be driven by a local <literal>ModifyTable</literal>
plan node. This approach is necessary for the general case where an
update requires reading local tables as well as foreign tables.
However, if the operation could be executed entirely by the foreign
server, the FDW could generate a path representing that and insert it
into the <literal>UPPERREL_FINAL</literal> upper relation, where it would
compete against the <literal>ModifyTable</literal> approach. This approach
could also be used to implement remote <literal>SELECT FOR UPDATE</literal>,
rather than using the row locking callbacks described in
<xref linkend="fdw-callbacks-row-locking"/>. Keep in mind that a path
inserted into <literal>UPPERREL_FINAL</literal> is responsible for
implementing <emphasis>all</emphasis> behavior of the query.
</para>
<para>
When planning an <command>UPDATE</command> or <command>DELETE</command>,
<function>PlanForeignModify</function> and <function>PlanDirectModify</function>
can look up the <structname>RelOptInfo</structname>
struct for the foreign table and make use of the
<literal>baserel->fdw_private</literal> data previously created by the
scan-planning functions. However, in <command>INSERT</command> the target
table is not scanned so there is no <structname>RelOptInfo</structname> for it.
The <structname>List</structname> returned by <function>PlanForeignModify</function> has
the same restrictions as the <structfield>fdw_private</structfield> list of a
<structname>ForeignScan</structname> plan node, that is it must contain only
structures that <function>copyObject</function> knows how to copy.
</para>
<para>
<command>INSERT</command> with an <literal>ON CONFLICT</literal> clause does not
support specifying the conflict target, as unique constraints or
exclusion constraints on remote tables are not locally known. This
in turn implies that <literal>ON CONFLICT DO UPDATE</literal> is not supported,
since the specification is mandatory there.
</para>
</sect1>
<sect1 id="fdw-row-locking">
<title>Row Locking in Foreign Data Wrappers</title>
<para>
If an FDW's underlying storage mechanism has a concept of locking
individual rows to prevent concurrent updates of those rows, it is
usually worthwhile for the FDW to perform row-level locking with as
close an approximation as practical to the semantics used in
ordinary <productname>PostgreSQL</productname> tables. There are multiple
considerations involved in this.
</para>
<para>
One key decision to be made is whether to perform <firstterm>early
locking</firstterm> or <firstterm>late locking</firstterm>. In early locking, a row is
locked when it is first retrieved from the underlying store, while in
late locking, the row is locked only when it is known that it needs to
be locked. (The difference arises because some rows may be discarded by
locally-checked restriction or join conditions.) Early locking is much
simpler and avoids extra round trips to a remote store, but it can cause
locking of rows that need not have been locked, resulting in reduced
concurrency or even unexpected deadlocks. Also, late locking is only
possible if the