aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/joinpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/joinpath.c')
-rw-r--r--src/backend/optimizer/path/joinpath.c187
1 files changed, 48 insertions, 139 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 2885b021546..3a68d79ca9e 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.110 2007/01/10 18:06:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.111 2007/01/20 20:45:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,7 +16,6 @@
#include <math.h>
-#include "access/skey.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
@@ -40,10 +39,6 @@ static List *select_mergejoin_clauses(RelOptInfo *joinrel,
RelOptInfo *innerrel,
List *restrictlist,
JoinType jointype);
-static void build_mergejoin_strat_arrays(List *mergeclauses,
- Oid **mergefamilies,
- int **mergestrategies,
- bool **mergenullsfirst);
/*
@@ -205,9 +200,9 @@ sort_inner_and_outer(PlannerInfo *root,
*
* Actually, it's not quite true that every mergeclause ordering will
* generate a different path order, because some of the clauses may be
- * redundant. Therefore, what we do is convert the mergeclause list to a
- * list of canonical pathkeys, and then consider different orderings of
- * the pathkeys.
+ * partially redundant (refer to the same EquivalenceClasses). Therefore,
+ * what we do is convert the mergeclause list to a list of canonical
+ * pathkeys, and then consider different orderings of the pathkeys.
*
* Generating a path for *every* permutation of the pathkeys doesn't seem
* like a winning strategy; the cost in planning time is too high. For
@@ -216,75 +211,58 @@ sort_inner_and_outer(PlannerInfo *root,
* mergejoin without re-sorting against any other possible mergejoin
* partner path. But if we've not guessed the right ordering of secondary
* keys, 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.)
+ * been done as mergeclauses. (In practice, it's rare that there's more
+ * than two or three mergeclauses, so expending a huge amount of thought
+ * on that is probably not worth it.)
+ *
+ * The pathkey order returned by select_outer_pathkeys_for_merge() has
+ * some heuristics behind it (see that function), so be sure to try it
+ * exactly as-is as well as making variants.
*/
- all_pathkeys = make_pathkeys_for_mergeclauses(root,
- mergeclause_list,
- outerrel);
+ all_pathkeys = select_outer_pathkeys_for_merge(root,
+ mergeclause_list,
+ joinrel);
foreach(l, all_pathkeys)
{
List *front_pathkey = (List *) lfirst(l);
- List *cur_pathkeys;
List *cur_mergeclauses;
- Oid *mergefamilies;
- int *mergestrategies;
- bool *mergenullsfirst;
List *outerkeys;
List *innerkeys;
List *merge_pathkeys;
- /* Make a pathkey list with this guy first. */
+ /* Make a pathkey list with this guy first */
if (l != list_head(all_pathkeys))
- cur_pathkeys = lcons(front_pathkey,
- list_delete_ptr(list_copy(all_pathkeys),
- front_pathkey));
+ outerkeys = lcons(front_pathkey,
+ list_delete_ptr(list_copy(all_pathkeys),
+ front_pathkey));
else
- cur_pathkeys = all_pathkeys; /* no work at first one... */
+ outerkeys = all_pathkeys; /* no work at first one... */
- /*
- * Select mergeclause(s) that match this sort ordering. If we had
- * redundant merge clauses then we will get a subset of the original
- * clause list. There had better be some match, however...
- */
+ /* Sort the mergeclauses into the corresponding ordering */
cur_mergeclauses = find_mergeclauses_for_pathkeys(root,
- cur_pathkeys,
+ outerkeys,
+ true,
mergeclause_list);
- Assert(cur_mergeclauses != NIL);
- /* Forget it if can't use all the clauses in right/full join */
- if (useallclauses &&
- list_length(cur_mergeclauses) != list_length(mergeclause_list))
- continue;
+ /* Should have used them all... */
+ Assert(list_length(cur_mergeclauses) == list_length(mergeclause_list));
- /*
- * Build sort pathkeys for both sides.
- *
- * Note: it's possible that the cheapest paths will already be sorted
- * properly. create_mergejoin_path will detect that case and suppress
- * an explicit sort step, so we needn't do so here.
- */
- outerkeys = make_pathkeys_for_mergeclauses(root,
- cur_mergeclauses,
- outerrel);
- innerkeys = make_pathkeys_for_mergeclauses(root,
- cur_mergeclauses,
- innerrel);
- /* Build pathkeys representing output sort order. */
+ /* Build sort pathkeys for the inner side */
+ innerkeys = make_inner_pathkeys_for_merge(root,
+ cur_mergeclauses,
+ outerkeys);
+
+ /* Build pathkeys representing output sort order */
merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
outerkeys);
- /* Build opfamily info for execution */
- build_mergejoin_strat_arrays(cur_mergeclauses,
- &mergefamilies,
- &mergestrategies,
- &mergenullsfirst);
-
/*
* And now we can make the path.
+ *
+ * Note: it's possible that the cheapest paths will already be sorted
+ * properly. create_mergejoin_path will detect that case and suppress
+ * an explicit sort step, so we needn't do so here.
*/
add_path(joinrel, (Path *)
create_mergejoin_path(root,
@@ -295,9 +273,6 @@ sort_inner_and_outer(PlannerInfo *root,
restrictlist,
merge_pathkeys,
cur_mergeclauses,
- mergefamilies,
- mergestrategies,
- mergenullsfirst,
outerkeys,
innerkeys));
}
@@ -427,9 +402,6 @@ match_unsorted_outer(PlannerInfo *root,
Path *outerpath = (Path *) lfirst(l);
List *merge_pathkeys;
List *mergeclauses;
- Oid *mergefamilies;
- int *mergestrategies;
- bool *mergenullsfirst;
List *innersortkeys;
List *trialsortkeys;
Path *cheapest_startup_inner;
@@ -510,6 +482,7 @@ match_unsorted_outer(PlannerInfo *root,
/* Look for useful mergeclauses (if any) */
mergeclauses = find_mergeclauses_for_pathkeys(root,
outerpath->pathkeys,
+ true,
mergeclause_list);
/*
@@ -532,15 +505,9 @@ match_unsorted_outer(PlannerInfo *root,
continue;
/* Compute the required ordering of the inner path */
- innersortkeys = make_pathkeys_for_mergeclauses(root,
- mergeclauses,
- innerrel);
-
- /* Build opfamily info for execution */
- build_mergejoin_strat_arrays(mergeclauses,
- &mergefamilies,
- &mergestrategies,
- &mergenullsfirst);
+ innersortkeys = make_inner_pathkeys_for_merge(root,
+ mergeclauses,
+ outerpath->pathkeys);
/*
* Generate a mergejoin on the basis of sorting the cheapest inner.
@@ -557,9 +524,6 @@ match_unsorted_outer(PlannerInfo *root,
restrictlist,
merge_pathkeys,
mergeclauses,
- mergefamilies,
- mergestrategies,
- mergenullsfirst,
NIL,
innersortkeys));
@@ -613,18 +577,12 @@ match_unsorted_outer(PlannerInfo *root,
newclauses =
find_mergeclauses_for_pathkeys(root,
trialsortkeys,
+ false,
mergeclauses);
Assert(newclauses != NIL);
}
else
newclauses = mergeclauses;
-
- /* Build opfamily info for execution */
- build_mergejoin_strat_arrays(newclauses,
- &mergefamilies,
- &mergestrategies,
- &mergenullsfirst);
-
add_path(joinrel, (Path *)
create_mergejoin_path(root,
joinrel,
@@ -634,9 +592,6 @@ match_unsorted_outer(PlannerInfo *root,
restrictlist,
merge_pathkeys,
newclauses,
- mergefamilies,
- mergestrategies,
- mergenullsfirst,
NIL,
NIL));
cheapest_total_inner = innerpath;
@@ -666,19 +621,13 @@ match_unsorted_outer(PlannerInfo *root,
newclauses =
find_mergeclauses_for_pathkeys(root,
trialsortkeys,
+ false,
mergeclauses);
Assert(newclauses != NIL);
}
else
newclauses = mergeclauses;
}
-
- /* Build opfamily info for execution */
- build_mergejoin_strat_arrays(newclauses,
- &mergefamilies,
- &mergestrategies,
- &mergenullsfirst);
-
add_path(joinrel, (Path *)
create_mergejoin_path(root,
joinrel,
@@ -688,9 +637,6 @@ match_unsorted_outer(PlannerInfo *root,
restrictlist,
merge_pathkeys,
newclauses,
- mergefamilies,
- mergestrategies,
- mergenullsfirst,
NIL,
NIL));
}
@@ -909,6 +855,10 @@ best_appendrel_indexscan(PlannerInfo *root, RelOptInfo *rel,
* Select mergejoin clauses that are usable for a particular join.
* Returns a list of RestrictInfo nodes for those clauses.
*
+ * We also mark each selected RestrictInfo to show which side is currently
+ * being considered as outer. These are transient markings that are only
+ * good for the duration of the current add_paths_to_joinrel() call!
+ *
* We examine each restrictinfo clause known for the join to see
* if it is mergejoinable and involves vars from the two sub-relations
* currently of interest.
@@ -939,7 +889,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
continue;
if (!restrictinfo->can_join ||
- restrictinfo->mergejoinoperator == InvalidOid)
+ restrictinfo->mergeopfamilies == NIL)
{
have_nonmergeable_joinclause = true;
continue; /* not mergejoinable */
@@ -954,11 +904,13 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
bms_is_subset(restrictinfo->right_relids, innerrel->relids))
{
/* righthand side is inner */
+ restrictinfo->outer_is_left = true;
}
else if (bms_is_subset(restrictinfo->left_relids, innerrel->relids) &&
bms_is_subset(restrictinfo->right_relids, outerrel->relids))
{
/* lefthand side is inner */
+ restrictinfo->outer_is_left = false;
}
else
{
@@ -966,7 +918,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
continue; /* no good for these input relations */
}
- result_list = lcons(restrictinfo, result_list);
+ result_list = lappend(result_list, restrictinfo);
}
/*
@@ -995,46 +947,3 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
return result_list;
}
-
-/*
- * Temporary hack to build opfamily and strategy info needed for mergejoin
- * by the executor. We need to rethink the planner's handling of merge
- * planning so that it can deal with multiple possible merge orders, but
- * that's not done yet.
- */
-static void
-build_mergejoin_strat_arrays(List *mergeclauses,
- Oid **mergefamilies,
- int **mergestrategies,
- bool **mergenullsfirst)
-{
- int nClauses = list_length(mergeclauses);
- int i;
- ListCell *l;
-
- *mergefamilies = (Oid *) palloc(nClauses * sizeof(Oid));
- *mergestrategies = (int *) palloc(nClauses * sizeof(int));
- *mergenullsfirst = (bool *) palloc(nClauses * sizeof(bool));
-
- i = 0;
- foreach(l, mergeclauses)
- {
- RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
-
- /*
- * We do not need to worry about whether the mergeclause will be
- * commuted at runtime --- it's the same opfamily either way.
- */
- (*mergefamilies)[i] = restrictinfo->mergeopfamily;
- /*
- * For the moment, strategy must always be LessThan --- see
- * hack version of get_op_mergejoin_info
- */
- (*mergestrategies)[i] = BTLessStrategyNumber;
-
- /* And we only allow NULLS LAST, too */
- (*mergenullsfirst)[i] = false;
-
- i++;
- }
-}