Commit cdf0231c authored by Tom Lane's avatar Tom Lane

Create a function variable "join_search_hook" to let plugins override the

join search order portion of the planner; this is specifically intended to
simplify developing a replacement for GEQO planning.  Patch by Julius
Stroffek, editorialized on by me.  I renamed make_one_rel_by_joins to
standard_join_search and make_rels_by_joins to join_search_one_level to better
reflect their place within this scheme.
parent 149af068
...@@ -292,16 +292,17 @@ planner() ...@@ -292,16 +292,17 @@ planner()
find qual clauses that enable merge and hash joins find qual clauses that enable merge and hash joins
----make_one_rel() ----make_one_rel()
set_base_rel_pathlist() 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 find selectivity of columns used in joins
-----make_one_rel_by_joins() make_rel_from_joinlist()
jump to geqo if needed hand off join subproblems to a plugin, GEQO, or standard_join_search()
else call make_rels_by_joins() for each level of join tree needed -----standard_join_search()
make_rels_by_joins(): 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() 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. if it has join clauses, or make_rels_by_clauseless_joins() if not.
Also generate "bushy plan" joins between joinrels of lower levels. 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. cheapest path for each newly constructed joinrel.
Loop back if this wasn't the top join level. Loop back if this wasn't the top join level.
Back at query_planner: Back at query_planner:
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
bool enable_geqo = false; /* just in case GUC doesn't set it */ bool enable_geqo = false; /* just in case GUC doesn't set it */
int geqo_threshold; 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_base_rel_pathlists(PlannerInfo *root);
static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
...@@ -53,8 +56,6 @@ static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, ...@@ -53,8 +56,6 @@ static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel,
static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel,
RangeTblEntry *rte); RangeTblEntry *rte);
static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist); 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, static bool subquery_is_pushdown_safe(Query *subquery, Query *topquery,
bool *differentTypes); bool *differentTypes);
static bool recurse_pushdown_safe(Node *setOp, Query *topquery, static bool recurse_pushdown_safe(Node *setOp, Query *topquery,
...@@ -672,18 +673,20 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist) ...@@ -672,18 +673,20 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
{ {
/* /*
* Consider the different orders in which we could join the rels, * 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); return geqo(root, levels_needed, initial_rels);
else 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 * standard_join_search
* Find all possible joinpaths for a query by successively finding ways * Find possible joinpaths for a query by successively finding ways
* to join component relations into join relations. * to join component relations into join relations.
* *
* 'levels_needed' is the number of iterations needed, ie, the number of * 'levels_needed' is the number of iterations needed, ie, the number of
...@@ -691,12 +694,27 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist) ...@@ -691,12 +694,27 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
* *
* 'initial_rels' is a list of RelOptInfo nodes for each independent * 'initial_rels' is a list of RelOptInfo nodes for each independent
* jointree item. These are the components to be joined together. * 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 * Returns the final level of join relations, i.e., the relation that is
* the result of joining all the original relations together. * 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 * RelOptInfo *
make_one_rel_by_joins(PlannerInfo *root, int levels_needed, List *initial_rels) standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
{ {
List **joinitems; List **joinitems;
int lev; int lev;
...@@ -725,7 +743,7 @@ make_one_rel_by_joins(PlannerInfo *root, int levels_needed, List *initial_rels) ...@@ -725,7 +743,7 @@ make_one_rel_by_joins(PlannerInfo *root, int levels_needed, List *initial_rels)
* level, and build paths for making each one from every available * level, and build paths for making each one from every available
* pair of lower-level relations. * 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. * Do cleanup work on each just-processed rel.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,10 +29,10 @@ static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel); ...@@ -29,10 +29,10 @@ static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
/* /*
* make_rels_by_joins * join_search_one_level
* Consider ways to produce join relations containing exactly 'level' * Consider ways to produce join relations containing exactly 'level'
* jointree items. (This is one step of the dynamic-programming method * 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. * combination of lower-level rels are created and returned in a list.
* Implementation paths are created for each such joinrel, too. * Implementation paths are created for each such joinrel, too.
* *
...@@ -40,7 +40,7 @@ static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel); ...@@ -40,7 +40,7 @@ static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
* joinrels[j], 1 <= j < level, is a list of rels containing j items. * joinrels[j], 1 <= j < level, is a list of rels containing j items.
*/ */
List * 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 *result_rels = NIL;
List *new_rels; List *new_rels;
...@@ -638,9 +638,9 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) ...@@ -638,9 +638,9 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
* Note: this is only a problem if one side of a degenerate outer join * 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 * 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 * 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 * join_search_one_level(). We could dispense with this test if we were
* to try bushy plans in the "last ditch" case, but that seems much less * willing to try bushy plans in the "last ditch" case, but that seems much
* efficient. * less efficient.
*/ */
bool bool
have_join_order_restriction(PlannerInfo *root, have_join_order_restriction(PlannerInfo *root,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -23,7 +23,16 @@ ...@@ -23,7 +23,16 @@
extern bool enable_geqo; extern bool enable_geqo;
extern int geqo_threshold; 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 *make_one_rel(PlannerInfo *root, List *joinlist);
extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
List *initial_rels);
#ifdef OPTIMIZER_DEBUG #ifdef OPTIMIZER_DEBUG
extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel); extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel);
...@@ -89,7 +98,8 @@ extern void add_paths_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, ...@@ -89,7 +98,8 @@ extern void add_paths_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
* joinrels.c * joinrels.c
* routines to determine which relations to join * 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, extern RelOptInfo *make_join_rel(PlannerInfo *root,
RelOptInfo *rel1, RelOptInfo *rel2); RelOptInfo *rel1, RelOptInfo *rel2);
extern bool have_join_order_restriction(PlannerInfo *root, extern bool have_join_order_restriction(PlannerInfo *root,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment