diff --git a/src/backend/optimizer/README b/src/backend/optimizer/README index 6f9d008cbff..fa16404fd4e 100644 --- a/src/backend/optimizer/README +++ b/src/backend/optimizer/README @@ -292,16 +292,17 @@ planner() 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: diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 0ad3dc5aae1..cc82380dc6d 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * 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 @@ 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, @@ -53,8 +56,6 @@ static void set_function_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, @@ -672,18 +673,20 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist) { /* * 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 @@ -691,12 +694,27 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist) * * '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; @@ -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 * 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. diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index d7f9d802bb3..6ee442236ef 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -8,7 +8,7 @@ * * * 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); /* - * 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. * @@ -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. */ 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; @@ -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 * 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, diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index 7199a545b29..cbde0c7b9a5 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -23,7 +23,16 @@ 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); @@ -89,7 +98,8 @@ extern void add_paths_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, * 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,