|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.131 2010/03/22 13:57:15 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.132 2010/03/28 22:59:32 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
|
22 | 22 | #include "optimizer/paths.h"
|
23 | 23 |
|
24 | 24 |
|
25 |
| -static bool join_is_removable(PlannerInfo *root, RelOptInfo *joinrel, |
26 |
| - RelOptInfo *outerrel, RelOptInfo *innerrel, |
27 |
| - List *restrictlist, JoinType jointype); |
28 |
| -static void generate_outer_only(PlannerInfo *root, RelOptInfo *joinrel, |
29 |
| - RelOptInfo *outerrel); |
30 | 25 | static void sort_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
|
31 | 26 | RelOptInfo *outerrel, RelOptInfo *innerrel,
|
32 | 27 | List *restrictlist, List *mergeclause_list,
|
@@ -83,27 +78,11 @@ add_paths_to_joinrel(PlannerInfo *root,
|
83 | 78 | {
|
84 | 79 | List *mergeclause_list = NIL;
|
85 | 80 |
|
86 |
| - /* |
87 |
| - * 0. Consider join removal. This is always the most efficient strategy, |
88 |
| - * so if it works, there's no need to consider anything further. |
89 |
| - */ |
90 |
| - if (join_is_removable(root, joinrel, outerrel, innerrel, |
91 |
| - restrictlist, jointype)) |
92 |
| - { |
93 |
| - generate_outer_only(root, joinrel, outerrel); |
94 |
| - return; |
95 |
| - } |
96 |
| - |
97 | 81 | /*
|
98 | 82 | * Find potential mergejoin clauses. We can skip this if we are not
|
99 | 83 | * interested in doing a mergejoin. However, mergejoin is currently our
|
100 | 84 | * only way of implementing full outer joins, so override mergejoin
|
101 | 85 | * disable if it's a full join.
|
102 |
| - * |
103 |
| - * Note: do this after join_is_removable(), because this sets the |
104 |
| - * outer_is_left flags in the mergejoin clauses, while join_is_removable |
105 |
| - * uses those flags for its own purposes. Currently, they set the flags |
106 |
| - * the same way anyway, but let's avoid unnecessary entanglement. |
107 | 86 | */
|
108 | 87 | if (enable_mergejoin || jointype == JOIN_FULL)
|
109 | 88 | mergeclause_list = select_mergejoin_clauses(root,
|
@@ -185,188 +164,6 @@ clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel,
|
185 | 164 | return false; /* no good for these input relations */
|
186 | 165 | }
|
187 | 166 |
|
188 |
| -/* |
189 |
| - * join_is_removable |
190 |
| - * Determine whether we need not perform the join at all, because |
191 |
| - * it will just duplicate its left input. |
192 |
| - * |
193 |
| - * This is true for a left join for which the join condition cannot match |
194 |
| - * more than one inner-side row. (There are other possibly interesting |
195 |
| - * cases, but we don't have the infrastructure to prove them.) We also |
196 |
| - * have to check that the inner side doesn't generate any variables needed |
197 |
| - * above the join. |
198 |
| - * |
199 |
| - * Note: there is no need to consider the symmetrical case of duplicating the |
200 |
| - * right input, because add_paths_to_joinrel() will be called with each rel |
201 |
| - * on the outer side. |
202 |
| - */ |
203 |
| -static bool |
204 |
| -join_is_removable(PlannerInfo *root, |
205 |
| - RelOptInfo *joinrel, |
206 |
| - RelOptInfo *outerrel, |
207 |
| - RelOptInfo *innerrel, |
208 |
| - List *restrictlist, |
209 |
| - JoinType jointype) |
210 |
| -{ |
211 |
| - List *clause_list = NIL; |
212 |
| - ListCell *l; |
213 |
| - int attroff; |
214 |
| - |
215 |
| - /* |
216 |
| - * Currently, we only know how to remove left joins to a baserel with |
217 |
| - * unique indexes. We can check most of these criteria pretty trivially |
218 |
| - * to avoid doing useless extra work. But checking whether any of the |
219 |
| - * indexes are unique would require iterating over the indexlist, so for |
220 |
| - * now we just make sure there are indexes of some sort or other. If none |
221 |
| - * of them are unique, join removal will still fail, just slightly later. |
222 |
| - */ |
223 |
| - if (jointype != JOIN_LEFT || |
224 |
| - innerrel->reloptkind == RELOPT_JOINREL || |
225 |
| - innerrel->rtekind != RTE_RELATION || |
226 |
| - innerrel->indexlist == NIL) |
227 |
| - return false; |
228 |
| - |
229 |
| - /* |
230 |
| - * We can't remove the join if any inner-rel attributes are used above the |
231 |
| - * join. |
232 |
| - * |
233 |
| - * Note that this test only detects use of inner-rel attributes in higher |
234 |
| - * join conditions and the target list. There might be such attributes in |
235 |
| - * pushed-down conditions at this join, too. We check that case below. |
236 |
| - * |
237 |
| - * As a micro-optimization, it seems better to start with max_attr and |
238 |
| - * count down rather than starting with min_attr and counting up, on the |
239 |
| - * theory that the system attributes are somewhat less likely to be wanted |
240 |
| - * and should be tested last. |
241 |
| - */ |
242 |
| - for (attroff = innerrel->max_attr - innerrel->min_attr; |
243 |
| - attroff >= 0; |
244 |
| - attroff--) |
245 |
| - { |
246 |
| - if (!bms_is_subset(innerrel->attr_needed[attroff], joinrel->relids)) |
247 |
| - return false; |
248 |
| - } |
249 |
| - |
250 |
| - /* |
251 |
| - * Similarly check that the inner rel doesn't produce any PlaceHolderVars |
252 |
| - * that will be used above the join. |
253 |
| - */ |
254 |
| - foreach(l, root->placeholder_list) |
255 |
| - { |
256 |
| - PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l); |
257 |
| - |
258 |
| - if (bms_is_subset(phinfo->ph_eval_at, innerrel->relids) && |
259 |
| - !bms_is_subset(phinfo->ph_needed, joinrel->relids)) |
260 |
| - return false; |
261 |
| - } |
262 |
| - |
263 |
| - /* |
264 |
| - * Search for mergejoinable clauses that constrain the inner rel against |
265 |
| - * either the outer rel or a pseudoconstant. If an operator is |
266 |
| - * mergejoinable then it behaves like equality for some btree opclass, so |
267 |
| - * it's what we want. The mergejoinability test also eliminates clauses |
268 |
| - * containing volatile functions, which we couldn't depend on. |
269 |
| - */ |
270 |
| - foreach(l, restrictlist) |
271 |
| - { |
272 |
| - RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l); |
273 |
| - |
274 |
| - /* |
275 |
| - * If we find a pushed-down clause, it must have come from above the |
276 |
| - * outer join and it must contain references to the inner rel. (If it |
277 |
| - * had only outer-rel variables, it'd have been pushed down into the |
278 |
| - * outer rel.) Therefore, we can conclude that join removal is unsafe |
279 |
| - * without any examination of the clause contents. |
280 |
| - */ |
281 |
| - if (restrictinfo->is_pushed_down) |
282 |
| - return false; |
283 |
| - |
284 |
| - /* Ignore if it's not a mergejoinable clause */ |
285 |
| - if (!restrictinfo->can_join || |
286 |
| - restrictinfo->mergeopfamilies == NIL) |
287 |
| - continue; /* not mergejoinable */ |
288 |
| - |
289 |
| - /* |
290 |
| - * Check if clause has the form "outer op inner" or "inner op outer". |
291 |
| - */ |
292 |
| - if (!clause_sides_match_join(restrictinfo, outerrel, innerrel)) |
293 |
| - continue; /* no good for these input relations */ |
294 |
| - |
295 |
| - /* OK, add to list */ |
296 |
| - clause_list = lappend(clause_list, restrictinfo); |
297 |
| - } |
298 |
| - |
299 |
| - /* Now examine the rel's restriction clauses for var = const clauses */ |
300 |
| - foreach(l, innerrel->baserestrictinfo) |
301 |
| - { |
302 |
| - RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l); |
303 |
| - |
304 |
| - /* |
305 |
| - * Note: can_join won't be set for a restriction clause, but |
306 |
| - * mergeopfamilies will be if it has a mergejoinable operator and |
307 |
| - * doesn't contain volatile functions. |
308 |
| - */ |
309 |
| - if (restrictinfo->mergeopfamilies == NIL) |
310 |
| - continue; /* not mergejoinable */ |
311 |
| - |
312 |
| - /* |
313 |
| - * The clause certainly doesn't refer to anything but the given rel. |
314 |
| - * If either side is pseudoconstant then we can use it. |
315 |
| - */ |
316 |
| - if (bms_is_empty(restrictinfo->left_relids)) |
317 |
| - { |
318 |
| - /* righthand side is inner */ |
319 |
| - restrictinfo->outer_is_left = true; |
320 |
| - } |
321 |
| - else if (bms_is_empty(restrictinfo->right_relids)) |
322 |
| - { |
323 |
| - /* lefthand side is inner */ |
324 |
| - restrictinfo->outer_is_left = false; |
325 |
| - } |
326 |
| - else |
327 |
| - continue; |
328 |
| - |
329 |
| - /* OK, add to list */ |
330 |
| - clause_list = lappend(clause_list, restrictinfo); |
331 |
| - } |
332 |
| - |
333 |
| - /* Now examine the indexes to see if we have a matching unique index */ |
334 |
| - if (relation_has_unique_index_for(root, innerrel, clause_list)) |
335 |
| - return true; |
336 |
| - |
337 |
| - /* |
338 |
| - * Some day it would be nice to check for other methods of establishing |
339 |
| - * distinctness. |
340 |
| - */ |
341 |
| - return false; |
342 |
| -} |
343 |
| - |
344 |
| -/* |
345 |
| - * generate_outer_only |
346 |
| - * Generate "join" paths when we have found the join is removable. |
347 |
| - */ |
348 |
| -static void |
349 |
| -generate_outer_only(PlannerInfo *root, RelOptInfo *joinrel, |
350 |
| - RelOptInfo *outerrel) |
351 |
| -{ |
352 |
| - ListCell *lc; |
353 |
| - |
354 |
| - /* |
355 |
| - * For the moment, replicate all of the outerrel's paths as join paths. |
356 |
| - * Some of them might not really be interesting above the join, if they |
357 |
| - * have sort orderings that have no real use except to do a mergejoin for |
358 |
| - * the join we've just found we don't need. But distinguishing that case |
359 |
| - * probably isn't worth the extra code it would take. |
360 |
| - */ |
361 |
| - foreach(lc, outerrel->pathlist) |
362 |
| - { |
363 |
| - Path *outerpath = (Path *) lfirst(lc); |
364 |
| - |
365 |
| - add_path(joinrel, (Path *) |
366 |
| - create_noop_path(root, joinrel, outerpath)); |
367 |
| - } |
368 |
| -} |
369 |
| - |
370 | 167 | /*
|
371 | 168 | * sort_inner_and_outer
|
372 | 169 | * Create mergejoin join paths by explicitly sorting both the outer and
|
|
0 commit comments