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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy