Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9e70398

Browse files
committed
Rethink the GetForeignUpperPaths API (again).
In the previous design, the GetForeignUpperPaths FDW callback hook was called before we got around to labeling upper relations with the proper consider_parallel flag; this meant that any upper paths created by an FDW would be marked not-parallel-safe. While that's probably just as well right now, we aren't going to want it to be true forever. Hence, abandon the idea that FDWs should be allowed to inject upper paths before the core code has gotten around to creating the relevant upper relation. (Well, actually they still can, but it's on their own heads how well it works.) Instead, adopt the same API already designed for create_upper_paths_hook: we call GetForeignUpperPaths after each upperrel has been created and populated with the paths the core planner knows how to make.
1 parent 5ce5e4a commit 9e70398

File tree

6 files changed

+135
-54
lines changed

6 files changed

+135
-54
lines changed

doc/src/sgml/fdwhandler.sgml

+35-20
Original file line numberDiff line numberDiff line change
@@ -357,19 +357,34 @@ GetForeignJoinPaths (PlannerInfo *root,
357357
<programlisting>
358358
void
359359
GetForeignUpperPaths (PlannerInfo *root,
360-
RelOptInfo *scan_join_rel);
360+
UpperRelationKind stage,
361+
RelOptInfo *input_rel,
362+
RelOptInfo *output_rel);
361363
</programlisting>
362364
Create possible access paths for <firstterm>upper relation</> processing,
363365
which is the planner's term for all post-scan/join query processing, such
364366
as aggregation, window functions, sorting, and table updates. This
365367
optional function is called during query planning. Currently, it is
366368
called only if all base relation(s) involved in the query belong to the
367369
same FDW. This function should generate <structname>ForeignPath</>
368-
path(s) for the steps that the FDW knows how to perform remotely, and
369-
call <function>add_path</> to add these paths to the appropriate upper
370-
relation. As with <function>GetForeignJoinPaths</>, it is not necessary
371-
that this function succeed in creating any paths, since paths involving
372-
local processing are always possible.
370+
path(s) for any post-scan/join processing that the FDW knows how to
371+
perform remotely, and call <function>add_path</> to add these paths to
372+
the indicated upper relation. As with <function>GetForeignJoinPaths</>,
373+
it is not necessary that this function succeed in creating any paths,
374+
since paths involving local processing are always possible.
375+
</para>
376+
377+
<para>
378+
The <literal>stage</> parameter identifies which post-scan/join step is
379+
currently being considered. <literal>output_rel</> is the upper relation
380+
that should receive paths representing computation of this step,
381+
and <literal>input_rel</> is the relation representing the input to this
382+
step. (Note that <structname>ForeignPath</> paths added
383+
to <literal>output_rel</> would typically not have any direct dependency
384+
on paths of the <literal>input_rel</>, since their processing is expected
385+
to be done externally. However, examining paths previously generated for
386+
the previous processing step can be useful to avoid redundant planning
387+
work.)
373388
</para>
374389

375390
<para>
@@ -1530,20 +1545,20 @@ GetForeignServerByName(const char *name, bool missing_ok);
15301545
<para>
15311546
An FDW might additionally support direct execution of some plan actions
15321547
that are above the level of scans and joins, such as grouping or
1533-
aggregation. To offer such options, the FDW should generate paths
1534-
and insert them into the
1535-
appropriate <firstterm>upper relation</>. For example, a path
1536-
representing remote aggregation should be inserted into the relation
1537-
obtained from <literal>fetch_upper_rel(root, UPPERREL_GROUP_AGG,
1538-
NULL)</>, using <function>add_path</>. This path will be compared on a
1539-
cost basis with local aggregation performed by reading a simple scan path
1540-
for the foreign relation (note that such a path must also be supplied,
1541-
else there will be an error at plan time). If the remote-aggregation
1542-
path wins, which it usually would, it will be converted into a plan in
1543-
the usual way, by calling <function>GetForeignPlan</>.
1544-
Usually the most convenient place to generate such paths is in
1545-
the <function>GetForeignUpperPaths</> callback function, although
1546-
it can be done earlier if that seems appropriate.
1548+
aggregation. To offer such options, the FDW should generate paths and
1549+
insert them into the appropriate <firstterm>upper relation</>. For
1550+
example, a path representing remote aggregation should be inserted into
1551+
the <literal>UPPERREL_GROUP_AGG</> relation, using <function>add_path</>.
1552+
This path will be compared on a cost basis with local aggregation
1553+
performed by reading a simple scan path for the foreign relation (note
1554+
that such a path must also be supplied, else there will be an error at
1555+
plan time). If the remote-aggregation path wins, which it usually would,
1556+
it will be converted into a plan in the usual way, by
1557+
calling <function>GetForeignPlan</>. The recommended place to generate
1558+
such paths is in the <function>GetForeignUpperPaths</>
1559+
callback function, which is called for each upper relation (i.e., each
1560+
post-scan/join processing step), if all the base relations of the query
1561+
come from the same FDW.
15471562
</para>
15481563

15491564
<para>

src/backend/optimizer/README

-13
Original file line numberDiff line numberDiff line change
@@ -919,19 +919,6 @@ The result of subquery_planner() is always returned as a set of Paths
919919
stored in the UPPERREL_FINAL rel with NULL relids. The other types of
920920
upperrels are created only if needed for the particular query.
921921

922-
The upper-relation infrastructure is designed so that things will work
923-
properly if a particular upper relation is created and Paths are added
924-
to it sooner than would normally happen. This allows, for example,
925-
for an FDW's GetForeignPaths function to insert a Path representing
926-
remote aggregation into the UPPERREL_GROUP_AGG upperrel, if it notices
927-
that the query represents an aggregation that could be done entirely on
928-
the foreign server. That Path will then compete with Paths representing
929-
local aggregation on a regular scan of the foreign table, once the core
930-
planner reaches the point of considering aggregation. (In practice,
931-
it will usually be more convenient for FDWs to detect such cases in a
932-
GetForeignUpperPaths callback; but that still represents injecting a
933-
Path before the core code has touched the corresponding upperrel.)
934-
935922

936923
Parallel Query and Partial Paths
937924
--------------------------------

src/backend/optimizer/plan/planagg.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,10 @@ preprocess_minmax_aggregates(PlannerInfo *root, List *tlist)
205205
* will likely always win, but we need not assume that here.)
206206
*
207207
* Note: grouping_planner won't have created this upperrel yet, but it's
208-
* fine for us to create it first.
208+
* fine for us to create it first. We will not have inserted the correct
209+
* consider_parallel value in it, but MinMaxAggPath paths are currently
210+
* never parallel-safe anyway, so that doesn't matter. Likewise, it
211+
* doesn't matter that we haven't filled FDW-related fields in the rel.
209212
*/
210213
grouped_rel = fetch_upper_rel(root, UPPERREL_GROUP_AGG, NULL);
211214
add_path(grouped_rel, (Path *)

src/backend/optimizer/plan/planner.c

+89-19
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,12 @@ inheritance_planner(PlannerInfo *root)
12911291
/* Result path must go into outer query's FINAL upperrel */
12921292
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
12931293

1294+
/*
1295+
* We don't currently worry about setting final_rel's consider_parallel
1296+
* flag in this case, nor about allowing FDWs or create_upper_paths_hook
1297+
* to get control here.
1298+
*/
1299+
12941300
/*
12951301
* If we managed to exclude every child rel, return a dummy plan; it
12961302
* doesn't even need a ModifyTable node.
@@ -1788,21 +1794,6 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
17881794
root->upper_targets[UPPERREL_WINDOW] = sort_input_target;
17891795
root->upper_targets[UPPERREL_GROUP_AGG] = grouping_target;
17901796

1791-
/*
1792-
* If there is an FDW that's responsible for the final scan/join rel,
1793-
* let it consider injecting extension Paths into the query's
1794-
* upperrels, where they will compete with the Paths we create below.
1795-
* We pass the final scan/join rel because that's not so easily
1796-
* findable from the PlannerInfo struct; anything else the FDW wants
1797-
* to know should be obtainable via "root".
1798-
*
1799-
* Note: CustomScan providers, as well as FDWs that don't want to use
1800-
* this hook, can use the create_upper_paths_hook; see below.
1801-
*/
1802-
if (current_rel->fdwroutine &&
1803-
current_rel->fdwroutine->GetForeignUpperPaths)
1804-
current_rel->fdwroutine->GetForeignUpperPaths(root, current_rel);
1805-
18061797
/*
18071798
* If we have grouping and/or aggregation, consider ways to implement
18081799
* that. We build a new upperrel representing the output of this
@@ -1891,9 +1882,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
18911882
}
18921883

18931884
/*
1894-
* Now we are prepared to build the final-output upperrel. Insert all
1895-
* surviving paths, with LockRows, Limit, and/or ModifyTable steps added
1896-
* if needed.
1885+
* Now we are prepared to build the final-output upperrel.
18971886
*/
18981887
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
18991888

@@ -1910,7 +1899,15 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
19101899
final_rel->consider_parallel = true;
19111900

19121901
/*
1913-
* Generate paths for the final rel.
1902+
* If the current_rel belongs to a single FDW, so does the final_rel.
1903+
*/
1904+
final_rel->serverid = current_rel->serverid;
1905+
final_rel->umid = current_rel->umid;
1906+
final_rel->fdwroutine = current_rel->fdwroutine;
1907+
1908+
/*
1909+
* Generate paths for the final_rel. Insert all surviving paths, with
1910+
* LockRows, Limit, and/or ModifyTable steps added if needed.
19141911
*/
19151912
foreach(lc, current_rel->pathlist)
19161913
{
@@ -1994,6 +1991,15 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
19941991
add_path(final_rel, path);
19951992
}
19961993

1994+
/*
1995+
* If there is an FDW that's responsible for all baserels of the query,
1996+
* let it consider adding ForeignPaths.
1997+
*/
1998+
if (final_rel->fdwroutine &&
1999+
final_rel->fdwroutine->GetForeignUpperPaths)
2000+
final_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_FINAL,
2001+
current_rel, final_rel);
2002+
19972003
/* Let extensions possibly add some more paths */
19982004
if (create_upper_paths_hook)
19992005
(*create_upper_paths_hook) (root, UPPERREL_FINAL,
@@ -3268,6 +3274,13 @@ create_grouping_paths(PlannerInfo *root,
32683274
!has_parallel_hazard((Node *) parse->havingQual, false))
32693275
grouped_rel->consider_parallel = true;
32703276

3277+
/*
3278+
* If the input rel belongs to a single FDW, so does the grouped rel.
3279+
*/
3280+
grouped_rel->serverid = input_rel->serverid;
3281+
grouped_rel->umid = input_rel->umid;
3282+
grouped_rel->fdwroutine = input_rel->fdwroutine;
3283+
32713284
/*
32723285
* Check for degenerate grouping.
32733286
*/
@@ -3770,6 +3783,15 @@ create_grouping_paths(PlannerInfo *root,
37703783
errmsg("could not implement GROUP BY"),
37713784
errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
37723785

3786+
/*
3787+
* If there is an FDW that's responsible for all baserels of the query,
3788+
* let it consider adding ForeignPaths.
3789+
*/
3790+
if (grouped_rel->fdwroutine &&
3791+
grouped_rel->fdwroutine->GetForeignUpperPaths)
3792+
grouped_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_GROUP_AGG,
3793+
input_rel, grouped_rel);
3794+
37733795
/* Let extensions possibly add some more paths */
37743796
if (create_upper_paths_hook)
37753797
(*create_upper_paths_hook) (root, UPPERREL_GROUP_AGG,
@@ -3820,6 +3842,13 @@ create_window_paths(PlannerInfo *root,
38203842
!has_parallel_hazard((Node *) activeWindows, false))
38213843
window_rel->consider_parallel = true;
38223844

3845+
/*
3846+
* If the input rel belongs to a single FDW, so does the window rel.
3847+
*/
3848+
window_rel->serverid = input_rel->serverid;
3849+
window_rel->umid = input_rel->umid;
3850+
window_rel->fdwroutine = input_rel->fdwroutine;
3851+
38233852
/*
38243853
* Consider computing window functions starting from the existing
38253854
* cheapest-total path (which will likely require a sort) as well as any
@@ -3841,6 +3870,15 @@ create_window_paths(PlannerInfo *root,
38413870
activeWindows);
38423871
}
38433872

3873+
/*
3874+
* If there is an FDW that's responsible for all baserels of the query,
3875+
* let it consider adding ForeignPaths.
3876+
*/
3877+
if (window_rel->fdwroutine &&
3878+
window_rel->fdwroutine->GetForeignUpperPaths)
3879+
window_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_WINDOW,
3880+
input_rel, window_rel);
3881+
38443882
/* Let extensions possibly add some more paths */
38453883
if (create_upper_paths_hook)
38463884
(*create_upper_paths_hook) (root, UPPERREL_WINDOW,
@@ -3984,6 +4022,13 @@ create_distinct_paths(PlannerInfo *root,
39844022
*/
39854023
distinct_rel->consider_parallel = input_rel->consider_parallel;
39864024

4025+
/*
4026+
* If the input rel belongs to a single FDW, so does the distinct_rel.
4027+
*/
4028+
distinct_rel->serverid = input_rel->serverid;
4029+
distinct_rel->umid = input_rel->umid;
4030+
distinct_rel->fdwroutine = input_rel->fdwroutine;
4031+
39874032
/* Estimate number of distinct rows there will be */
39884033
if (parse->groupClause || parse->groupingSets || parse->hasAggs ||
39894034
root->hasHavingQual)
@@ -4129,6 +4174,15 @@ create_distinct_paths(PlannerInfo *root,
41294174
errmsg("could not implement DISTINCT"),
41304175
errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
41314176

4177+
/*
4178+
* If there is an FDW that's responsible for all baserels of the query,
4179+
* let it consider adding ForeignPaths.
4180+
*/
4181+
if (distinct_rel->fdwroutine &&
4182+
distinct_rel->fdwroutine->GetForeignUpperPaths)
4183+
distinct_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_DISTINCT,
4184+
input_rel, distinct_rel);
4185+
41324186
/* Let extensions possibly add some more paths */
41334187
if (create_upper_paths_hook)
41344188
(*create_upper_paths_hook) (root, UPPERREL_DISTINCT,
@@ -4176,6 +4230,13 @@ create_ordered_paths(PlannerInfo *root,
41764230
!has_parallel_hazard((Node *) target->exprs, false))
41774231
ordered_rel->consider_parallel = true;
41784232

4233+
/*
4234+
* If the input rel belongs to a single FDW, so does the ordered_rel.
4235+
*/
4236+
ordered_rel->serverid = input_rel->serverid;
4237+
ordered_rel->umid = input_rel->umid;
4238+
ordered_rel->fdwroutine = input_rel->fdwroutine;
4239+
41794240
foreach(lc, input_rel->pathlist)
41804241
{
41814242
Path *path = (Path *) lfirst(lc);
@@ -4204,6 +4265,15 @@ create_ordered_paths(PlannerInfo *root,
42044265
}
42054266
}
42064267

4268+
/*
4269+
* If there is an FDW that's responsible for all baserels of the query,
4270+
* let it consider adding ForeignPaths.
4271+
*/
4272+
if (ordered_rel->fdwroutine &&
4273+
ordered_rel->fdwroutine->GetForeignUpperPaths)
4274+
ordered_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_ORDERED,
4275+
input_rel, ordered_rel);
4276+
42074277
/* Let extensions possibly add some more paths */
42084278
if (create_upper_paths_hook)
42094279
(*create_upper_paths_hook) (root, UPPERREL_ORDERED,

src/backend/optimizer/prep/prepunion.c

+4
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@ plan_set_operations(PlannerInfo *root)
174174
*/
175175
setop_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
176176

177+
/*
178+
* We don't currently worry about setting setop_rel's consider_parallel
179+
* flag, nor about allowing FDWs to contribute paths to it.
180+
*/
177181

178182
/*
179183
* If the topmost node is a recursive union, it needs special processing.

src/include/foreign/fdwapi.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ typedef void (*GetForeignJoinPaths_function) (PlannerInfo *root,
6060
JoinPathExtraData *extra);
6161

6262
typedef void (*GetForeignUpperPaths_function) (PlannerInfo *root,
63-
RelOptInfo *scan_join_rel);
63+
UpperRelationKind stage,
64+
RelOptInfo *input_rel,
65+
RelOptInfo *output_rel);
6466

6567
typedef void (*AddForeignUpdateTargets_function) (Query *parsetree,
6668
RangeTblEntry *target_rte,

0 commit comments

Comments
 (0)