diff options
Diffstat (limited to 'src/backend/optimizer/path/joinpath.c')
-rw-r--r-- | src/backend/optimizer/path/joinpath.c | 592 |
1 files changed, 314 insertions, 278 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 4a7018aa64a..55891d87a95 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.44 1999/08/09 03:16:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.45 1999/08/16 02:17:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,20 +22,26 @@ #include "optimizer/cost.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" +#include "optimizer/restrictinfo.h" #include "parser/parsetree.h" #include "utils/lsyscache.h" static Path *best_innerjoin(List *join_paths, List *outer_relid); -static List *sort_inner_and_outer(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, - List *mergeinfo_list); -static List *match_unsorted_outer(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, - List *outerpath_list, Path *cheapest_inner, Path *best_innerjoin, - List *mergeinfo_list); -static List *match_unsorted_inner(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, - List *innerpath_list, List *mergeinfo_list); +static List *sort_inner_and_outer(RelOptInfo *joinrel, + RelOptInfo *outerrel, + RelOptInfo *innerrel, + List *mergeclause_list); +static List *match_unsorted_outer(RelOptInfo *joinrel, RelOptInfo *outerrel, + RelOptInfo *innerrel, List *outerpath_list, + Path *cheapest_inner, Path *best_innerjoin, + List *mergeclause_list); +static List *match_unsorted_inner(RelOptInfo *joinrel, RelOptInfo *outerrel, + RelOptInfo *innerrel, List *innerpath_list, + List *mergeclause_list); static List *hash_inner_and_outer(Query *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel); static Cost estimate_disbursion(Query *root, Var *var); +static List *select_mergejoin_clauses(List *restrictinfo_list); /* * update_rels_pathlist_for_joins @@ -43,19 +49,10 @@ static Cost estimate_disbursion(Query *root, Var *var); * relations in the list 'joinrels.' Each unique path will be included * in the join relation's 'pathlist' field. * - * In postgres, n-way joins are handled left-only(permuting clauseless - * joins doesn't usually win much). - * - * if BushyPlanFlag is true, bushy tree plans will be generated - * * 'joinrels' is the list of relation entries to be joined * * Modifies the pathlist field of each joinrel node to contain * the unique join paths. - * If bushy trees are considered, may modify the relid field of the - * join rel nodes to flatten the lists. - * - * It does a destructive modification. */ void update_rels_pathlist_for_joins(Query *root, List *joinrels) @@ -70,8 +67,8 @@ update_rels_pathlist_for_joins(Query *root, List *joinrels) RelOptInfo *innerrel; RelOptInfo *outerrel; Path *bestinnerjoin; - List *pathlist = NIL; - List *mergeinfo_list = NIL; + List *pathlist; + List *mergeclause_list = NIL; /* * On entry, joinrel->relids is a list of two sublists of relids, @@ -98,24 +95,26 @@ update_rels_pathlist_for_joins(Query *root, List *joinrels) get_join_rel(root, outerrelids); /* - * Get the best inner join for match_unsorted_outer. + * Get the best inner join for match_unsorted_outer(). */ bestinnerjoin = best_innerjoin(innerrel->innerjoin, outerrel->relids); + /* + * Find potential mergejoin clauses. + */ if (_enable_mergejoin_) - mergeinfo_list = group_clauses_by_order(joinrel->restrictinfo, - innerrel->relids); + mergeclause_list = select_mergejoin_clauses(joinrel->restrictinfo); /* * 1. Consider mergejoin paths where both relations must be * explicitly sorted. */ pathlist = sort_inner_and_outer(joinrel, outerrel, - innerrel, mergeinfo_list); + innerrel, mergeclause_list); /* * 2. Consider paths where the outer relation need not be - * explicitly sorted. This may include either nestloops and + * explicitly sorted. This includes both nestloops and * mergejoins where the outer path is already ordered. */ pathlist = add_pathlist(joinrel, pathlist, @@ -123,21 +122,20 @@ update_rels_pathlist_for_joins(Query *root, List *joinrels) outerrel, innerrel, outerrel->pathlist, - innerrel->cheapestpath, + innerrel->cheapestpath, bestinnerjoin, - mergeinfo_list)); + mergeclause_list)); /* * 3. Consider paths where the inner relation need not be - * explicitly sorted. This may include nestloops and mergejoins - * the actual nestloop nodes were constructed in - * (match_unsorted_outer). + * explicitly sorted. This includes mergejoins only + * (nestloops were already built in match_unsorted_outer). */ pathlist = add_pathlist(joinrel, pathlist, match_unsorted_inner(joinrel, outerrel, innerrel, innerrel->pathlist, - mergeinfo_list)); + mergeclause_list)); /* * 4. Consider paths where both outer and inner relations must be @@ -176,11 +174,13 @@ best_innerjoin(List *join_paths, Relids outer_relids) { Path *path = (Path *) lfirst(join_path); - /* path->joinid is the set of base rels that must be part of + Assert(IsA(path, IndexPath)); + + /* path->joinrelids is the set of base rels that must be part of * outer_relids in order to use this inner path, because those * rels are used in the index join quals of this inner path. */ - if (is_subset(path->joinid, outer_relids) && + if (is_subset(((IndexPath *) path)->joinrelids, outer_relids) && (cheapest == NULL || path_is_cheaper(path, cheapest))) cheapest = path; @@ -196,8 +196,8 @@ best_innerjoin(List *join_paths, Relids outer_relids) * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation - * 'mergeinfo_list' is a list of nodes containing info on(mergejoinable) - * clauses for joining the relations + * 'mergeclause_list' is a list of RestrictInfo nodes for available + * mergejoin clauses between these two relations * * Returns a list of mergejoin paths. */ @@ -205,32 +205,59 @@ static List * sort_inner_and_outer(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, - List *mergeinfo_list) + List *mergeclause_list) { - List *ms_list = NIL; - MergeInfo *xmergeinfo = (MergeInfo *) NULL; - MergePath *temp_node = (MergePath *) NULL; + List *path_list = NIL; List *i; - List *outerkeys = NIL; - List *innerkeys = NIL; - List *merge_pathkeys = NIL; - foreach(i, mergeinfo_list) + /* + * Each possible ordering of the available mergejoin clauses will + * generate a differently-sorted result path at essentially the + * same cost. We have no basis for choosing one over another at + * this level of joining, but some sort orders may be more useful + * than others for higher-level mergejoins. Generating a path here + * for *every* permutation of mergejoin clauses doesn't seem like + * a winning strategy, however; the cost in planning time is too high. + * + * For now, we generate one path for each mergejoin clause, listing that + * clause first and the rest in random order. This should allow at least + * a one-clause mergejoin without re-sorting against any other possible + * mergejoin partner path. But if we've not guessed the right ordering + * of secondary clauses, we may end up evaluating clauses as qpquals when + * they could have been done as mergeclauses. We need to figure out a + * better way. (Two possible approaches: look at all the relevant index + * relations to suggest plausible sort orders, or make just one output + * path and somehow mark it as having a sort-order that can be rearranged + * freely.) + */ + foreach(i, mergeclause_list) { - xmergeinfo = (MergeInfo *) lfirst(i); - - outerkeys = make_pathkeys_from_joinkeys(xmergeinfo->jmethod.jmkeys, - outerrel->targetlist, - OUTER); - - innerkeys = make_pathkeys_from_joinkeys(xmergeinfo->jmethod.jmkeys, - innerrel->targetlist, - INNER); - - merge_pathkeys = new_join_pathkeys(outerkeys, joinrel->targetlist, - xmergeinfo->jmethod.clauses); - - temp_node = create_mergejoin_path(joinrel, + RestrictInfo *restrictinfo = lfirst(i); + List *curclause_list; + List *outerkeys; + List *innerkeys; + List *merge_pathkeys; + MergePath *path_node; + + /* Make a mergeclause list with this guy first. */ + curclause_list = lcons(restrictinfo, + lremove(restrictinfo, + listCopy(mergeclause_list))); + /* Build sort pathkeys for both sides. + * + * Note: it's possible that the cheapest path will already be + * sorted properly --- create_mergejoin_path will detect that case + * and suppress an explicit sort step. + */ + outerkeys = make_pathkeys_for_mergeclauses(curclause_list, + outerrel->targetlist); + innerkeys = make_pathkeys_for_mergeclauses(curclause_list, + innerrel->targetlist); + /* Build pathkeys representing output sort order. */ + merge_pathkeys = build_join_pathkeys(outerkeys, joinrel->targetlist, + curclause_list); + /* And now we can make the path. */ + path_node = create_mergejoin_path(joinrel, outerrel->size, innerrel->size, outerrel->width, @@ -238,40 +265,50 @@ sort_inner_and_outer(RelOptInfo *joinrel, (Path *) outerrel->cheapestpath, (Path *) innerrel->cheapestpath, merge_pathkeys, - xmergeinfo->m_ordering, - xmergeinfo->jmethod.clauses, + get_actual_clauses(curclause_list), outerkeys, innerkeys); - ms_list = lappend(ms_list, temp_node); + path_list = lappend(path_list, path_node); } - return ms_list; + return path_list; } /* * match_unsorted_outer * Creates possible join paths for processing a single join relation * 'joinrel' by employing either iterative substitution or - * mergejoining on each of its possible outer paths(assuming that the - * outer relation need not be explicitly sorted). + * mergejoining on each of its possible outer paths (considering + * only outer paths that are already ordered well enough for merging). * - * 1. The inner path is the cheapest available inner path. - * 2. Mergejoin wherever possible. Mergejoin are considered if there - * are mergejoinable join clauses between the outer and inner join - * relations such that the outer path is keyed on the variables - * appearing in the clauses. The corresponding inner merge path is - * either a path whose keys match those of the outer path(if such a - * path is available) or an explicit sort on the appropriate inner - * join keys, whichever is cheaper. + * We always generate a nestloop path for each available outer path. + * If an indexscan inner path exists that is compatible with this outer rel + * and cheaper than the cheapest general-purpose inner path, then we use + * the indexscan inner path; else we use the cheapest general-purpose inner. + * + * We also consider mergejoins if mergejoin clauses are available. We have + * two ways to generate the inner path for a mergejoin: use the cheapest + * inner path (sorting it if it's not suitably ordered already), or using an + * inner path that is already suitably ordered for the merge. If the + * cheapest inner path is suitably ordered, then by definition it's the one + * to use. Otherwise, we look for ordered paths that are cheaper than the + * cheapest inner + sort costs. If we have several mergeclauses, it could be + * that there is no inner path (or only a very expensive one) for the full + * list of mergeclauses, but better paths exist if we truncate the + * mergeclause list (thereby discarding some sort key requirements). So, we + * consider truncations of the mergeclause list as well as the full list. + * In any case, we find the cheapest suitable path and generate a single + * output mergejoin path. (Since all the possible mergejoins will have + * identical output pathkeys, there is no need to keep any but the cheapest.) * * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation * 'outerpath_list' is the list of possible outer paths * 'cheapest_inner' is the cheapest inner path - * 'best_innerjoin' is the best inner index path(if any) - * 'mergeinfo_list' is a list of nodes containing info on mergejoinable - * clauses + * 'best_innerjoin' is the best inner index path (if any) + * 'mergeclause_list' is a list of RestrictInfo nodes for available + * mergejoin clauses between these two relations * * Returns a list of possible join path nodes. */ @@ -282,139 +319,139 @@ match_unsorted_outer(RelOptInfo *joinrel, List *outerpath_list, Path *cheapest_inner, Path *best_innerjoin, - List *mergeinfo_list) + List *mergeclause_list) { - Path *outerpath = (Path *) NULL; - List *jp_list = NIL; - List *temp_node = NIL; - List *merge_pathkeys = NIL; - Path *nestinnerpath = (Path *) NULL; - List *paths = NIL; - List *i = NIL; - PathOrder *outerpath_ordering = NULL; + List *path_list = NIL; + Path *nestinnerpath; + List *i; + + /* + * We only use the best innerjoin indexpath if it is cheaper + * than the cheapest general-purpose inner path. + */ + if (best_innerjoin && + path_is_cheaper(best_innerjoin, cheapest_inner)) + nestinnerpath = best_innerjoin; + else + nestinnerpath = cheapest_inner; foreach(i, outerpath_list) { - List *clauses = NIL; - List *matchedJoinKeys = NIL; - List *matchedJoinClauses = NIL; - MergeInfo *xmergeinfo = NULL; - - outerpath = (Path *) lfirst(i); - - outerpath_ordering = outerpath->pathorder; - - if (outerpath_ordering) - xmergeinfo = match_order_mergeinfo(outerpath_ordering, - mergeinfo_list); - - if (xmergeinfo) - clauses = xmergeinfo->jmethod.clauses; - - if (clauses) + Path *outerpath = (Path *) lfirst(i); + List *mergeclauses; + List *merge_pathkeys; + List *innersortkeys; + Path *mergeinnerpath; + int mergeclausecount; + + /* Look for useful mergeclauses (if any) */ + mergeclauses = find_mergeclauses_for_pathkeys(outerpath->pathkeys, + mergeclause_list); + /* + * The result will have this sort order (even if it is implemented + * as a nestloop, and even if some of the mergeclauses are implemented + * by qpquals rather than as true mergeclauses): + */ + merge_pathkeys = build_join_pathkeys(outerpath->pathkeys, + joinrel->targetlist, + mergeclauses); + + /* Always consider a nestloop join with this outer and best inner. */ + path_list = lappend(path_list, + create_nestloop_path(joinrel, + outerrel, + outerpath, + nestinnerpath, + merge_pathkeys)); + + /* Done with this outer path if no chance for a mergejoin */ + if (mergeclauses == NIL) + continue; + + /* Compute the required ordering of the inner path */ + innersortkeys = make_pathkeys_for_mergeclauses(mergeclauses, + innerrel->targetlist); + + /* Set up on the assumption that we will use the cheapest_inner */ + mergeinnerpath = cheapest_inner; + mergeclausecount = length(mergeclauses); + + /* If the cheapest_inner doesn't need to be sorted, it is the winner + * by definition. + */ + if (pathkeys_contained_in(innersortkeys, + cheapest_inner->pathkeys)) { - List *jmkeys = xmergeinfo->jmethod.jmkeys; - - order_joinkeys_by_pathkeys(outerpath->pathkeys, - jmkeys, - clauses, - OUTER, - &matchedJoinKeys, - &matchedJoinClauses); - merge_pathkeys = new_join_pathkeys(outerpath->pathkeys, - joinrel->targetlist, clauses); + /* cheapest_inner is the winner */ + innersortkeys = NIL; /* we do not need to sort it... */ } else - merge_pathkeys = outerpath->pathkeys; - - if (best_innerjoin && - path_is_cheaper(best_innerjoin, cheapest_inner)) - nestinnerpath = best_innerjoin; - else - nestinnerpath = cheapest_inner; + { + /* look for a presorted path that's cheaper */ + List *trialsortkeys = listCopy(innersortkeys); + Cost cheapest_cost; + int clausecount; - paths = lcons(create_nestloop_path(joinrel, - outerrel, - outerpath, - nestinnerpath, - merge_pathkeys), - NIL); + cheapest_cost = cheapest_inner->path_cost + + cost_sort(innersortkeys, innerrel->size, innerrel->width); - if (clauses && matchedJoinKeys) - { - bool path_is_cheaper_than_sort; - List *varkeys = NIL; - Path *mergeinnerpath = get_cheapest_path_for_joinkeys( - matchedJoinKeys, - outerpath_ordering, - innerrel->pathlist, - INNER); - - /* Should we use the mergeinner, or sort the cheapest inner? */ - path_is_cheaper_than_sort = (bool) (mergeinnerpath && - (mergeinnerpath->path_cost < - (cheapest_inner->path_cost + - cost_sort(matchedJoinKeys, innerrel->size, - innerrel->width)))); - if (!path_is_cheaper_than_sort) + for (clausecount = mergeclausecount; + clausecount > 0; + clausecount--) { - varkeys = make_pathkeys_from_joinkeys(matchedJoinKeys, - innerrel->targetlist, - INNER); + Path *trialinnerpath; + + /* Look for an inner path ordered well enough to merge with + * the first 'clausecount' mergeclauses. NB: trialsortkeys + * is modified destructively, which is why we made a copy... + */ + trialinnerpath = + get_cheapest_path_for_pathkeys(innerrel->pathlist, + ltruncate(clausecount, + trialsortkeys)); + if (trialinnerpath != NULL && + trialinnerpath->path_cost < cheapest_cost) + { + /* Found a cheaper (or even-cheaper) sorted path */ + cheapest_cost = trialinnerpath->path_cost; + mergeinnerpath = trialinnerpath; + mergeclausecount = clausecount; + innersortkeys = NIL; /* we will not need to sort it... */ + } } - - - /* - * Keep track of the cost of the outer path used with this - * ordered inner path for later processing in - * (match_unsorted_inner), since it isn't a sort and thus - * wouldn't otherwise be considered. - */ - if (path_is_cheaper_than_sort) - mergeinnerpath->outerjoincost = outerpath->path_cost; - else - mergeinnerpath = cheapest_inner; - - temp_node = lcons(create_mergejoin_path(joinrel, - outerrel->size, - innerrel->size, - outerrel->width, - innerrel->width, - outerpath, - mergeinnerpath, - merge_pathkeys, - xmergeinfo->m_ordering, - matchedJoinClauses, - NIL, - varkeys), - paths); } - else - temp_node = paths; - jp_list = nconc(jp_list, temp_node); + + /* Finally, we can build the mergejoin path */ + mergeclauses = ltruncate(mergeclausecount, + get_actual_clauses(mergeclauses)); + path_list = lappend(path_list, + create_mergejoin_path(joinrel, + outerrel->size, + innerrel->size, + outerrel->width, + innerrel->width, + outerpath, + mergeinnerpath, + merge_pathkeys, + mergeclauses, + NIL, + innersortkeys)); } - return jp_list; + + return path_list; } /* * match_unsorted_inner - * Find the cheapest ordered join path for a given(ordered, unsorted) - * inner join path. - * - * Scans through each path available on an inner join relation and tries - * matching its ordering keys against those of mergejoin clauses. - * If 1. an appropriately_ordered inner path and matching mergeclause are - * found, and - * 2. sorting the cheapest outer path is cheaper than using an ordered - * but unsorted outer path(as was considered in - * (match_unsorted_outer)), then this merge path is considered. + * Generate mergejoin paths that use an explicit sort of the outer path + * with an already-ordered inner path. * * 'joinrel' is the join result relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation * 'innerpath_list' is the list of possible inner join paths - * 'mergeinfo_list' is a list of nodes containing info on mergejoinable - * clauses + * 'mergeclause_list' is a list of RestrictInfo nodes for available + * mergejoin clauses between these two relations * * Returns a list of possible merge paths. */ @@ -423,78 +460,74 @@ match_unsorted_inner(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, List *innerpath_list, - List *mergeinfo_list) + List *mergeclause_list) { - List *mp_list = NIL; + List *path_list = NIL; List *i; foreach(i, innerpath_list) { Path *innerpath = (Path *) lfirst(i); - PathOrder *innerpath_ordering = innerpath->pathorder; - MergeInfo *xmergeinfo = (MergeInfo *) NULL; - List *clauses = NIL; - List *matchedJoinKeys = NIL; - List *matchedJoinClauses = NIL; + List *mergeclauses; - if (innerpath_ordering) - xmergeinfo = match_order_mergeinfo(innerpath_ordering, - mergeinfo_list); + /* Look for useful mergeclauses (if any) */ + mergeclauses = find_mergeclauses_for_pathkeys(innerpath->pathkeys, + mergeclause_list); - if (xmergeinfo) - clauses = ((JoinMethod *) xmergeinfo)->clauses; - - if (clauses) - { - List *jmkeys = xmergeinfo->jmethod.jmkeys; - - order_joinkeys_by_pathkeys(innerpath->pathkeys, - jmkeys, - clauses, - INNER, - &matchedJoinKeys, - &matchedJoinClauses); - } - - /* - * (match_unsorted_outer) if it is applicable. 'OuterJoinCost was - * set above in - */ - if (clauses && matchedJoinKeys) + if (mergeclauses) { - Cost temp1; - - temp1 = outerrel->cheapestpath->path_cost + - cost_sort(matchedJoinKeys, outerrel->size, outerrel->width); - - if (innerpath->outerjoincost <= 0 /* unset? */ - || innerpath->outerjoincost > temp1) + List *outersortkeys; + Path *mergeouterpath; + List *merge_pathkeys; + + /* Compute the required ordering of the outer path */ + outersortkeys = + make_pathkeys_for_mergeclauses(mergeclauses, + outerrel->targetlist); + + /* Look for an outer path already ordered well enough to merge */ + mergeouterpath = + get_cheapest_path_for_pathkeys(outerrel->pathlist, + outersortkeys); + + /* Should we use the mergeouter, or sort the cheapest outer? */ + if (mergeouterpath != NULL && + mergeouterpath->path_cost <= + (outerrel->cheapestpath->path_cost + + cost_sort(outersortkeys, outerrel->size, outerrel->width))) { - List *outerkeys = make_pathkeys_from_joinkeys(matchedJoinKeys, - outerrel->targetlist, - OUTER); - List *merge_pathkeys = new_join_pathkeys(outerkeys, - joinrel->targetlist, - clauses); - - mp_list = lappend(mp_list, - create_mergejoin_path(joinrel, - outerrel->size, - innerrel->size, - outerrel->width, - innerrel->width, - (Path *) outerrel->cheapestpath, - innerpath, - merge_pathkeys, - xmergeinfo->m_ordering, - matchedJoinClauses, - outerkeys, - NIL)); + /* Use mergeouterpath */ + outersortkeys = NIL; /* no explicit sort step */ } + else + { + /* Use outerrel->cheapestpath, with the outersortkeys */ + mergeouterpath = outerrel->cheapestpath; + } + + /* Compute pathkeys the result will have */ + merge_pathkeys = build_join_pathkeys( + outersortkeys ? outersortkeys : mergeouterpath->pathkeys, + joinrel->targetlist, + mergeclauses); + + mergeclauses = get_actual_clauses(mergeclauses); + path_list = lappend(path_list, + create_mergejoin_path(joinrel, + outerrel->size, + innerrel->size, + outerrel->width, + innerrel->width, + mergeouterpath, + innerpath, + merge_pathkeys, + mergeclauses, + outersortkeys, + NIL)); } } - return mp_list; + return path_list; } /* @@ -520,49 +553,23 @@ hash_inner_and_outer(Query *root, foreach(i, joinrel->restrictinfo) { RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i); - Oid hashjoinop = restrictinfo->hashjoinoperator; /* we consider only clauses previously marked hashjoinable */ - if (hashjoinop) + if (restrictinfo->hashjoinoperator) { Expr *clause = restrictinfo->clause; Var *leftop = get_leftop(clause); Var *rightop = get_rightop(clause); - JoinKey *joinkey = makeNode(JoinKey); - List *joinkey_list; - List *outerkeys; - List *innerkeys; + Var *innerop; Cost innerdisbursion; - List *hash_pathkeys; HashPath *hash_path; - /* construct joinkey and pathkeys for this clause */ + /* find the inner var and estimate its disbursion */ if (intMember(leftop->varno, innerrel->relids)) - { - joinkey->outer = rightop; - joinkey->inner = leftop; - } + innerop = leftop; else - { - joinkey->outer = leftop; - joinkey->inner = rightop; - } - joinkey_list = lcons(joinkey, NIL); - - outerkeys = make_pathkeys_from_joinkeys(joinkey_list, - outerrel->targetlist, - OUTER); - innerkeys = make_pathkeys_from_joinkeys(joinkey_list, - innerrel->targetlist, - INNER); - - innerdisbursion = estimate_disbursion(root, joinkey->inner); - - /* - * We cannot assume that the output of the hashjoin appears in - * any particular order, so it should have NIL pathkeys. - */ - hash_pathkeys = NIL; + innerop = rightop; + innerdisbursion = estimate_disbursion(root, innerop); hash_path = create_hashjoin_path(joinrel, outerrel->size, @@ -571,11 +578,7 @@ hash_inner_and_outer(Query *root, innerrel->width, (Path *) outerrel->cheapestpath, (Path *) innerrel->cheapestpath, - hash_pathkeys, - hashjoinop, lcons(clause, NIL), - outerkeys, - innerkeys, innerdisbursion); hpath_list = lappend(hpath_list, hash_path); } @@ -605,3 +608,36 @@ estimate_disbursion(Query *root, Var *var) return (Cost) get_attdisbursion(relid, var->varattno, 0.1); } + +/* + * select_mergejoin_clauses + * Select mergejoin clauses that are usable for a particular join. + * Returns a list of RestrictInfo nodes for those clauses. + * + * Currently, all we need is the restrictinfo list of the joinrel. + * By definition, any mergejoinable clause in that list will work --- + * it must involve only vars in the join, or it wouldn't have been + * in the restrict list, and it must involve vars on both sides of + * the join, or it wouldn't have made it up to this level of join. + * Since we currently allow only simple Vars as the left and right + * sides of mergejoin clauses, that means the mergejoin clauses must + * be usable for this join. If we ever allow more complex expressions + * containing multiple Vars, we would need to check that each side + * of a potential joinclause uses only vars from one side of the join. + */ +static List * +select_mergejoin_clauses(List *restrictinfo_list) +{ + List *result_list = NIL; + List *i; + + foreach(i, restrictinfo_list) + { + RestrictInfo *restrictinfo = lfirst(i); + + if (restrictinfo->mergejoinoperator != InvalidOid) + result_list = lcons(restrictinfo, result_list); + } + + return result_list; +} |