summaryrefslogtreecommitdiff
path: root/doc/src
diff options
context:
space:
mode:
Diffstat (limited to 'doc/src')
-rw-r--r--doc/src/sgml/fdwhandler.sgml42
1 files changed, 39 insertions, 3 deletions
diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml
index 1533a6bf80c..0090e2427eb 100644
--- a/doc/src/sgml/fdwhandler.sgml
+++ b/doc/src/sgml/fdwhandler.sgml
@@ -168,7 +168,8 @@ GetForeignPlan (PlannerInfo *root,
Oid foreigntableid,
ForeignPath *best_path,
List *tlist,
- List *scan_clauses);
+ List *scan_clauses,
+ Plan *outer_plan);
</programlisting>
Create a <structname>ForeignScan</> plan node from the selected foreign
@@ -765,6 +766,35 @@ RefetchForeignRow (EState *estate,
See <xref linkend="fdw-row-locking"> for more information.
</para>
+ <para>
+<programlisting>
+bool
+RecheckForeignScan (ForeignScanState *node, TupleTableSlot *slot);
+</programlisting>
+ Recheck that a previously-returned tuple still matches the relevant
+ scan and join qualifiers, and possibly provide a modified version of
+ the tuple. For foreign data wrappers which do not perform join pushdown,
+ it will typically be more convenient to set this to <literal>NULL</> and
+ instead set <structfield>fdw_recheck_quals</structfield> appropriately.
+ When outer joins are pushed down, however, it isn't sufficient to
+ reapply the checks relevant to all the base tables to the result tuple,
+ even if all needed attributes are present, because failure to match some
+ qualifier might result in some attributes going to NULL, rather than in
+ no tuple being returned. <literal>RecheckForeignScan</> can recheck
+ qualifiers and return true if they are still satisfied and false
+ otherwise, but it can also store a replacement tuple into the supplied
+ slot.
+ </para>
+
+ <para>
+ To implement join pushdown, a foreign data wrapper will typically
+ construct an alternative local join plan which is used only for
+ rechecks; this will become the outer subplan of the
+ <literal>ForeignScan</>. When a recheck is required, this subplan
+ can be executed and the resulting tuple can be stored in the slot.
+ This plan need not be efficient since no base table will return more
+ that one row; for example, it may implement all joins as nested loops.
+ </para>
</sect2>
<sect2 id="fdw-callbacks-explain">
@@ -1137,11 +1167,17 @@ GetForeignServerByName(const char *name, bool missing_ok);
<para>
Any clauses removed from the plan node's qual list must instead be added
- to <literal>fdw_recheck_quals</> in order to ensure correct behavior
+ to <literal>fdw_recheck_quals</> or rechecked by
+ <literal>RecheckForeignScan</> in order to ensure correct behavior
at the <literal>READ COMMITTED</> isolation level. When a concurrent
update occurs for some other table involved in the query, the executor
may need to verify that all of the original quals are still satisfied for
- the tuple, possibly against a different set of parameter values.
+ the tuple, possibly against a different set of parameter values. Using
+ <literal>fdw_recheck_quals</> is typically easier than implementing checks
+ inside <literal>RecheckForeignScan</>, but this method will be
+ insufficient when outer joins have been pushed down, since the join tuples
+ in that case might have some fields go to NULL without rejecting the
+ tuple entirely.
</para>
<para>