summaryrefslogtreecommitdiff
path: root/doc/src
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2015-12-08 12:31:03 -0500
committerRobert Haas <rhaas@postgresql.org>2015-12-08 12:54:33 -0500
commit325b357bc255149c5ace7d77f5c15c941bafef0a (patch)
tree46ec7eba83520a4746b584b1065805682507c9bd /doc/src
parent25517ee14c1a018876b64dce73e8f7fb7e937783 (diff)
Allow foreign and custom joins to handle EvalPlanQual rechecks.
Commit e7cb7ee14555cc9c5773e2c102efd6371f6f2005 provided basic infrastructure for allowing a foreign data wrapper or custom scan provider to replace a join of one or more tables with a scan. However, this infrastructure failed to take into account the need for possible EvalPlanQual rechecks, and ExecScanFetch would fail an assertion (or just overwrite memory) if such a check was attempted for a plan containing a pushed-down join. To fix, adjust the EPQ machinery to skip some processing steps when scanrelid == 0, making those the responsibility of scan's recheck method, which also has the responsibility in this case of correctly populating the relevant slot. To allow foreign scans to gain control in the right place to make use of this new facility, add a new, optional RecheckForeignScan method. Also, allow a foreign scan to have a child plan, which can be used to correctly populate the slot (or perhaps for something else, but this is the only use currently envisioned). KaiGai Kohei, reviewed by Robert Haas, Etsuro Fujita, and Kyotaro Horiguchi.
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>