1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-11 10:01:57 +03:00

Code review for foreign/custom join pushdown patch.

Commit e7cb7ee145 included some design
decisions that seem pretty questionable to me, and there was quite a lot
of stuff not to like about the documentation and comments.  Clean up
as follows:

* Consider foreign joins only between foreign tables on the same server,
rather than between any two foreign tables with the same underlying FDW
handler function.  In most if not all cases, the FDW would simply have had
to apply the same-server restriction itself (far more expensively, both for
lack of caching and because it would be repeated for each combination of
input sub-joins), or else risk nasty bugs.  Anyone who's really intent on
doing something outside this restriction can always use the
set_join_pathlist_hook.

* Rename fdw_ps_tlist/custom_ps_tlist to fdw_scan_tlist/custom_scan_tlist
to better reflect what they're for, and allow these custom scan tlists
to be used even for base relations.

* Change make_foreignscan() API to include passing the fdw_scan_tlist
value, since the FDW is required to set that.  Backwards compatibility
doesn't seem like an adequate reason to expect FDWs to set it in some
ad-hoc extra step, and anyway existing FDWs can just pass NIL.

* Change the API of path-generating subroutines of add_paths_to_joinrel,
and in particular that of GetForeignJoinPaths and set_join_pathlist_hook,
so that various less-used parameters are passed in a struct rather than
as separate parameter-list entries.  The objective here is to reduce the
probability that future additions to those parameter lists will result in
source-level API breaks for users of these hooks.  It's possible that this
is even a small win for the core code, since most CPU architectures can't
pass more than half a dozen parameters efficiently anyway.  I kept root,
joinrel, outerrel, innerrel, and jointype as separate parameters to reduce
code churn in joinpath.c --- in particular, putting jointype into the
struct would have been problematic because of the subroutines' habit of
changing their local copies of that variable.

* Avoid ad-hocery in ExecAssignScanProjectionInfo.  It was probably all
right for it to know about IndexOnlyScan, but if the list is to grow
we should refactor the knowledge out to the callers.

* Restore nodeForeignscan.c's previous use of the relcache to avoid
extra GetFdwRoutine lookups for base-relation scans.

* Lots of cleanup of documentation and missed comments.  Re-order some
code additions into more logical places.
This commit is contained in:
Tom Lane
2015-05-10 14:36:30 -04:00
parent c594c75078
commit 1a8a4e5cde
26 changed files with 701 additions and 653 deletions

View File

@ -30,21 +30,13 @@ set_join_pathlist_hook_type set_join_pathlist_hook = NULL;
static void sort_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel,
List *restrictlist, List *mergeclause_list,
JoinType jointype, SpecialJoinInfo *sjinfo,
Relids param_source_rels, Relids extra_lateral_rels);
JoinType jointype, JoinPathExtraData *extra);
static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel,
List *restrictlist, List *mergeclause_list,
JoinType jointype, SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors,
Relids param_source_rels, Relids extra_lateral_rels);
JoinType jointype, JoinPathExtraData *extra);
static void hash_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel,
List *restrictlist,
JoinType jointype, SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors,
Relids param_source_rels, Relids extra_lateral_rels);
JoinType jointype, JoinPathExtraData *extra);
static List *select_mergejoin_clauses(PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *outerrel,
@ -86,13 +78,16 @@ add_paths_to_joinrel(PlannerInfo *root,
SpecialJoinInfo *sjinfo,
List *restrictlist)
{
List *mergeclause_list = NIL;
JoinPathExtraData extra;
bool mergejoin_allowed = true;
SemiAntiJoinFactors semifactors;
Relids param_source_rels = NULL;
Relids extra_lateral_rels = NULL;
ListCell *lc;
extra.restrictlist = restrictlist;
extra.mergeclause_list = NIL;
extra.sjinfo = sjinfo;
extra.param_source_rels = NULL;
extra.extra_lateral_rels = NULL;
/*
* Find potential mergejoin clauses. We can skip this if we are not
* interested in doing a mergejoin. However, mergejoin may be our only
@ -100,13 +95,13 @@ add_paths_to_joinrel(PlannerInfo *root,
* it's a full join.
*/
if (enable_mergejoin || jointype == JOIN_FULL)
mergeclause_list = select_mergejoin_clauses(root,
joinrel,
outerrel,
innerrel,
restrictlist,
jointype,
&mergejoin_allowed);
extra.mergeclause_list = select_mergejoin_clauses(root,
joinrel,
outerrel,
innerrel,
restrictlist,
jointype,
&mergejoin_allowed);
/*
* If it's SEMI or ANTI join, compute correction factors for cost
@ -115,7 +110,7 @@ add_paths_to_joinrel(PlannerInfo *root,
if (jointype == JOIN_SEMI || jointype == JOIN_ANTI)
compute_semi_anti_join_factors(root, outerrel, innerrel,
jointype, sjinfo, restrictlist,
&semifactors);
&extra.semifactors);
/*
* Decide whether it's sensible to generate parameterized paths for this
@ -142,16 +137,16 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (bms_overlap(joinrel->relids, sjinfo->min_righthand) &&
!bms_overlap(joinrel->relids, sjinfo->min_lefthand))
param_source_rels = bms_join(param_source_rels,
bms_difference(root->all_baserels,
extra.param_source_rels = bms_join(extra.param_source_rels,
bms_difference(root->all_baserels,
sjinfo->min_righthand));
/* full joins constrain both sides symmetrically */
if (sjinfo->jointype == JOIN_FULL &&
bms_overlap(joinrel->relids, sjinfo->min_lefthand) &&
!bms_overlap(joinrel->relids, sjinfo->min_righthand))
param_source_rels = bms_join(param_source_rels,
bms_difference(root->all_baserels,
extra.param_source_rels = bms_join(extra.param_source_rels,
bms_difference(root->all_baserels,
sjinfo->min_lefthand));
}
@ -168,9 +163,9 @@ add_paths_to_joinrel(PlannerInfo *root,
LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(lc);
if (bms_is_subset(ljinfo->lateral_rhs, joinrel->relids))
param_source_rels = bms_join(param_source_rels,
bms_difference(ljinfo->lateral_lhs,
joinrel->relids));
extra.param_source_rels = bms_join(extra.param_source_rels,
bms_difference(ljinfo->lateral_lhs,
joinrel->relids));
}
/*
@ -195,8 +190,8 @@ add_paths_to_joinrel(PlannerInfo *root,
!bms_is_subset(phinfo->ph_eval_at, innerrel->relids))
{
/* Yes, remember its lateral rels */
extra_lateral_rels = bms_add_members(extra_lateral_rels,
phinfo->ph_lateral);
extra.extra_lateral_rels = bms_add_members(extra.extra_lateral_rels,
phinfo->ph_lateral);
}
}
@ -206,9 +201,10 @@ add_paths_to_joinrel(PlannerInfo *root,
* it to required_outer below, while preserving the property that
* required_outer is exactly NULL if empty.)
*/
extra_lateral_rels = bms_del_members(extra_lateral_rels, joinrel->relids);
if (bms_is_empty(extra_lateral_rels))
extra_lateral_rels = NULL;
extra.extra_lateral_rels = bms_del_members(extra.extra_lateral_rels,
joinrel->relids);
if (bms_is_empty(extra.extra_lateral_rels))
extra.extra_lateral_rels = NULL;
/*
* 1. Consider mergejoin paths where both relations must be explicitly
@ -216,9 +212,7 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (mergejoin_allowed)
sort_inner_and_outer(root, joinrel, outerrel, innerrel,
restrictlist, mergeclause_list, jointype,
sjinfo,
param_source_rels, extra_lateral_rels);
jointype, &extra);
/*
* 2. Consider paths where the outer relation need not be explicitly
@ -229,9 +223,7 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (mergejoin_allowed)
match_unsorted_outer(root, joinrel, outerrel, innerrel,
restrictlist, mergeclause_list, jointype,
sjinfo, &semifactors,
param_source_rels, extra_lateral_rels);
jointype, &extra);
#ifdef NOT_USED
@ -248,9 +240,7 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (mergejoin_allowed)
match_unsorted_inner(root, joinrel, outerrel, innerrel,
restrictlist, mergeclause_list, jointype,
sjinfo, &semifactors,
param_source_rels, extra_lateral_rels);
jointype, &extra);
#endif
/*
@ -260,30 +250,24 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (enable_hashjoin || jointype == JOIN_FULL)
hash_inner_and_outer(root, joinrel, outerrel, innerrel,
restrictlist, jointype,
sjinfo, &semifactors,
param_source_rels, extra_lateral_rels);
jointype, &extra);
/*
* 5. If both inner and outer relations are managed by the same FDW,
* give it a chance to push down joins.
* 5. If inner and outer relations are foreign tables (or joins) belonging
* to the same server, give the FDW a chance to push down joins.
*/
if (joinrel->fdwroutine &&
joinrel->fdwroutine->GetForeignJoinPaths)
joinrel->fdwroutine->GetForeignJoinPaths(root, joinrel,
outerrel, innerrel,
restrictlist, jointype, sjinfo,
&semifactors,
param_source_rels,
extra_lateral_rels);
jointype, &extra);
/*
* 6. Finally, give extensions a chance to manipulate the path list.
*/
if (set_join_pathlist_hook)
set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
restrictlist, jointype,
sjinfo, &semifactors,
param_source_rels, extra_lateral_rels);
jointype, &extra);
}
/*
@ -294,15 +278,11 @@ add_paths_to_joinrel(PlannerInfo *root,
static void
try_nestloop_path(PlannerInfo *root,
RelOptInfo *joinrel,
JoinType jointype,
SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors,
Relids param_source_rels,
Relids extra_lateral_rels,
Path *outer_path,
Path *inner_path,
List *restrict_clauses,
List *pathkeys)
List *pathkeys,
JoinType jointype,
JoinPathExtraData *extra)
{
Relids required_outer;
JoinCostWorkspace workspace;
@ -314,7 +294,7 @@ try_nestloop_path(PlannerInfo *root,
required_outer = calc_nestloop_required_outer(outer_path,
inner_path);
if (required_outer &&
!bms_overlap(required_outer, param_source_rels))
!bms_overlap(required_outer, extra->param_source_rels))
{
/*
* We override the param_source_rels heuristic to accept nestloop
@ -345,7 +325,7 @@ try_nestloop_path(PlannerInfo *root,
* Independently of that, add parameterization needed for any
* PlaceHolderVars that need to be computed at the join.
*/
required_outer = bms_add_members(required_outer, extra_lateral_rels);
required_outer = bms_add_members(required_outer, extra->extra_lateral_rels);
/*
* Do a precheck to quickly eliminate obviously-inferior paths. We
@ -358,7 +338,7 @@ try_nestloop_path(PlannerInfo *root,
*/
initial_cost_nestloop(root, &workspace, jointype,
outer_path, inner_path,
sjinfo, semifactors);
extra->sjinfo, &extra->semifactors);
if (add_path_precheck(joinrel,
workspace.startup_cost, workspace.total_cost,
@ -369,11 +349,11 @@ try_nestloop_path(PlannerInfo *root,
joinrel,
jointype,
&workspace,
sjinfo,
semifactors,
extra->sjinfo,
&extra->semifactors,
outer_path,
inner_path,
restrict_clauses,
extra->restrictlist,
pathkeys,
required_outer));
}
@ -392,17 +372,14 @@ try_nestloop_path(PlannerInfo *root,
static void
try_mergejoin_path(PlannerInfo *root,
RelOptInfo *joinrel,
JoinType jointype,
SpecialJoinInfo *sjinfo,
Relids param_source_rels,
Relids extra_lateral_rels,
Path *outer_path,
Path *inner_path,
List *restrict_clauses,
List *pathkeys,
List *mergeclauses,
List *outersortkeys,
List *innersortkeys)
List *innersortkeys,
JoinType jointype,
JoinPathExtraData *extra)
{
Relids required_outer;
JoinCostWorkspace workspace;
@ -414,7 +391,7 @@ try_mergejoin_path(PlannerInfo *root,
required_outer = calc_non_nestloop_required_outer(outer_path,
inner_path);
if (required_outer &&
!bms_overlap(required_outer, param_source_rels))
!bms_overlap(required_outer, extra->param_source_rels))
{
/* Waste no memory when we reject a path here */
bms_free(required_outer);
@ -425,7 +402,7 @@ try_mergejoin_path(PlannerInfo *root,
* Independently of that, add parameterization needed for any
* PlaceHolderVars that need to be computed at the join.
*/
required_outer = bms_add_members(required_outer, extra_lateral_rels);
required_outer = bms_add_members(required_outer, extra->extra_lateral_rels);
/*
* If the given paths are already well enough ordered, we can skip doing
@ -444,7 +421,7 @@ try_mergejoin_path(PlannerInfo *root,
initial_cost_mergejoin(root, &workspace, jointype, mergeclauses,
outer_path, inner_path,
outersortkeys, innersortkeys,
sjinfo);
extra->sjinfo);
if (add_path_precheck(joinrel,
workspace.startup_cost, workspace.total_cost,
@ -455,10 +432,10 @@ try_mergejoin_path(PlannerInfo *root,
joinrel,
jointype,
&workspace,
sjinfo,
extra->sjinfo,
outer_path,
inner_path,
restrict_clauses,
extra->restrictlist,
pathkeys,
required_outer,
mergeclauses,
@ -480,15 +457,11 @@ try_mergejoin_path(PlannerInfo *root,
static void
try_hashjoin_path(PlannerInfo *root,
RelOptInfo *joinrel,
JoinType jointype,
SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors,
Relids param_source_rels,
Relids extra_lateral_rels,
Path *outer_path,
Path *inner_path,
List *restrict_clauses,
List *hashclauses)
List *hashclauses,
JoinType jointype,
JoinPathExtraData *extra)
{
Relids required_outer;
JoinCostWorkspace workspace;
@ -500,7 +473,7 @@ try_hashjoin_path(PlannerInfo *root,
required_outer = calc_non_nestloop_required_outer(outer_path,
inner_path);
if (required_outer &&
!bms_overlap(required_outer, param_source_rels))
!bms_overlap(required_outer, extra->param_source_rels))
{
/* Waste no memory when we reject a path here */
bms_free(required_outer);
@ -511,7 +484,7 @@ try_hashjoin_path(PlannerInfo *root,
* Independently of that, add parameterization needed for any
* PlaceHolderVars that need to be computed at the join.
*/
required_outer = bms_add_members(required_outer, extra_lateral_rels);
required_outer = bms_add_members(required_outer, extra->extra_lateral_rels);
/*
* See comments in try_nestloop_path(). Also note that hashjoin paths
@ -519,7 +492,7 @@ try_hashjoin_path(PlannerInfo *root,
*/
initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
outer_path, inner_path,
sjinfo, semifactors);
extra->sjinfo, &extra->semifactors);
if (add_path_precheck(joinrel,
workspace.startup_cost, workspace.total_cost,
@ -530,11 +503,11 @@ try_hashjoin_path(PlannerInfo *root,
joinrel,
jointype,
&workspace,
sjinfo,
semifactors,
extra->sjinfo,
&extra->semifactors,
outer_path,
inner_path,
restrict_clauses,
extra->restrictlist,
required_outer,
hashclauses));
}
@ -584,26 +557,16 @@ clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel,
* 'joinrel' is the join relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
* 'restrictlist' contains all of the RestrictInfo nodes for restriction
* clauses that apply to this join
* 'mergeclause_list' is a list of RestrictInfo nodes for available
* mergejoin clauses in this join
* 'jointype' is the type of join to do
* 'sjinfo' is extra info about the join for selectivity estimation
* 'param_source_rels' are OK targets for parameterization of result paths
* 'extra_lateral_rels' are additional parameterization for result paths
* 'extra' contains additional input values
*/
static void
sort_inner_and_outer(PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
List *restrictlist,
List *mergeclause_list,
JoinType jointype,
SpecialJoinInfo *sjinfo,
Relids param_source_rels,
Relids extra_lateral_rels)
JoinPathExtraData *extra)
{
Path *outer_path;
Path *inner_path;
@ -643,14 +606,14 @@ sort_inner_and_outer(PlannerInfo *root,
if (jointype == JOIN_UNIQUE_OUTER)
{
outer_path = (Path *) create_unique_path(root, outerrel,
outer_path, sjinfo);
outer_path, extra->sjinfo);
Assert(outer_path);
jointype = JOIN_INNER;
}
else if (jointype == JOIN_UNIQUE_INNER)
{
inner_path = (Path *) create_unique_path(root, innerrel,
inner_path, sjinfo);
inner_path, extra->sjinfo);
Assert(inner_path);
jointype = JOIN_INNER;
}
@ -684,7 +647,7 @@ sort_inner_and_outer(PlannerInfo *root,
* exactly as-is as well as making variants.
*/
all_pathkeys = select_outer_pathkeys_for_merge(root,
mergeclause_list,
extra->mergeclause_list,
joinrel);
foreach(l, all_pathkeys)
@ -707,10 +670,10 @@ sort_inner_and_outer(PlannerInfo *root,
cur_mergeclauses = find_mergeclauses_for_pathkeys(root,
outerkeys,
true,
mergeclause_list);
extra->mergeclause_list);
/* Should have used them all... */
Assert(list_length(cur_mergeclauses) == list_length(mergeclause_list));
Assert(list_length(cur_mergeclauses) == list_length(extra->mergeclause_list));
/* Build sort pathkeys for the inner side */
innerkeys = make_inner_pathkeys_for_merge(root,
@ -730,17 +693,14 @@ sort_inner_and_outer(PlannerInfo *root,
*/
try_mergejoin_path(root,
joinrel,
jointype,
sjinfo,
param_source_rels,
extra_lateral_rels,
outer_path,
inner_path,
restrictlist,
merge_pathkeys,
cur_mergeclauses,
outerkeys,
innerkeys);
innerkeys,
jointype,
extra);
}
}
@ -771,28 +731,16 @@ sort_inner_and_outer(PlannerInfo *root,
* 'joinrel' is the join relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
* 'restrictlist' contains all of the RestrictInfo nodes for restriction
* clauses that apply to this join
* 'mergeclause_list' is a list of RestrictInfo nodes for available
* mergejoin clauses in this join
* 'jointype' is the type of join to do
* 'sjinfo' is extra info about the join for selectivity estimation
* 'semifactors' contains valid data if jointype is SEMI or ANTI
* 'param_source_rels' are OK targets for parameterization of result paths
* 'extra_lateral_rels' are additional parameterization for result paths
* 'extra' contains additional input values
*/
static void
match_unsorted_outer(PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
List *restrictlist,
List *mergeclause_list,
JoinType jointype,
SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors,
Relids param_source_rels,
Relids extra_lateral_rels)
JoinPathExtraData *extra)
{
JoinType save_jointype = jointype;
bool nestjoinOK;
@ -854,7 +802,7 @@ match_unsorted_outer(PlannerInfo *root,
if (inner_cheapest_total == NULL)
return;
inner_cheapest_total = (Path *)
create_unique_path(root, innerrel, inner_cheapest_total, sjinfo);
create_unique_path(root, innerrel, inner_cheapest_total, extra->sjinfo);
Assert(inner_cheapest_total);
}
else if (nestjoinOK)
@ -898,7 +846,7 @@ match_unsorted_outer(PlannerInfo *root,
if (outerpath != outerrel->cheapest_total_path)
continue;
outerpath = (Path *) create_unique_path(root, outerrel,
outerpath, sjinfo);
outerpath, extra->sjinfo);
Assert(outerpath);
}
@ -918,15 +866,11 @@ match_unsorted_outer(PlannerInfo *root,
*/
try_nestloop_path(root,
joinrel,
jointype,
sjinfo,
semifactors,
param_source_rels,
extra_lateral_rels,
outerpath,
inner_cheapest_total,
restrictlist,
merge_pathkeys);
merge_pathkeys,
jointype,
extra);
}
else if (nestjoinOK)
{
@ -944,30 +888,22 @@ match_unsorted_outer(PlannerInfo *root,
try_nestloop_path(root,
joinrel,
jointype,
sjinfo,
semifactors,
param_source_rels,
extra_lateral_rels,
outerpath,
innerpath,
restrictlist,
merge_pathkeys);
merge_pathkeys,
jointype,
extra);
}
/* Also consider materialized form of the cheapest inner path */
if (matpath != NULL)
try_nestloop_path(root,
joinrel,
jointype,
sjinfo,
semifactors,
param_source_rels,
extra_lateral_rels,
outerpath,
matpath,
restrictlist,
merge_pathkeys);
merge_pathkeys,
jointype,
extra);
}
/* Can't do anything else if outer path needs to be unique'd */
@ -982,7 +918,7 @@ match_unsorted_outer(PlannerInfo *root,
mergeclauses = find_mergeclauses_for_pathkeys(root,
outerpath->pathkeys,
true,
mergeclause_list);
extra->mergeclause_list);
/*
* Done with this outer path if no chance for a mergejoin.
@ -1000,7 +936,7 @@ match_unsorted_outer(PlannerInfo *root,
else
continue;
}
if (useallclauses && list_length(mergeclauses) != list_length(mergeclause_list))
if (useallclauses && list_length(mergeclauses) != list_length(extra->mergeclause_list))
continue;
/* Compute the required ordering of the inner path */
@ -1016,17 +952,14 @@ match_unsorted_outer(PlannerInfo *root,
*/
try_mergejoin_path(root,
joinrel,
jointype,
sjinfo,
param_source_rels,
extra_lateral_rels,
outerpath,
inner_cheapest_total,
restrictlist,
merge_pathkeys,
mergeclauses,
NIL,
innersortkeys);
innersortkeys,
jointype,
extra);
/* Can't do anything else if inner path needs to be unique'd */
if (save_jointype == JOIN_UNIQUE_INNER)
@ -1115,17 +1048,14 @@ match_unsorted_outer(PlannerInfo *root,
newclauses = mergeclauses;
try_mergejoin_path(root,
joinrel,
jointype,
sjinfo,
param_source_rels,
extra_lateral_rels,
outerpath,
innerpath,
restrictlist,
merge_pathkeys,
newclauses,
NIL,
NIL);
NIL,
jointype,
extra);
cheapest_total_inner = innerpath;
}
/* Same on the basis of cheapest startup cost ... */
@ -1161,17 +1091,14 @@ match_unsorted_outer(PlannerInfo *root,
}
try_mergejoin_path(root,
joinrel,
jointype,
sjinfo,
param_source_rels,
extra_lateral_rels,
outerpath,
innerpath,
restrictlist,
merge_pathkeys,
newclauses,
NIL,
NIL);
NIL,
jointype,
extra);
}
cheapest_startup_inner = innerpath;
}
@ -1193,25 +1120,16 @@ match_unsorted_outer(PlannerInfo *root,
* 'joinrel' is the join relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
* 'restrictlist' contains all of the RestrictInfo nodes for restriction
* clauses that apply to this join
* 'jointype' is the type of join to do
* 'sjinfo' is extra info about the join for selectivity estimation
* 'semifactors' contains valid data if jointype is SEMI or ANTI
* 'param_source_rels' are OK targets for parameterization of result paths
* 'extra_lateral_rels' are additional parameterization for result paths
* 'extra' contains additional input values
*/
static void
hash_inner_and_outer(PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
List *restrictlist,
JoinType jointype,
SpecialJoinInfo *sjinfo,
SemiAntiJoinFactors *semifactors,
Relids param_source_rels,
Relids extra_lateral_rels)
JoinPathExtraData *extra)
{
bool isouterjoin = IS_OUTER_JOIN(jointype);
List *hashclauses;
@ -1225,7 +1143,7 @@ hash_inner_and_outer(PlannerInfo *root,
* usable with this pair of sub-relations.
*/
hashclauses = NIL;
foreach(l, restrictlist)
foreach(l, extra->restrictlist)
{
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
@ -1276,53 +1194,41 @@ hash_inner_and_outer(PlannerInfo *root,
{
cheapest_total_outer = (Path *)
create_unique_path(root, outerrel,
cheapest_total_outer, sjinfo);
cheapest_total_outer, extra->sjinfo);
Assert(cheapest_total_outer);
jointype = JOIN_INNER;
try_hashjoin_path(root,
joinrel,
jointype,
sjinfo,
semifactors,
param_source_rels,
extra_lateral_rels,
cheapest_total_outer,
cheapest_total_inner,
restrictlist,
hashclauses);
hashclauses,
jointype,
extra);
/* no possibility of cheap startup here */
}
else if (jointype == JOIN_UNIQUE_INNER)
{
cheapest_total_inner = (Path *)
create_unique_path(root, innerrel,
cheapest_total_inner, sjinfo);
cheapest_total_inner, extra->sjinfo);
Assert(cheapest_total_inner);
jointype = JOIN_INNER;
try_hashjoin_path(root,
joinrel,
jointype,
sjinfo,
semifactors,
param_source_rels,
extra_lateral_rels,
cheapest_total_outer,
cheapest_total_inner,
restrictlist,
hashclauses);
hashclauses,
jointype,
extra);
if (cheapest_startup_outer != NULL &&
cheapest_startup_outer != cheapest_total_outer)
try_hashjoin_path(root,
joinrel,
jointype,
sjinfo,
semifactors,
param_source_rels,
extra_lateral_rels,
cheapest_startup_outer,
cheapest_total_inner,
restrictlist,
hashclauses);
hashclauses,
jointype,
extra);
}
else
{
@ -1339,15 +1245,11 @@ hash_inner_and_outer(PlannerInfo *root,
if (cheapest_startup_outer != NULL)
try_hashjoin_path(root,
joinrel,
jointype,
sjinfo,
semifactors,
param_source_rels,
extra_lateral_rels,
cheapest_startup_outer,
cheapest_total_inner,
restrictlist,
hashclauses);
hashclauses,
jointype,
extra);
foreach(lc1, outerrel->cheapest_parameterized_paths)
{
@ -1377,15 +1279,11 @@ hash_inner_and_outer(PlannerInfo *root,
try_hashjoin_path(root,
joinrel,
jointype,
sjinfo,
semifactors,
param_source_rels,
extra_lateral_rels,
outerpath,
innerpath,
restrictlist,
hashclauses);
hashclauses,
jointype,
extra);
}
}
}