Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit cdf0231

Browse files
committed
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.
1 parent 149af06 commit cdf0231

File tree

4 files changed

+55
-26
lines changed

4 files changed

+55
-26
lines changed

src/backend/optimizer/README

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,16 +292,17 @@ planner()
292292
find qual clauses that enable merge and hash joins
293293
----make_one_rel()
294294
set_base_rel_pathlist()
295-
find scan and all index paths for each base relation
295+
find seqscan and all index paths for each base relation
296296
find selectivity of columns used in joins
297-
-----make_one_rel_by_joins()
298-
jump to geqo if needed
299-
else call make_rels_by_joins() for each level of join tree needed
300-
make_rels_by_joins():
297+
make_rel_from_joinlist()
298+
hand off join subproblems to a plugin, GEQO, or standard_join_search()
299+
-----standard_join_search()
300+
call join_search_one_level() for each level of join tree needed
301+
join_search_one_level():
301302
For each joinrel of the prior level, do make_rels_by_clause_joins()
302303
if it has join clauses, or make_rels_by_clauseless_joins() if not.
303304
Also generate "bushy plan" joins between joinrels of lower levels.
304-
Back at make_one_rel_by_joins(), apply set_cheapest() to extract the
305+
Back at standard_join_search(), apply set_cheapest() to extract the
305306
cheapest path for each newly constructed joinrel.
306307
Loop back if this wasn't the top join level.
307308
Back at query_planner:

src/backend/optimizer/path/allpaths.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.164 2007/05/26 18:23:01 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.165 2007/09/26 18:51:50 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -37,6 +37,9 @@
3737
bool enable_geqo = false; /* just in case GUC doesn't set it */
3838
int geqo_threshold;
3939

40+
/* Hook for plugins to replace standard_join_search() */
41+
join_search_hook_type join_search_hook = NULL;
42+
4043

4144
static void set_base_rel_pathlists(PlannerInfo *root);
4245
static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
@@ -53,8 +56,6 @@ static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel,
5356
static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel,
5457
RangeTblEntry *rte);
5558
static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist);
56-
static RelOptInfo *make_one_rel_by_joins(PlannerInfo *root, int levels_needed,
57-
List *initial_rels);
5859
static bool subquery_is_pushdown_safe(Query *subquery, Query *topquery,
5960
bool *differentTypes);
6061
static bool recurse_pushdown_safe(Node *setOp, Query *topquery,
@@ -672,31 +673,48 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
672673
{
673674
/*
674675
* Consider the different orders in which we could join the rels,
675-
* using either GEQO or regular optimizer.
676+
* using a plugin, GEQO, or the regular join search code.
676677
*/
677-
if (enable_geqo && levels_needed >= geqo_threshold)
678+
if (join_search_hook)
679+
return (*join_search_hook) (root, levels_needed, initial_rels);
680+
else if (enable_geqo && levels_needed >= geqo_threshold)
678681
return geqo(root, levels_needed, initial_rels);
679682
else
680-
return make_one_rel_by_joins(root, levels_needed, initial_rels);
683+
return standard_join_search(root, levels_needed, initial_rels);
681684
}
682685
}
683686

684687
/*
685-
* make_one_rel_by_joins
686-
* Find all possible joinpaths for a query by successively finding ways
688+
* standard_join_search
689+
* Find possible joinpaths for a query by successively finding ways
687690
* to join component relations into join relations.
688691
*
689692
* 'levels_needed' is the number of iterations needed, ie, the number of
690693
* independent jointree items in the query. This is > 1.
691694
*
692695
* 'initial_rels' is a list of RelOptInfo nodes for each independent
693696
* jointree item. These are the components to be joined together.
697+
* Note that levels_needed == list_length(initial_rels).
694698
*
695699
* Returns the final level of join relations, i.e., the relation that is
696700
* the result of joining all the original relations together.
701+
* At least one implementation path must be provided for this relation and
702+
* all required sub-relations.
703+
*
704+
* To support loadable plugins that modify planner behavior by changing the
705+
* join searching algorithm, we provide a hook variable that lets a plugin
706+
* replace or supplement this function. Any such hook must return the same
707+
* final join relation as the standard code would, but it might have a
708+
* different set of implementation paths attached, and only the sub-joinrels
709+
* needed for these paths need have been instantiated.
710+
*
711+
* Note to plugin authors: the functions invoked during standard_join_search()
712+
* modify root->join_rel_list and root->join_rel_hash. If you want to do more
713+
* than one join-order search, you'll probably need to save and restore the
714+
* original states of those data structures. See geqo_eval() for an example.
697715
*/
698-
static RelOptInfo *
699-
make_one_rel_by_joins(PlannerInfo *root, int levels_needed, List *initial_rels)
716+
RelOptInfo *
717+
standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
700718
{
701719
List **joinitems;
702720
int lev;
@@ -725,7 +743,7 @@ make_one_rel_by_joins(PlannerInfo *root, int levels_needed, List *initial_rels)
725743
* level, and build paths for making each one from every available
726744
* pair of lower-level relations.
727745
*/
728-
joinitems[lev] = make_rels_by_joins(root, lev, joinitems);
746+
joinitems[lev] = join_search_one_level(root, lev, joinitems);
729747

730748
/*
731749
* Do cleanup work on each just-processed rel.

src/backend/optimizer/path/joinrels.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.86 2007/02/16 00:14:01 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.87 2007/09/26 18:51:50 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -29,18 +29,18 @@ static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
2929

3030

3131
/*
32-
* make_rels_by_joins
32+
* join_search_one_level
3333
* Consider ways to produce join relations containing exactly 'level'
3434
* jointree items. (This is one step of the dynamic-programming method
35-
* embodied in make_one_rel_by_joins.) Join rel nodes for each feasible
35+
* embodied in standard_join_search.) Join rel nodes for each feasible
3636
* combination of lower-level rels are created and returned in a list.
3737
* Implementation paths are created for each such joinrel, too.
3838
*
3939
* level: level of rels we want to make this time.
4040
* joinrels[j], 1 <= j < level, is a list of rels containing j items.
4141
*/
4242
List *
43-
make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
43+
join_search_one_level(PlannerInfo *root, int level, List **joinrels)
4444
{
4545
List *result_rels = NIL;
4646
List *new_rels;
@@ -638,9 +638,9 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
638638
* Note: this is only a problem if one side of a degenerate outer join
639639
* contains multiple rels, or a clauseless join is required within an IN's
640640
* RHS; else we will find a join path via the "last ditch" case in
641-
* make_rels_by_joins(). We could dispense with this test if we were willing
642-
* to try bushy plans in the "last ditch" case, but that seems much less
643-
* efficient.
641+
* join_search_one_level(). We could dispense with this test if we were
642+
* willing to try bushy plans in the "last ditch" case, but that seems much
643+
* less efficient.
644644
*/
645645
bool
646646
have_join_order_restriction(PlannerInfo *root,

src/include/optimizer/paths.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.98 2007/05/22 01:40:33 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.99 2007/09/26 18:51:51 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -23,7 +23,16 @@
2323
extern bool enable_geqo;
2424
extern int geqo_threshold;
2525

26+
/* Hook for plugins to replace standard_join_search() */
27+
typedef RelOptInfo * (*join_search_hook_type) (PlannerInfo *root,
28+
int levels_needed,
29+
List *initial_rels);
30+
extern PGDLLIMPORT join_search_hook_type join_search_hook;
31+
32+
2633
extern RelOptInfo *make_one_rel(PlannerInfo *root, List *joinlist);
34+
extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
35+
List *initial_rels);
2736

2837
#ifdef OPTIMIZER_DEBUG
2938
extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel);
@@ -89,7 +98,8 @@ extern void add_paths_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
8998
* joinrels.c
9099
* routines to determine which relations to join
91100
*/
92-
extern List *make_rels_by_joins(PlannerInfo *root, int level, List **joinrels);
101+
extern List *join_search_one_level(PlannerInfo *root, int level,
102+
List **joinrels);
93103
extern RelOptInfo *make_join_rel(PlannerInfo *root,
94104
RelOptInfo *rel1, RelOptInfo *rel2);
95105
extern bool have_join_order_restriction(PlannerInfo *root,

0 commit comments

Comments
 (0)