summaryrefslogtreecommitdiff
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.c109
1 files changed, 78 insertions, 31 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 3e646d1032..845f429a4b 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.116 2008/03/24 21:53:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.117 2008/08/14 18:47:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,14 +24,15 @@
static void sort_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel,
List *restrictlist, List *mergeclause_list,
- JoinType jointype);
+ JoinType jointype, SpecialJoinInfo *sjinfo);
static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel,
List *restrictlist, List *mergeclause_list,
- JoinType jointype);
+ JoinType jointype, SpecialJoinInfo *sjinfo);
static void hash_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel,
- List *restrictlist, JoinType jointype);
+ List *restrictlist,
+ JoinType jointype, SpecialJoinInfo *sjinfo);
static Path *best_appendrel_indexscan(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *outer_rel, JoinType jointype);
static List *select_mergejoin_clauses(PlannerInfo *root,
@@ -52,6 +53,18 @@ static List *select_mergejoin_clauses(PlannerInfo *root,
*
* Modifies the pathlist field of the joinrel node to contain the best
* paths found so far.
+ *
+ * jointype is not necessarily the same as sjinfo->jointype; it might be
+ * "flipped around" if we are considering joining the rels in the opposite
+ * direction from what's indicated in sjinfo.
+ *
+ * Also, this routine and others in this module accept the special JoinTypes
+ * JOIN_UNIQUE_OUTER and JOIN_UNIQUE_INNER to indicate that we should
+ * unique-ify the outer or inner relation and then apply a regular inner
+ * join. These values are not allowed to propagate outside this module,
+ * however. Path cost estimation code may need to recognize that it's
+ * dealing with such a case --- the combination of nominal jointype INNER
+ * with sjinfo->jointype == JOIN_SEMI indicates that.
*/
void
add_paths_to_joinrel(PlannerInfo *root,
@@ -59,6 +72,7 @@ add_paths_to_joinrel(PlannerInfo *root,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
JoinType jointype,
+ SpecialJoinInfo *sjinfo,
List *restrictlist)
{
List *mergeclause_list = NIL;
@@ -82,7 +96,7 @@ add_paths_to_joinrel(PlannerInfo *root,
* sorted.
*/
sort_inner_and_outer(root, joinrel, outerrel, innerrel,
- restrictlist, mergeclause_list, jointype);
+ restrictlist, mergeclause_list, jointype, sjinfo);
/*
* 2. Consider paths where the outer relation need not be explicitly
@@ -90,7 +104,7 @@ add_paths_to_joinrel(PlannerInfo *root,
* path is already ordered.
*/
match_unsorted_outer(root, joinrel, outerrel, innerrel,
- restrictlist, mergeclause_list, jointype);
+ restrictlist, mergeclause_list, jointype, sjinfo);
#ifdef NOT_USED
@@ -106,7 +120,7 @@ add_paths_to_joinrel(PlannerInfo *root,
* invoked with the two rels given in the other order.
*/
match_unsorted_inner(root, joinrel, outerrel, innerrel,
- restrictlist, mergeclause_list, jointype);
+ restrictlist, mergeclause_list, jointype, sjinfo);
#endif
/*
@@ -115,7 +129,7 @@ add_paths_to_joinrel(PlannerInfo *root,
*/
if (enable_hashjoin)
hash_inner_and_outer(root, joinrel, outerrel, innerrel,
- restrictlist, jointype);
+ restrictlist, jointype, sjinfo);
}
/*
@@ -131,6 +145,7 @@ add_paths_to_joinrel(PlannerInfo *root,
* '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
*/
static void
sort_inner_and_outer(PlannerInfo *root,
@@ -139,7 +154,8 @@ sort_inner_and_outer(PlannerInfo *root,
RelOptInfo *innerrel,
List *restrictlist,
List *mergeclause_list,
- JoinType jointype)
+ JoinType jointype,
+ SpecialJoinInfo *sjinfo)
{
bool useallclauses;
Path *outer_path;
@@ -155,7 +171,8 @@ sort_inner_and_outer(PlannerInfo *root,
{
case JOIN_INNER:
case JOIN_LEFT:
- case JOIN_IN:
+ case JOIN_SEMI:
+ case JOIN_ANTI:
case JOIN_UNIQUE_OUTER:
case JOIN_UNIQUE_INNER:
useallclauses = false;
@@ -184,12 +201,16 @@ sort_inner_and_outer(PlannerInfo *root,
inner_path = innerrel->cheapest_total_path;
if (jointype == JOIN_UNIQUE_OUTER)
{
- outer_path = (Path *) create_unique_path(root, outerrel, outer_path);
+ outer_path = (Path *) create_unique_path(root, outerrel,
+ outer_path, sjinfo);
+ Assert(outer_path);
jointype = JOIN_INNER;
}
else if (jointype == JOIN_UNIQUE_INNER)
{
- inner_path = (Path *) create_unique_path(root, innerrel, inner_path);
+ inner_path = (Path *) create_unique_path(root, innerrel,
+ inner_path, sjinfo);
+ Assert(inner_path);
jointype = JOIN_INNER;
}
@@ -270,6 +291,7 @@ sort_inner_and_outer(PlannerInfo *root,
create_mergejoin_path(root,
joinrel,
jointype,
+ sjinfo,
outer_path,
inner_path,
restrictlist,
@@ -312,6 +334,7 @@ sort_inner_and_outer(PlannerInfo *root,
* '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
*/
static void
match_unsorted_outer(PlannerInfo *root,
@@ -320,7 +343,8 @@ match_unsorted_outer(PlannerInfo *root,
RelOptInfo *innerrel,
List *restrictlist,
List *mergeclause_list,
- JoinType jointype)
+ JoinType jointype,
+ SpecialJoinInfo *sjinfo)
{
JoinType save_jointype = jointype;
bool nestjoinOK;
@@ -333,19 +357,18 @@ match_unsorted_outer(PlannerInfo *root,
ListCell *l;
/*
- * Nestloop only supports inner, left, and IN joins. Also, if we are
- * doing a right or full join, we must use *all* the mergeclauses as join
- * clauses, else we will not have a valid plan. (Although these two flags
- * are currently inverses, keep them separate for clarity and possible
- * future changes.)
+ * Nestloop only supports inner, left, semi, and anti joins. Also, if we
+ * are doing a right or full join, we must use *all* the mergeclauses as
+ * join clauses, else we will not have a valid plan. (Although these two
+ * flags are currently inverses, keep them separate for clarity and
+ * possible future changes.)
*/
switch (jointype)
{
case JOIN_INNER:
case JOIN_LEFT:
- case JOIN_IN:
- case JOIN_UNIQUE_OUTER:
- case JOIN_UNIQUE_INNER:
+ case JOIN_SEMI:
+ case JOIN_ANTI:
nestjoinOK = true;
useallclauses = false;
break;
@@ -354,6 +377,12 @@ match_unsorted_outer(PlannerInfo *root,
nestjoinOK = false;
useallclauses = true;
break;
+ case JOIN_UNIQUE_OUTER:
+ case JOIN_UNIQUE_INNER:
+ jointype = JOIN_INNER;
+ nestjoinOK = true;
+ useallclauses = false;
+ break;
default:
elog(ERROR, "unrecognized join type: %d",
(int) jointype);
@@ -366,12 +395,12 @@ match_unsorted_outer(PlannerInfo *root,
* If we need to unique-ify the inner path, we will consider only the
* cheapest inner.
*/
- if (jointype == JOIN_UNIQUE_INNER)
+ if (save_jointype == JOIN_UNIQUE_INNER)
{
inner_cheapest_total = (Path *)
- create_unique_path(root, innerrel, inner_cheapest_total);
+ create_unique_path(root, innerrel, inner_cheapest_total, sjinfo);
+ Assert(inner_cheapest_total);
inner_cheapest_startup = inner_cheapest_total;
- jointype = JOIN_INNER;
}
else if (nestjoinOK)
{
@@ -424,8 +453,9 @@ match_unsorted_outer(PlannerInfo *root,
{
if (outerpath != outerrel->cheapest_total_path)
continue;
- outerpath = (Path *) create_unique_path(root, outerrel, outerpath);
- jointype = JOIN_INNER;
+ outerpath = (Path *) create_unique_path(root, outerrel,
+ outerpath, sjinfo);
+ Assert(outerpath);
}
/*
@@ -449,6 +479,7 @@ match_unsorted_outer(PlannerInfo *root,
create_nestloop_path(root,
joinrel,
jointype,
+ sjinfo,
outerpath,
inner_cheapest_total,
restrictlist,
@@ -458,6 +489,7 @@ match_unsorted_outer(PlannerInfo *root,
create_nestloop_path(root,
joinrel,
jointype,
+ sjinfo,
outerpath,
matpath,
restrictlist,
@@ -467,6 +499,7 @@ match_unsorted_outer(PlannerInfo *root,
create_nestloop_path(root,
joinrel,
jointype,
+ sjinfo,
outerpath,
inner_cheapest_startup,
restrictlist,
@@ -476,6 +509,7 @@ match_unsorted_outer(PlannerInfo *root,
create_nestloop_path(root,
joinrel,
jointype,
+ sjinfo,
outerpath,
index_cheapest_total,
restrictlist,
@@ -486,6 +520,7 @@ match_unsorted_outer(PlannerInfo *root,
create_nestloop_path(root,
joinrel,
jointype,
+ sjinfo,
outerpath,
index_cheapest_startup,
restrictlist,
@@ -536,6 +571,7 @@ match_unsorted_outer(PlannerInfo *root,
create_mergejoin_path(root,
joinrel,
jointype,
+ sjinfo,
outerpath,
inner_cheapest_total,
restrictlist,
@@ -604,6 +640,7 @@ match_unsorted_outer(PlannerInfo *root,
create_mergejoin_path(root,
joinrel,
jointype,
+ sjinfo,
outerpath,
innerpath,
restrictlist,
@@ -649,6 +686,7 @@ match_unsorted_outer(PlannerInfo *root,
create_mergejoin_path(root,
joinrel,
jointype,
+ sjinfo,
outerpath,
innerpath,
restrictlist,
@@ -680,6 +718,7 @@ match_unsorted_outer(PlannerInfo *root,
* '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
*/
static void
hash_inner_and_outer(PlannerInfo *root,
@@ -687,24 +726,26 @@ hash_inner_and_outer(PlannerInfo *root,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
List *restrictlist,
- JoinType jointype)
+ JoinType jointype,
+ SpecialJoinInfo *sjinfo)
{
bool isouterjoin;
List *hashclauses;
ListCell *l;
/*
- * Hashjoin only supports inner, left, and IN joins.
+ * Hashjoin only supports inner, left, semi, and anti joins.
*/
switch (jointype)
{
case JOIN_INNER:
- case JOIN_IN:
case JOIN_UNIQUE_OUTER:
case JOIN_UNIQUE_INNER:
isouterjoin = false;
break;
case JOIN_LEFT:
+ case JOIN_SEMI:
+ case JOIN_ANTI:
isouterjoin = true;
break;
default:
@@ -769,14 +810,18 @@ hash_inner_and_outer(PlannerInfo *root,
if (jointype == JOIN_UNIQUE_OUTER)
{
cheapest_total_outer = (Path *)
- create_unique_path(root, outerrel, cheapest_total_outer);
+ create_unique_path(root, outerrel,
+ cheapest_total_outer, sjinfo);
+ Assert(cheapest_total_outer);
cheapest_startup_outer = cheapest_total_outer;
jointype = JOIN_INNER;
}
else if (jointype == JOIN_UNIQUE_INNER)
{
cheapest_total_inner = (Path *)
- create_unique_path(root, innerrel, cheapest_total_inner);
+ create_unique_path(root, innerrel,
+ cheapest_total_inner, sjinfo);
+ Assert(cheapest_total_inner);
jointype = JOIN_INNER;
}
@@ -784,6 +829,7 @@ hash_inner_and_outer(PlannerInfo *root,
create_hashjoin_path(root,
joinrel,
jointype,
+ sjinfo,
cheapest_total_outer,
cheapest_total_inner,
restrictlist,
@@ -793,6 +839,7 @@ hash_inner_and_outer(PlannerInfo *root,
create_hashjoin_path(root,
joinrel,
jointype,
+ sjinfo,
cheapest_startup_outer,
cheapest_total_inner,
restrictlist,