aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/allpaths.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/allpaths.c')
-rw-r--r--src/backend/optimizer/path/allpaths.c101
1 files changed, 70 insertions, 31 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 999364d5637..605b60b5845 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.62 2000/05/31 00:28:22 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.63 2000/09/12 21:06:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,7 +26,9 @@ int geqo_rels = DEFAULT_GEQO_RELS;
static void set_base_rel_pathlist(Query *root);
-static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed);
+static List *build_jointree_rels(Query *root);
+static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed,
+ List *initial_rels);
#ifdef OPTIMIZER_DEBUG
static void debug_print_rel(Query *root, RelOptInfo *rel);
@@ -43,27 +45,38 @@ RelOptInfo *
make_one_rel(Query *root)
{
int levels_needed;
+ List *initial_rels;
/*
- * Set the number of join (not nesting) levels yet to be processed.
+ * Count the number of top-level jointree nodes. This is the depth
+ * of the dynamic-programming algorithm we must employ to consider
+ * all ways of joining the top-level nodes. Currently, we build
+ * JoinExpr joins in exactly the order implied by the join expression,
+ * so no dynamic-programming search is needed within a JoinExpr.
*/
- levels_needed = length(root->base_rel_list);
+ levels_needed = length(root->jointree);
if (levels_needed <= 0)
- return NULL;
+ return NULL; /* nothing to do? */
/*
* Generate access paths for the base rels.
*/
set_base_rel_pathlist(root);
+ /*
+ * Construct a list of rels corresponding to the toplevel jointree nodes.
+ * This may contain both base rels and rels constructed according to
+ * explicit JOIN directives.
+ */
+ initial_rels = build_jointree_rels(root);
+
if (levels_needed == 1)
{
-
/*
- * Single relation, no more processing is required.
+ * Single jointree node, so we're done.
*/
- return (RelOptInfo *) lfirst(root->base_rel_list);
+ return (RelOptInfo *) lfirst(initial_rels);
}
else
{
@@ -71,7 +84,7 @@ make_one_rel(Query *root)
/*
* Generate join tree.
*/
- return make_one_rel_by_joins(root, levels_needed);
+ return make_one_rel_by_joins(root, levels_needed, initial_rels);
}
}
@@ -126,19 +139,46 @@ set_base_rel_pathlist(Query *root)
}
/*
+ * build_jointree_rels
+ * Construct a RelOptInfo for each item in the query's jointree.
+ *
+ * At present, we handle explicit joins in the FROM clause exactly as
+ * specified, with no search for other join orders. Only the cross-product
+ * joins at the top level are involved in the dynamic-programming search.
+ */
+static List *
+build_jointree_rels(Query *root)
+{
+ List *rels = NIL;
+ List *jt;
+
+ foreach(jt, root->jointree)
+ {
+ Node *jtnode = (Node *) lfirst(jt);
+
+ rels = lappend(rels, make_rel_from_jointree(root, jtnode));
+ }
+ return rels;
+}
+
+/*
* make_one_rel_by_joins
* Find all possible joinpaths for a query by successively finding ways
* to join component relations into join relations.
*
* 'levels_needed' is the number of iterations needed, ie, the number of
- * base relations present in the query
+ * independent jointree items in the query. This is > 1.
+ *
+ * 'initial_rels' is a list of RelOptInfo nodes for each independent
+ * jointree item. These are the components to be joined together.
*
* Returns the final level of join relations, i.e., the relation that is
* the result of joining all the original relations together.
*/
static RelOptInfo *
-make_one_rel_by_joins(Query *root, int levels_needed)
+make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels)
{
+ List **joinitems;
int lev;
RelOptInfo *rel;
@@ -152,34 +192,35 @@ make_one_rel_by_joins(Query *root, int levels_needed)
/*
* We employ a simple "dynamic programming" algorithm: we first find
- * all ways to build joins of two base relations, then all ways to
- * build joins of three base relations (from two-base-rel joins and
- * other base rels), then four-base-rel joins, and so on until we have
- * considered all ways to join all N relations into one rel.
+ * all ways to build joins of two jointree items, then all ways to
+ * build joins of three items (from two-item joins and single items),
+ * then four-item joins, and so on until we have considered all ways
+ * to join all the items into one rel.
+ *
+ * joinitems[j] is a list of all the j-item rels. Initially we set
+ * joinitems[1] to represent all the single-jointree-item relations.
*/
+ joinitems = (List **) palloc((levels_needed+1) * sizeof(List *));
+ MemSet(joinitems, 0, (levels_needed+1) * sizeof(List *));
+
+ joinitems[1] = initial_rels;
for (lev = 2; lev <= levels_needed; lev++)
{
- List *first_old_rel = root->join_rel_list;
List *x;
/*
* Determine all possible pairs of relations to be joined at this
* level, and build paths for making each one from every available
- * pair of lower-level relations. Results are prepended to
- * root->join_rel_list.
+ * pair of lower-level relations.
*/
- make_rels_by_joins(root, lev);
+ joinitems[lev] = make_rels_by_joins(root, lev, joinitems);
/*
- * The relations created at the current level will appear at the
- * front of root->join_rel_list.
+ * Do cleanup work on each just-processed rel.
*/
- foreach(x, root->join_rel_list)
+ foreach(x, joinitems[lev])
{
- if (x == first_old_rel)
- break; /* no more rels added at this level */
-
rel = (RelOptInfo *) lfirst(x);
#ifdef NOT_USED
@@ -202,14 +243,12 @@ make_one_rel_by_joins(Query *root, int levels_needed)
}
/*
- * Now, the front of the join_rel_list should be the single rel
+ * We should have a single rel at the final level,
* representing the join of all the base rels.
*/
- Assert(length(root->join_rel_list) > 0);
- rel = (RelOptInfo *) lfirst(root->join_rel_list);
- Assert(length(rel->relids) == levels_needed);
- Assert(length(root->join_rel_list) == 1 ||
- length(((RelOptInfo *) lsecond(root->join_rel_list))->relids) < levels_needed);
+ Assert(length(joinitems[levels_needed]) == 1);
+ rel = (RelOptInfo *) lfirst(joinitems[levels_needed]);
+ Assert(length(rel->relids) == length(root->base_rel_list));
return rel;
}