88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.102 2009/07/23 17:42:06 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.103 2009/11/28 00:46:19 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
1919#include "optimizer/paths.h"
2020
2121
22- static List * make_rels_by_clause_joins (PlannerInfo * root ,
22+ static void make_rels_by_clause_joins (PlannerInfo * root ,
2323RelOptInfo * old_rel ,
2424ListCell * other_rels );
25- static List * make_rels_by_clauseless_joins (PlannerInfo * root ,
25+ static void make_rels_by_clauseless_joins (PlannerInfo * root ,
2626RelOptInfo * old_rel ,
2727ListCell * other_rels );
2828static bool has_join_restriction (PlannerInfo * root ,RelOptInfo * rel );
@@ -40,17 +40,23 @@ static bool restriction_is_constant_false(List *restrictlist);
4040 * combination of lower-level rels are created and returned in a list.
4141 * Implementation paths are created for each such joinrel, too.
4242 *
43- * level: level of rels we want to make this time.
44- * joinrels[j], 1 <= j < level, is a list of rels containing j items.
43+ * level: level of rels we want to make this time
44+ * root->join_rel_level[j], 1 <= j < level, is a list of rels containing j items
45+ *
46+ * The result is returned in root->join_rel_level[level].
4547 */
46- List *
47- join_search_one_level (PlannerInfo * root ,int level , List * * joinrels )
48+ void
49+ join_search_one_level (PlannerInfo * root ,int level )
4850{
49- List * result_rels = NIL ;
50- List * new_rels ;
51+ List * * joinrels = root -> join_rel_level ;
5152ListCell * r ;
5253int k ;
5354
55+ Assert (joinrels [level ]== NIL );
56+
57+ /* Set join_cur_level so that new joinrels are added to proper list */
58+ root -> join_cur_level = level ;
59+
5460/*
5561 * First, consider left-sided and right-sided plans, in which rels of
5662 * exactly level-1 member relations are joined against initial relations.
@@ -88,9 +94,9 @@ join_search_one_level(PlannerInfo *root, int level, List **joinrels)
8894 *
8995 * See also the last-ditch case below.
9096 */
91- new_rels = make_rels_by_clause_joins (root ,
92- old_rel ,
93- other_rels );
97+ make_rels_by_clause_joins (root ,
98+ old_rel ,
99+ other_rels );
94100}
95101else
96102{
@@ -99,20 +105,10 @@ join_search_one_level(PlannerInfo *root, int level, List **joinrels)
99105 * relation, either directly or by join-order restrictions.
100106 * Cartesian product time.
101107 */
102- new_rels = make_rels_by_clauseless_joins (root ,
103- old_rel ,
104- other_rels );
108+ make_rels_by_clauseless_joins (root ,
109+ old_rel ,
110+ other_rels );
105111}
106-
107- /*
108- * At levels above 2 we will generate the same joined relation in
109- * multiple ways --- for example (a join b) join c is the same
110- * RelOptInfo as (b join c) join a, though the second case will add a
111- * different set of Paths to it. To avoid making extra work for
112- * subsequent passes, do not enter the same RelOptInfo into our output
113- * list multiple times.
114- */
115- result_rels = list_concat_unique_ptr (result_rels ,new_rels );
116112}
117113
118114/*
@@ -168,13 +164,7 @@ join_search_one_level(PlannerInfo *root, int level, List **joinrels)
168164if (have_relevant_joinclause (root ,old_rel ,new_rel )||
169165have_join_order_restriction (root ,old_rel ,new_rel ))
170166{
171- RelOptInfo * jrel ;
172-
173- jrel = make_join_rel (root ,old_rel ,new_rel );
174- /* Avoid making duplicate entries ... */
175- if (jrel )
176- result_rels = list_append_unique_ptr (result_rels ,
177- jrel );
167+ (void )make_join_rel (root ,old_rel ,new_rel );
178168}
179169}
180170}
@@ -193,7 +183,7 @@ join_search_one_level(PlannerInfo *root, int level, List **joinrels)
193183 * choice but to make cartesian joins.We consider only left-sided and
194184 * right-sided cartesian joins in this case (no bushy).
195185 */
196- if (result_rels == NIL )
186+ if (joinrels [ level ] == NIL )
197187{
198188/*
199189 * This loop is just like the first one, except we always call
@@ -211,11 +201,9 @@ join_search_one_level(PlannerInfo *root, int level, List **joinrels)
211201other_rels = list_head (joinrels [1 ]);/* consider all initial
212202 * rels */
213203
214- new_rels = make_rels_by_clauseless_joins (root ,
215- old_rel ,
216- other_rels );
217-
218- result_rels = list_concat_unique_ptr (result_rels ,new_rels );
204+ make_rels_by_clauseless_joins (root ,
205+ old_rel ,
206+ other_rels );
219207}
220208
221209/*----------
@@ -235,19 +223,23 @@ join_search_one_level(PlannerInfo *root, int level, List **joinrels)
235223 * never fail, and so the following sanity check is useful.
236224 *----------
237225 */
238- if (result_rels == NIL && root -> join_info_list == NIL )
226+ if (joinrels [ level ] == NIL && root -> join_info_list == NIL )
239227elog (ERROR ,"failed to build any %d-way joins" ,level );
240228}
241-
242- return result_rels ;
243229}
244230
245231/*
246232 * make_rels_by_clause_joins
247233 * Build joins between the given relation 'old_rel' and other relations
248234 * that participate in join clauses that 'old_rel' also participates in
249235 * (or participate in join-order restrictions with it).
250- * The join rel nodes are returned in a list.
236+ * The join rels are returned in root->join_rel_level[join_cur_level].
237+ *
238+ * Note: at levels above 2 we will generate the same joined relation in
239+ * multiple ways --- for example (a join b) join c is the same RelOptInfo as
240+ * (b join c) join a, though the second case will add a different set of Paths
241+ * to it. This is the reason for using the join_rel_level mechanism, which
242+ * automatically ensures that each new joinrel is only added to the list once.
251243 *
252244 * 'old_rel' is the relation entry for the relation to be joined
253245 * 'other_rels': the first cell in a linked list containing the other
@@ -256,12 +248,11 @@ join_search_one_level(PlannerInfo *root, int level, List **joinrels)
256248 * Currently, this is only used with initial rels in other_rels, but it
257249 * will work for joining to joinrels too.
258250 */
259- static List *
251+ static void
260252make_rels_by_clause_joins (PlannerInfo * root ,
261253RelOptInfo * old_rel ,
262254ListCell * other_rels )
263255{
264- List * result = NIL ;
265256ListCell * l ;
266257
267258for_each_cell (l ,other_rels )
@@ -272,23 +263,17 @@ make_rels_by_clause_joins(PlannerInfo *root,
272263(have_relevant_joinclause (root ,old_rel ,other_rel )||
273264have_join_order_restriction (root ,old_rel ,other_rel )))
274265{
275- RelOptInfo * jrel ;
276-
277- jrel = make_join_rel (root ,old_rel ,other_rel );
278- if (jrel )
279- result = lcons (jrel ,result );
266+ (void )make_join_rel (root ,old_rel ,other_rel );
280267}
281268}
282-
283- return result ;
284269}
285270
286271/*
287272 * make_rels_by_clauseless_joins
288273 * Given a relation 'old_rel' and a list of other relations
289274 * 'other_rels', create a join relation between 'old_rel' and each
290275 * member of 'other_rels' that isn't already included in 'old_rel'.
291- * The joinrel nodes are returned ina list .
276+ * The joinrels are returned inroot->join_rel_level[join_cur_level] .
292277 *
293278 * 'old_rel' is the relation entry for the relation to be joined
294279 * 'other_rels': the first cell of a linked list containing the
@@ -297,34 +282,22 @@ make_rels_by_clause_joins(PlannerInfo *root,
297282 * Currently, this is only used with initial rels in other_rels, but it would
298283 * work for joining to joinrels too.
299284 */
300- static List *
285+ static void
301286make_rels_by_clauseless_joins (PlannerInfo * root ,
302287RelOptInfo * old_rel ,
303288ListCell * other_rels )
304289{
305- List * result = NIL ;
306- ListCell * i ;
290+ ListCell * l ;
307291
308- for_each_cell (i ,other_rels )
292+ for_each_cell (l ,other_rels )
309293{
310- RelOptInfo * other_rel = (RelOptInfo * )lfirst (i );
294+ RelOptInfo * other_rel = (RelOptInfo * )lfirst (l );
311295
312296if (!bms_overlap (other_rel -> relids ,old_rel -> relids ))
313297{
314- RelOptInfo * jrel ;
315-
316- jrel = make_join_rel (root ,old_rel ,other_rel );
317-
318- /*
319- * As long as given other_rels are distinct, don't need to test to
320- * see if jrel is already part of output list.
321- */
322- if (jrel )
323- result = lcons (jrel ,result );
298+ (void )make_join_rel (root ,old_rel ,other_rel );
324299}
325300}
326-
327- return result ;
328301}
329302
330303