Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * joinpath.c
4 : : * Routines to find all possible paths for processing a set of joins
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/optimizer/path/joinpath.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include "executor/executor.h"
18 : : #include "foreign/fdwapi.h"
19 : : #include "nodes/nodeFuncs.h"
20 : : #include "optimizer/cost.h"
21 : : #include "optimizer/optimizer.h"
22 : : #include "optimizer/pathnode.h"
23 : : #include "optimizer/paths.h"
24 : : #include "optimizer/placeholder.h"
25 : : #include "optimizer/planmain.h"
26 : : #include "optimizer/restrictinfo.h"
27 : : #include "utils/lsyscache.h"
28 : : #include "utils/typcache.h"
29 : :
30 : : /* Hooks for plugins to get control in add_paths_to_joinrel() */
31 : : set_join_pathlist_hook_type set_join_pathlist_hook = NULL;
32 : : join_path_setup_hook_type join_path_setup_hook = NULL;
33 : :
34 : : /*
35 : : * Paths parameterized by a parent rel can be considered to be parameterized
36 : : * by any of its children, when we are performing partitionwise joins. These
37 : : * macros simplify checking for such cases. Beware multiple eval of args.
38 : : */
39 : : #define PATH_PARAM_BY_PARENT(path, rel) \
40 : : ((path)->param_info && bms_overlap(PATH_REQ_OUTER(path), \
41 : : (rel)->top_parent_relids))
42 : : #define PATH_PARAM_BY_REL_SELF(path, rel) \
43 : : ((path)->param_info && bms_overlap(PATH_REQ_OUTER(path), (rel)->relids))
44 : :
45 : : #define PATH_PARAM_BY_REL(path, rel) \
46 : : (PATH_PARAM_BY_REL_SELF(path, rel) || PATH_PARAM_BY_PARENT(path, rel))
47 : :
48 : : static void try_partial_mergejoin_path(PlannerInfo *root,
49 : : RelOptInfo *joinrel,
50 : : Path *outer_path,
51 : : Path *inner_path,
52 : : List *pathkeys,
53 : : List *mergeclauses,
54 : : List *outersortkeys,
55 : : List *innersortkeys,
56 : : JoinType jointype,
57 : : JoinPathExtraData *extra);
58 : : static void sort_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
59 : : RelOptInfo *outerrel, RelOptInfo *innerrel,
60 : : JoinType jointype, JoinPathExtraData *extra);
61 : : static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel,
62 : : RelOptInfo *outerrel, RelOptInfo *innerrel,
63 : : JoinType jointype, JoinPathExtraData *extra);
64 : : static void consider_parallel_nestloop(PlannerInfo *root,
65 : : RelOptInfo *joinrel,
66 : : RelOptInfo *outerrel,
67 : : RelOptInfo *innerrel,
68 : : JoinType jointype,
69 : : JoinPathExtraData *extra);
70 : : static void consider_parallel_mergejoin(PlannerInfo *root,
71 : : RelOptInfo *joinrel,
72 : : RelOptInfo *outerrel,
73 : : RelOptInfo *innerrel,
74 : : JoinType jointype,
75 : : JoinPathExtraData *extra,
76 : : Path *inner_cheapest_total);
77 : : static void hash_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
78 : : RelOptInfo *outerrel, RelOptInfo *innerrel,
79 : : JoinType jointype, JoinPathExtraData *extra);
80 : : static List *select_mergejoin_clauses(PlannerInfo *root,
81 : : RelOptInfo *joinrel,
82 : : RelOptInfo *outerrel,
83 : : RelOptInfo *innerrel,
84 : : List *restrictlist,
85 : : JoinType jointype,
86 : : bool *mergejoin_allowed);
87 : : static void generate_mergejoin_paths(PlannerInfo *root,
88 : : RelOptInfo *joinrel,
89 : : RelOptInfo *innerrel,
90 : : Path *outerpath,
91 : : JoinType jointype,
92 : : JoinPathExtraData *extra,
93 : : bool useallclauses,
94 : : Path *inner_cheapest_total,
95 : : List *merge_pathkeys,
96 : : bool is_partial);
97 : :
98 : :
99 : : /*
100 : : * add_paths_to_joinrel
101 : : * Given a join relation and two component rels from which it can be made,
102 : : * consider all possible paths that use the two component rels as outer
103 : : * and inner rel respectively. Add these paths to the join rel's pathlist
104 : : * if they survive comparison with other paths (and remove any existing
105 : : * paths that are dominated by these paths).
106 : : *
107 : : * Modifies the pathlist field of the joinrel node to contain the best
108 : : * paths found so far.
109 : : *
110 : : * jointype is not necessarily the same as sjinfo->jointype; it might be
111 : : * "flipped around" if we are considering joining the rels in the opposite
112 : : * direction from what's indicated in sjinfo.
113 : : *
114 : : * Also, this routine accepts the special JoinTypes JOIN_UNIQUE_OUTER and
115 : : * JOIN_UNIQUE_INNER to indicate that the outer or inner relation has been
116 : : * unique-ified and a regular inner join should then be applied. These values
117 : : * are not allowed to propagate outside this routine, however. Path cost
118 : : * estimation code, as well as match_unsorted_outer, may need to recognize that
119 : : * it's dealing with such a case --- the combination of nominal jointype INNER
120 : : * with sjinfo->jointype == JOIN_SEMI indicates that.
121 : : */
122 : : void
7588 tgl@sss.pgh.pa.us 123 :CBC 450500 : add_paths_to_joinrel(PlannerInfo *root,
124 : : RelOptInfo *joinrel,
125 : : RelOptInfo *outerrel,
126 : : RelOptInfo *innerrel,
127 : : JoinType jointype,
128 : : SpecialJoinInfo *sjinfo,
129 : : List *restrictlist)
130 : : {
208 rguo@postgresql.org 131 :GNC 450500 : JoinType save_jointype = jointype;
132 : : JoinPathExtraData extra;
5553 tgl@sss.pgh.pa.us 133 :CBC 450500 : bool mergejoin_allowed = true;
134 : : ListCell *lc;
135 : : Relids joinrelids;
136 : :
137 : : /*
138 : : * PlannerInfo doesn't contain the SpecialJoinInfos created for joins
139 : : * between child relations, even if there is a SpecialJoinInfo node for
140 : : * the join between the topmost parents. So, while calculating Relids set
141 : : * representing the restriction, consider relids of topmost parent of
142 : : * partitions.
143 : : */
3082 rhaas@postgresql.org 144 [ + + ]: 450500 : if (joinrel->reloptkind == RELOPT_OTHER_JOINREL)
145 : 32690 : joinrelids = joinrel->top_parent_relids;
146 : : else
147 : 417810 : joinrelids = joinrel->relids;
148 : :
3962 tgl@sss.pgh.pa.us 149 : 450500 : extra.restrictlist = restrictlist;
150 : 450500 : extra.mergeclause_list = NIL;
151 : 450500 : extra.sjinfo = sjinfo;
152 : 450500 : extra.param_source_rels = NULL;
46 rhaas@postgresql.org 153 :GNC 450500 : extra.pgs_mask = joinrel->pgs_mask;
154 : :
155 : : /*
156 : : * Give extensions a chance to take control. In particular, an extension
157 : : * might want to modify extra.pgs_mask. It's possible to override pgs_mask
158 : : * on a query-wide basis using join_search_hook, or for a particular
159 : : * relation using joinrel_setup_hook, but extensions that want to provide
160 : : * different advice for the same joinrel based on the choice of innerrel
161 : : * and outerrel will need to use this hook.
162 : : *
163 : : * A very simple way for an extension to use this hook is to set
164 : : * extra.pgs_mask &= ~PGS_JOIN_ANY, if it simply doesn't want any of the
165 : : * paths generated by this call to add_paths_to_joinrel() to be selected.
166 : : * An extension could use this technique to constrain the join order,
167 : : * since it could thereby arrange to reject all paths from join orders
168 : : * that it does not like. An extension can also selectively clear bits
169 : : * from extra.pgs_mask to rule out specific techniques for specific joins,
170 : : * or could even set additional bits to re-allow methods disabled at some
171 : : * higher level.
172 : : *
173 : : * NB: Below this point, this function should be careful to reference
174 : : * extra.pgs_mask rather than rel->pgs_mask to avoid disregarding any
175 : : * changes made by the hook we're about to call.
176 : : */
177 [ + + ]: 450500 : if (join_path_setup_hook)
178 : 584 : join_path_setup_hook(root, joinrel, outerrel, innerrel,
179 : : jointype, &extra);
180 : :
181 : : /*
182 : : * See if the inner relation is provably unique for this outer rel.
183 : : *
184 : : * We have some special cases: for JOIN_SEMI, it doesn't matter since the
185 : : * executor can make the equivalent optimization anyway. It also doesn't
186 : : * help enable use of Memoize, since a semijoin with a provably unique
187 : : * inner side should have been reduced to an inner join in that case.
188 : : * Therefore, we need not expend planner cycles on proofs. (For
189 : : * JOIN_ANTI, although it doesn't help the executor for the same reason,
190 : : * it can benefit Memoize paths.) For JOIN_UNIQUE_INNER, we must be
191 : : * considering a semijoin whose inner side is not provably unique (else
192 : : * reduce_unique_semijoins would've simplified it), so there's no point in
193 : : * calling innerrel_is_unique. However, if the LHS covers all of the
194 : : * semijoin's min_lefthand, then it's appropriate to set inner_unique
195 : : * because the unique relation produced by create_unique_paths will be
196 : : * unique relative to the LHS. (If we have an LHS that's only part of the
197 : : * min_lefthand, that is *not* true.) For JOIN_UNIQUE_OUTER, pass
198 : : * JOIN_INNER to avoid letting that value escape this module.
199 : : */
3264 tgl@sss.pgh.pa.us 200 [ + + + + ]:CBC 450500 : switch (jointype)
201 : : {
202 : 3852 : case JOIN_SEMI:
203 : 3852 : extra.inner_unique = false; /* well, unproven */
204 : 3852 : break;
205 : 3194 : case JOIN_UNIQUE_INNER:
3240 206 : 6388 : extra.inner_unique = bms_is_subset(sjinfo->min_lefthand,
207 : 3194 : outerrel->relids);
3264 208 : 3194 : break;
209 : 3194 : case JOIN_UNIQUE_OUTER:
3240 210 : 3194 : extra.inner_unique = innerrel_is_unique(root,
211 : : joinrel->relids,
212 : : outerrel->relids,
213 : : innerrel,
214 : : JOIN_INNER,
215 : : restrictlist,
216 : : false);
3264 217 : 3194 : break;
218 : 440260 : default:
3240 219 : 440260 : extra.inner_unique = innerrel_is_unique(root,
220 : : joinrel->relids,
221 : : outerrel->relids,
222 : : innerrel,
223 : : jointype,
224 : : restrictlist,
225 : : false);
3264 226 : 440260 : break;
227 : : }
228 : :
229 : : /*
230 : : * If the outer or inner relation has been unique-ified, handle as a plain
231 : : * inner join.
232 : : */
208 rguo@postgresql.org 233 [ + + + + ]:GNC 450500 : if (jointype == JOIN_UNIQUE_OUTER || jointype == JOIN_UNIQUE_INNER)
234 : 6388 : jointype = JOIN_INNER;
235 : :
236 : : /*
237 : : * Find potential mergejoin clauses. We can skip this if we are not
238 : : * interested in doing a mergejoin. However, mergejoin may be our only
239 : : * way of implementing a full outer join, so in that case we don't care
240 : : * whether mergejoins are disabled.
241 : : */
46 rhaas@postgresql.org 242 [ + + + + ]: 450500 : if ((extra.pgs_mask & PGS_MERGEJOIN_ANY) != 0 || jointype == JOIN_FULL)
3962 tgl@sss.pgh.pa.us 243 :CBC 448340 : extra.mergeclause_list = select_mergejoin_clauses(root,
244 : : joinrel,
245 : : outerrel,
246 : : innerrel,
247 : : restrictlist,
248 : : jointype,
249 : : &mergejoin_allowed);
250 : :
251 : : /*
252 : : * If it's SEMI, ANTI, or inner_unique join, compute correction factors
253 : : * for cost estimation. These will be the same for all paths.
254 : : */
3264 255 [ + + + + : 450500 : if (jointype == JOIN_SEMI || jointype == JOIN_ANTI || extra.inner_unique)
+ + ]
2886 256 : 134190 : compute_semi_anti_join_factors(root, joinrel, outerrel, innerrel,
257 : : jointype, sjinfo, restrictlist,
258 : : &extra.semifactors);
259 : :
260 : : /*
261 : : * Decide whether it's sensible to generate parameterized paths for this
262 : : * joinrel, and if so, which relations such paths should require. There
263 : : * is usually no need to create a parameterized result path unless there
264 : : * is a join order restriction that prevents joining one of our input rels
265 : : * directly to the parameter source rel instead of joining to the other
266 : : * input rel. (But see allow_star_schema_join().) This restriction
267 : : * reduces the number of parameterized paths we have to deal with at
268 : : * higher join levels, without compromising the quality of the resulting
269 : : * plan. We express the restriction as a Relids set that must overlap the
270 : : * parameterization of any proposed join path. Note: param_source_rels
271 : : * should contain only baserels, not OJ relids, so starting from
272 : : * all_baserels not all_query_rels is correct.
273 : : */
5161 274 [ + + + + : 883026 : foreach(lc, root->join_info_list)
+ + ]
275 : : {
3399 276 : 432526 : SpecialJoinInfo *sjinfo2 = (SpecialJoinInfo *) lfirst(lc);
277 : :
278 : : /*
279 : : * SJ is relevant to this join if we have some part of its RHS
280 : : * (possibly not all of it), and haven't yet joined to its LHS. (This
281 : : * test is pretty simplistic, but should be sufficient considering the
282 : : * join has already been proven legal.) If the SJ is relevant, it
283 : : * presents constraints for joining to anything not in its RHS.
284 : : */
3082 rhaas@postgresql.org 285 [ + + ]: 432526 : if (bms_overlap(joinrelids, sjinfo2->min_righthand) &&
286 [ + + ]: 285846 : !bms_overlap(joinrelids, sjinfo2->min_lefthand))
3962 tgl@sss.pgh.pa.us 287 : 11160 : extra.param_source_rels = bms_join(extra.param_source_rels,
3189 288 : 11160 : bms_difference(root->all_baserels,
289 : 11160 : sjinfo2->min_righthand));
290 : :
291 : : /* full joins constrain both sides symmetrically */
3399 292 [ + + + + ]: 435028 : if (sjinfo2->jointype == JOIN_FULL &&
3082 rhaas@postgresql.org 293 : 2502 : bms_overlap(joinrelids, sjinfo2->min_lefthand) &&
294 [ + + ]: 2474 : !bms_overlap(joinrelids, sjinfo2->min_righthand))
3962 tgl@sss.pgh.pa.us 295 : 336 : extra.param_source_rels = bms_join(extra.param_source_rels,
3189 296 : 336 : bms_difference(root->all_baserels,
297 : 336 : sjinfo2->min_lefthand));
298 : : }
299 : :
300 : : /*
301 : : * However, when a LATERAL subquery is involved, there will simply not be
302 : : * any paths for the joinrel that aren't parameterized by whatever the
303 : : * subquery is parameterized by, unless its parameterization is resolved
304 : : * within the joinrel. So we might as well allow additional dependencies
305 : : * on whatever residual lateral dependencies the joinrel will have.
306 : : */
3751 307 : 901000 : extra.param_source_rels = bms_add_members(extra.param_source_rels,
308 : 450500 : joinrel->lateral_relids);
309 : :
310 : : /*
311 : : * 1. Consider mergejoin paths where both relations must be explicitly
312 : : * sorted. Skip this if we can't mergejoin.
313 : : */
5553 314 [ + + ]: 450500 : if (mergejoin_allowed)
5554 315 : 440484 : sort_inner_and_outer(root, joinrel, outerrel, innerrel,
316 : : jointype, &extra);
317 : :
318 : : /*
319 : : * 2. Consider paths where the outer relation need not be explicitly
320 : : * sorted. This includes both nestloops and mergejoins where the outer
321 : : * path is already ordered. Again, skip this if we can't mergejoin.
322 : : * (That's okay because we know that nestloop can't handle
323 : : * right/right-anti/right-semi/full joins at all, so it wouldn't work in
324 : : * the prohibited cases either.)
325 : : */
5553 326 [ + + ]: 450500 : if (mergejoin_allowed)
5554 327 : 440484 : match_unsorted_outer(root, joinrel, outerrel, innerrel,
328 : : jointype, &extra);
329 : :
330 : : #ifdef NOT_USED
331 : :
332 : : /*
333 : : * 3. Consider paths where the inner relation need not be explicitly
334 : : * sorted. This includes mergejoins only (nestloops were already built in
335 : : * match_unsorted_outer).
336 : : *
337 : : * Diked out as redundant 2/13/2000 -- tgl. There isn't any really
338 : : * significant difference between the inner and outer side of a mergejoin,
339 : : * so match_unsorted_inner creates no paths that aren't equivalent to
340 : : * those made by match_unsorted_outer when add_paths_to_joinrel() is
341 : : * invoked with the two rels given in the other order.
342 : : */
343 : : if (mergejoin_allowed)
344 : : match_unsorted_inner(root, joinrel, outerrel, innerrel,
345 : : jointype, &extra);
346 : : #endif
347 : :
348 : : /*
349 : : * 4. Consider paths where both outer and inner relations must be hashed
350 : : * before being joined. As above, when it's a full join, we must try this
351 : : * even when the path type is disabled, because it may be our only option.
352 : : */
46 rhaas@postgresql.org 353 [ + + + + ]:GNC 450500 : if ((extra.pgs_mask & PGS_HASHJOIN) != 0 || jointype == JOIN_FULL)
9525 tgl@sss.pgh.pa.us 354 :CBC 447638 : hash_inner_and_outer(root, joinrel, outerrel, innerrel,
355 : : jointype, &extra);
356 : :
357 : : /*
358 : : * 5. If inner and outer relations are foreign tables (or joins) belonging
359 : : * to the same server and assigned to the same user to check access
360 : : * permissions as, give the FDW a chance to push down joins.
361 : : */
46 rhaas@postgresql.org 362 [ + + + + ]:GNC 450500 : if ((extra.pgs_mask & PGS_FOREIGNJOIN) != 0 && joinrel->fdwroutine &&
943 efujita@postgresql.o 363 [ + + ]:CBC 1362 : joinrel->fdwroutine->GetForeignJoinPaths)
3971 rhaas@postgresql.org 364 : 1360 : joinrel->fdwroutine->GetForeignJoinPaths(root, joinrel,
365 : : outerrel, innerrel,
366 : : save_jointype, &extra);
367 : :
368 : : /*
369 : : * 6. Finally, give extensions a chance to manipulate the path list. They
370 : : * could add new paths (such as CustomPaths) by calling add_path(), or
371 : : * add_partial_path() if parallel aware.
372 : : *
373 : : * In theory, extensions could also use this hook to delete or modify
374 : : * paths added by the core code, but in practice this is difficult to make
375 : : * work, since it's too late to get back any paths that have already been
376 : : * discarded by add_path() or add_partial_path(). If you're trying to
377 : : * suppress paths, consider using join_path_setup_hook instead.
378 : : */
943 efujita@postgresql.o 379 [ - + ]: 450500 : if (set_join_pathlist_hook)
3971 rhaas@postgresql.org 380 :UBC 0 : set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
381 : : save_jointype, &extra);
5161 tgl@sss.pgh.pa.us 382 :CBC 450500 : }
383 : :
384 : : /*
385 : : * We override the param_source_rels heuristic to accept nestloop paths in
386 : : * which the outer rel satisfies some but not all of the inner path's
387 : : * parameterization. This is necessary to get good plans for star-schema
388 : : * scenarios, in which a parameterized path for a large table may require
389 : : * parameters from multiple small tables that will not get joined directly to
390 : : * each other. We can handle that by stacking nestloops that have the small
391 : : * tables on the outside; but this breaks the rule the param_source_rels
392 : : * heuristic is based on, namely that parameters should not be passed down
393 : : * across joins unless there's a join-order-constraint-based reason to do so.
394 : : * So we ignore the param_source_rels restriction when this case applies.
395 : : *
396 : : * allow_star_schema_join() returns true if the param_source_rels restriction
397 : : * should be overridden, ie, it's okay to perform this join.
398 : : */
399 : : static inline bool
3876 400 : 198494 : allow_star_schema_join(PlannerInfo *root,
401 : : Relids outerrelids,
402 : : Relids inner_paramrels)
403 : : {
404 : : /*
405 : : * It's a star-schema case if the outer rel provides some but not all of
406 : : * the inner rel's parameterization.
407 : : */
3134 rhaas@postgresql.org 408 [ + + + + ]: 233017 : return (bms_overlap(inner_paramrels, outerrelids) &&
409 : 34523 : bms_nonempty_difference(inner_paramrels, outerrelids));
410 : : }
411 : :
412 : : /*
413 : : * If the parameterization is only partly satisfied by the outer rel,
414 : : * the unsatisfied part can't include any outer-join relids that could
415 : : * null rels of the satisfied part. That would imply that we're trying
416 : : * to use a clause involving a Var with nonempty varnullingrels at
417 : : * a join level where that value isn't yet computable.
418 : : *
419 : : * In practice, this test never finds a problem because earlier join order
420 : : * restrictions prevent us from attempting a join that would cause a problem.
421 : : * (That's unsurprising, because the code worked before we ever added
422 : : * outer-join relids to expression relids.) It still seems worth checking
423 : : * as a backstop, but we only do so in assert-enabled builds.
424 : : */
425 : : #ifdef USE_ASSERT_CHECKING
426 : : static inline bool
1140 tgl@sss.pgh.pa.us 427 : 1884644 : have_unsafe_outer_join_ref(PlannerInfo *root,
428 : : Relids outerrelids,
429 : : Relids inner_paramrels)
430 : : {
431 : 1884644 : bool result = false;
432 : 1884644 : Relids unsatisfied = bms_difference(inner_paramrels, outerrelids);
1126 433 : 1884644 : Relids satisfied = bms_intersect(inner_paramrels, outerrelids);
434 : :
435 [ + + ]: 1884644 : if (bms_overlap(unsatisfied, root->outer_join_rels))
436 : : {
437 : : ListCell *lc;
438 : :
1140 439 [ + - + + : 90 : foreach(lc, root->join_info_list)
+ + ]
440 : : {
441 : 60 : SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
442 : :
443 [ + + ]: 60 : if (!bms_is_member(sjinfo->ojrelid, unsatisfied))
444 : 12 : continue; /* not relevant */
1126 445 [ + - ]: 48 : if (bms_overlap(satisfied, sjinfo->min_righthand) ||
1140 446 [ - + - - ]: 48 : (sjinfo->jointype == JOIN_FULL &&
1126 tgl@sss.pgh.pa.us 447 :UBC 0 : bms_overlap(satisfied, sjinfo->min_lefthand)))
448 : : {
1140 449 : 0 : result = true; /* doesn't work */
450 : 0 : break;
451 : : }
452 : : }
453 : : }
454 : :
455 : : /* Waste no memory when we reject a path here */
1140 tgl@sss.pgh.pa.us 456 :CBC 1884644 : bms_free(unsatisfied);
1126 457 : 1884644 : bms_free(satisfied);
458 : :
1140 459 : 1884644 : return result;
460 : : }
461 : : #endif /* USE_ASSERT_CHECKING */
462 : :
463 : : /*
464 : : * paraminfo_get_equal_hashops
465 : : * Determine if the clauses in param_info and innerrel's lateral vars
466 : : * can be hashed.
467 : : * Returns true if hashing is possible, otherwise false.
468 : : *
469 : : * Additionally, on success we collect the outer expressions and the
470 : : * appropriate equality operators for each hashable parameter to innerrel.
471 : : * These are returned in parallel lists in *param_exprs and *operators.
472 : : * We also set *binary_mode to indicate whether strict binary matching is
473 : : * required.
474 : : */
475 : : static bool
1808 drowley@postgresql.o 476 : 239240 : paraminfo_get_equal_hashops(PlannerInfo *root, ParamPathInfo *param_info,
477 : : RelOptInfo *outerrel, RelOptInfo *innerrel,
478 : : List *ph_lateral_vars, List **param_exprs,
479 : : List **operators, bool *binary_mode)
480 : :
481 : : {
482 : : List *lateral_vars;
483 : : ListCell *lc;
484 : :
485 : 239240 : *param_exprs = NIL;
486 : 239240 : *operators = NIL;
1572 487 : 239240 : *binary_mode = false;
488 : :
489 : : /* Add join clauses from param_info to the hash key */
1808 490 [ + - ]: 239240 : if (param_info != NULL)
491 : : {
492 : 239240 : List *clauses = param_info->ppi_clauses;
493 : :
494 [ + + + + : 452064 : foreach(lc, clauses)
+ + ]
495 : : {
496 : 261778 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
497 : : OpExpr *opexpr;
498 : : Node *expr;
499 : : Oid hasheqoperator;
500 : :
1588 501 : 261778 : opexpr = (OpExpr *) rinfo->clause;
502 : :
503 : : /*
504 : : * Bail if the rinfo is not compatible. We need a join OpExpr
505 : : * with 2 args.
506 : : */
507 [ + + + - ]: 261778 : if (!IsA(opexpr, OpExpr) || list_length(opexpr->args) != 2 ||
516 508 [ + + ]: 250452 : !clause_sides_match_join(rinfo, outerrel->relids,
509 : : innerrel->relids))
510 : : {
1808 511 : 48909 : list_free(*operators);
512 : 48909 : list_free(*param_exprs);
513 : 48954 : return false;
514 : : }
515 : :
516 [ + + ]: 212869 : if (rinfo->outer_is_left)
517 : : {
518 : 122775 : expr = (Node *) linitial(opexpr->args);
1588 519 : 122775 : hasheqoperator = rinfo->left_hasheqoperator;
520 : : }
521 : : else
522 : : {
1808 523 : 90094 : expr = (Node *) lsecond(opexpr->args);
1588 524 : 90094 : hasheqoperator = rinfo->right_hasheqoperator;
525 : : }
526 : :
527 : : /* can't do memoize if we can't hash the outer type */
528 [ + + ]: 212869 : if (!OidIsValid(hasheqoperator))
529 : : {
530 : 45 : list_free(*operators);
531 : 45 : list_free(*param_exprs);
532 : 45 : return false;
533 : : }
534 : :
535 : : /*
536 : : * 'expr' may already exist as a parameter from a previous item in
537 : : * ppi_clauses. No need to include it again, however we'd better
538 : : * ensure we do switch into binary mode if required. See below.
539 : : */
779 540 [ + + ]: 212824 : if (!list_member(*param_exprs, expr))
541 : : {
542 : 212821 : *operators = lappend_oid(*operators, hasheqoperator);
543 : 212821 : *param_exprs = lappend(*param_exprs, expr);
544 : : }
545 : :
546 : : /*
547 : : * When the join operator is not hashable then it's possible that
548 : : * the operator will be able to distinguish something that the
549 : : * hash equality operator could not. For example with floating
550 : : * point types -0.0 and +0.0 are classed as equal by the hash
551 : : * function and equality function, but some other operator may be
552 : : * able to tell those values apart. This means that we must put
553 : : * memoize into binary comparison mode so that it does bit-by-bit
554 : : * comparisons rather than a "logical" comparison as it would
555 : : * using the hash equality operator.
556 : : */
1572 557 [ + + ]: 212824 : if (!OidIsValid(rinfo->hashjoinoperator))
558 : 635 : *binary_mode = true;
559 : : }
560 : : }
561 : :
562 : : /* Now add any lateral vars to the cache key too */
608 rguo@postgresql.org 563 : 190286 : lateral_vars = list_concat(ph_lateral_vars, innerrel->lateral_vars);
564 [ + + + + : 195112 : foreach(lc, lateral_vars)
+ + ]
565 : : {
1808 drowley@postgresql.o 566 : 5530 : Node *expr = (Node *) lfirst(lc);
567 : : TypeCacheEntry *typentry;
568 : :
569 : : /* Reject if there are any volatile functions in lateral vars */
570 [ - + ]: 5530 : if (contain_volatile_functions(expr))
571 : : {
1808 drowley@postgresql.o 572 :UBC 0 : list_free(*operators);
573 : 0 : list_free(*param_exprs);
1808 drowley@postgresql.o 574 :CBC 704 : return false;
575 : : }
576 : :
577 : 5530 : typentry = lookup_type_cache(exprType(expr),
578 : : TYPECACHE_HASH_PROC | TYPECACHE_EQ_OPR);
579 : :
580 : : /* can't use memoize without a valid hash proc and equals operator */
581 [ + + - + ]: 5530 : if (!OidIsValid(typentry->hash_proc) || !OidIsValid(typentry->eq_opr))
582 : : {
583 : 704 : list_free(*operators);
584 : 704 : list_free(*param_exprs);
585 : 704 : return false;
586 : : }
587 : :
588 : : /*
589 : : * 'expr' may already exist as a parameter from the ppi_clauses. No
590 : : * need to include it again, however we'd better ensure we do switch
591 : : * into binary mode.
592 : : */
779 593 [ + + ]: 4826 : if (!list_member(*param_exprs, expr))
594 : : {
595 : 4577 : *operators = lappend_oid(*operators, typentry->eq_opr);
596 : 4577 : *param_exprs = lappend(*param_exprs, expr);
597 : : }
598 : :
599 : : /*
600 : : * We must go into binary mode as we don't have too much of an idea of
601 : : * how these lateral Vars are being used. See comment above when we
602 : : * set *binary_mode for the non-lateral Var case. This could be
603 : : * relaxed a bit if we had the RestrictInfos and knew the operators
604 : : * being used, however for cases like Vars that are arguments to
605 : : * functions we must operate in binary mode as we don't have
606 : : * visibility into what the function is doing with the Vars.
607 : : */
1572 608 : 4826 : *binary_mode = true;
609 : : }
610 : :
611 : : /* We're okay to use memoize */
1808 612 : 189582 : return true;
613 : : }
614 : :
615 : : /*
616 : : * extract_lateral_vars_from_PHVs
617 : : * Extract lateral references within PlaceHolderVars that are due to be
618 : : * evaluated at 'innerrelids'.
619 : : */
620 : : static List *
608 rguo@postgresql.org 621 : 886632 : extract_lateral_vars_from_PHVs(PlannerInfo *root, Relids innerrelids)
622 : : {
623 : 886632 : List *ph_lateral_vars = NIL;
624 : : ListCell *lc;
625 : :
626 : : /* Nothing would be found if the query contains no LATERAL RTEs */
627 [ + + ]: 886632 : if (!root->hasLateralRTEs)
628 : 845054 : return NIL;
629 : :
630 : : /*
631 : : * No need to consider PHVs that are due to be evaluated at joinrels,
632 : : * since we do not add Memoize nodes on top of joinrel paths.
633 : : */
634 [ + + ]: 41578 : if (bms_membership(innerrelids) == BMS_MULTIPLE)
635 : 17262 : return NIL;
636 : :
637 [ + + + + : 25748 : foreach(lc, root->placeholder_list)
+ + ]
638 : : {
639 : 1432 : PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
640 : : List *vars;
641 : : ListCell *cell;
642 : :
643 : : /* PHV is uninteresting if no lateral refs */
644 [ + + ]: 1432 : if (phinfo->ph_lateral == NULL)
645 : 819 : continue;
646 : :
647 : : /* PHV is uninteresting if not due to be evaluated at innerrelids */
648 [ + + ]: 613 : if (!bms_equal(phinfo->ph_eval_at, innerrelids))
649 : 491 : continue;
650 : :
651 : : /*
652 : : * If the PHV does not reference any rels in innerrelids, use its
653 : : * contained expression as a cache key rather than extracting the
654 : : * Vars/PHVs from it and using those. This can be beneficial in cases
655 : : * where the expression results in fewer distinct values to cache
656 : : * tuples for.
657 : : */
658 [ + + ]: 122 : if (!bms_overlap(pull_varnos(root, (Node *) phinfo->ph_var->phexpr),
659 : : innerrelids))
660 : : {
661 : 116 : ph_lateral_vars = lappend(ph_lateral_vars, phinfo->ph_var->phexpr);
662 : 116 : continue;
663 : : }
664 : :
665 : : /* Fetch Vars and PHVs of lateral references within PlaceHolderVars */
666 : 6 : vars = pull_vars_of_level((Node *) phinfo->ph_var->phexpr, 0);
667 [ + - + + : 18 : foreach(cell, vars)
+ + ]
668 : : {
669 : 12 : Node *node = (Node *) lfirst(cell);
670 : :
671 [ + + ]: 12 : if (IsA(node, Var))
672 : : {
673 : 6 : Var *var = (Var *) node;
674 : :
675 [ - + ]: 6 : Assert(var->varlevelsup == 0);
676 : :
677 [ - + ]: 6 : if (bms_is_member(var->varno, phinfo->ph_lateral))
608 rguo@postgresql.org 678 :UBC 0 : ph_lateral_vars = lappend(ph_lateral_vars, node);
679 : : }
608 rguo@postgresql.org 680 [ + - ]:CBC 6 : else if (IsA(node, PlaceHolderVar))
681 : : {
682 : 6 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
683 : :
684 [ - + ]: 6 : Assert(phv->phlevelsup == 0);
685 : :
686 [ + - ]: 6 : if (bms_is_subset(find_placeholder_info(root, phv)->ph_eval_at,
687 : 6 : phinfo->ph_lateral))
688 : 6 : ph_lateral_vars = lappend(ph_lateral_vars, node);
689 : : }
690 : : else
608 rguo@postgresql.org 691 :UBC 0 : Assert(false);
692 : : }
693 : :
608 rguo@postgresql.org 694 :CBC 6 : list_free(vars);
695 : : }
696 : :
697 : 24316 : return ph_lateral_vars;
698 : : }
699 : :
700 : : /*
701 : : * get_memoize_path
702 : : * If possible, make and return a Memoize path atop of 'inner_path'.
703 : : * Otherwise return NULL.
704 : : *
705 : : * Note that currently we do not add Memoize nodes on top of join relation
706 : : * paths. This is because the ParamPathInfos for join relation paths do not
707 : : * maintain ppi_clauses, as the set of relevant clauses varies depending on how
708 : : * the join is formed. In addition, joinrels do not maintain lateral_vars. So
709 : : * we do not have a way to extract cache keys from joinrels.
710 : : */
711 : : static Path *
1705 drowley@postgresql.o 712 : 1245865 : get_memoize_path(PlannerInfo *root, RelOptInfo *innerrel,
713 : : RelOptInfo *outerrel, Path *inner_path,
714 : : Path *outer_path, JoinType jointype,
715 : : JoinPathExtraData *extra)
716 : : {
717 : : List *param_exprs;
718 : : List *hash_operators;
719 : : ListCell *lc;
720 : : bool binary_mode;
721 : : List *ph_lateral_vars;
722 : :
723 : : /* Obviously not if it's disabled */
46 rhaas@postgresql.org 724 [ + + ]:GNC 1245865 : if ((extra->pgs_mask & PGS_NESTLOOP_MEMOIZE) == 0)
1808 drowley@postgresql.o 725 :CBC 3916 : return NULL;
726 : :
727 : : /*
728 : : * We can safely not bother with all this unless we expect to perform more
729 : : * than one inner scan. The first scan is always going to be a cache
730 : : * miss. This would likely fail later anyway based on costs, so this is
731 : : * really just to save some wasted effort.
732 : : */
733 [ + + ]: 1241949 : if (outer_path->parent->rows < 2)
734 : 355317 : return NULL;
735 : :
736 : : /*
737 : : * Extract lateral Vars/PHVs within PlaceHolderVars that are due to be
738 : : * evaluated at innerrel. These lateral Vars/PHVs could be used as
739 : : * memoize cache keys.
740 : : */
608 rguo@postgresql.org 741 : 886632 : ph_lateral_vars = extract_lateral_vars_from_PHVs(root, innerrel->relids);
742 : :
743 : : /*
744 : : * We can only have a memoize node when there's some kind of cache key,
745 : : * either parameterized path clauses or lateral Vars. No cache key sounds
746 : : * more like something a Materialize node might be more useful for.
747 : : */
1808 drowley@postgresql.o 748 [ + + ]: 886632 : if ((inner_path->param_info == NULL ||
749 [ + + ]: 332817 : inner_path->param_info->ppi_clauses == NIL) &&
608 rguo@postgresql.org 750 [ + + + + ]: 574885 : innerrel->lateral_vars == NIL &&
751 : : ph_lateral_vars == NIL)
1808 drowley@postgresql.o 752 : 570638 : return NULL;
753 : :
754 : : /*
755 : : * Currently we don't do this for SEMI and ANTI joins, because nested loop
756 : : * SEMI/ANTI joins don't scan the inner node to completion, which means
757 : : * memoize cannot mark the cache entry as complete. Nor can we mark the
758 : : * cache entry as complete after fetching the first inner tuple, because
759 : : * if that tuple and the current outer tuple don't satisfy the join
760 : : * clauses, a second inner tuple that satisfies the parameters would find
761 : : * the cache entry already marked as complete. The only exception is when
762 : : * the inner relation is provably unique, as in that case, there won't be
763 : : * a second matching tuple and we can safely mark the cache entry as
764 : : * complete after fetching the first inner tuple. Note that in such
765 : : * cases, the SEMI join should have been reduced to an inner join by
766 : : * reduce_unique_semijoins.
767 : : */
255 rguo@postgresql.org 768 [ + + + + ]:GNC 315994 : if ((jointype == JOIN_SEMI || jointype == JOIN_ANTI) &&
769 [ + + ]: 7950 : !extra->inner_unique)
1808 drowley@postgresql.o 770 :CBC 3772 : return NULL;
771 : :
772 : : /*
773 : : * Memoize normally marks cache entries as complete when it runs out of
774 : : * tuples to read from its subplan. However, with unique joins, Nested
775 : : * Loop will skip to the next outer tuple after finding the first matching
776 : : * inner tuple. This means that we may not read the inner side of the
777 : : * join to completion which leaves no opportunity to mark the cache entry
778 : : * as complete. To work around that, when the join is unique we
779 : : * automatically mark cache entries as complete after fetching the first
780 : : * tuple. This works when the entire join condition is parameterized.
781 : : * Otherwise, when the parameterization is only a subset of the join
782 : : * condition, we can't be sure which part of it causes the join to be
783 : : * unique. This means there are no guarantees that only 1 tuple will be
784 : : * read. We cannot mark the cache entry as complete after reading the
785 : : * first tuple without that guarantee. This means the scope of Memoize
786 : : * node's usefulness is limited to only outer rows that have no join
787 : : * partner as this is the only case where Nested Loop would exhaust the
788 : : * inner scan of a unique join. Since the scope is limited to that, we
789 : : * just don't bother making a memoize path in this case.
790 : : *
791 : : * Lateral vars needn't be considered here as they're not considered when
792 : : * determining if the join is unique.
793 : : */
333 rguo@postgresql.org 794 [ + + ]: 312222 : if (extra->inner_unique)
795 : : {
796 : : Bitmapset *ppi_serials;
797 : :
798 [ - + ]: 190328 : if (inner_path->param_info == NULL)
333 rguo@postgresql.org 799 :UBC 0 : return NULL;
800 : :
333 rguo@postgresql.org 801 :CBC 190328 : ppi_serials = inner_path->param_info->ppi_serials;
802 : :
803 [ + - + + : 449425 : foreach_node(RestrictInfo, rinfo, extra->restrictlist)
+ + ]
804 : : {
805 [ + + ]: 214575 : if (!bms_is_member(rinfo->rinfo_serial, ppi_serials))
806 : 72903 : return NULL;
807 : : }
808 : : }
809 : :
810 : : /*
811 : : * We can't use a memoize node if there are volatile functions in the
812 : : * inner rel's target list or restrict list. A cache hit could reduce the
813 : : * number of calls to these functions.
814 : : */
1808 drowley@postgresql.o 815 [ - + ]: 239319 : if (contain_volatile_functions((Node *) innerrel->reltarget))
1808 drowley@postgresql.o 816 :UBC 0 : return NULL;
817 : :
1808 drowley@postgresql.o 818 [ + + + + :CBC 394589 : foreach(lc, innerrel->baserestrictinfo)
+ + ]
819 : : {
820 : 155348 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
821 : :
822 [ + + ]: 155348 : if (contain_volatile_functions((Node *) rinfo))
823 : 78 : return NULL;
824 : : }
825 : :
826 : : /*
827 : : * Also check the parameterized path restrictinfos for volatile functions.
828 : : * Indexed functions must be immutable so shouldn't have any volatile
829 : : * functions, however, with a lateral join the inner scan may not be an
830 : : * index scan.
831 : : */
951 832 [ + - ]: 239241 : if (inner_path->param_info != NULL)
833 : : {
834 [ + + + + : 519760 : foreach(lc, inner_path->param_info->ppi_clauses)
+ + ]
835 : : {
836 : 280520 : RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
837 : :
838 [ + + ]: 280520 : if (contain_volatile_functions((Node *) rinfo))
839 : 1 : return NULL;
840 : : }
841 : : }
842 : :
843 : : /* Check if we have hash ops for each parameter to the path */
1808 844 [ + + ]: 239240 : if (paraminfo_get_equal_hashops(root,
845 : : inner_path->param_info,
1196 tgl@sss.pgh.pa.us 846 [ + + ]: 239240 : outerrel->top_parent ?
847 : : outerrel->top_parent : outerrel,
848 : : innerrel,
849 : : ph_lateral_vars,
850 : : ¶m_exprs,
851 : : &hash_operators,
852 : : &binary_mode))
853 : : {
1705 drowley@postgresql.o 854 : 189582 : return (Path *) create_memoize_path(root,
855 : : innerrel,
856 : : inner_path,
857 : : param_exprs,
858 : : hash_operators,
859 : 189582 : extra->inner_unique,
860 : : binary_mode,
861 : : outer_path->rows);
862 : : }
863 : :
1808 864 : 49658 : return NULL;
865 : : }
866 : :
867 : : /*
868 : : * try_nestloop_path
869 : : * Consider a nestloop join path; if it appears useful, push it into
870 : : * the joinrel's pathlist via add_path().
871 : : */
872 : : static void
5161 tgl@sss.pgh.pa.us 873 : 2081453 : try_nestloop_path(PlannerInfo *root,
874 : : RelOptInfo *joinrel,
875 : : Path *outer_path,
876 : : Path *inner_path,
877 : : List *pathkeys,
878 : : JoinType jointype,
879 : : uint64 nestloop_subtype,
880 : : JoinPathExtraData *extra)
881 : : {
882 : : Relids required_outer;
883 : : JoinCostWorkspace workspace;
3134 rhaas@postgresql.org 884 : 2081453 : RelOptInfo *innerrel = inner_path->parent;
885 : 2081453 : RelOptInfo *outerrel = outer_path->parent;
886 : : Relids innerrelids;
887 : : Relids outerrelids;
888 [ + + ]: 2081453 : Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
889 [ + + ]: 2081453 : Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
890 : :
891 : : /*
892 : : * If we are forming an outer join at this join, it's nonsensical to use
893 : : * an input path that uses the outer join as part of its parameterization.
894 : : * (This can happen despite our join order restrictions, since those apply
895 : : * to what is in an input relation not what its parameters are.)
896 : : */
990 tgl@sss.pgh.pa.us 897 [ + + + - ]: 2490829 : if (extra->sjinfo->ojrelid != 0 &&
898 [ + + ]: 818752 : (bms_is_member(extra->sjinfo->ojrelid, inner_paramrels) ||
899 : 409376 : bms_is_member(extra->sjinfo->ojrelid, outer_paramrels)))
900 : 196809 : return;
901 : :
902 : : /*
903 : : * Any parameterization of the input paths refers to topmost parents of
904 : : * the relevant relations, because reparameterize_path_by_child() hasn't
905 : : * been called yet. So we must consider topmost parents of the relations
906 : : * being joined, too, while determining parameterization of the result and
907 : : * checking for disallowed parameterization cases.
908 : : */
3082 rhaas@postgresql.org 909 [ + + ]: 2081393 : if (innerrel->top_parent_relids)
910 : 88796 : innerrelids = innerrel->top_parent_relids;
911 : : else
912 : 1992597 : innerrelids = innerrel->relids;
913 : :
914 [ + + ]: 2081393 : if (outerrel->top_parent_relids)
915 : 88796 : outerrelids = outerrel->top_parent_relids;
916 : : else
917 : 1992597 : outerrelids = outerrel->relids;
918 : :
919 : : /*
920 : : * Check to see if proposed path is still parameterized, and reject if the
921 : : * parameterization wouldn't be sensible --- unless allow_star_schema_join
922 : : * says to allow it anyway.
923 : : */
3134 924 : 2081393 : required_outer = calc_nestloop_required_outer(outerrelids, outer_paramrels,
925 : : innerrelids, inner_paramrels);
5161 tgl@sss.pgh.pa.us 926 [ + + ]: 2081393 : if (required_outer &&
268 927 [ + + ]: 232647 : !bms_overlap(required_outer, extra->param_source_rels) &&
928 [ + + ]: 198494 : !allow_star_schema_join(root, outerrelids, inner_paramrels))
929 : : {
930 : : /* Waste no memory when we reject a path here */
3876 931 : 196749 : bms_free(required_outer);
932 : 196749 : return;
933 : : }
934 : :
935 : : /* If we got past that, we shouldn't have any unsafe outer-join refs */
1126 936 [ - + ]: 1884644 : Assert(!have_unsafe_outer_join_ref(root, outerrelids, inner_paramrels));
937 : :
938 : : /*
939 : : * If the inner path is parameterized, it is parameterized by the topmost
940 : : * parent of the outer rel, not the outer rel itself. We will need to
941 : : * translate the parameterization, if this path is chosen, during
942 : : * create_plan(). Here we just check whether we will be able to perform
943 : : * the translation, and if not avoid creating a nestloop path.
944 : : */
726 945 [ + + + - : 1884644 : if (PATH_PARAM_BY_PARENT(inner_path, outer_path->parent) &&
+ + ]
946 [ - + ]: 7322 : !path_is_reparameterizable_by_child(inner_path, outer_path->parent))
947 : : {
726 tgl@sss.pgh.pa.us 948 :UBC 0 : bms_free(required_outer);
949 : 0 : return;
950 : : }
951 : :
952 : : /*
953 : : * Do a precheck to quickly eliminate obviously-inferior paths. We
954 : : * calculate a cheap lower bound on the path's cost and then use
955 : : * add_path_precheck() to see if the path is clearly going to be dominated
956 : : * by some existing path for the joinrel. If not, do the full pushup with
957 : : * creating a fully valid path structure and submitting it to add_path().
958 : : * The latter two steps are expensive enough to make this two-phase
959 : : * methodology worthwhile.
960 : : */
5161 tgl@sss.pgh.pa.us 961 :CBC 1884644 : initial_cost_nestloop(root, &workspace, jointype,
962 : : nestloop_subtype | PGS_CONSIDER_NONPARTIAL,
963 : : outer_path, inner_path, extra);
964 : :
571 rhaas@postgresql.org 965 [ + + ]: 1884644 : if (add_path_precheck(joinrel, workspace.disabled_nodes,
966 : : workspace.startup_cost, workspace.total_cost,
967 : : pathkeys, required_outer))
968 : : {
5161 tgl@sss.pgh.pa.us 969 : 864591 : add_path(joinrel, (Path *)
970 : 864591 : create_nestloop_path(root,
971 : : joinrel,
972 : : jointype,
973 : : &workspace,
974 : : extra,
975 : : outer_path,
976 : : inner_path,
977 : : extra->restrictlist,
978 : : pathkeys,
979 : : required_outer));
980 : : }
981 : : else
982 : : {
983 : : /* Waste no memory when we reject a path here */
984 : 1020053 : bms_free(required_outer);
985 : : }
986 : : }
987 : :
988 : : /*
989 : : * try_partial_nestloop_path
990 : : * Consider a partial nestloop join path; if it appears useful, push it into
991 : : * the joinrel's partial_pathlist via add_partial_path().
992 : : */
993 : : static void
3707 rhaas@postgresql.org 994 : 100921 : try_partial_nestloop_path(PlannerInfo *root,
995 : : RelOptInfo *joinrel,
996 : : Path *outer_path,
997 : : Path *inner_path,
998 : : List *pathkeys,
999 : : JoinType jointype,
1000 : : uint64 nestloop_subtype,
1001 : : JoinPathExtraData *extra)
1002 : : {
1003 : : JoinCostWorkspace workspace;
1004 : :
1005 : : /*
1006 : : * If the inner path is parameterized, the parameterization must be fully
1007 : : * satisfied by the proposed outer path. Parameterized partial paths are
1008 : : * not supported. The caller should already have verified that no lateral
1009 : : * rels are required here.
1010 : : */
1011 [ - + ]: 100921 : Assert(bms_is_empty(joinrel->lateral_relids));
593 rguo@postgresql.org 1012 [ - + - - ]: 100921 : Assert(bms_is_empty(PATH_REQ_OUTER(outer_path)));
3707 rhaas@postgresql.org 1013 [ + + ]: 100921 : if (inner_path->param_info != NULL)
1014 : : {
1015 : 7719 : Relids inner_paramrels = inner_path->param_info->ppi_req_outer;
3082 1016 : 7719 : RelOptInfo *outerrel = outer_path->parent;
1017 : : Relids outerrelids;
1018 : :
1019 : : /*
1020 : : * The inner and outer paths are parameterized, if at all, by the top
1021 : : * level parents, not the child relations, so we must use those relids
1022 : : * for our parameterization tests.
1023 : : */
1024 [ + + ]: 7719 : if (outerrel->top_parent_relids)
1025 : 5706 : outerrelids = outerrel->top_parent_relids;
1026 : : else
1027 : 2013 : outerrelids = outerrel->relids;
1028 : :
1029 [ + + ]: 7719 : if (!bms_is_subset(inner_paramrels, outerrelids))
3707 1030 : 79543 : return;
1031 : : }
1032 : :
1033 : : /*
1034 : : * If the inner path is parameterized, it is parameterized by the topmost
1035 : : * parent of the outer rel, not the outer rel itself. We will need to
1036 : : * translate the parameterization, if this path is chosen, during
1037 : : * create_plan(). Here we just check whether we will be able to perform
1038 : : * the translation, and if not avoid creating a nestloop path.
1039 : : */
726 tgl@sss.pgh.pa.us 1040 [ + + + - : 100242 : if (PATH_PARAM_BY_PARENT(inner_path, outer_path->parent) &&
+ + ]
1041 [ - + ]: 5220 : !path_is_reparameterizable_by_child(inner_path, outer_path->parent))
726 tgl@sss.pgh.pa.us 1042 :UBC 0 : return;
1043 : :
1044 : : /*
1045 : : * Before creating a path, get a quick lower bound on what it is likely to
1046 : : * cost. Bail out right away if it looks terrible.
1047 : : */
46 rhaas@postgresql.org 1048 :GNC 100242 : initial_cost_nestloop(root, &workspace, jointype, nestloop_subtype,
1049 : : outer_path, inner_path, extra);
571 rhaas@postgresql.org 1050 [ + + ]:CBC 100242 : if (!add_partial_path_precheck(joinrel, workspace.disabled_nodes,
1051 : : workspace.startup_cost,
1052 : : workspace.total_cost, pathkeys))
3707 1053 : 78864 : return;
1054 : :
1055 : : /* Might be good enough to be worth trying, so let's try it. */
1056 : 21378 : add_partial_path(joinrel, (Path *)
3630 tgl@sss.pgh.pa.us 1057 : 21378 : create_nestloop_path(root,
1058 : : joinrel,
1059 : : jointype,
1060 : : &workspace,
1061 : : extra,
1062 : : outer_path,
1063 : : inner_path,
1064 : : extra->restrictlist,
1065 : : pathkeys,
1066 : : NULL));
1067 : : }
1068 : :
1069 : : /*
1070 : : * try_mergejoin_path
1071 : : * Consider a merge join path; if it appears useful, push it into
1072 : : * the joinrel's pathlist via add_path().
1073 : : */
1074 : : static void
5161 1075 : 898191 : try_mergejoin_path(PlannerInfo *root,
1076 : : RelOptInfo *joinrel,
1077 : : Path *outer_path,
1078 : : Path *inner_path,
1079 : : List *pathkeys,
1080 : : List *mergeclauses,
1081 : : List *outersortkeys,
1082 : : List *innersortkeys,
1083 : : JoinType jointype,
1084 : : JoinPathExtraData *extra,
1085 : : bool is_partial)
1086 : : {
1087 : : Relids required_outer;
311 rguo@postgresql.org 1088 : 898191 : int outer_presorted_keys = 0;
1089 : : JoinCostWorkspace workspace;
1090 : :
3295 rhaas@postgresql.org 1091 [ + + ]: 898191 : if (is_partial)
1092 : : {
1093 : 11657 : try_partial_mergejoin_path(root,
1094 : : joinrel,
1095 : : outer_path,
1096 : : inner_path,
1097 : : pathkeys,
1098 : : mergeclauses,
1099 : : outersortkeys,
1100 : : innersortkeys,
1101 : : jointype,
1102 : : extra);
1103 : 37641 : return;
1104 : : }
1105 : :
1106 : : /*
1107 : : * If we are forming an outer join at this join, it's nonsensical to use
1108 : : * an input path that uses the outer join as part of its parameterization.
1109 : : * (This can happen despite our join order restrictions, since those apply
1110 : : * to what is in an input relation not what its parameters are.)
1111 : : */
990 tgl@sss.pgh.pa.us 1112 [ + + + - ]: 1114075 : if (extra->sjinfo->ojrelid != 0 &&
1113 [ + + + + ]: 455082 : (bms_is_member(extra->sjinfo->ojrelid, PATH_REQ_OUTER(inner_path)) ||
1114 [ + + ]: 227541 : bms_is_member(extra->sjinfo->ojrelid, PATH_REQ_OUTER(outer_path))))
1115 : 6 : return;
1116 : :
1117 : : /*
1118 : : * Check to see if proposed path is still parameterized, and reject if the
1119 : : * parameterization wouldn't be sensible.
1120 : : */
5161 1121 : 886528 : required_outer = calc_non_nestloop_required_outer(outer_path,
1122 : : inner_path);
1123 [ + + ]: 886528 : if (required_outer &&
3962 1124 [ + + ]: 31110 : !bms_overlap(required_outer, extra->param_source_rels))
1125 : : {
1126 : : /* Waste no memory when we reject a path here */
5161 1127 : 25978 : bms_free(required_outer);
1128 : 25978 : return;
1129 : : }
1130 : :
1131 : : /*
1132 : : * If the given paths are already well enough ordered, we can skip doing
1133 : : * an explicit sort.
1134 : : *
1135 : : * We need to determine the number of presorted keys of the outer path to
1136 : : * decide whether explicit incremental sort can be applied when
1137 : : * outersortkeys is not NIL. We do not need to do the same for the inner
1138 : : * path though, as incremental sort currently does not support
1139 : : * mark/restore.
1140 : : */
1141 [ + + + + ]: 1280238 : if (outersortkeys &&
311 rguo@postgresql.org 1142 : 419688 : pathkeys_count_contained_in(outersortkeys, outer_path->pathkeys,
1143 : : &outer_presorted_keys))
5161 tgl@sss.pgh.pa.us 1144 : 9064 : outersortkeys = NIL;
1145 [ + + + + ]: 1548450 : if (innersortkeys &&
1146 : 687900 : pathkeys_contained_in(innersortkeys, inner_path->pathkeys))
1147 : 15639 : innersortkeys = NIL;
1148 : :
1149 : : /*
1150 : : * See comments in try_nestloop_path().
1151 : : */
1152 : 860550 : initial_cost_mergejoin(root, &workspace, jointype, mergeclauses,
1153 : : outer_path, inner_path,
1154 : : outersortkeys, innersortkeys,
1155 : : outer_presorted_keys,
1156 : : extra);
1157 : :
571 rhaas@postgresql.org 1158 [ + + ]: 860550 : if (add_path_precheck(joinrel, workspace.disabled_nodes,
1159 : : workspace.startup_cost, workspace.total_cost,
1160 : : pathkeys, required_outer))
1161 : : {
5161 tgl@sss.pgh.pa.us 1162 : 228609 : add_path(joinrel, (Path *)
1163 : 228609 : create_mergejoin_path(root,
1164 : : joinrel,
1165 : : jointype,
1166 : : &workspace,
1167 : : extra,
1168 : : outer_path,
1169 : : inner_path,
1170 : : extra->restrictlist,
1171 : : pathkeys,
1172 : : required_outer,
1173 : : mergeclauses,
1174 : : outersortkeys,
1175 : : innersortkeys,
1176 : : outer_presorted_keys));
1177 : : }
1178 : : else
1179 : : {
1180 : : /* Waste no memory when we reject a path here */
1181 : 631941 : bms_free(required_outer);
1182 : : }
1183 : : }
1184 : :
1185 : : /*
1186 : : * try_partial_mergejoin_path
1187 : : * Consider a partial merge join path; if it appears useful, push it into
1188 : : * the joinrel's pathlist via add_partial_path().
1189 : : */
1190 : : static void
3295 rhaas@postgresql.org 1191 : 49949 : try_partial_mergejoin_path(PlannerInfo *root,
1192 : : RelOptInfo *joinrel,
1193 : : Path *outer_path,
1194 : : Path *inner_path,
1195 : : List *pathkeys,
1196 : : List *mergeclauses,
1197 : : List *outersortkeys,
1198 : : List *innersortkeys,
1199 : : JoinType jointype,
1200 : : JoinPathExtraData *extra)
1201 : : {
311 rguo@postgresql.org 1202 : 49949 : int outer_presorted_keys = 0;
1203 : : JoinCostWorkspace workspace;
1204 : :
1205 : : /*
1206 : : * See comments in try_partial_hashjoin_path().
1207 : : */
3295 rhaas@postgresql.org 1208 [ - + ]: 49949 : Assert(bms_is_empty(joinrel->lateral_relids));
593 rguo@postgresql.org 1209 [ - + - - ]: 49949 : Assert(bms_is_empty(PATH_REQ_OUTER(outer_path)));
1210 [ - + - - ]: 49949 : if (!bms_is_empty(PATH_REQ_OUTER(inner_path)))
1211 : 17153 : return;
1212 : :
1213 : : /*
1214 : : * If the given paths are already well enough ordered, we can skip doing
1215 : : * an explicit sort.
1216 : : *
1217 : : * We need to determine the number of presorted keys of the outer path to
1218 : : * decide whether explicit incremental sort can be applied when
1219 : : * outersortkeys is not NIL. We do not need to do the same for the inner
1220 : : * path though, as incremental sort currently does not support
1221 : : * mark/restore.
1222 : : */
3295 rhaas@postgresql.org 1223 [ + + + + ]: 88241 : if (outersortkeys &&
311 rguo@postgresql.org 1224 : 38292 : pathkeys_count_contained_in(outersortkeys, outer_path->pathkeys,
1225 : : &outer_presorted_keys))
3295 rhaas@postgresql.org 1226 : 114 : outersortkeys = NIL;
1227 [ + + + + ]: 98283 : if (innersortkeys &&
1228 : 48334 : pathkeys_contained_in(innersortkeys, inner_path->pathkeys))
1229 : 321 : innersortkeys = NIL;
1230 : :
1231 : : /*
1232 : : * See comments in try_partial_nestloop_path().
1233 : : */
1234 : 49949 : initial_cost_mergejoin(root, &workspace, jointype, mergeclauses,
1235 : : outer_path, inner_path,
1236 : : outersortkeys, innersortkeys,
1237 : : outer_presorted_keys,
1238 : : extra);
1239 : :
571 1240 [ + + ]: 49949 : if (!add_partial_path_precheck(joinrel, workspace.disabled_nodes,
1241 : : workspace.startup_cost,
1242 : : workspace.total_cost, pathkeys))
3295 1243 : 17153 : return;
1244 : :
1245 : : /* Might be good enough to be worth trying, so let's try it. */
1246 : 32796 : add_partial_path(joinrel, (Path *)
1247 : 32796 : create_mergejoin_path(root,
1248 : : joinrel,
1249 : : jointype,
1250 : : &workspace,
1251 : : extra,
1252 : : outer_path,
1253 : : inner_path,
1254 : : extra->restrictlist,
1255 : : pathkeys,
1256 : : NULL,
1257 : : mergeclauses,
1258 : : outersortkeys,
1259 : : innersortkeys,
1260 : : outer_presorted_keys));
1261 : : }
1262 : :
1263 : : /*
1264 : : * try_hashjoin_path
1265 : : * Consider a hash join path; if it appears useful, push it into
1266 : : * the joinrel's pathlist via add_path().
1267 : : */
1268 : : static void
5161 tgl@sss.pgh.pa.us 1269 : 515575 : try_hashjoin_path(PlannerInfo *root,
1270 : : RelOptInfo *joinrel,
1271 : : Path *outer_path,
1272 : : Path *inner_path,
1273 : : List *hashclauses,
1274 : : JoinType jointype,
1275 : : JoinPathExtraData *extra)
1276 : : {
1277 : : Relids required_outer;
1278 : : JoinCostWorkspace workspace;
1279 : :
1280 : : /*
1281 : : * If we are forming an outer join at this join, it's nonsensical to use
1282 : : * an input path that uses the outer join as part of its parameterization.
1283 : : * (This can happen despite our join order restrictions, since those apply
1284 : : * to what is in an input relation not what its parameters are.)
1285 : : */
990 1286 [ + + + + ]: 661551 : if (extra->sjinfo->ojrelid != 0 &&
1287 [ + + + + ]: 291937 : (bms_is_member(extra->sjinfo->ojrelid, PATH_REQ_OUTER(inner_path)) ||
1288 [ + + ]: 145961 : bms_is_member(extra->sjinfo->ojrelid, PATH_REQ_OUTER(outer_path))))
1289 : 78976 : return;
1290 : :
1291 : : /*
1292 : : * Check to see if proposed path is still parameterized, and reject if the
1293 : : * parameterization wouldn't be sensible.
1294 : : */
5161 1295 : 515545 : required_outer = calc_non_nestloop_required_outer(outer_path,
1296 : : inner_path);
1297 [ + + ]: 515545 : if (required_outer &&
3962 1298 [ + + ]: 89699 : !bms_overlap(required_outer, extra->param_source_rels))
1299 : : {
1300 : : /* Waste no memory when we reject a path here */
5161 1301 : 78946 : bms_free(required_outer);
1302 : 78946 : return;
1303 : : }
1304 : :
1305 : : /*
1306 : : * See comments in try_nestloop_path(). Also note that hashjoin paths
1307 : : * never have any output pathkeys, per comments in create_hashjoin_path.
1308 : : */
1309 : 436599 : initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
1310 : : outer_path, inner_path, extra, false);
1311 : :
571 rhaas@postgresql.org 1312 [ + + ]: 436599 : if (add_path_precheck(joinrel, workspace.disabled_nodes,
1313 : : workspace.startup_cost, workspace.total_cost,
1314 : : NIL, required_outer))
1315 : : {
5161 tgl@sss.pgh.pa.us 1316 : 201767 : add_path(joinrel, (Path *)
1317 : 201767 : create_hashjoin_path(root,
1318 : : joinrel,
1319 : : jointype,
1320 : : &workspace,
1321 : : extra,
1322 : : outer_path,
1323 : : inner_path,
1324 : : false, /* parallel_hash */
1325 : : extra->restrictlist,
1326 : : required_outer,
1327 : : hashclauses));
1328 : : }
1329 : : else
1330 : : {
1331 : : /* Waste no memory when we reject a path here */
1332 : 234832 : bms_free(required_outer);
1333 : : }
1334 : : }
1335 : :
1336 : : /*
1337 : : * try_partial_hashjoin_path
1338 : : * Consider a partial hashjoin join path; if it appears useful, push it into
1339 : : * the joinrel's partial_pathlist via add_partial_path().
1340 : : * The outer side is partial. If parallel_hash is true, then the inner path
1341 : : * must be partial and will be run in parallel to create one or more shared
1342 : : * hash tables; otherwise the inner path must be complete and a copy of it
1343 : : * is run in every process to create separate identical private hash tables.
1344 : : */
1345 : : static void
3707 rhaas@postgresql.org 1346 : 73968 : try_partial_hashjoin_path(PlannerInfo *root,
1347 : : RelOptInfo *joinrel,
1348 : : Path *outer_path,
1349 : : Path *inner_path,
1350 : : List *hashclauses,
1351 : : JoinType jointype,
1352 : : JoinPathExtraData *extra,
1353 : : bool parallel_hash)
1354 : : {
1355 : : JoinCostWorkspace workspace;
1356 : :
1357 : : /*
1358 : : * If the inner path is parameterized, we can't use a partial hashjoin.
1359 : : * Parameterized partial paths are not supported. The caller should
1360 : : * already have verified that no lateral rels are required here.
1361 : : */
1362 [ - + ]: 73968 : Assert(bms_is_empty(joinrel->lateral_relids));
593 rguo@postgresql.org 1363 [ - + - - ]: 73968 : Assert(bms_is_empty(PATH_REQ_OUTER(outer_path)));
1364 [ - + - - ]: 73968 : if (!bms_is_empty(PATH_REQ_OUTER(inner_path)))
1365 : 21019 : return;
1366 : :
1367 : : /*
1368 : : * Before creating a path, get a quick lower bound on what it is likely to
1369 : : * cost. Bail out right away if it looks terrible.
1370 : : */
3707 rhaas@postgresql.org 1371 : 73968 : initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
1372 : : outer_path, inner_path, extra, parallel_hash);
571 1373 [ + + ]: 73968 : if (!add_partial_path_precheck(joinrel, workspace.disabled_nodes,
1374 : : workspace.startup_cost,
1375 : : workspace.total_cost, NIL))
3707 1376 : 21019 : return;
1377 : :
1378 : : /* Might be good enough to be worth trying, so let's try it. */
1379 : 52949 : add_partial_path(joinrel, (Path *)
3630 tgl@sss.pgh.pa.us 1380 : 52949 : create_hashjoin_path(root,
1381 : : joinrel,
1382 : : jointype,
1383 : : &workspace,
1384 : : extra,
1385 : : outer_path,
1386 : : inner_path,
1387 : : parallel_hash,
1388 : : extra->restrictlist,
1389 : : NULL,
1390 : : hashclauses));
1391 : : }
1392 : :
1393 : : /*
1394 : : * sort_inner_and_outer
1395 : : * Create mergejoin join paths by explicitly sorting both the outer and
1396 : : * inner join relations on each available merge ordering.
1397 : : *
1398 : : * 'joinrel' is the join relation
1399 : : * 'outerrel' is the outer join relation
1400 : : * 'innerrel' is the inner join relation
1401 : : * 'jointype' is the type of join to do
1402 : : * 'extra' contains additional input values
1403 : : */
1404 : : static void
7588 1405 : 440484 : sort_inner_and_outer(PlannerInfo *root,
1406 : : RelOptInfo *joinrel,
1407 : : RelOptInfo *outerrel,
1408 : : RelOptInfo *innerrel,
1409 : : JoinType jointype,
1410 : : JoinPathExtraData *extra)
1411 : : {
1412 : : Path *outer_path;
1413 : : Path *inner_path;
3295 rhaas@postgresql.org 1414 : 440484 : Path *cheapest_partial_outer = NULL;
1415 : 440484 : Path *cheapest_safe_inner = NULL;
1416 : : List *all_pathkeys;
1417 : : ListCell *l;
1418 : :
1419 : : /* Nothing to do if there are no available mergejoin clauses */
593 rguo@postgresql.org 1420 [ + + ]: 440484 : if (extra->mergeclause_list == NIL)
1421 : 65929 : return;
1422 : :
1423 : : /*
1424 : : * We only consider the cheapest-total-cost input paths, since we are
1425 : : * assuming here that a sort is required. We will consider
1426 : : * cheapest-startup-cost input paths later, and only if they don't need a
1427 : : * sort.
1428 : : *
1429 : : * This function intentionally does not consider parameterized input
1430 : : * paths, except when the cheapest-total is parameterized. If we did so,
1431 : : * we'd have a combinatorial explosion of mergejoin paths of dubious
1432 : : * value. This interacts with decisions elsewhere that also discriminate
1433 : : * against mergejoins with parameterized inputs; see comments in
1434 : : * src/backend/optimizer/README.
1435 : : */
8455 tgl@sss.pgh.pa.us 1436 : 374555 : outer_path = outerrel->cheapest_total_path;
1437 : 374555 : inner_path = innerrel->cheapest_total_path;
1438 : :
1439 : : /*
1440 : : * If either cheapest-total path is parameterized by the other rel, we
1441 : : * can't use a mergejoin. (There's no use looking for alternative input
1442 : : * paths, since these should already be the least-parameterized available
1443 : : * paths.)
1444 : : */
4946 1445 [ + + + - : 374555 : if (PATH_PARAM_BY_REL(outer_path, innerrel) ||
+ + + + +
- + + ]
1446 [ + + + - : 372845 : PATH_PARAM_BY_REL(inner_path, outerrel))
+ + + + +
- + + ]
4968 1447 : 3438 : return;
1448 : :
1449 : : /*
1450 : : * If the joinrel is parallel-safe, we may be able to consider a partial
1451 : : * merge join. However, we can't handle JOIN_FULL, JOIN_RIGHT and
1452 : : * JOIN_RIGHT_ANTI, because they can produce false null extended rows.
1453 : : * Also, the resulting path must not be parameterized.
1454 : : */
3295 rhaas@postgresql.org 1455 [ + + + + ]: 371117 : if (joinrel->consider_parallel &&
208 rguo@postgresql.org 1456 [ + + ]:GNC 333442 : jointype != JOIN_FULL &&
1457 [ + + ]: 286438 : jointype != JOIN_RIGHT &&
1458 : 283957 : jointype != JOIN_RIGHT_ANTI &&
3295 rhaas@postgresql.org 1459 [ + + ]:CBC 283957 : outerrel->partial_pathlist != NIL &&
1460 [ + - ]: 36461 : bms_is_empty(joinrel->lateral_relids))
1461 : : {
1462 : 36461 : cheapest_partial_outer = (Path *) linitial(outerrel->partial_pathlist);
1463 : :
1464 [ + + ]: 36461 : if (inner_path->parallel_safe)
1465 : 36360 : cheapest_safe_inner = inner_path;
1466 : : else
1467 : : cheapest_safe_inner =
1468 : 101 : get_cheapest_parallel_safe_total_inner(innerrel->pathlist);
1469 : : }
1470 : :
1471 : : /*
1472 : : * Each possible ordering of the available mergejoin clauses will generate
1473 : : * a differently-sorted result path at essentially the same cost. We have
1474 : : * no basis for choosing one over another at this level of joining, but
1475 : : * some sort orders may be more useful than others for higher-level
1476 : : * mergejoins, so it's worth considering multiple orderings.
1477 : : *
1478 : : * Actually, it's not quite true that every mergeclause ordering will
1479 : : * generate a different path order, because some of the clauses may be
1480 : : * partially redundant (refer to the same EquivalenceClasses). Therefore,
1481 : : * what we do is convert the mergeclause list to a list of canonical
1482 : : * pathkeys, and then consider different orderings of the pathkeys.
1483 : : *
1484 : : * Generating a path for *every* permutation of the pathkeys doesn't seem
1485 : : * like a winning strategy; the cost in planning time is too high. For
1486 : : * now, we generate one path for each pathkey, listing that pathkey first
1487 : : * and the rest in random order. This should allow at least a one-clause
1488 : : * mergejoin without re-sorting against any other possible mergejoin
1489 : : * partner path. But if we've not guessed the right ordering of secondary
1490 : : * keys, we may end up evaluating clauses as qpquals when they could have
1491 : : * been done as mergeclauses. (In practice, it's rare that there's more
1492 : : * than two or three mergeclauses, so expending a huge amount of thought
1493 : : * on that is probably not worth it.)
1494 : : *
1495 : : * The pathkey order returned by select_outer_pathkeys_for_merge() has
1496 : : * some heuristics behind it (see that function), so be sure to try it
1497 : : * exactly as-is as well as making variants.
1498 : : */
6994 tgl@sss.pgh.pa.us 1499 : 371117 : all_pathkeys = select_outer_pathkeys_for_merge(root,
1500 : : extra->mergeclause_list,
1501 : : joinrel);
1502 : :
7963 neilc@samurai.com 1503 [ + - + + : 790805 : foreach(l, all_pathkeys)
+ + ]
1504 : : {
1403 tgl@sss.pgh.pa.us 1505 : 419688 : PathKey *front_pathkey = (PathKey *) lfirst(l);
1506 : : List *cur_mergeclauses;
1507 : : List *outerkeys;
1508 : : List *innerkeys;
1509 : : List *merge_pathkeys;
1510 : :
1511 : : /* Make a pathkey list with this guy first */
7963 neilc@samurai.com 1512 [ + + ]: 419688 : if (l != list_head(all_pathkeys))
6994 tgl@sss.pgh.pa.us 1513 : 48571 : outerkeys = lcons(front_pathkey,
1514 : : list_delete_nth_cell(list_copy(all_pathkeys),
1515 : : foreach_current_index(l)));
1516 : : else
6695 bruce@momjian.us 1517 : 371117 : outerkeys = all_pathkeys; /* no work at first one... */
1518 : :
1519 : : /* Sort the mergeclauses into the corresponding ordering */
1520 : : cur_mergeclauses =
2942 tgl@sss.pgh.pa.us 1521 : 419688 : find_mergeclauses_for_outer_pathkeys(root,
1522 : : outerkeys,
1523 : : extra->mergeclause_list);
1524 : :
1525 : : /* Should have used them all... */
3962 1526 [ - + ]: 419688 : Assert(list_length(cur_mergeclauses) == list_length(extra->mergeclause_list));
1527 : :
1528 : : /* Build sort pathkeys for the inner side */
6994 1529 : 419688 : innerkeys = make_inner_pathkeys_for_merge(root,
1530 : : cur_mergeclauses,
1531 : : outerkeys);
1532 : :
1533 : : /* Build pathkeys representing output sort order */
7721 1534 : 419688 : merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
1535 : : outerkeys);
1536 : :
1537 : : /*
1538 : : * And now we can make the path.
1539 : : *
1540 : : * Note: it's possible that the cheapest paths will already be sorted
1541 : : * properly. try_mergejoin_path will detect that case and suppress an
1542 : : * explicit sort step, so we needn't do so here.
1543 : : */
5161 1544 : 419688 : try_mergejoin_path(root,
1545 : : joinrel,
1546 : : outer_path,
1547 : : inner_path,
1548 : : merge_pathkeys,
1549 : : cur_mergeclauses,
1550 : : outerkeys,
1551 : : innerkeys,
1552 : : jointype,
1553 : : extra,
1554 : : false);
1555 : :
1556 : : /*
1557 : : * If we have partial outer and parallel safe inner path then try
1558 : : * partial mergejoin path.
1559 : : */
3295 rhaas@postgresql.org 1560 [ + + + + ]: 419688 : if (cheapest_partial_outer && cheapest_safe_inner)
1561 : 38292 : try_partial_mergejoin_path(root,
1562 : : joinrel,
1563 : : cheapest_partial_outer,
1564 : : cheapest_safe_inner,
1565 : : merge_pathkeys,
1566 : : cur_mergeclauses,
1567 : : outerkeys,
1568 : : innerkeys,
1569 : : jointype,
1570 : : extra);
1571 : : }
1572 : : }
1573 : :
1574 : : /*
1575 : : * generate_mergejoin_paths
1576 : : * Creates possible mergejoin paths for input outerpath.
1577 : : *
1578 : : * We generate mergejoins if mergejoin clauses are available. We have
1579 : : * two ways to generate the inner path for a mergejoin: sort the cheapest
1580 : : * inner path, or use an inner path that is already suitably ordered for the
1581 : : * merge. If we have several mergeclauses, it could be that there is no inner
1582 : : * path (or only a very expensive one) for the full list of mergeclauses, but
1583 : : * better paths exist if we truncate the mergeclause list (thereby discarding
1584 : : * some sort key requirements). So, we consider truncations of the
1585 : : * mergeclause list as well as the full list. (Ideally we'd consider all
1586 : : * subsets of the mergeclause list, but that seems way too expensive.)
1587 : : */
1588 : : static void
3371 1589 : 891637 : generate_mergejoin_paths(PlannerInfo *root,
1590 : : RelOptInfo *joinrel,
1591 : : RelOptInfo *innerrel,
1592 : : Path *outerpath,
1593 : : JoinType jointype,
1594 : : JoinPathExtraData *extra,
1595 : : bool useallclauses,
1596 : : Path *inner_cheapest_total,
1597 : : List *merge_pathkeys,
1598 : : bool is_partial)
1599 : : {
1600 : : List *mergeclauses;
1601 : : List *innersortkeys;
1602 : : List *trialsortkeys;
1603 : : Path *cheapest_startup_inner;
1604 : : Path *cheapest_total_inner;
1605 : : int num_sortkeys;
1606 : : int sortkeycnt;
1607 : :
1608 : : /* Look for useful mergeclauses (if any) */
1609 : : mergeclauses =
2942 tgl@sss.pgh.pa.us 1610 : 891637 : find_mergeclauses_for_outer_pathkeys(root,
1611 : : outerpath->pathkeys,
1612 : : extra->mergeclause_list);
1613 : :
1614 : : /*
1615 : : * Done with this outer path if no chance for a mergejoin.
1616 : : *
1617 : : * Special corner case: for "x FULL JOIN y ON true", there will be no join
1618 : : * clauses at all. Ordinarily we'd generate a clauseless nestloop path,
1619 : : * but since mergejoin is our only join type that supports FULL JOIN
1620 : : * without any join clauses, it's necessary to generate a clauseless
1621 : : * mergejoin path instead.
1622 : : */
3371 rhaas@postgresql.org 1623 [ + + ]: 891637 : if (mergeclauses == NIL)
1624 : : {
1625 [ + + ]: 591962 : if (jointype == JOIN_FULL)
1626 : : /* okay to try for mergejoin */ ;
1627 : : else
1628 : 590232 : return;
1629 : : }
1630 [ + + + + ]: 353618 : if (useallclauses &&
1631 : 52213 : list_length(mergeclauses) != list_length(extra->mergeclause_list))
1632 : 8772 : return;
1633 : :
1634 : : /* Compute the required ordering of the inner path */
1635 : 292633 : innersortkeys = make_inner_pathkeys_for_merge(root,
1636 : : mergeclauses,
1637 : : outerpath->pathkeys);
1638 : :
1639 : : /*
1640 : : * Generate a mergejoin on the basis of sorting the cheapest inner. Since
1641 : : * a sort will be needed, only cheapest total cost matters. (But
1642 : : * try_mergejoin_path will do the right thing if inner_cheapest_total is
1643 : : * already correctly sorted.)
1644 : : */
1645 : 292633 : try_mergejoin_path(root,
1646 : : joinrel,
1647 : : outerpath,
1648 : : inner_cheapest_total,
1649 : : merge_pathkeys,
1650 : : mergeclauses,
1651 : : NIL,
1652 : : innersortkeys,
1653 : : jointype,
1654 : : extra,
1655 : : is_partial);
1656 : :
1657 : : /*
1658 : : * Look for presorted inner paths that satisfy the innersortkey list ---
1659 : : * or any truncation thereof, if we are allowed to build a mergejoin using
1660 : : * a subset of the merge clauses. Here, we consider both cheap startup
1661 : : * cost and cheap total cost.
1662 : : *
1663 : : * Currently we do not consider parameterized inner paths here. This
1664 : : * interacts with decisions elsewhere that also discriminate against
1665 : : * mergejoins with parameterized inputs; see comments in
1666 : : * src/backend/optimizer/README.
1667 : : *
1668 : : * As we shorten the sortkey list, we should consider only paths that are
1669 : : * strictly cheaper than (in particular, not the same as) any path found
1670 : : * in an earlier iteration. Otherwise we'd be intentionally using fewer
1671 : : * merge keys than a given path allows (treating the rest as plain
1672 : : * joinquals), which is unlikely to be a good idea. Also, eliminating
1673 : : * paths here on the basis of compare_path_costs is a lot cheaper than
1674 : : * building the mergejoin path only to throw it away.
1675 : : *
1676 : : * If inner_cheapest_total is well enough sorted to have not required a
1677 : : * sort in the path made above, we shouldn't make a duplicate path with
1678 : : * it, either. We handle that case with the same logic that handles the
1679 : : * previous consideration, by initializing the variables that track
1680 : : * cheapest-so-far properly. Note that we do NOT reject
1681 : : * inner_cheapest_total if we find it matches some shorter set of
1682 : : * pathkeys. That case corresponds to using fewer mergekeys to avoid
1683 : : * sorting inner_cheapest_total, whereas we did sort it above, so the
1684 : : * plans being considered are different.
1685 : : */
1686 [ + + ]: 292633 : if (pathkeys_contained_in(innersortkeys,
1687 : : inner_cheapest_total->pathkeys))
1688 : : {
1689 : : /* inner_cheapest_total didn't require a sort */
1690 : 7243 : cheapest_startup_inner = inner_cheapest_total;
1691 : 7243 : cheapest_total_inner = inner_cheapest_total;
1692 : : }
1693 : : else
1694 : : {
1695 : : /* it did require a sort, at least for the full set of keys */
1696 : 285390 : cheapest_startup_inner = NULL;
1697 : 285390 : cheapest_total_inner = NULL;
1698 : : }
1699 : 292633 : num_sortkeys = list_length(innersortkeys);
1700 [ + + + + ]: 292633 : if (num_sortkeys > 1 && !useallclauses)
3189 tgl@sss.pgh.pa.us 1701 : 14905 : trialsortkeys = list_copy(innersortkeys); /* need modifiable copy */
1702 : : else
3371 rhaas@postgresql.org 1703 : 277728 : trialsortkeys = innersortkeys; /* won't really truncate */
1704 : :
1705 [ + + ]: 557316 : for (sortkeycnt = num_sortkeys; sortkeycnt > 0; sortkeycnt--)
1706 : : {
1707 : : Path *innerpath;
1708 : 308052 : List *newclauses = NIL;
1709 : :
1710 : : /*
1711 : : * Look for an inner path ordered well enough for the first
1712 : : * 'sortkeycnt' innersortkeys. NB: trialsortkeys list is modified
1713 : : * destructively, which is why we made a copy...
1714 : : */
1715 : 308052 : trialsortkeys = list_truncate(trialsortkeys, sortkeycnt);
1716 : 308052 : innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist,
1717 : : trialsortkeys,
1718 : : NULL,
1719 : : TOTAL_COST,
1720 : : is_partial);
1721 [ + + + + ]: 308052 : if (innerpath != NULL &&
1722 [ + + ]: 12744 : (cheapest_total_inner == NULL ||
1723 : 12744 : compare_path_costs(innerpath, cheapest_total_inner,
1724 : : TOTAL_COST) < 0))
1725 : : {
1726 : : /* Found a cheap (or even-cheaper) sorted path */
1727 : : /* Select the right mergeclauses, if we didn't already */
1728 [ + + ]: 184464 : if (sortkeycnt < num_sortkeys)
1729 : : {
1730 : : newclauses =
2942 tgl@sss.pgh.pa.us 1731 : 9694 : trim_mergeclauses_for_inner_pathkeys(root,
1732 : : mergeclauses,
1733 : : trialsortkeys);
3371 rhaas@postgresql.org 1734 [ - + ]: 9694 : Assert(newclauses != NIL);
1735 : : }
1736 : : else
1737 : 174770 : newclauses = mergeclauses;
1738 : 184464 : try_mergejoin_path(root,
1739 : : joinrel,
1740 : : outerpath,
1741 : : innerpath,
1742 : : merge_pathkeys,
1743 : : newclauses,
1744 : : NIL,
1745 : : NIL,
1746 : : jointype,
1747 : : extra,
1748 : : is_partial);
1749 : 184464 : cheapest_total_inner = innerpath;
1750 : : }
1751 : : /* Same on the basis of cheapest startup cost ... */
1752 : 308052 : innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist,
1753 : : trialsortkeys,
1754 : : NULL,
1755 : : STARTUP_COST,
1756 : : is_partial);
1757 [ + + + + ]: 308052 : if (innerpath != NULL &&
1758 [ + + ]: 12744 : (cheapest_startup_inner == NULL ||
1759 : 12744 : compare_path_costs(innerpath, cheapest_startup_inner,
1760 : : STARTUP_COST) < 0))
1761 : : {
1762 : : /* Found a cheap (or even-cheaper) sorted path */
1763 [ + + ]: 183153 : if (innerpath != cheapest_total_inner)
1764 : : {
1765 : : /*
1766 : : * Avoid rebuilding clause list if we already made one; saves
1767 : : * memory in big join trees...
1768 : : */
1769 [ + + ]: 1406 : if (newclauses == NIL)
1770 : : {
1771 [ - + ]: 41 : if (sortkeycnt < num_sortkeys)
1772 : : {
1773 : : newclauses =
2942 tgl@sss.pgh.pa.us 1774 :UBC 0 : trim_mergeclauses_for_inner_pathkeys(root,
1775 : : mergeclauses,
1776 : : trialsortkeys);
3371 rhaas@postgresql.org 1777 [ # # ]: 0 : Assert(newclauses != NIL);
1778 : : }
1779 : : else
3371 rhaas@postgresql.org 1780 :CBC 41 : newclauses = mergeclauses;
1781 : : }
1782 : 1406 : try_mergejoin_path(root,
1783 : : joinrel,
1784 : : outerpath,
1785 : : innerpath,
1786 : : merge_pathkeys,
1787 : : newclauses,
1788 : : NIL,
1789 : : NIL,
1790 : : jointype,
1791 : : extra,
1792 : : is_partial);
1793 : : }
1794 : 183153 : cheapest_startup_inner = innerpath;
1795 : : }
1796 : :
1797 : : /*
1798 : : * Don't consider truncated sortkeys if we need all clauses.
1799 : : */
1800 [ + + ]: 308052 : if (useallclauses)
1801 : 43369 : break;
1802 : : }
1803 : : }
1804 : :
1805 : : /*
1806 : : * match_unsorted_outer
1807 : : * Creates possible join paths for processing a single join relation
1808 : : * 'joinrel' by employing either iterative substitution or
1809 : : * mergejoining on each of its possible outer paths (considering
1810 : : * only outer paths that are already ordered well enough for merging).
1811 : : *
1812 : : * We always generate a nestloop path for each available outer path.
1813 : : * In fact we may generate as many as five: one on the cheapest-total-cost
1814 : : * inner path, one on the same with materialization, one on the
1815 : : * cheapest-startup-cost inner path (if different), one on the
1816 : : * cheapest-total inner-indexscan path (if any), and one on the
1817 : : * cheapest-startup inner-indexscan path (if different).
1818 : : *
1819 : : * We also consider mergejoins if mergejoin clauses are available. See
1820 : : * detailed comments in generate_mergejoin_paths.
1821 : : *
1822 : : * 'joinrel' is the join relation
1823 : : * 'outerrel' is the outer join relation
1824 : : * 'innerrel' is the inner join relation
1825 : : * 'jointype' is the type of join to do
1826 : : * 'extra' contains additional input values
1827 : : */
1828 : : static void
7588 tgl@sss.pgh.pa.us 1829 : 440484 : match_unsorted_outer(PlannerInfo *root,
1830 : : RelOptInfo *joinrel,
1831 : : RelOptInfo *outerrel,
1832 : : RelOptInfo *innerrel,
1833 : : JoinType jointype,
1834 : : JoinPathExtraData *extra)
1835 : : {
1836 : : bool nestjoinOK;
1837 : : bool useallclauses;
8455 1838 : 440484 : Path *inner_cheapest_total = innerrel->cheapest_total_path;
8506 1839 : 440484 : Path *matpath = NULL;
1840 : : ListCell *lc1;
1841 : :
1842 : : /*
1843 : : * For now we do not support RIGHT_SEMI join in mergejoin or nestloop
1844 : : * join.
1845 : : */
618 rguo@postgresql.org 1846 [ + + ]: 440484 : if (jointype == JOIN_RIGHT_SEMI)
1847 : 57 : return;
1848 : :
1849 : : /*
1850 : : * Nestloop only supports inner, left, semi, and anti joins. Also, if we
1851 : : * are doing a right, right-anti or full mergejoin, we must use *all* the
1852 : : * mergeclauses as join clauses, else we will not have a valid plan.
1853 : : * (Although these two flags are currently inverses, keep them separate
1854 : : * for clarity and possible future changes.)
1855 : : */
9315 tgl@sss.pgh.pa.us 1856 [ + + - - ]: 440427 : switch (jointype)
1857 : : {
1858 : 384154 : case JOIN_INNER:
1859 : : case JOIN_LEFT:
1860 : : case JOIN_SEMI:
1861 : : case JOIN_ANTI:
1862 : 384154 : nestjoinOK = true;
9100 1863 : 384154 : useallclauses = false;
9315 1864 : 384154 : break;
9100 1865 : 56273 : case JOIN_RIGHT:
1866 : : case JOIN_RIGHT_ANTI:
1867 : : case JOIN_FULL:
9315 1868 : 56273 : nestjoinOK = false;
9100 1869 : 56273 : useallclauses = true;
1870 : 56273 : break;
9100 tgl@sss.pgh.pa.us 1871 :UBC 0 : default:
8269 1872 [ # # ]: 0 : elog(ERROR, "unrecognized join type: %d",
1873 : : (int) jointype);
1874 : : nestjoinOK = false; /* keep compiler quiet */
1875 : : useallclauses = false;
1876 : : break;
1877 : : }
1878 : :
1879 : : /*
1880 : : * If inner_cheapest_total is parameterized by the outer rel, ignore it;
1881 : : * we will consider it below as a member of cheapest_parameterized_paths,
1882 : : * but the other possibilities considered in this routine aren't usable.
1883 : : *
1884 : : * Furthermore, if the inner side is a unique-ified relation, we cannot
1885 : : * generate any valid paths here, because the inner rel's dependency on
1886 : : * the outer rel makes unique-ification meaningless.
1887 : : */
4946 tgl@sss.pgh.pa.us 1888 [ + + + - :CBC 440427 : if (PATH_PARAM_BY_REL(inner_cheapest_total, outerrel))
+ + + + +
- + + ]
1889 : : {
1890 : 10538 : inner_cheapest_total = NULL;
1891 : :
208 rguo@postgresql.org 1892 [ + + + + :GNC 10538 : if (RELATION_WAS_MADE_UNIQUE(innerrel, extra->sjinfo, jointype))
+ - ]
4968 tgl@sss.pgh.pa.us 1893 :CBC 18 : return;
1894 : : }
1895 : :
208 rguo@postgresql.org 1896 [ + + ]:GNC 440409 : if (nestjoinOK)
1897 : : {
1898 : : /*
1899 : : * Consider materializing the cheapest inner path, unless that is
1900 : : * disabled or the path in question materializes its output anyway.
1901 : : *
1902 : : * At present, we only consider materialization for non-partial outer
1903 : : * paths, so it's correct to test PGS_CONSIDER_NONPARTIAL here. If we
1904 : : * ever want to consider materialization for partial paths, we'll need
1905 : : * to create matpath whenever PGS_NESTLOOP_MATERIALIZE is set, use it
1906 : : * for partial paths either way, and use it for non-partial paths only
1907 : : * when PGS_CONSIDER_NONPARTIAL is also set.
1908 : : */
33 rhaas@postgresql.org 1909 [ + + ]: 384136 : if ((extra->pgs_mask &
1910 : : (PGS_NESTLOOP_MATERIALIZE | PGS_CONSIDER_NONPARTIAL)) ==
1911 [ + + ]: 382924 : (PGS_NESTLOOP_MATERIALIZE | PGS_CONSIDER_NONPARTIAL) &&
46 1912 : 372404 : inner_cheapest_total != NULL &&
5809 rhaas@postgresql.org 1913 [ + + ]:CBC 372404 : !ExecMaterializesOutput(inner_cheapest_total->pathtype))
1914 : : matpath = (Path *)
46 rhaas@postgresql.org 1915 :GNC 355883 : create_material_path(innerrel, inner_cheapest_total, true);
1916 : : }
1917 : :
5161 tgl@sss.pgh.pa.us 1918 [ + - + + :CBC 1462151 : foreach(lc1, outerrel->pathlist)
+ + ]
1919 : : {
1920 : 1021742 : Path *outerpath = (Path *) lfirst(lc1);
1921 : : List *merge_pathkeys;
1922 : :
1923 : : /*
1924 : : * We cannot use an outer path that is parameterized by the inner rel.
1925 : : */
4946 1926 [ + + + - : 1021742 : if (PATH_PARAM_BY_REL(outerpath, innerrel))
+ + + + +
- + + ]
5161 1927 : 160410 : continue;
1928 : :
1929 : : /*
1930 : : * The result will have this sort order (even if it is implemented as
1931 : : * a nestloop, and even if some of the mergeclauses are implemented by
1932 : : * qpquals rather than as true mergeclauses):
1933 : : */
7721 1934 : 861332 : merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
1935 : : outerpath->pathkeys);
1936 : :
208 rguo@postgresql.org 1937 [ + + ]:GNC 861332 : if (nestjoinOK)
1938 : : {
1939 : : /*
1940 : : * Consider nestloop joins using this outer path and various
1941 : : * available paths for the inner relation. We consider the
1942 : : * cheapest-total paths for each available parameterization of the
1943 : : * inner relation, including the unparameterized case.
1944 : : */
1945 : : ListCell *lc2;
1946 : :
5161 tgl@sss.pgh.pa.us 1947 [ + - + + :CBC 1947963 : foreach(lc2, innerrel->cheapest_parameterized_paths)
+ + ]
1948 : : {
1949 : 1194268 : Path *innerpath = (Path *) lfirst(lc2);
1950 : : Path *mpath;
1951 : :
1952 : 1194268 : try_nestloop_path(root,
1953 : : joinrel,
1954 : : outerpath,
1955 : : innerpath,
1956 : : merge_pathkeys,
1957 : : jointype,
1958 : : PGS_NESTLOOP_PLAIN,
1959 : : extra);
1960 : :
1961 : : /*
1962 : : * Try generating a memoize path and see if that makes the
1963 : : * nested loop any cheaper.
1964 : : */
1705 drowley@postgresql.o 1965 : 1194268 : mpath = get_memoize_path(root, innerrel, outerrel,
1966 : : innerpath, outerpath, jointype,
1967 : : extra);
1968 [ + + ]: 1194268 : if (mpath != NULL)
1808 1969 : 186657 : try_nestloop_path(root,
1970 : : joinrel,
1971 : : outerpath,
1972 : : mpath,
1973 : : merge_pathkeys,
1974 : : jointype,
1975 : : PGS_NESTLOOP_MEMOIZE,
1976 : : extra);
1977 : : }
1978 : :
1979 : : /* Also consider materialized form of the cheapest inner path */
8506 tgl@sss.pgh.pa.us 1980 [ + + ]: 753695 : if (matpath != NULL)
5161 1981 : 700528 : try_nestloop_path(root,
1982 : : joinrel,
1983 : : outerpath,
1984 : : matpath,
1985 : : merge_pathkeys,
1986 : : jointype,
1987 : : PGS_NESTLOOP_MATERIALIZE,
1988 : : extra);
1989 : : }
1990 : :
1991 : : /* Can't do anything else if inner rel is parameterized by outer */
4946 1992 [ + + ]: 861332 : if (inner_cheapest_total == NULL)
4968 1993 : 16734 : continue;
1994 : :
1995 : : /* Generate merge join paths */
3371 rhaas@postgresql.org 1996 : 844598 : generate_mergejoin_paths(root, joinrel, innerrel, outerpath,
1997 : : jointype, extra, useallclauses,
1998 : : inner_cheapest_total, merge_pathkeys,
1999 : : false);
2000 : : }
2001 : :
2002 : : /*
2003 : : * Consider partial nestloop and mergejoin plan if outerrel has any
2004 : : * partial path and the joinrel is parallel-safe. However, we can't
2005 : : * handle joins needing lateral rels, since partial paths must not be
2006 : : * parameterized. Similarly, we can't handle JOIN_FULL, JOIN_RIGHT and
2007 : : * JOIN_RIGHT_ANTI, because they can produce false null extended rows.
2008 : : */
3295 2009 [ + + + + ]: 440409 : if (joinrel->consider_parallel &&
208 rguo@postgresql.org 2010 [ + + ]:GNC 376164 : jointype != JOIN_FULL &&
2011 [ + + ]: 328316 : jointype != JOIN_RIGHT &&
2012 : 325826 : jointype != JOIN_RIGHT_ANTI &&
3295 rhaas@postgresql.org 2013 [ + + ]:CBC 325826 : outerrel->partial_pathlist != NIL &&
3707 2014 [ + - ]: 37332 : bms_is_empty(joinrel->lateral_relids))
2015 : : {
3295 2016 [ + - ]: 37332 : if (nestjoinOK)
2017 : 37332 : consider_parallel_nestloop(root, joinrel, outerrel, innerrel,
2018 : : jointype, extra);
2019 : :
2020 : : /*
2021 : : * If inner_cheapest_total is NULL or non parallel-safe then find the
2022 : : * cheapest total parallel safe path.
2023 : : */
2024 [ + + ]: 37332 : if (inner_cheapest_total == NULL ||
2025 [ + + ]: 37122 : !inner_cheapest_total->parallel_safe)
2026 : : {
2027 : : inner_cheapest_total =
208 rguo@postgresql.org 2028 :GNC 449 : get_cheapest_parallel_safe_total_inner(innerrel->pathlist);
2029 : : }
2030 : :
3295 rhaas@postgresql.org 2031 [ + + ]:CBC 37332 : if (inner_cheapest_total)
2032 : 37101 : consider_parallel_mergejoin(root, joinrel, outerrel, innerrel,
2033 : : jointype, extra,
2034 : : inner_cheapest_total);
2035 : : }
2036 : : }
2037 : :
2038 : : /*
2039 : : * consider_parallel_mergejoin
2040 : : * Try to build partial paths for a joinrel by joining a partial path
2041 : : * for the outer relation to a complete path for the inner relation.
2042 : : *
2043 : : * 'joinrel' is the join relation
2044 : : * 'outerrel' is the outer join relation
2045 : : * 'innerrel' is the inner join relation
2046 : : * 'jointype' is the type of join to do
2047 : : * 'extra' contains additional input values
2048 : : * 'inner_cheapest_total' cheapest total path for innerrel
2049 : : */
2050 : : static void
2051 : 37101 : consider_parallel_mergejoin(PlannerInfo *root,
2052 : : RelOptInfo *joinrel,
2053 : : RelOptInfo *outerrel,
2054 : : RelOptInfo *innerrel,
2055 : : JoinType jointype,
2056 : : JoinPathExtraData *extra,
2057 : : Path *inner_cheapest_total)
2058 : : {
2059 : : ListCell *lc1;
2060 : :
2061 : : /* generate merge join path for each partial outer path */
2062 [ + - + + : 84140 : foreach(lc1, outerrel->partial_pathlist)
+ + ]
2063 : : {
2064 : 47039 : Path *outerpath = (Path *) lfirst(lc1);
2065 : : List *merge_pathkeys;
2066 : :
2067 : : /*
2068 : : * Figure out what useful ordering any paths we create will have.
2069 : : */
2070 : 47039 : merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
2071 : : outerpath->pathkeys);
2072 : :
2073 : 47039 : generate_mergejoin_paths(root, joinrel, innerrel, outerpath, jointype,
2074 : : extra, false, inner_cheapest_total,
2075 : : merge_pathkeys, true);
2076 : : }
3707 2077 : 37101 : }
2078 : :
2079 : : /*
2080 : : * consider_parallel_nestloop
2081 : : * Try to build partial paths for a joinrel by joining a partial path for the
2082 : : * outer relation to a complete path for the inner relation.
2083 : : *
2084 : : * 'joinrel' is the join relation
2085 : : * 'outerrel' is the outer join relation
2086 : : * 'innerrel' is the inner join relation
2087 : : * 'jointype' is the type of join to do
2088 : : * 'extra' contains additional input values
2089 : : */
2090 : : static void
2091 : 37332 : consider_parallel_nestloop(PlannerInfo *root,
2092 : : RelOptInfo *joinrel,
2093 : : RelOptInfo *outerrel,
2094 : : RelOptInfo *innerrel,
2095 : : JoinType jointype,
2096 : : JoinPathExtraData *extra)
2097 : : {
611 rguo@postgresql.org 2098 : 37332 : Path *inner_cheapest_total = innerrel->cheapest_total_path;
2099 : 37332 : Path *matpath = NULL;
2100 : : ListCell *lc1;
2101 : :
2102 : : /*
2103 : : * Consider materializing the cheapest inner path, unless: 1)
2104 : : * materialization is disabled here, 2) the cheapest inner path is not
2105 : : * parallel-safe, 3) the cheapest inner path is parameterized by the outer
2106 : : * rel, or 4) the cheapest inner path materializes its output anyway.
2107 : : */
46 rhaas@postgresql.org 2108 [ + + ]:GNC 37332 : if ((extra->pgs_mask & PGS_NESTLOOP_MATERIALIZE) != 0 &&
2109 [ + + ]: 37000 : inner_cheapest_total->parallel_safe &&
611 rguo@postgresql.org 2110 [ + + + - :CBC 36848 : !PATH_PARAM_BY_REL(inner_cheapest_total, outerrel) &&
+ + + + +
- - + ]
2111 [ + + ]: 36653 : !ExecMaterializesOutput(inner_cheapest_total->pathtype))
2112 : : {
2113 : : matpath = (Path *)
46 rhaas@postgresql.org 2114 :GNC 36605 : create_material_path(innerrel, inner_cheapest_total, true);
611 rguo@postgresql.org 2115 [ - + ]:CBC 36605 : Assert(matpath->parallel_safe);
2116 : : }
2117 : :
3707 rhaas@postgresql.org 2118 [ + - + + : 84671 : foreach(lc1, outerrel->partial_pathlist)
+ + ]
2119 : : {
2120 : 47339 : Path *outerpath = (Path *) lfirst(lc1);
2121 : : List *pathkeys;
2122 : : ListCell *lc2;
2123 : :
2124 : : /* Figure out what useful ordering any paths we create will have. */
2125 : 47339 : pathkeys = build_join_pathkeys(root, joinrel, jointype,
2126 : : outerpath->pathkeys);
2127 : :
2128 : : /*
2129 : : * Try the cheapest parameterized paths; only those which will produce
2130 : : * an unparameterized path when joined to this outerrel will survive
2131 : : * try_partial_nestloop_path. The cheapest unparameterized path is
2132 : : * also in this list.
2133 : : */
2134 [ + - + + : 99214 : foreach(lc2, innerrel->cheapest_parameterized_paths)
+ + ]
2135 : : {
2136 : 51875 : Path *innerpath = (Path *) lfirst(lc2);
2137 : : Path *mpath;
2138 : :
2139 : : /* Can't join to an inner path that is not parallel-safe */
2140 [ + + ]: 51875 : if (!innerpath->parallel_safe)
2141 : 278 : continue;
2142 : :
2143 : 51597 : try_partial_nestloop_path(root, joinrel, outerpath, innerpath,
2144 : : pathkeys, jointype,
2145 : : PGS_NESTLOOP_PLAIN, extra);
2146 : :
2147 : : /*
2148 : : * Try generating a memoize path and see if that makes the nested
2149 : : * loop any cheaper.
2150 : : */
1705 drowley@postgresql.o 2151 : 51597 : mpath = get_memoize_path(root, innerrel, outerrel,
2152 : : innerpath, outerpath, jointype,
2153 : : extra);
2154 [ + + ]: 51597 : if (mpath != NULL)
2155 : 2925 : try_partial_nestloop_path(root, joinrel, outerpath, mpath,
2156 : : pathkeys, jointype,
2157 : : PGS_NESTLOOP_MEMOIZE, extra);
2158 : : }
2159 : :
2160 : : /* Also consider materialized form of the cheapest inner path */
611 rguo@postgresql.org 2161 [ + + ]: 47339 : if (matpath != NULL)
2162 : 46399 : try_partial_nestloop_path(root, joinrel, outerpath, matpath,
2163 : : pathkeys, jointype,
2164 : : PGS_NESTLOOP_MATERIALIZE, extra);
2165 : : }
10841 scrappy@hub.org 2166 : 37332 : }
2167 : :
2168 : : /*
2169 : : * hash_inner_and_outer
2170 : : * Create hashjoin join paths by explicitly hashing both the outer and
2171 : : * inner keys of each available hash clause.
2172 : : *
2173 : : * 'joinrel' is the join relation
2174 : : * 'outerrel' is the outer join relation
2175 : : * 'innerrel' is the inner join relation
2176 : : * 'jointype' is the type of join to do
2177 : : * 'extra' contains additional input values
2178 : : */
2179 : : static void
7588 tgl@sss.pgh.pa.us 2180 : 447638 : hash_inner_and_outer(PlannerInfo *root,
2181 : : RelOptInfo *joinrel,
2182 : : RelOptInfo *outerrel,
2183 : : RelOptInfo *innerrel,
2184 : : JoinType jointype,
2185 : : JoinPathExtraData *extra)
2186 : : {
5554 2187 : 447638 : bool isouterjoin = IS_OUTER_JOIN(jointype);
2188 : : List *hashclauses;
2189 : : ListCell *l;
2190 : :
2191 : : /*
2192 : : * We need to build only one hashclauses list for any given pair of outer
2193 : : * and inner relations; all of the hashable clauses will be used as keys.
2194 : : *
2195 : : * Scan the join's restrictinfo list to find hashjoinable clauses that are
2196 : : * usable with this pair of sub-relations.
2197 : : */
8506 2198 : 447638 : hashclauses = NIL;
3962 2199 [ + + + + : 946230 : foreach(l, extra->restrictlist)
+ + ]
2200 : : {
7963 neilc@samurai.com 2201 : 498592 : RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
2202 : :
2203 : : /*
2204 : : * If processing an outer join, only use its own join clauses for
2205 : : * hashing. For inner joins we need not be so picky.
2206 : : */
2886 tgl@sss.pgh.pa.us 2207 [ + + + + : 498592 : if (isouterjoin && RINFO_IS_PUSHED_DOWN(restrictinfo, joinrel->relids))
- + ]
9315 2208 : 9180 : continue;
2209 : :
6022 2210 [ + + ]: 489412 : if (!restrictinfo->can_join ||
2211 [ + + ]: 442843 : restrictinfo->hashjoinoperator == InvalidOid)
2212 : 58603 : continue; /* not hashjoinable */
2213 : :
2214 : : /*
2215 : : * Check if clause has the form "outer op inner" or "inner op outer".
2216 : : */
516 drowley@postgresql.o 2217 [ + + ]: 430809 : if (!clause_sides_match_join(restrictinfo, outerrel->relids,
2218 : : innerrel->relids))
9533 tgl@sss.pgh.pa.us 2219 : 108 : continue; /* no good for these input relations */
2220 : :
2221 : : /*
2222 : : * If clause has the form "inner op outer", check if its operator has
2223 : : * valid commutator. This is necessary because hashclauses in this
2224 : : * form will get commuted in createplan.c to put the outer var on the
2225 : : * left (see get_switched_clauses). This probably shouldn't ever
2226 : : * fail, since hashable operators ought to have commutators, but be
2227 : : * paranoid.
2228 : : *
2229 : : * The clause being hashjoinable indicates that it's an OpExpr.
2230 : : */
557 rguo@postgresql.org 2231 [ + + + + ]: 646056 : if (!restrictinfo->outer_is_left &&
2232 : 215355 : !OidIsValid(get_commutator(castNode(OpExpr, restrictinfo->clause)->opno)))
2233 : 3 : continue;
2234 : :
8506 tgl@sss.pgh.pa.us 2235 : 430698 : hashclauses = lappend(hashclauses, restrictinfo);
2236 : : }
2237 : :
2238 : : /* If we found any usable hashclauses, make paths */
2239 [ + + ]: 447638 : if (hashclauses)
2240 : : {
2241 : : /*
2242 : : * We consider both the cheapest-total-cost and cheapest-startup-cost
2243 : : * outer paths. There's no need to consider any but the
2244 : : * cheapest-total-cost inner path, however.
2245 : : */
8259 bruce@momjian.us 2246 : 381714 : Path *cheapest_startup_outer = outerrel->cheapest_startup_path;
2247 : 381714 : Path *cheapest_total_outer = outerrel->cheapest_total_path;
2248 : 381714 : Path *cheapest_total_inner = innerrel->cheapest_total_path;
2249 : : ListCell *lc1;
2250 : : ListCell *lc2;
2251 : :
2252 : : /*
2253 : : * If either cheapest-total path is parameterized by the other rel, we
2254 : : * can't use a hashjoin. (There's no use looking for alternative
2255 : : * input paths, since these should already be the least-parameterized
2256 : : * available paths.)
2257 : : */
4946 tgl@sss.pgh.pa.us 2258 [ + + + - : 381714 : if (PATH_PARAM_BY_REL(cheapest_total_outer, innerrel) ||
+ + + + +
- + + ]
2259 [ + + + - : 379998 : PATH_PARAM_BY_REL(cheapest_total_inner, outerrel))
+ + + + +
- + + ]
4968 2260 : 3432 : return;
2261 : :
2262 : : /*
2263 : : * Consider the cheapest startup outer together with the cheapest
2264 : : * total inner, and then consider pairings of cheapest-total paths
2265 : : * including parameterized ones. There is no use in generating
2266 : : * parameterized paths on the basis of possibly cheap startup cost, so
2267 : : * this is sufficient.
2268 : : */
208 rguo@postgresql.org 2269 [ + + ]:GNC 378282 : if (cheapest_startup_outer != NULL)
5161 tgl@sss.pgh.pa.us 2270 :CBC 376691 : try_hashjoin_path(root,
2271 : : joinrel,
2272 : : cheapest_startup_outer,
2273 : : cheapest_total_inner,
2274 : : hashclauses,
2275 : : jointype,
2276 : : extra);
2277 : :
208 rguo@postgresql.org 2278 [ + - + + :GNC 947858 : foreach(lc1, outerrel->cheapest_parameterized_paths)
+ + ]
2279 : : {
2280 : 569576 : Path *outerpath = (Path *) lfirst(lc1);
2281 : :
2282 : : /*
2283 : : * We cannot use an outer path that is parameterized by the inner
2284 : : * rel.
2285 : : */
2286 [ + + + - : 569576 : if (PATH_PARAM_BY_REL(outerpath, innerrel))
+ + + + +
- + + ]
2287 : 153055 : continue;
2288 : :
2289 [ + - + + : 1055521 : foreach(lc2, innerrel->cheapest_parameterized_paths)
+ + ]
2290 : : {
2291 : 639000 : Path *innerpath = (Path *) lfirst(lc2);
2292 : :
2293 : : /*
2294 : : * We cannot use an inner path that is parameterized by the
2295 : : * outer rel, either.
2296 : : */
2297 [ + + + - : 639000 : if (PATH_PARAM_BY_REL(innerpath, outerrel))
+ + + + +
- + + ]
5161 tgl@sss.pgh.pa.us 2298 :CBC 174270 : continue;
2299 : :
208 rguo@postgresql.org 2300 [ + + + + ]:GNC 464730 : if (outerpath == cheapest_startup_outer &&
2301 : : innerpath == cheapest_total_inner)
2302 : 325846 : continue; /* already tried it */
2303 : :
2304 : 138884 : try_hashjoin_path(root,
2305 : : joinrel,
2306 : : outerpath,
2307 : : innerpath,
2308 : : hashclauses,
2309 : : jointype,
2310 : : extra);
2311 : : }
2312 : : }
2313 : :
2314 : : /*
2315 : : * If the joinrel is parallel-safe, we may be able to consider a
2316 : : * partial hash join.
2317 : : *
2318 : : * However, we can't handle JOIN_RIGHT_SEMI, because the hash table is
2319 : : * either a shared hash table or a private hash table per backend. In
2320 : : * the shared case, there is no concurrency protection for the match
2321 : : * flags, so multiple workers could inspect and set the flags
2322 : : * concurrently, potentially producing incorrect results. In the
2323 : : * private case, each worker has its own copy of the hash table, so no
2324 : : * single process has all the match flags.
2325 : : *
2326 : : * Also, the resulting path must not be parameterized.
2327 : : */
3616 rhaas@postgresql.org 2328 [ + + + + ]:CBC 378282 : if (joinrel->consider_parallel &&
136 rguo@postgresql.org 2329 :GNC 339177 : jointype != JOIN_RIGHT_SEMI &&
3707 rhaas@postgresql.org 2330 [ + + ]:CBC 339177 : outerrel->partial_pathlist != NIL &&
2331 [ + - ]: 38441 : bms_is_empty(joinrel->lateral_relids))
2332 : : {
2333 : : Path *cheapest_partial_outer;
3007 andres@anarazel.de 2334 : 38441 : Path *cheapest_partial_inner = NULL;
3630 tgl@sss.pgh.pa.us 2335 : 38441 : Path *cheapest_safe_inner = NULL;
2336 : :
3707 rhaas@postgresql.org 2337 : 38441 : cheapest_partial_outer =
2338 : 38441 : (Path *) linitial(outerrel->partial_pathlist);
2339 : :
2340 : : /*
2341 : : * Can we use a partial inner plan too, so that we can build a
2342 : : * shared hash table in parallel?
2343 : : */
2462 tmunro@postgresql.or 2344 [ + + + + ]: 38441 : if (innerrel->partial_pathlist != NIL &&
2345 : : enable_parallel_hash)
2346 : : {
3007 andres@anarazel.de 2347 : 37621 : cheapest_partial_inner =
2348 : 37621 : (Path *) linitial(innerrel->partial_pathlist);
2349 : 37621 : try_partial_hashjoin_path(root, joinrel,
2350 : : cheapest_partial_outer,
2351 : : cheapest_partial_inner,
2352 : : hashclauses, jointype, extra,
2353 : : true /* parallel_hash */ );
2354 : : }
2355 : :
2356 : : /*
2357 : : * Normally, given that the joinrel is parallel-safe, the cheapest
2358 : : * total inner path will also be parallel-safe, but if not, we'll
2359 : : * have to search for the cheapest safe, unparameterized inner
2360 : : * path. If full, right, or right-anti join, we can't use
2361 : : * parallelism (building the hash table in each backend) because
2362 : : * no one process has all the match bits.
2363 : : */
208 rguo@postgresql.org 2364 [ + + + + ]:GNC 38441 : if (jointype == JOIN_FULL ||
2365 [ + + ]: 36533 : jointype == JOIN_RIGHT ||
2366 : : jointype == JOIN_RIGHT_ANTI)
1080 tmunro@postgresql.or 2367 :CBC 2073 : cheapest_safe_inner = NULL;
2368 [ + + ]: 36368 : else if (cheapest_total_inner->parallel_safe)
3707 rhaas@postgresql.org 2369 : 36201 : cheapest_safe_inner = cheapest_total_inner;
2370 : : else
2371 : : cheapest_safe_inner =
3295 2372 : 167 : get_cheapest_parallel_safe_total_inner(innerrel->pathlist);
2373 : :
3707 2374 [ + + ]: 38441 : if (cheapest_safe_inner != NULL)
2375 : 36347 : try_partial_hashjoin_path(root, joinrel,
2376 : : cheapest_partial_outer,
2377 : : cheapest_safe_inner,
2378 : : hashclauses, jointype, extra,
2379 : : false /* parallel_hash */ );
2380 : : }
2381 : : }
2382 : : }
2383 : :
2384 : : /*
2385 : : * select_mergejoin_clauses
2386 : : * Select mergejoin clauses that are usable for a particular join.
2387 : : * Returns a list of RestrictInfo nodes for those clauses.
2388 : : *
2389 : : * *mergejoin_allowed is normally set to true, but it is set to false if
2390 : : * this is a right-semi join, or this is a right/right-anti/full join and
2391 : : * there are nonmergejoinable join clauses. The executor's mergejoin
2392 : : * machinery cannot handle such cases, so we have to avoid generating a
2393 : : * mergejoin plan. (Note that this flag does NOT consider whether there are
2394 : : * actually any mergejoinable clauses. This is correct because in some
2395 : : * cases we need to build a clauseless mergejoin. Simply returning NIL is
2396 : : * therefore not enough to distinguish safe from unsafe cases.)
2397 : : *
2398 : : * We also mark each selected RestrictInfo to show which side is currently
2399 : : * being considered as outer. These are transient markings that are only
2400 : : * good for the duration of the current add_paths_to_joinrel() call!
2401 : : *
2402 : : * We examine each restrictinfo clause known for the join to see
2403 : : * if it is mergejoinable and involves vars from the two sub-relations
2404 : : * currently of interest.
2405 : : */
2406 : : static List *
6640 tgl@sss.pgh.pa.us 2407 : 448340 : select_mergejoin_clauses(PlannerInfo *root,
2408 : : RelOptInfo *joinrel,
2409 : : RelOptInfo *outerrel,
2410 : : RelOptInfo *innerrel,
2411 : : List *restrictlist,
2412 : : JoinType jointype,
2413 : : bool *mergejoin_allowed)
2414 : : {
9708 2415 : 448340 : List *result_list = NIL;
9315 2416 : 448340 : bool isouterjoin = IS_OUTER_JOIN(jointype);
5553 2417 : 448340 : bool have_nonmergeable_joinclause = false;
2418 : : ListCell *l;
2419 : :
2420 : : /*
2421 : : * For now we do not support RIGHT_SEMI join in mergejoin: the benefit of
2422 : : * swapping inputs tends to be small here.
2423 : : */
618 rguo@postgresql.org 2424 [ + + ]: 448340 : if (jointype == JOIN_RIGHT_SEMI)
2425 : : {
2426 : 3795 : *mergejoin_allowed = false;
2427 : 3795 : return NIL;
2428 : : }
2429 : :
7963 neilc@samurai.com 2430 [ + + + + : 940680 : foreach(l, restrictlist)
+ + ]
2431 : : {
2432 : 496135 : RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
2433 : :
2434 : : /*
2435 : : * If processing an outer join, only use its own join clauses in the
2436 : : * merge. For inner joins we can use pushed-down clauses too. (Note:
2437 : : * we don't set have_nonmergeable_joinclause here because pushed-down
2438 : : * clauses will become otherquals not joinquals.)
2439 : : */
2886 tgl@sss.pgh.pa.us 2440 [ + + + + : 496135 : if (isouterjoin && RINFO_IS_PUSHED_DOWN(restrictinfo, joinrel->relids))
- + ]
7446 2441 : 9192 : continue;
2442 : :
2443 : : /* Check that clause is a mergeable operator clause */
8105 2444 [ + + ]: 486943 : if (!restrictinfo->can_join ||
6994 2445 [ + + ]: 440383 : restrictinfo->mergeopfamilies == NIL)
2446 : : {
2447 : : /*
2448 : : * The executor can handle extra joinquals that are constants, but
2449 : : * not anything else, when doing right/right-anti/full merge join.
2450 : : * (The reason to support constants is so we can do FULL JOIN ON
2451 : : * FALSE.)
2452 : : */
5913 2453 [ + - + + ]: 57861 : if (!restrictinfo->clause || !IsA(restrictinfo->clause, Const))
5553 2454 : 52505 : have_nonmergeable_joinclause = true;
9533 2455 : 57861 : continue; /* not mergejoinable */
2456 : : }
2457 : :
2458 : : /*
2459 : : * Check if clause has the form "outer op inner" or "inner op outer".
2460 : : */
516 drowley@postgresql.o 2461 [ + + ]: 429082 : if (!clause_sides_match_join(restrictinfo, outerrel->relids,
2462 : : innerrel->relids))
2463 : : {
5553 tgl@sss.pgh.pa.us 2464 : 504 : have_nonmergeable_joinclause = true;
8460 2465 : 504 : continue; /* no good for these input relations */
2466 : : }
2467 : :
2468 : : /*
2469 : : * If clause has the form "inner op outer", check if its operator has
2470 : : * valid commutator. This is necessary because mergejoin clauses in
2471 : : * this form will get commuted in createplan.c to put the outer var on
2472 : : * the left (see get_switched_clauses). This probably shouldn't ever
2473 : : * fail, since mergejoinable operators ought to have commutators, but
2474 : : * be paranoid.
2475 : : *
2476 : : * The clause being mergejoinable indicates that it's an OpExpr.
2477 : : */
557 rguo@postgresql.org 2478 [ + + + + ]: 641390 : if (!restrictinfo->outer_is_left &&
2479 : 212812 : !OidIsValid(get_commutator(castNode(OpExpr, restrictinfo->clause)->opno)))
2480 : : {
2481 : 18 : have_nonmergeable_joinclause = true;
2482 : 18 : continue;
2483 : : }
2484 : :
2485 : : /*
2486 : : * Insist that each side have a non-redundant eclass. This
2487 : : * restriction is needed because various bits of the planner expect
2488 : : * that each clause in a merge be associable with some pathkey in a
2489 : : * canonical pathkey list, but redundant eclasses can't appear in
2490 : : * canonical sort orderings. (XXX it might be worth relaxing this,
2491 : : * but not enough time to address it for 8.3.)
2492 : : */
5616 tgl@sss.pgh.pa.us 2493 : 428560 : update_mergeclause_eclasses(root, restrictinfo);
2494 : :
6640 2495 [ + + ]: 428560 : if (EC_MUST_BE_REDUNDANT(restrictinfo->left_ec) ||
2496 [ + + ]: 428536 : EC_MUST_BE_REDUNDANT(restrictinfo->right_ec))
2497 : : {
5553 2498 : 64 : have_nonmergeable_joinclause = true;
6640 2499 : 64 : continue; /* can't handle redundant eclasses */
2500 : : }
2501 : :
6994 2502 : 428496 : result_list = lappend(result_list, restrictinfo);
2503 : : }
2504 : :
2505 : : /*
2506 : : * Report whether mergejoin is allowed (see comment at top of function).
2507 : : */
5554 2508 [ + + ]: 444545 : switch (jointype)
2509 : : {
2510 : 62359 : case JOIN_RIGHT:
2511 : : case JOIN_RIGHT_ANTI:
2512 : : case JOIN_FULL:
5553 2513 : 62359 : *mergejoin_allowed = !have_nonmergeable_joinclause;
5554 2514 : 62359 : break;
2515 : 382186 : default:
5553 2516 : 382186 : *mergejoin_allowed = true;
5554 2517 : 382186 : break;
2518 : : }
2519 : :
9708 2520 : 444545 : return result_list;
2521 : : }
|