find qual clauses that enable merge and hash joins
----make_one_rel()
set_base_rel_pathlist()
- find scan and all index paths for each base relation
+ find seqscan and all index paths for each base relation
find selectivity of columns used in joins
------make_one_rel_by_joins()
- jump to geqo if needed
- else call make_rels_by_joins() for each level of join tree needed
- make_rels_by_joins():
+ make_rel_from_joinlist()
+ hand off join subproblems to a plugin, GEQO, or standard_join_search()
+-----standard_join_search()
+ call join_search_one_level() for each level of join tree needed
+ join_search_one_level():
For each joinrel of the prior level, do make_rels_by_clause_joins()
if it has join clauses, or make_rels_by_clauseless_joins() if not.
Also generate "bushy plan" joins between joinrels of lower levels.
- Back at make_one_rel_by_joins(), apply set_cheapest() to extract the
+ Back at standard_join_search(), apply set_cheapest() to extract the
cheapest path for each newly constructed joinrel.
Loop back if this wasn't the top join level.
Back at query_planner:
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.164 2007/05/26 18:23:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.165 2007/09/26 18:51:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool enable_geqo = false; /* just in case GUC doesn't set it */
int geqo_threshold;
+/* Hook for plugins to replace standard_join_search() */
+join_search_hook_type join_search_hook = NULL;
+
static void set_base_rel_pathlists(PlannerInfo *root);
static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel,
RangeTblEntry *rte);
static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist);
-static RelOptInfo *make_one_rel_by_joins(PlannerInfo *root, int levels_needed,
- List *initial_rels);
static bool subquery_is_pushdown_safe(Query *subquery, Query *topquery,
bool *differentTypes);
static bool recurse_pushdown_safe(Node *setOp, Query *topquery,
{
/*
* Consider the different orders in which we could join the rels,
- * using either GEQO or regular optimizer.
+ * using a plugin, GEQO, or the regular join search code.
*/
- if (enable_geqo && levels_needed >= geqo_threshold)
+ if (join_search_hook)
+ return (*join_search_hook) (root, levels_needed, initial_rels);
+ else if (enable_geqo && levels_needed >= geqo_threshold)
return geqo(root, levels_needed, initial_rels);
else
- return make_one_rel_by_joins(root, levels_needed, initial_rels);
+ return standard_join_search(root, levels_needed, initial_rels);
}
}
/*
- * make_one_rel_by_joins
- * Find all possible joinpaths for a query by successively finding ways
+ * standard_join_search
+ * Find 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
*
* 'initial_rels' is a list of RelOptInfo nodes for each independent
* jointree item. These are the components to be joined together.
+ * Note that levels_needed == list_length(initial_rels).
*
* Returns the final level of join relations, i.e., the relation that is
* the result of joining all the original relations together.
+ * At least one implementation path must be provided for this relation and
+ * all required sub-relations.
+ *
+ * To support loadable plugins that modify planner behavior by changing the
+ * join searching algorithm, we provide a hook variable that lets a plugin
+ * replace or supplement this function. Any such hook must return the same
+ * final join relation as the standard code would, but it might have a
+ * different set of implementation paths attached, and only the sub-joinrels
+ * needed for these paths need have been instantiated.
+ *
+ * Note to plugin authors: the functions invoked during standard_join_search()
+ * modify root->join_rel_list and root->join_rel_hash. If you want to do more
+ * than one join-order search, you'll probably need to save and restore the
+ * original states of those data structures. See geqo_eval() for an example.
*/
-static RelOptInfo *
-make_one_rel_by_joins(PlannerInfo *root, int levels_needed, List *initial_rels)
+RelOptInfo *
+standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
{
List **joinitems;
int lev;
* level, and build paths for making each one from every available
* pair of lower-level relations.
*/
- joinitems[lev] = make_rels_by_joins(root, lev, joinitems);
+ joinitems[lev] = join_search_one_level(root, lev, joinitems);
/*
* Do cleanup work on each just-processed rel.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.86 2007/02/16 00:14:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.87 2007/09/26 18:51:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * make_rels_by_joins
+ * join_search_one_level
* Consider ways to produce join relations containing exactly 'level'
* jointree items. (This is one step of the dynamic-programming method
- * embodied in make_one_rel_by_joins.) Join rel nodes for each feasible
+ * embodied in standard_join_search.) Join rel nodes for each feasible
* combination of lower-level rels are created and returned in a list.
* Implementation paths are created for each such joinrel, too.
*
* joinrels[j], 1 <= j < level, is a list of rels containing j items.
*/
List *
-make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
+join_search_one_level(PlannerInfo *root, int level, List **joinrels)
{
List *result_rels = NIL;
List *new_rels;
* Note: this is only a problem if one side of a degenerate outer join
* contains multiple rels, or a clauseless join is required within an IN's
* RHS; else we will find a join path via the "last ditch" case in
- * make_rels_by_joins(). We could dispense with this test if we were willing
- * to try bushy plans in the "last ditch" case, but that seems much less
- * efficient.
+ * join_search_one_level(). We could dispense with this test if we were
+ * willing to try bushy plans in the "last ditch" case, but that seems much
+ * less efficient.
*/
bool
have_join_order_restriction(PlannerInfo *root,
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.98 2007/05/22 01:40:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.99 2007/09/26 18:51:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern bool enable_geqo;
extern int geqo_threshold;
+/* Hook for plugins to replace standard_join_search() */
+typedef RelOptInfo * (*join_search_hook_type) (PlannerInfo *root,
+ int levels_needed,
+ List *initial_rels);
+extern PGDLLIMPORT join_search_hook_type join_search_hook;
+
+
extern RelOptInfo *make_one_rel(PlannerInfo *root, List *joinlist);
+extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
+ List *initial_rels);
#ifdef OPTIMIZER_DEBUG
extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel);
* joinrels.c
* routines to determine which relations to join
*/
-extern List *make_rels_by_joins(PlannerInfo *root, int level, List **joinrels);
+extern List *join_search_one_level(PlannerInfo *root, int level,
+ List **joinrels);
extern RelOptInfo *make_join_rel(PlannerInfo *root,
RelOptInfo *rel1, RelOptInfo *rel2);
extern bool have_join_order_restriction(PlannerInfo *root,