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 row to be locked can be uniquely re-identified later.
Preferably the row identifier should identify a specific version of the
row, as <productname>PostgreSQL</productname> TIDs do.
</para>
<para>
By default, <productname>PostgreSQL</productname> ignores locking considerations
when interfacing to FDWs, but an FDW can perform early locking without
any explicit support from the core code. The API functions described
in <xref linkend="fdw-callbacks-row-locking"/>, which were added
in <productname>PostgreSQL</productname> 9.5, allow an FDW to use late locking if
it wishes.
</para>
<para>
An additional consideration is that in <literal>READ COMMITTED</literal>
isolation mode, <productname>PostgreSQL</productname> may need to re-check
restriction and join conditions against an updated version of some
target tuple. Rechecking join conditions requires re-obtaining copies
of the non-target rows that were previously joined to the target tuple.
When working with standard <productname>PostgreSQL</productname> tables, this is
done by including the TIDs of the non-target tables in the column list
projected through the join, and then re-fetching non-target rows when
required. This approach keeps the join data set compact, but it
requires inexpensive re-fetch capability, as well as a TID that can
uniquely identify the row version to be re-fetched. By default,
therefore, the approach used with foreign tables is to include a copy of
the entire row fetched from a foreign table in the column list projected
through the join. This puts no special demands on the FDW but can
result in reduced performance of merge and hash joins. An FDW that is
capable of meeting the re-fetch requirements can choose to do it the
first way.
</para>
<para>
For an <command>UPDATE</command> or <command>DELETE</command> on a foreign table, it
is recommended that the <literal>ForeignScan</literal> operation on the target
table perform early locking on the