<structfield>fdw_state</structfield> field is still NULL. Information about
the table to modify is accessible through the
<structname>ForeignScanState</structname> node (in particular, from the underlying
<structname>ForeignScan</structname> plan node, which contains any FDW-private
information provided by <function>PlanDirectModify</function>).
<literal>eflags</literal> contains flag bits describing the executor's
operating mode for this plan node.
</para>
<para>
Note that when <literal>(eflags & EXEC_FLAG_EXPLAIN_ONLY)</literal> is
true, this function should not perform any externally-visible actions;
it should only do the minimum required to make the node state valid
for <function>ExplainDirectModify</function> and <function>EndDirectModify</function>.
</para>
<para>
If the <function>BeginDirectModify</function> pointer is set to
<literal>NULL</literal>, no attempts to execute a direct modification on the
remote server are taken.
</para>
<para>
<programlisting>
TupleTableSlot *
IterateDirectModify(ForeignScanState *node);
</programlisting>
When the <command>INSERT</command>, <command>UPDATE</command> or <command>DELETE</command>
query doesn't have a <literal>RETURNING</literal> clause, just return NULL
after a direct modification on the remote server.
When the query has the clause, fetch one result containing the data
needed for the <literal>RETURNING</literal> calculation, returning it in a
tuple table slot (the node's <structfield>ScanTupleSlot</structfield> should be
used for this purpose). The data that was actually inserted, updated
or deleted must be stored in
<literal>node->resultRelInfo->ri_projectReturning->pi_exprContext->ecxt_scantuple</literal>.
Return NULL if no more rows are available.
Note that this is called in a short-lived memory context that will be
reset between invocations. Create a memory context in
<function>BeginDirectModify</function> if you need longer-lived storage, or use
the <structfield>es_query_cxt</structfield> of the node's <structname>EState</structname>.
</para>
<para>
The rows returned must match the <structfield>fdw_scan_tlist</structfield> target
list if one was supplied, otherwise they must match the row type of the
foreign table being updated. If you choose to optimize away fetching
columns that are not needed for the <literal>RETURNING</literal> calculation,
you should insert nulls in those column positions, or else generate a
<structfield>fdw_scan_tlist</structfield> list with those columns omitted.
</para>
<para>
Whether the query has the clause or not, the query's reported row count
must be incremented by the FDW itself. When the query doesn't have the
clause, the FDW must also increment the row count for the
<structname>ForeignScanState</structname> node in the <command>EXPLAIN ANALYZE</command>
case.
</para>
<para>
If the <function>IterateDirectModify</function> pointer is set to
<literal>NULL</literal>, no attempts to execute a direct modification on the
remote server are taken.
</para>
<para>
<programlisting>
void
EndDirectModify(ForeignScanState *node);
</programlisting>
Clean up following a direct modification on the remote server. It is
normally not important to release palloc'd memory, but for example open
files and connections to the remote server should be cleaned up.
</para>
<para>
If the <function>EndDirectModify</function> pointer is set to
<literal>NULL</literal>, no attempts to execute a direct modification on the
remote server are taken.
</para>
</sect2>
<sect2 id="fdw-callbacks-truncate">
<title>FDW Routines for <command>TRUNCATE</command></title>
<para>
<programlisting>
void
ExecForeignTruncate(List *rels,