]> begriffs open source - ai-pg/blob - full-docs/src/sgml/html/fdw-planning.html
WIP: toc builder
[ai-pg] / full-docs / src / sgml / html / fdw-planning.html
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>58.4. Foreign Data Wrapper Query Planning</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="fdw-helpers.html" title="58.3. Foreign Data Wrapper Helper Functions" /><link rel="next" href="fdw-row-locking.html" title="58.5. Row Locking in Foreign Data Wrappers" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">58.4. Foreign Data Wrapper Query Planning</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="fdw-helpers.html" title="58.3. Foreign Data Wrapper Helper Functions">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="fdwhandler.html" title="Chapter 58. Writing a Foreign Data Wrapper">Up</a></td><th width="60%" align="center">Chapter 58. Writing a Foreign Data Wrapper</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="fdw-row-locking.html" title="58.5. Row Locking in Foreign Data Wrappers">Next</a></td></tr></table><hr /></div><div class="sect1" id="FDW-PLANNING"><div class="titlepage"><div><div><h2 class="title" style="clear: both">58.4. Foreign Data Wrapper Query Planning <a href="#FDW-PLANNING" class="id_link">#</a></h2></div></div></div><p>
3      The FDW callback functions <code class="function">GetForeignRelSize</code>,
4      <code class="function">GetForeignPaths</code>, <code class="function">GetForeignPlan</code>,
5      <code class="function">PlanForeignModify</code>, <code class="function">GetForeignJoinPaths</code>,
6      <code class="function">GetForeignUpperPaths</code>, and <code class="function">PlanDirectModify</code>
7      must fit into the workings of the <span class="productname">PostgreSQL</span> planner.
8      Here are some notes about what they must do.
9     </p><p>
10      The information in <code class="literal">root</code> and <code class="literal">baserel</code> can be used
11      to reduce the amount of information that has to be fetched from the
12      foreign table (and therefore reduce the cost).
13      <code class="literal">baserel-&gt;baserestrictinfo</code> is particularly interesting, as
14      it contains restriction quals (<code class="literal">WHERE</code> clauses) that should be
15      used to filter the rows to be fetched.  (The FDW itself is not required
16      to enforce these quals, as the core executor can check them instead.)
17      <code class="literal">baserel-&gt;reltarget-&gt;exprs</code> can be used to determine which
18      columns need to be fetched; but note that it only lists columns that
19      have to be emitted by the <code class="structname">ForeignScan</code> plan node, not
20      columns that are used in qual evaluation but not output by the query.
21     </p><p>
22      Various private fields are available for the FDW planning functions to
23      keep information in.  Generally, whatever you store in FDW private fields
24      should be palloc'd, so that it will be reclaimed at the end of planning.
25     </p><p>
26      <code class="literal">baserel-&gt;fdw_private</code> is a <code class="type">void</code> pointer that is
27      available for FDW planning functions to store information relevant to
28      the particular foreign table.  The core planner does not touch it except
29      to initialize it to NULL when the <code class="literal">RelOptInfo</code> node is created.
30      It is useful for passing information forward from
31      <code class="function">GetForeignRelSize</code> to <code class="function">GetForeignPaths</code> and/or
32      <code class="function">GetForeignPaths</code> to <code class="function">GetForeignPlan</code>, thereby
33      avoiding recalculation.
34     </p><p>
35      <code class="function">GetForeignPaths</code> can identify the meaning of different
36      access paths by storing private information in the
37      <code class="structfield">fdw_private</code> field of <code class="structname">ForeignPath</code> nodes.
38      <code class="structfield">fdw_private</code> is declared as a <code class="type">List</code> pointer, but
39      could actually contain anything since the core planner does not touch
40      it.  However, best practice is to use a representation that's dumpable
41      by <code class="function">nodeToString</code>, for use with debugging support available
42      in the backend.
43     </p><p>
44      <code class="function">GetForeignPlan</code> can examine the <code class="structfield">fdw_private</code>
45      field of the selected <code class="structname">ForeignPath</code> node, and can generate
46      <code class="structfield">fdw_exprs</code> and <code class="structfield">fdw_private</code> lists to be
47      placed in the <code class="structname">ForeignScan</code> plan node, where they will be
48      available at execution time.  Both of these lists must be
49      represented in a form that <code class="function">copyObject</code> knows how to copy.
50      The <code class="structfield">fdw_private</code> list has no other restrictions and is
51      not interpreted by the core backend in any way.  The
52      <code class="structfield">fdw_exprs</code> list, if not NIL, is expected to contain
53      expression trees that are intended to be executed at run time.  These
54      trees will undergo post-processing by the planner to make them fully
55      executable.
56     </p><p>
57      In <code class="function">GetForeignPlan</code>, generally the passed-in target list can
58      be copied into the plan node as-is.  The passed <code class="literal">scan_clauses</code> list
59      contains the same clauses as <code class="literal">baserel-&gt;baserestrictinfo</code>,
60      but may be re-ordered for better execution efficiency.  In simple cases
61      the FDW can just strip <code class="structname">RestrictInfo</code> nodes from the
62      <code class="literal">scan_clauses</code> list (using <code class="function">extract_actual_clauses</code>) and put
63      all the clauses into the plan node's qual list, which means that all the
64      clauses will be checked by the executor at run time.  More complex FDWs
65      may be able to check some of the clauses internally, in which case those
66      clauses can be removed from the plan node's qual list so that the
67      executor doesn't waste time rechecking them.
68     </p><p>
69      As an example, the FDW might identify some restriction clauses of the
70      form <em class="replaceable"><code>foreign_variable</code></em> <code class="literal">=</code>
71      <em class="replaceable"><code>sub_expression</code></em>, which it determines can be executed on
72      the remote server given the locally-evaluated value of the
73      <em class="replaceable"><code>sub_expression</code></em>.  The actual identification of such a
74      clause should happen during <code class="function">GetForeignPaths</code>, since it would
75      affect the cost estimate for the path.  The path's
76      <code class="structfield">fdw_private</code> field would probably include a pointer to
77      the identified clause's <code class="structname">RestrictInfo</code> node.  Then
78      <code class="function">GetForeignPlan</code> would remove that clause from <code class="literal">scan_clauses</code>,
79      but add the <em class="replaceable"><code>sub_expression</code></em> to <code class="structfield">fdw_exprs</code>
80      to ensure that it gets massaged into executable form.  It would probably
81      also put control information into the plan node's
82      <code class="structfield">fdw_private</code> field to tell the execution functions what
83      to do at run time.  The query transmitted to the remote server would
84      involve something like <code class="literal">WHERE <em class="replaceable"><code>foreign_variable</code></em> =
85      $1</code>, with the parameter value obtained at run time from
86      evaluation of the <code class="structfield">fdw_exprs</code> expression tree.
87     </p><p>
88      Any clauses removed from the plan node's qual list must instead be added
89      to <code class="literal">fdw_recheck_quals</code> or rechecked by
90      <code class="literal">RecheckForeignScan</code> in order to ensure correct behavior
91      at the <code class="literal">READ COMMITTED</code> isolation level.  When a concurrent
92      update occurs for some other table involved in the query, the executor
93      may need to verify that all of the original quals are still satisfied for
94      the tuple, possibly against a different set of parameter values.  Using
95      <code class="literal">fdw_recheck_quals</code> is typically easier than implementing checks
96      inside <code class="literal">RecheckForeignScan</code>, but this method will be
97      insufficient when outer joins have been pushed down, since the join tuples
98      in that case might have some fields go to NULL without rejecting the
99      tuple entirely.
100     </p><p>
101      Another <code class="structname">ForeignScan</code> field that can be filled by FDWs
102      is <code class="structfield">fdw_scan_tlist</code>, which describes the tuples returned by
103      the FDW for this plan node.  For simple foreign table scans this can be
104      set to <code class="literal">NIL</code>, implying that the returned tuples have the
105      row type declared for the foreign table.  A non-<code class="symbol">NIL</code> value must be a
106      target list (list of <code class="structname">TargetEntry</code>s) containing Vars and/or
107      expressions representing the returned columns.  This might be used, for
108      example, to show that the FDW has omitted some columns that it noticed
109      won't be needed for the query.  Also, if the FDW can compute expressions
110      used by the query more cheaply than can be done locally, it could add
111      those expressions to <code class="structfield">fdw_scan_tlist</code>.  Note that join
112      plans (created from paths made by <code class="function">GetForeignJoinPaths</code>) must
113      always supply <code class="structfield">fdw_scan_tlist</code> to describe the set of
114      columns they will return.
115     </p><p>
116      The FDW should always construct at least one path that depends only on
117      the table's restriction clauses.  In join queries, it might also choose
118      to construct path(s) that depend on join clauses, for example
119      <em class="replaceable"><code>foreign_variable</code></em> <code class="literal">=</code>
120      <em class="replaceable"><code>local_variable</code></em>.  Such clauses will not be found in
121      <code class="literal">baserel-&gt;baserestrictinfo</code> but must be sought in the
122      relation's join lists.  A path using such a clause is called a
123      <span class="quote">“<span class="quote">parameterized path</span>”</span>.  It must identify the other relations
124      used in the selected join clause(s) with a suitable value of
125      <code class="literal">param_info</code>; use <code class="function">get_baserel_parampathinfo</code>
126      to compute that value.  In <code class="function">GetForeignPlan</code>, the
127      <em class="replaceable"><code>local_variable</code></em> portion of the join clause would be added
128      to <code class="structfield">fdw_exprs</code>, and then at run time the case works the
129      same as for an ordinary restriction clause.
130     </p><p>
131      If an FDW supports remote joins, <code class="function">GetForeignJoinPaths</code> should
132      produce <code class="structname">ForeignPath</code>s for potential remote joins in much
133      the same way as <code class="function">GetForeignPaths</code> works for base tables.
134      Information about the intended join can be passed forward
135      to <code class="function">GetForeignPlan</code> in the same ways described above.
136      However, <code class="structfield">baserestrictinfo</code> is not relevant for join
137      relations; instead, the relevant join clauses for a particular join are
138      passed to <code class="function">GetForeignJoinPaths</code> as a separate parameter
139      (<code class="literal">extra-&gt;restrictlist</code>).
140     </p><p>
141      An FDW might additionally support direct execution of some plan actions
142      that are above the level of scans and joins, such as grouping or
143      aggregation.  To offer such options, the FDW should generate paths and
144      insert them into the appropriate <em class="firstterm">upper relation</em>.  For
145      example, a path representing remote aggregation should be inserted into
146      the <code class="literal">UPPERREL_GROUP_AGG</code> relation, using <code class="function">add_path</code>.
147      This path will be compared on a cost basis with local aggregation
148      performed by reading a simple scan path for the foreign relation (note
149      that such a path must also be supplied, else there will be an error at
150      plan time).  If the remote-aggregation path wins, which it usually would,
151      it will be converted into a plan in the usual way, by
152      calling <code class="function">GetForeignPlan</code>.  The recommended place to generate
153      such paths is in the <code class="function">GetForeignUpperPaths</code>
154      callback function, which is called for each upper relation (i.e., each
155      post-scan/join processing step), if all the base relations of the query
156      come from the same FDW.
157     </p><p>
158      <code class="function">PlanForeignModify</code> and the other callbacks described in
159      <a class="xref" href="fdw-callbacks.html#FDW-CALLBACKS-UPDATE" title="58.2.4. FDW Routines for Updating Foreign Tables">Section 58.2.4</a> are designed around the assumption
160      that the foreign relation will be scanned in the usual way and then
161      individual row updates will be driven by a local <code class="literal">ModifyTable</code>
162      plan node.  This approach is necessary for the general case where an
163      update requires reading local tables as well as foreign tables.
164      However, if the operation could be executed entirely by the foreign
165      server, the FDW could generate a path representing that and insert it
166      into the <code class="literal">UPPERREL_FINAL</code> upper relation, where it would
167      compete against the <code class="literal">ModifyTable</code> approach.  This approach
168      could also be used to implement remote <code class="literal">SELECT FOR UPDATE</code>,
169      rather than using the row locking callbacks described in
170      <a class="xref" href="fdw-callbacks.html#FDW-CALLBACKS-ROW-LOCKING" title="58.2.6. FDW Routines for Row Locking">Section 58.2.6</a>.  Keep in mind that a path
171      inserted into <code class="literal">UPPERREL_FINAL</code> is responsible for
172      implementing <span class="emphasis"><em>all</em></span> behavior of the query.
173     </p><p>
174      When planning an <code class="command">UPDATE</code> or <code class="command">DELETE</code>,
175      <code class="function">PlanForeignModify</code> and <code class="function">PlanDirectModify</code>
176      can look up the <code class="structname">RelOptInfo</code>
177      struct for the foreign table and make use of the
178      <code class="literal">baserel-&gt;fdw_private</code> data previously created by the
179      scan-planning functions.  However, in <code class="command">INSERT</code> the target
180      table is not scanned so there is no <code class="structname">RelOptInfo</code> for it.
181      The <code class="structname">List</code> returned by <code class="function">PlanForeignModify</code> has
182      the same restrictions as the <code class="structfield">fdw_private</code> list of a
183      <code class="structname">ForeignScan</code> plan node, that is it must contain only
184      structures that <code class="function">copyObject</code> knows how to copy.
185     </p><p>
186      <code class="command">INSERT</code> with an <code class="literal">ON CONFLICT</code> clause does not
187      support specifying the conflict target, as unique constraints or
188      exclusion constraints on remote tables are not locally known. This
189      in turn implies that <code class="literal">ON CONFLICT DO UPDATE</code> is not supported,
190      since the specification is mandatory there.
191     </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="fdw-helpers.html" title="58.3. Foreign Data Wrapper Helper Functions">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="fdwhandler.html" title="Chapter 58. Writing a Foreign Data Wrapper">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="fdw-row-locking.html" title="58.5. Row Locking in Foreign Data Wrappers">Next</a></td></tr><tr><td width="40%" align="left" valign="top">58.3. Foreign Data Wrapper Helper Functions </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 58.5. Row Locking in Foreign Data Wrappers</td></tr></table></div></body></html>