~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/optimizer/path/joinpath.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * joinpath.c
 
4
 *        Routines to find all possible paths for processing a set of joins
 
5
 *
 
6
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.91.4.1 2005-01-23 02:22:27 tgl Exp $
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
17
#include <math.h>
 
18
 
 
19
#include "optimizer/clauses.h"
 
20
#include "optimizer/cost.h"
 
21
#include "optimizer/pathnode.h"
 
22
#include "optimizer/paths.h"
 
23
#include "parser/parsetree.h"
 
24
#include "utils/lsyscache.h"
 
25
 
 
26
 
 
27
static void sort_inner_and_outer(Query *root, RelOptInfo *joinrel,
 
28
                                         RelOptInfo *outerrel, RelOptInfo *innerrel,
 
29
                                         List *restrictlist, List *mergeclause_list,
 
30
                                         JoinType jointype);
 
31
static void match_unsorted_outer(Query *root, RelOptInfo *joinrel,
 
32
                                         RelOptInfo *outerrel, RelOptInfo *innerrel,
 
33
                                         List *restrictlist, List *mergeclause_list,
 
34
                                         JoinType jointype);
 
35
static void hash_inner_and_outer(Query *root, RelOptInfo *joinrel,
 
36
                                         RelOptInfo *outerrel, RelOptInfo *innerrel,
 
37
                                         List *restrictlist, JoinType jointype);
 
38
static List *select_mergejoin_clauses(RelOptInfo *joinrel,
 
39
                                                 RelOptInfo *outerrel,
 
40
                                                 RelOptInfo *innerrel,
 
41
                                                 List *restrictlist,
 
42
                                                 JoinType jointype);
 
43
 
 
44
 
 
45
/*
 
46
 * add_paths_to_joinrel
 
47
 *        Given a join relation and two component rels from which it can be made,
 
48
 *        consider all possible paths that use the two component rels as outer
 
49
 *        and inner rel respectively.  Add these paths to the join rel's pathlist
 
50
 *        if they survive comparison with other paths (and remove any existing
 
51
 *        paths that are dominated by these paths).
 
52
 *
 
53
 * Modifies the pathlist field of the joinrel node to contain the best
 
54
 * paths found so far.
 
55
 */
 
56
void
 
57
add_paths_to_joinrel(Query *root,
 
58
                                         RelOptInfo *joinrel,
 
59
                                         RelOptInfo *outerrel,
 
60
                                         RelOptInfo *innerrel,
 
61
                                         JoinType jointype,
 
62
                                         List *restrictlist)
 
63
{
 
64
        List       *mergeclause_list = NIL;
 
65
 
 
66
        /*
 
67
         * Find potential mergejoin clauses.  We can skip this if we are not
 
68
         * interested in doing a mergejoin.  However, mergejoin is currently
 
69
         * our only way of implementing full outer joins, so override
 
70
         * mergejoin disable if it's a full join.
 
71
         */
 
72
        if (enable_mergejoin || jointype == JOIN_FULL)
 
73
                mergeclause_list = select_mergejoin_clauses(joinrel,
 
74
                                                                                                        outerrel,
 
75
                                                                                                        innerrel,
 
76
                                                                                                        restrictlist,
 
77
                                                                                                        jointype);
 
78
 
 
79
        /*
 
80
         * 1. Consider mergejoin paths where both relations must be explicitly
 
81
         * sorted.
 
82
         */
 
83
        sort_inner_and_outer(root, joinrel, outerrel, innerrel,
 
84
                                                 restrictlist, mergeclause_list, jointype);
 
85
 
 
86
        /*
 
87
         * 2. Consider paths where the outer relation need not be explicitly
 
88
         * sorted. This includes both nestloops and mergejoins where the outer
 
89
         * path is already ordered.
 
90
         */
 
91
        match_unsorted_outer(root, joinrel, outerrel, innerrel,
 
92
                                                 restrictlist, mergeclause_list, jointype);
 
93
 
 
94
#ifdef NOT_USED
 
95
 
 
96
        /*
 
97
         * 3. Consider paths where the inner relation need not be explicitly
 
98
         * sorted.      This includes mergejoins only (nestloops were already
 
99
         * built in match_unsorted_outer).
 
100
         *
 
101
         * Diked out as redundant 2/13/2000 -- tgl.  There isn't any really
 
102
         * significant difference between the inner and outer side of a
 
103
         * mergejoin, so match_unsorted_inner creates no paths that aren't
 
104
         * equivalent to those made by match_unsorted_outer when
 
105
         * add_paths_to_joinrel() is invoked with the two rels given in the
 
106
         * other order.
 
107
         */
 
108
        match_unsorted_inner(root, joinrel, outerrel, innerrel,
 
109
                                                 restrictlist, mergeclause_list, jointype);
 
110
#endif
 
111
 
 
112
        /*
 
113
         * 4. Consider paths where both outer and inner relations must be
 
114
         * hashed before being joined.
 
115
         */
 
116
        if (enable_hashjoin)
 
117
                hash_inner_and_outer(root, joinrel, outerrel, innerrel,
 
118
                                                         restrictlist, jointype);
 
119
}
 
120
 
 
121
/*
 
122
 * sort_inner_and_outer
 
123
 *        Create mergejoin join paths by explicitly sorting both the outer and
 
124
 *        inner join relations on each available merge ordering.
 
125
 *
 
126
 * 'joinrel' is the join relation
 
127
 * 'outerrel' is the outer join relation
 
128
 * 'innerrel' is the inner join relation
 
129
 * 'restrictlist' contains all of the RestrictInfo nodes for restriction
 
130
 *              clauses that apply to this join
 
131
 * 'mergeclause_list' is a list of RestrictInfo nodes for available
 
132
 *              mergejoin clauses in this join
 
133
 * 'jointype' is the type of join to do
 
134
 */
 
135
static void
 
136
sort_inner_and_outer(Query *root,
 
137
                                         RelOptInfo *joinrel,
 
138
                                         RelOptInfo *outerrel,
 
139
                                         RelOptInfo *innerrel,
 
140
                                         List *restrictlist,
 
141
                                         List *mergeclause_list,
 
142
                                         JoinType jointype)
 
143
{
 
144
        bool            useallclauses;
 
145
        Path       *outer_path;
 
146
        Path       *inner_path;
 
147
        List       *all_pathkeys;
 
148
        ListCell   *l;
 
149
 
 
150
        /*
 
151
         * If we are doing a right or full join, we must use *all* the
 
152
         * mergeclauses as join clauses, else we will not have a valid plan.
 
153
         */
 
154
        switch (jointype)
 
155
        {
 
156
                case JOIN_INNER:
 
157
                case JOIN_LEFT:
 
158
                case JOIN_IN:
 
159
                case JOIN_UNIQUE_OUTER:
 
160
                case JOIN_UNIQUE_INNER:
 
161
                        useallclauses = false;
 
162
                        break;
 
163
                case JOIN_RIGHT:
 
164
                case JOIN_FULL:
 
165
                        useallclauses = true;
 
166
                        break;
 
167
                default:
 
168
                        elog(ERROR, "unrecognized join type: %d",
 
169
                                 (int) jointype);
 
170
                        useallclauses = false;          /* keep compiler quiet */
 
171
                        break;
 
172
        }
 
173
 
 
174
        /*
 
175
         * We only consider the cheapest-total-cost input paths, since we are
 
176
         * assuming here that a sort is required.  We will consider
 
177
         * cheapest-startup-cost input paths later, and only if they don't
 
178
         * need a sort.
 
179
         *
 
180
         * If unique-ification is requested, do it and then handle as a plain
 
181
         * inner join.
 
182
         */
 
183
        outer_path = outerrel->cheapest_total_path;
 
184
        inner_path = innerrel->cheapest_total_path;
 
185
        if (jointype == JOIN_UNIQUE_OUTER)
 
186
        {
 
187
                outer_path = (Path *) create_unique_path(root, outerrel, outer_path);
 
188
                jointype = JOIN_INNER;
 
189
        }
 
190
        else if (jointype == JOIN_UNIQUE_INNER)
 
191
        {
 
192
                inner_path = (Path *) create_unique_path(root, innerrel, inner_path);
 
193
                jointype = JOIN_INNER;
 
194
        }
 
195
 
 
196
        /*
 
197
         * Each possible ordering of the available mergejoin clauses will
 
198
         * generate a differently-sorted result path at essentially the same
 
199
         * cost.  We have no basis for choosing one over another at this level
 
200
         * of joining, but some sort orders may be more useful than others for
 
201
         * higher-level mergejoins, so it's worth considering multiple
 
202
         * orderings.
 
203
         *
 
204
         * Actually, it's not quite true that every mergeclause ordering will
 
205
         * generate a different path order, because some of the clauses may be
 
206
         * redundant.  Therefore, what we do is convert the mergeclause list
 
207
         * to a list of canonical pathkeys, and then consider different
 
208
         * orderings of the pathkeys.
 
209
         *
 
210
         * Generating a path for *every* permutation of the pathkeys doesn't seem
 
211
         * like a winning strategy; the cost in planning time is too high. For
 
212
         * now, we generate one path for each pathkey, listing that pathkey
 
213
         * first and the rest in random order.  This should allow at least a
 
214
         * one-clause mergejoin without re-sorting against any other possible
 
215
         * mergejoin partner path.      But if we've not guessed the right
 
216
         * ordering of secondary keys, we may end up evaluating clauses as
 
217
         * qpquals when they could have been done as mergeclauses. We need to
 
218
         * figure out a better way.  (Two possible approaches: look at all the
 
219
         * relevant index relations to suggest plausible sort orders, or make
 
220
         * just one output path and somehow mark it as having a sort-order
 
221
         * that can be rearranged freely.)
 
222
         */
 
223
        all_pathkeys = make_pathkeys_for_mergeclauses(root,
 
224
                                                                                                  mergeclause_list,
 
225
                                                                                                  outerrel);
 
226
 
 
227
        foreach(l, all_pathkeys)
 
228
        {
 
229
                List       *front_pathkey = (List *) lfirst(l);
 
230
                List       *cur_pathkeys;
 
231
                List       *cur_mergeclauses;
 
232
                List       *outerkeys;
 
233
                List       *innerkeys;
 
234
                List       *merge_pathkeys;
 
235
 
 
236
                /* Make a pathkey list with this guy first. */
 
237
                if (l != list_head(all_pathkeys))
 
238
                        cur_pathkeys = lcons(front_pathkey,
 
239
                                                                 list_delete_ptr(list_copy(all_pathkeys),
 
240
                                                                                                 front_pathkey));
 
241
                else
 
242
                        cur_pathkeys = all_pathkeys;            /* no work at first one... */
 
243
 
 
244
                /*
 
245
                 * Select mergeclause(s) that match this sort ordering.  If we had
 
246
                 * redundant merge clauses then we will get a subset of the
 
247
                 * original clause list.  There had better be some match,
 
248
                 * however...
 
249
                 */
 
250
                cur_mergeclauses = find_mergeclauses_for_pathkeys(root,
 
251
                                                                                                                  cur_pathkeys,
 
252
                                                                                                           mergeclause_list);
 
253
                Assert(cur_mergeclauses != NIL);
 
254
 
 
255
                /* Forget it if can't use all the clauses in right/full join */
 
256
                if (useallclauses &&
 
257
                  list_length(cur_mergeclauses) != list_length(mergeclause_list))
 
258
                        continue;
 
259
 
 
260
                /*
 
261
                 * Build sort pathkeys for both sides.
 
262
                 *
 
263
                 * Note: it's possible that the cheapest paths will already be sorted
 
264
                 * properly.  create_mergejoin_path will detect that case and
 
265
                 * suppress an explicit sort step, so we needn't do so here.
 
266
                 */
 
267
                outerkeys = make_pathkeys_for_mergeclauses(root,
 
268
                                                                                                   cur_mergeclauses,
 
269
                                                                                                   outerrel);
 
270
                innerkeys = make_pathkeys_for_mergeclauses(root,
 
271
                                                                                                   cur_mergeclauses,
 
272
                                                                                                   innerrel);
 
273
                /* Build pathkeys representing output sort order. */
 
274
                merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
 
275
                                                                                         outerkeys);
 
276
 
 
277
                /*
 
278
                 * And now we can make the path.
 
279
                 */
 
280
                add_path(joinrel, (Path *)
 
281
                                 create_mergejoin_path(root,
 
282
                                                                           joinrel,
 
283
                                                                           jointype,
 
284
                                                                           outer_path,
 
285
                                                                           inner_path,
 
286
                                                                           restrictlist,
 
287
                                                                           merge_pathkeys,
 
288
                                                                           cur_mergeclauses,
 
289
                                                                           outerkeys,
 
290
                                                                           innerkeys));
 
291
        }
 
292
}
 
293
 
 
294
/*
 
295
 * match_unsorted_outer
 
296
 *        Creates possible join paths for processing a single join relation
 
297
 *        'joinrel' by employing either iterative substitution or
 
298
 *        mergejoining on each of its possible outer paths (considering
 
299
 *        only outer paths that are already ordered well enough for merging).
 
300
 *
 
301
 * We always generate a nestloop path for each available outer path.
 
302
 * In fact we may generate as many as four: one on the cheapest-total-cost
 
303
 * inner path, one on the same with materialization, one on the
 
304
 * cheapest-startup-cost inner path (if different),
 
305
 * and one on the best inner-indexscan path (if any).
 
306
 *
 
307
 * We also consider mergejoins if mergejoin clauses are available.      We have
 
308
 * two ways to generate the inner path for a mergejoin: sort the cheapest
 
309
 * inner path, or use an inner path that is already suitably ordered for the
 
310
 * merge.  If we have several mergeclauses, it could be that there is no inner
 
311
 * path (or only a very expensive one) for the full list of mergeclauses, but
 
312
 * better paths exist if we truncate the mergeclause list (thereby discarding
 
313
 * some sort key requirements).  So, we consider truncations of the
 
314
 * mergeclause list as well as the full list.  (Ideally we'd consider all
 
315
 * subsets of the mergeclause list, but that seems way too expensive.)
 
316
 *
 
317
 * 'joinrel' is the join relation
 
318
 * 'outerrel' is the outer join relation
 
319
 * 'innerrel' is the inner join relation
 
320
 * 'restrictlist' contains all of the RestrictInfo nodes for restriction
 
321
 *              clauses that apply to this join
 
322
 * 'mergeclause_list' is a list of RestrictInfo nodes for available
 
323
 *              mergejoin clauses in this join
 
324
 * 'jointype' is the type of join to do
 
325
 */
 
326
static void
 
327
match_unsorted_outer(Query *root,
 
328
                                         RelOptInfo *joinrel,
 
329
                                         RelOptInfo *outerrel,
 
330
                                         RelOptInfo *innerrel,
 
331
                                         List *restrictlist,
 
332
                                         List *mergeclause_list,
 
333
                                         JoinType jointype)
 
334
{
 
335
        JoinType        save_jointype = jointype;
 
336
        bool            nestjoinOK;
 
337
        bool            useallclauses;
 
338
        Path       *inner_cheapest_startup = innerrel->cheapest_startup_path;
 
339
        Path       *inner_cheapest_total = innerrel->cheapest_total_path;
 
340
        Path       *matpath = NULL;
 
341
        Path       *bestinnerjoin = NULL;
 
342
        ListCell   *l;
 
343
 
 
344
        /*
 
345
         * Nestloop only supports inner, left, and IN joins.  Also, if we are
 
346
         * doing a right or full join, we must use *all* the mergeclauses as
 
347
         * join clauses, else we will not have a valid plan.  (Although these
 
348
         * two flags are currently inverses, keep them separate for clarity
 
349
         * and possible future changes.)
 
350
         */
 
351
        switch (jointype)
 
352
        {
 
353
                case JOIN_INNER:
 
354
                case JOIN_LEFT:
 
355
                case JOIN_IN:
 
356
                case JOIN_UNIQUE_OUTER:
 
357
                case JOIN_UNIQUE_INNER:
 
358
                        nestjoinOK = true;
 
359
                        useallclauses = false;
 
360
                        break;
 
361
                case JOIN_RIGHT:
 
362
                case JOIN_FULL:
 
363
                        nestjoinOK = false;
 
364
                        useallclauses = true;
 
365
                        break;
 
366
                default:
 
367
                        elog(ERROR, "unrecognized join type: %d",
 
368
                                 (int) jointype);
 
369
                        nestjoinOK = false; /* keep compiler quiet */
 
370
                        useallclauses = false;
 
371
                        break;
 
372
        }
 
373
 
 
374
        /*
 
375
         * If we need to unique-ify the inner path, we will consider only the
 
376
         * cheapest inner.
 
377
         */
 
378
        if (jointype == JOIN_UNIQUE_INNER)
 
379
        {
 
380
                inner_cheapest_total = (Path *)
 
381
                        create_unique_path(root, innerrel, inner_cheapest_total);
 
382
                inner_cheapest_startup = inner_cheapest_total;
 
383
                jointype = JOIN_INNER;
 
384
        }
 
385
        else if (nestjoinOK)
 
386
        {
 
387
                /*
 
388
                 * If the cheapest inner path is a join or seqscan, we should
 
389
                 * consider materializing it.  (This is a heuristic: we could
 
390
                 * consider it always, but for inner indexscans it's probably a
 
391
                 * waste of time.)
 
392
                 */
 
393
                if (!(IsA(inner_cheapest_total, IndexPath) ||
 
394
                          IsA(inner_cheapest_total, TidPath)))
 
395
                        matpath = (Path *)
 
396
                                create_material_path(innerrel, inner_cheapest_total);
 
397
 
 
398
                /*
 
399
                 * Get the best innerjoin indexpath (if any) for this outer rel.
 
400
                 * It's the same for all outer paths.
 
401
                 */
 
402
                bestinnerjoin = best_inner_indexscan(root, innerrel,
 
403
                                                                                         outerrel->relids, jointype);
 
404
        }
 
405
 
 
406
        foreach(l, outerrel->pathlist)
 
407
        {
 
408
                Path       *outerpath = (Path *) lfirst(l);
 
409
                List       *merge_pathkeys;
 
410
                List       *mergeclauses;
 
411
                List       *innersortkeys;
 
412
                List       *trialsortkeys;
 
413
                Path       *cheapest_startup_inner;
 
414
                Path       *cheapest_total_inner;
 
415
                int                     num_sortkeys;
 
416
                int                     sortkeycnt;
 
417
 
 
418
                /*
 
419
                 * If we need to unique-ify the outer path, it's pointless to
 
420
                 * consider any but the cheapest outer.
 
421
                 */
 
422
                if (save_jointype == JOIN_UNIQUE_OUTER)
 
423
                {
 
424
                        if (outerpath != outerrel->cheapest_total_path)
 
425
                                continue;
 
426
                        outerpath = (Path *) create_unique_path(root, outerrel, outerpath);
 
427
                        jointype = JOIN_INNER;
 
428
                }
 
429
 
 
430
                /*
 
431
                 * The result will have this sort order (even if it is implemented
 
432
                 * as a nestloop, and even if some of the mergeclauses are
 
433
                 * implemented by qpquals rather than as true mergeclauses):
 
434
                 */
 
435
                merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
 
436
                                                                                         outerpath->pathkeys);
 
437
 
 
438
                if (nestjoinOK)
 
439
                {
 
440
                        /*
 
441
                         * Always consider a nestloop join with this outer and
 
442
                         * cheapest-total-cost inner.  When appropriate, also consider
 
443
                         * using the materialized form of the cheapest inner, the
 
444
                         * cheapest-startup-cost inner path, and the best innerjoin
 
445
                         * indexpath.
 
446
                         */
 
447
                        add_path(joinrel, (Path *)
 
448
                                         create_nestloop_path(root,
 
449
                                                                                  joinrel,
 
450
                                                                                  jointype,
 
451
                                                                                  outerpath,
 
452
                                                                                  inner_cheapest_total,
 
453
                                                                                  restrictlist,
 
454
                                                                                  merge_pathkeys));
 
455
                        if (matpath != NULL)
 
456
                                add_path(joinrel, (Path *)
 
457
                                                 create_nestloop_path(root,
 
458
                                                                                          joinrel,
 
459
                                                                                          jointype,
 
460
                                                                                          outerpath,
 
461
                                                                                          matpath,
 
462
                                                                                          restrictlist,
 
463
                                                                                          merge_pathkeys));
 
464
                        if (inner_cheapest_startup != inner_cheapest_total)
 
465
                                add_path(joinrel, (Path *)
 
466
                                                 create_nestloop_path(root,
 
467
                                                                                          joinrel,
 
468
                                                                                          jointype,
 
469
                                                                                          outerpath,
 
470
                                                                                          inner_cheapest_startup,
 
471
                                                                                          restrictlist,
 
472
                                                                                          merge_pathkeys));
 
473
                        if (bestinnerjoin != NULL)
 
474
                                add_path(joinrel, (Path *)
 
475
                                                 create_nestloop_path(root,
 
476
                                                                                          joinrel,
 
477
                                                                                          jointype,
 
478
                                                                                          outerpath,
 
479
                                                                                          bestinnerjoin,
 
480
                                                                                          restrictlist,
 
481
                                                                                          merge_pathkeys));
 
482
                }
 
483
 
 
484
                /* Can't do anything else if outer path needs to be unique'd */
 
485
                if (save_jointype == JOIN_UNIQUE_OUTER)
 
486
                        continue;
 
487
 
 
488
                /* Look for useful mergeclauses (if any) */
 
489
                mergeclauses = find_mergeclauses_for_pathkeys(root,
 
490
                                                                                                          outerpath->pathkeys,
 
491
                                                                                                          mergeclause_list);
 
492
 
 
493
                /*
 
494
                 * Done with this outer path if no chance for a mergejoin.
 
495
                 *
 
496
                 * Special corner case: for "x FULL JOIN y ON true", there will be no
 
497
                 * join clauses at all.  Ordinarily we'd generate a clauseless
 
498
                 * nestloop path, but since mergejoin is our only join type that
 
499
                 * supports FULL JOIN, it's necessary to generate a clauseless
 
500
                 * mergejoin path instead.
 
501
                 *
 
502
                 * Unfortunately this can't easily be extended to handle the case
 
503
                 * where there are joinclauses but none of them use mergejoinable
 
504
                 * operators; nodeMergejoin.c can only do a full join correctly if
 
505
                 * all the joinclauses are mergeclauses.
 
506
                 */
 
507
                if (mergeclauses == NIL)
 
508
                {
 
509
                        if (jointype == JOIN_FULL && restrictlist == NIL)
 
510
                                 /* okay to try for mergejoin */ ;
 
511
                        else
 
512
                                continue;
 
513
                }
 
514
                if (useallclauses && list_length(mergeclauses) != list_length(mergeclause_list))
 
515
                        continue;
 
516
 
 
517
                /* Compute the required ordering of the inner path */
 
518
                innersortkeys = make_pathkeys_for_mergeclauses(root,
 
519
                                                                                                           mergeclauses,
 
520
                                                                                                           innerrel);
 
521
 
 
522
                /*
 
523
                 * Generate a mergejoin on the basis of sorting the cheapest
 
524
                 * inner. Since a sort will be needed, only cheapest total cost
 
525
                 * matters.  (But create_mergejoin_path will do the right thing if
 
526
                 * inner_cheapest_total is already correctly sorted.)
 
527
                 */
 
528
                add_path(joinrel, (Path *)
 
529
                                 create_mergejoin_path(root,
 
530
                                                                           joinrel,
 
531
                                                                           jointype,
 
532
                                                                           outerpath,
 
533
                                                                           inner_cheapest_total,
 
534
                                                                           restrictlist,
 
535
                                                                           merge_pathkeys,
 
536
                                                                           mergeclauses,
 
537
                                                                           NIL,
 
538
                                                                           innersortkeys));
 
539
 
 
540
                /* Can't do anything else if inner path needs to be unique'd */
 
541
                if (save_jointype == JOIN_UNIQUE_INNER)
 
542
                        continue;
 
543
 
 
544
                /*
 
545
                 * Look for presorted inner paths that satisfy the innersortkey
 
546
                 * list --- or any truncation thereof, if we are allowed to build
 
547
                 * a mergejoin using a subset of the merge clauses.  Here, we
 
548
                 * consider both cheap startup cost and cheap total cost.  Ignore
 
549
                 * inner_cheapest_total, since we already made a path with it.
 
550
                 */
 
551
                num_sortkeys = list_length(innersortkeys);
 
552
                if (num_sortkeys > 1 && !useallclauses)
 
553
                        trialsortkeys = list_copy(innersortkeys);       /* need modifiable copy */
 
554
                else
 
555
                        trialsortkeys = innersortkeys;          /* won't really truncate */
 
556
                cheapest_startup_inner = NULL;
 
557
                cheapest_total_inner = NULL;
 
558
 
 
559
                for (sortkeycnt = num_sortkeys; sortkeycnt > 0; sortkeycnt--)
 
560
                {
 
561
                        Path       *innerpath;
 
562
                        List       *newclauses = NIL;
 
563
 
 
564
                        /*
 
565
                         * Look for an inner path ordered well enough for the first
 
566
                         * 'sortkeycnt' innersortkeys.  NB: trialsortkeys list is
 
567
                         * modified destructively, which is why we made a copy...
 
568
                         */
 
569
                        trialsortkeys = list_truncate(trialsortkeys, sortkeycnt);
 
570
                        innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist,
 
571
                                                                                                           trialsortkeys,
 
572
                                                                                                           TOTAL_COST);
 
573
                        if (innerpath != NULL &&
 
574
                                innerpath != inner_cheapest_total &&
 
575
                                (cheapest_total_inner == NULL ||
 
576
                                 compare_path_costs(innerpath, cheapest_total_inner,
 
577
                                                                        TOTAL_COST) < 0))
 
578
                        {
 
579
                                /* Found a cheap (or even-cheaper) sorted path */
 
580
                                /* Select the right mergeclauses, if we didn't already */
 
581
                                if (sortkeycnt < num_sortkeys)
 
582
                                {
 
583
                                        newclauses =
 
584
                                                find_mergeclauses_for_pathkeys(root,
 
585
                                                                                                           trialsortkeys,
 
586
                                                                                                           mergeclauses);
 
587
                                        Assert(newclauses != NIL);
 
588
                                }
 
589
                                else
 
590
                                        newclauses = mergeclauses;
 
591
                                add_path(joinrel, (Path *)
 
592
                                                 create_mergejoin_path(root,
 
593
                                                                                           joinrel,
 
594
                                                                                           jointype,
 
595
                                                                                           outerpath,
 
596
                                                                                           innerpath,
 
597
                                                                                           restrictlist,
 
598
                                                                                           merge_pathkeys,
 
599
                                                                                           newclauses,
 
600
                                                                                           NIL,
 
601
                                                                                           NIL));
 
602
                                cheapest_total_inner = innerpath;
 
603
                        }
 
604
                        /* Same on the basis of cheapest startup cost ... */
 
605
                        innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist,
 
606
                                                                                                           trialsortkeys,
 
607
                                                                                                           STARTUP_COST);
 
608
                        if (innerpath != NULL &&
 
609
                                innerpath != inner_cheapest_total &&
 
610
                                (cheapest_startup_inner == NULL ||
 
611
                                 compare_path_costs(innerpath, cheapest_startup_inner,
 
612
                                                                        STARTUP_COST) < 0))
 
613
                        {
 
614
                                /* Found a cheap (or even-cheaper) sorted path */
 
615
                                if (innerpath != cheapest_total_inner)
 
616
                                {
 
617
                                        /*
 
618
                                         * Avoid rebuilding clause list if we already made
 
619
                                         * one; saves memory in big join trees...
 
620
                                         */
 
621
                                        if (newclauses == NIL)
 
622
                                        {
 
623
                                                if (sortkeycnt < num_sortkeys)
 
624
                                                {
 
625
                                                        newclauses =
 
626
                                                                find_mergeclauses_for_pathkeys(root,
 
627
                                                                                                                   trialsortkeys,
 
628
                                                                                                                   mergeclauses);
 
629
                                                        Assert(newclauses != NIL);
 
630
                                                }
 
631
                                                else
 
632
                                                        newclauses = mergeclauses;
 
633
                                        }
 
634
                                        add_path(joinrel, (Path *)
 
635
                                                         create_mergejoin_path(root,
 
636
                                                                                                   joinrel,
 
637
                                                                                                   jointype,
 
638
                                                                                                   outerpath,
 
639
                                                                                                   innerpath,
 
640
                                                                                                   restrictlist,
 
641
                                                                                                   merge_pathkeys,
 
642
                                                                                                   newclauses,
 
643
                                                                                                   NIL,
 
644
                                                                                                   NIL));
 
645
                                }
 
646
                                cheapest_startup_inner = innerpath;
 
647
                        }
 
648
 
 
649
                        /*
 
650
                         * Don't consider truncated sortkeys if we need all clauses.
 
651
                         */
 
652
                        if (useallclauses)
 
653
                                break;
 
654
                }
 
655
        }
 
656
}
 
657
 
 
658
/*
 
659
 * hash_inner_and_outer
 
660
 *        Create hashjoin join paths by explicitly hashing both the outer and
 
661
 *        inner keys of each available hash clause.
 
662
 *
 
663
 * 'joinrel' is the join relation
 
664
 * 'outerrel' is the outer join relation
 
665
 * 'innerrel' is the inner join relation
 
666
 * 'restrictlist' contains all of the RestrictInfo nodes for restriction
 
667
 *              clauses that apply to this join
 
668
 * 'jointype' is the type of join to do
 
669
 */
 
670
static void
 
671
hash_inner_and_outer(Query *root,
 
672
                                         RelOptInfo *joinrel,
 
673
                                         RelOptInfo *outerrel,
 
674
                                         RelOptInfo *innerrel,
 
675
                                         List *restrictlist,
 
676
                                         JoinType jointype)
 
677
{
 
678
        bool            isouterjoin;
 
679
        List       *hashclauses;
 
680
        ListCell   *l;
 
681
 
 
682
        /*
 
683
         * Hashjoin only supports inner, left, and IN joins.
 
684
         */
 
685
        switch (jointype)
 
686
        {
 
687
                case JOIN_INNER:
 
688
                case JOIN_IN:
 
689
                case JOIN_UNIQUE_OUTER:
 
690
                case JOIN_UNIQUE_INNER:
 
691
                        isouterjoin = false;
 
692
                        break;
 
693
                case JOIN_LEFT:
 
694
                        isouterjoin = true;
 
695
                        break;
 
696
                default:
 
697
                        return;
 
698
        }
 
699
 
 
700
        /*
 
701
         * We need to build only one hashpath for any given pair of outer and
 
702
         * inner relations; all of the hashable clauses will be used as keys.
 
703
         *
 
704
         * Scan the join's restrictinfo list to find hashjoinable clauses that
 
705
         * are usable with this pair of sub-relations.
 
706
         */
 
707
        hashclauses = NIL;
 
708
        foreach(l, restrictlist)
 
709
        {
 
710
                RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
 
711
 
 
712
                if (!restrictinfo->can_join ||
 
713
                        restrictinfo->hashjoinoperator == InvalidOid)
 
714
                        continue;                       /* not hashjoinable */
 
715
 
 
716
                /*
 
717
                 * If processing an outer join, only use its own join clauses for
 
718
                 * hashing.  For inner joins we need not be so picky.
 
719
                 */
 
720
                if (isouterjoin && restrictinfo->is_pushed_down)
 
721
                        continue;
 
722
 
 
723
                /*
 
724
                 * Check if clause is usable with these input rels.
 
725
                 */
 
726
                if (bms_is_subset(restrictinfo->left_relids, outerrel->relids) &&
 
727
                        bms_is_subset(restrictinfo->right_relids, innerrel->relids))
 
728
                {
 
729
                        /* righthand side is inner */
 
730
                }
 
731
                else if (bms_is_subset(restrictinfo->left_relids, innerrel->relids) &&
 
732
                         bms_is_subset(restrictinfo->right_relids, outerrel->relids))
 
733
                {
 
734
                        /* lefthand side is inner */
 
735
                }
 
736
                else
 
737
                        continue;                       /* no good for these input relations */
 
738
 
 
739
                hashclauses = lappend(hashclauses, restrictinfo);
 
740
        }
 
741
 
 
742
        /* If we found any usable hashclauses, make a path */
 
743
        if (hashclauses)
 
744
        {
 
745
                /*
 
746
                 * We consider both the cheapest-total-cost and
 
747
                 * cheapest-startup-cost outer paths.  There's no need to consider
 
748
                 * any but the cheapest-total-cost inner path, however.
 
749
                 */
 
750
                Path       *cheapest_startup_outer = outerrel->cheapest_startup_path;
 
751
                Path       *cheapest_total_outer = outerrel->cheapest_total_path;
 
752
                Path       *cheapest_total_inner = innerrel->cheapest_total_path;
 
753
 
 
754
                /* Unique-ify if need be */
 
755
                if (jointype == JOIN_UNIQUE_OUTER)
 
756
                {
 
757
                        cheapest_total_outer = (Path *)
 
758
                                create_unique_path(root, outerrel, cheapest_total_outer);
 
759
                        cheapest_startup_outer = cheapest_total_outer;
 
760
                        jointype = JOIN_INNER;
 
761
                }
 
762
                else if (jointype == JOIN_UNIQUE_INNER)
 
763
                {
 
764
                        cheapest_total_inner = (Path *)
 
765
                                create_unique_path(root, innerrel, cheapest_total_inner);
 
766
                        jointype = JOIN_INNER;
 
767
                }
 
768
 
 
769
                add_path(joinrel, (Path *)
 
770
                                 create_hashjoin_path(root,
 
771
                                                                          joinrel,
 
772
                                                                          jointype,
 
773
                                                                          cheapest_total_outer,
 
774
                                                                          cheapest_total_inner,
 
775
                                                                          restrictlist,
 
776
                                                                          hashclauses));
 
777
                if (cheapest_startup_outer != cheapest_total_outer)
 
778
                        add_path(joinrel, (Path *)
 
779
                                         create_hashjoin_path(root,
 
780
                                                                                  joinrel,
 
781
                                                                                  jointype,
 
782
                                                                                  cheapest_startup_outer,
 
783
                                                                                  cheapest_total_inner,
 
784
                                                                                  restrictlist,
 
785
                                                                                  hashclauses));
 
786
        }
 
787
}
 
788
 
 
789
/*
 
790
 * select_mergejoin_clauses
 
791
 *        Select mergejoin clauses that are usable for a particular join.
 
792
 *        Returns a list of RestrictInfo nodes for those clauses.
 
793
 *
 
794
 * We examine each restrictinfo clause known for the join to see
 
795
 * if it is mergejoinable and involves vars from the two sub-relations
 
796
 * currently of interest.
 
797
 */
 
798
static List *
 
799
select_mergejoin_clauses(RelOptInfo *joinrel,
 
800
                                                 RelOptInfo *outerrel,
 
801
                                                 RelOptInfo *innerrel,
 
802
                                                 List *restrictlist,
 
803
                                                 JoinType jointype)
 
804
{
 
805
        List       *result_list = NIL;
 
806
        bool            isouterjoin = IS_OUTER_JOIN(jointype);
 
807
        ListCell   *l;
 
808
 
 
809
        foreach(l, restrictlist)
 
810
        {
 
811
                RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
 
812
 
 
813
                /*
 
814
                 * If processing an outer join, only use its own join clauses in
 
815
                 * the merge.  For inner joins we need not be so picky.
 
816
                 *
 
817
                 * Furthermore, if it is a right/full join then *all* the explicit
 
818
                 * join clauses must be mergejoinable, else the executor will
 
819
                 * fail. If we are asked for a right join then just return NIL to
 
820
                 * indicate no mergejoin is possible (we can handle it as a left
 
821
                 * join instead). If we are asked for a full join then emit an
 
822
                 * error, because there is no fallback.
 
823
                 */
 
824
                if (isouterjoin)
 
825
                {
 
826
                        if (restrictinfo->is_pushed_down)
 
827
                                continue;
 
828
                        switch (jointype)
 
829
                        {
 
830
                                case JOIN_RIGHT:
 
831
                                        if (!restrictinfo->can_join ||
 
832
                                                restrictinfo->mergejoinoperator == InvalidOid)
 
833
                                                return NIL;             /* not mergejoinable */
 
834
                                        break;
 
835
                                case JOIN_FULL:
 
836
                                        if (!restrictinfo->can_join ||
 
837
                                                restrictinfo->mergejoinoperator == InvalidOid)
 
838
                                                ereport(ERROR,
 
839
                                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
840
                                                                 errmsg("FULL JOIN is only supported with merge-joinable join conditions")));
 
841
                                        break;
 
842
                                default:
 
843
                                        /* otherwise, it's OK to have nonmergeable join quals */
 
844
                                        break;
 
845
                        }
 
846
                }
 
847
 
 
848
                if (!restrictinfo->can_join ||
 
849
                        restrictinfo->mergejoinoperator == InvalidOid)
 
850
                        continue;                       /* not mergejoinable */
 
851
 
 
852
                /*
 
853
                 * Check if clause is usable with these input rels.  All the vars
 
854
                 * needed on each side of the clause must be available from one or
 
855
                 * the other of the input rels.
 
856
                 */
 
857
                if (bms_is_subset(restrictinfo->left_relids, outerrel->relids) &&
 
858
                        bms_is_subset(restrictinfo->right_relids, innerrel->relids))
 
859
                {
 
860
                        /* righthand side is inner */
 
861
                }
 
862
                else if (bms_is_subset(restrictinfo->left_relids, innerrel->relids) &&
 
863
                         bms_is_subset(restrictinfo->right_relids, outerrel->relids))
 
864
                {
 
865
                        /* lefthand side is inner */
 
866
                }
 
867
                else
 
868
                        continue;                       /* no good for these input relations */
 
869
 
 
870
                result_list = lcons(restrictinfo, result_list);
 
871
        }
 
872
 
 
873
        return result_list;
 
874
}