OSDN Git Service

EXTENTIONではなく、SQL関数をもたないモジュールに変更
[pghintplan/pg_hint_plan.git] / pg_hint_plan.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_hint_plan.c
4  *              Track statement execution in current/last transaction.
5  *
6  * Copyright (c) 2011, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  *        contrib/pg_hint_plan/pg_hint_plan.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 #include "fmgr.h"
15 #include "nodes/print.h"
16 #include "utils/elog.h"
17 #include "utils/builtins.h"
18 #include "utils/memutils.h"
19 #include "optimizer/cost.h"
20 #include "optimizer/joininfo.h"
21 #include "optimizer/pathnode.h"
22 #include "optimizer/paths.h"
23
24 #ifdef PG_MODULE_MAGIC
25 PG_MODULE_MAGIC;
26 #endif
27
28 #define HASH_ENTRIES 201
29
30 enum
31 {
32         ENABLE_SEQSCAN          = 0x01,
33         ENABLE_INDEXSCAN        = 0x02,
34         ENABLE_BITMAPSCAN       = 0x04,
35         ENABLE_TIDSCAN          = 0x08,
36         ENABLE_NESTLOOP         = 0x10,
37         ENABLE_MERGEJOIN        = 0x20,
38         ENABLE_HASHJOIN         = 0x40
39 } TYPE_BITS;
40
41 typedef struct tidlist
42 {
43         int nrels;
44         Oid *oids;
45 } TidList;
46
47 typedef struct hash_entry
48 {
49         TidList tidlist;
50         unsigned char enforce_mask;
51         struct hash_entry *next;
52 } HashEntry;
53
54 static HashEntry *hashent[HASH_ENTRIES];
55 static bool print_log = false;
56
57 /* Module callbacks */
58 void            _PG_init(void);
59 void            _PG_fini(void);
60
61 /* Join Method Hints */
62 typedef struct RelIdInfo
63 {
64         Index           relid;
65         Oid                     oid;
66         Alias      *eref;
67 } RelIdInfo;
68
69 typedef struct JoinHint
70 {
71         int                             nrels;
72         List               *relidinfos;
73         Relids                  joinrelids;
74         unsigned char   enforce_mask;
75 } JoinHint;
76
77 typedef struct GucVariables
78 {
79         bool    enable_seqscan;
80         bool    enable_indexscan;
81         bool    enable_bitmapscan;
82         bool    enable_tidscan;
83         bool    enable_sort;
84         bool    enable_hashagg;
85         bool    enable_nestloop;
86         bool    enable_material;
87         bool    enable_mergejoin;
88         bool    enable_hashjoin;
89 } GucVariables;
90
91 static void backup_guc(GucVariables *backup);
92 static void restore_guc(GucVariables *backup);
93 static void set_guc(unsigned char enforce_mask);
94 static void build_join_hints(PlannerInfo *root, int level, List *initial_rels);
95 static RelOptInfo *my_make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2);
96 static RelOptInfo *my_join_search(PlannerInfo *root, int levels_needed,
97                                                           List *initial_rels);
98 static void my_join_search_one_level(PlannerInfo *root, int level);
99 static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel, ListCell *other_rels);
100 static void make_rels_by_clauseless_joins(PlannerInfo *root, RelOptInfo *old_rel, ListCell *other_rels);
101 static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
102
103 static join_search_hook_type org_join_search = NULL;
104 static List **join_hint_level = NULL;
105
106 /*
107  * Module load callbacks
108  */
109 void
110 _PG_init(void)
111 {
112         org_join_search = join_search_hook;
113         join_search_hook = my_join_search;
114 }
115
116 /*
117  * Module unload callback
118  */
119 void
120 _PG_fini(void)
121 {
122         join_search_hook = org_join_search;
123 }
124
125 /*
126  * pg_add_hint()で登録した個別のヒントを、使用しやすい構造に変換する。
127  */
128 static JoinHint *
129 set_relids(HashEntry *ent, RelIdInfo **relids, int nrels)
130 {
131         int                     i;
132         int                     j;
133         JoinHint   *hint;
134
135         hint = palloc(sizeof(JoinHint));
136         hint->joinrelids = NULL;
137         hint->relidinfos = NIL;
138
139         for (i = 0; i < ent->tidlist.nrels; i++)
140         {
141                 for (j = 0; j < nrels; j++)
142                 {
143                         if (ent->tidlist.oids[i] == relids[j]->oid)
144                         {
145                                 hint->relidinfos = lappend(hint->relidinfos, relids[j]);
146                                 hint->joinrelids =
147                                         bms_add_member(hint->joinrelids, relids[j]->relid);
148                                 break;
149                         }
150                 }
151
152                 if (j == nrels)
153                 {
154                         list_free(hint->relidinfos);
155                         pfree(hint);
156                         return NULL;
157                 }
158         }
159
160         hint->nrels = ent->tidlist.nrels;
161         hint->enforce_mask = ent->enforce_mask;
162
163         return hint;
164 }
165
166 /*
167  * pg_add_hint()で登録したヒントから、今回のクエリで使用するもののみ抽出し、
168  * 使用しやすい構造に変換する。
169  */
170 static void
171 build_join_hints(PlannerInfo *root, int level, List *initial_rels)
172 {
173         int                     i;
174         int                     nrels;
175         RelIdInfo **relids;
176         JoinHint   *hint;
177
178         relids = palloc(sizeof(RelIdInfo *) * root->simple_rel_array_size);
179
180         if (print_log)
181         {
182                 ListCell   *l;
183                 foreach(l, initial_rels)
184                 {
185                         RelOptInfo *rel = (RelOptInfo *) lfirst(l);
186                         elog_node_display(INFO, "initial_rels", rel, true);
187                 }
188                 elog_node_display(INFO, "root", root, true);
189                 elog(INFO, "%s(simple_rel_array_size:%d, level:%d, query_level:%d, parent_root:%p)",
190                         __func__, root->simple_rel_array_size, level, root->query_level, root->parent_root);
191         }
192
193         for (i = 0, nrels = 0; i < root->simple_rel_array_size; i++)
194         {
195                 if (root->simple_rel_array[i] == NULL)
196                         continue;
197
198                 relids[nrels] = palloc(sizeof(RelIdInfo));
199
200                 Assert(i == root->simple_rel_array[i]->relid);
201
202                 relids[nrels]->relid = i;
203                 relids[nrels]->oid = root->simple_rte_array[i]->relid;
204                 relids[nrels]->eref = root->simple_rte_array[i]->eref;
205                 //elog(INFO, "%d:%d:%d:%s", i, relids[nrels]->relid, relids[nrels]->oid, relids[nrels]->eref->aliasname);
206
207                 nrels++;
208         }
209
210         join_hint_level = palloc0(sizeof(List *) * (root->simple_rel_array_size));
211
212         for (i = 0; i < HASH_ENTRIES; i++)
213         {
214                 HashEntry *next;
215
216                 for (next = hashent[i]; next; next = next->next)
217                 {
218                         int     lv;
219                         if (!(next->enforce_mask & ENABLE_HASHJOIN) &&
220                                 !(next->enforce_mask & ENABLE_NESTLOOP) &&
221                                 !(next->enforce_mask & ENABLE_MERGEJOIN))
222                                 continue;
223
224                         if ((hint = set_relids(next, relids, nrels)) == NULL)
225                                 continue;
226
227                         lv = bms_num_members(hint->joinrelids);
228                         join_hint_level[lv] = lappend(join_hint_level[lv], hint);
229                 }
230         }
231 }
232
233 static void
234 backup_guc(GucVariables *backup)
235 {
236         backup->enable_seqscan = enable_seqscan;
237         backup->enable_indexscan = enable_indexscan;
238         backup->enable_bitmapscan = enable_bitmapscan;
239         backup->enable_tidscan = enable_tidscan;
240         backup->enable_sort = enable_sort;
241         backup->enable_hashagg = enable_hashagg;
242         backup->enable_nestloop = enable_nestloop;
243         backup->enable_material = enable_material;
244         backup->enable_mergejoin = enable_mergejoin;
245         backup->enable_hashjoin = enable_hashjoin;
246 }
247
248 static void
249 restore_guc(GucVariables *backup)
250 {
251         enable_seqscan = backup->enable_seqscan;
252         enable_indexscan = backup->enable_indexscan;
253         enable_bitmapscan = backup->enable_bitmapscan;
254         enable_tidscan = backup->enable_tidscan;
255         enable_sort = backup->enable_sort;
256         enable_hashagg = backup->enable_hashagg;
257         enable_nestloop = backup->enable_nestloop;
258         enable_material = backup->enable_material;
259         enable_mergejoin = backup->enable_mergejoin;
260         enable_hashjoin = backup->enable_hashjoin;
261 }
262
263 static void
264 set_guc(unsigned char enforce_mask)
265 {
266         enable_mergejoin = enforce_mask & ENABLE_MERGEJOIN ? true : false;
267         enable_hashjoin = enforce_mask & ENABLE_HASHJOIN ? true : false;
268         enable_nestloop = enforce_mask & ENABLE_NESTLOOP ? true : false;
269 }
270
271 /*
272  * relidビットマスクと一致するヒントを探す
273  */
274 static JoinHint *
275 find_join_hint(Relids joinrelids)
276 {
277         List       *join_hint;
278         ListCell   *l;
279
280         join_hint = join_hint_level[bms_num_members(joinrelids)];
281         foreach(l, join_hint)
282         {
283                 JoinHint   *hint = (JoinHint *) lfirst(l);
284                 if (bms_equal(joinrelids, hint->joinrelids))
285                         return hint;
286         }
287
288         return NULL;
289 }
290
291 /*
292  * src/backend/optimizer/path/joinrels.c
293  * export make_join_rel() をラップする関数
294  * 
295  * ヒントにしたがって、enabele_* パラメータを変更した上で、make_join_rel()を
296  * 呼び出す。
297  */
298 static RelOptInfo *
299 my_make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
300 {
301         GucVariables    guc;
302         Relids                  joinrelids;
303         JoinHint           *hint;
304         RelOptInfo         *rel;
305
306         joinrelids = bms_union(rel1->relids, rel2->relids);
307         hint = find_join_hint(joinrelids);
308         bms_free(joinrelids);
309
310         if (hint)
311         {
312                 backup_guc(&guc);
313                 set_guc(hint->enforce_mask);
314         }
315
316         rel = make_join_rel(root, rel1, rel2);
317
318         if (hint)
319                 restore_guc(&guc);
320
321         return rel;
322 }
323
324 /*
325  * PostgreSQL 本体から流用した関数
326  */
327
328 /*
329  * src/backend/optimizer/path/allpaths.c
330  * export standard_join_search() を流用
331  * 
332  * 変更箇所
333  *  build_join_hints() の呼び出しを追加
334  */
335 /*
336  * standard_join_search
337  *        Find possible joinpaths for a query by successively finding ways
338  *        to join component relations into join relations.
339  *
340  * 'levels_needed' is the number of iterations needed, ie, the number of
341  *              independent jointree items in the query.  This is > 1.
342  *
343  * 'initial_rels' is a list of RelOptInfo nodes for each independent
344  *              jointree item.  These are the components to be joined together.
345  *              Note that levels_needed == list_length(initial_rels).
346  *
347  * Returns the final level of join relations, i.e., the relation that is
348  * the result of joining all the original relations together.
349  * At least one implementation path must be provided for this relation and
350  * all required sub-relations.
351  *
352  * To support loadable plugins that modify planner behavior by changing the
353  * join searching algorithm, we provide a hook variable that lets a plugin
354  * replace or supplement this function.  Any such hook must return the same
355  * final join relation as the standard code would, but it might have a
356  * different set of implementation paths attached, and only the sub-joinrels
357  * needed for these paths need have been instantiated.
358  *
359  * Note to plugin authors: the functions invoked during standard_join_search()
360  * modify root->join_rel_list and root->join_rel_hash.  If you want to do more
361  * than one join-order search, you'll probably need to save and restore the
362  * original states of those data structures.  See geqo_eval() for an example.
363  */
364 static RelOptInfo *
365 my_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
366 {
367         int                     lev;
368         RelOptInfo *rel;
369
370         /*
371          * This function cannot be invoked recursively within any one planning
372          * problem, so join_rel_level[] can't be in use already.
373          */
374         Assert(root->join_rel_level == NULL);
375
376         /*
377          * We employ a simple "dynamic programming" algorithm: we first find all
378          * ways to build joins of two jointree items, then all ways to build joins
379          * of three items (from two-item joins and single items), then four-item
380          * joins, and so on until we have considered all ways to join all the
381          * items into one rel.
382          *
383          * root->join_rel_level[j] is a list of all the j-item rels.  Initially we
384          * set root->join_rel_level[1] to represent all the single-jointree-item
385          * relations.
386          */
387         root->join_rel_level = (List **) palloc0((levels_needed + 1) * sizeof(List *));
388
389         root->join_rel_level[1] = initial_rels;
390
391         build_join_hints(root, levels_needed, initial_rels);
392
393         for (lev = 2; lev <= levels_needed; lev++)
394         {
395                 ListCell   *lc;
396
397                 /*
398                  * Determine all possible pairs of relations to be joined at this
399                  * level, and build paths for making each one from every available
400                  * pair of lower-level relations.
401                  */
402                 my_join_search_one_level(root, lev);
403
404                 /*
405                  * Do cleanup work on each just-processed rel.
406                  */
407                 foreach(lc, root->join_rel_level[lev])
408                 {
409                         rel = (RelOptInfo *) lfirst(lc);
410
411                         /* Find and save the cheapest paths for this rel */
412                         set_cheapest(rel);
413
414 #ifdef OPTIMIZER_DEBUG
415                         debug_print_rel(root, rel);
416 #endif
417                 }
418         }
419
420         /*
421          * We should have a single rel at the final level.
422          */
423         if (root->join_rel_level[levels_needed] == NIL)
424                 elog(ERROR, "failed to build any %d-way joins", levels_needed);
425         Assert(list_length(root->join_rel_level[levels_needed]) == 1);
426
427         rel = (RelOptInfo *) linitial(root->join_rel_level[levels_needed]);
428
429         root->join_rel_level = NULL;
430
431         return rel;
432 }
433
434 /*
435  * src/backend/optimizer/path/joinrels.c
436  * static join_search_one_level() を流用
437  * 
438  * 変更箇所
439  *  make_join_rel() の呼び出しをラップする、my_make_join_rel()の呼び出しに変更
440  */
441 /*
442  * join_search_one_level
443  *        Consider ways to produce join relations containing exactly 'level'
444  *        jointree items.  (This is one step of the dynamic-programming method
445  *        embodied in standard_join_search.)  Join rel nodes for each feasible
446  *        combination of lower-level rels are created and returned in a list.
447  *        Implementation paths are created for each such joinrel, too.
448  *
449  * level: level of rels we want to make this time
450  * root->join_rel_level[j], 1 <= j < level, is a list of rels containing j items
451  *
452  * The result is returned in root->join_rel_level[level].
453  */
454 static void
455 my_join_search_one_level(PlannerInfo *root, int level)
456 {
457         List      **joinrels = root->join_rel_level;
458         ListCell   *r;
459         int                     k;
460
461         Assert(joinrels[level] == NIL);
462
463         /* Set join_cur_level so that new joinrels are added to proper list */
464         root->join_cur_level = level;
465
466         /*
467          * First, consider left-sided and right-sided plans, in which rels of
468          * exactly level-1 member relations are joined against initial relations.
469          * We prefer to join using join clauses, but if we find a rel of level-1
470          * members that has no join clauses, we will generate Cartesian-product
471          * joins against all initial rels not already contained in it.
472          *
473          * In the first pass (level == 2), we try to join each initial rel to each
474          * initial rel that appears later in joinrels[1].  (The mirror-image joins
475          * are handled automatically by make_join_rel.)  In later passes, we try
476          * to join rels of size level-1 from joinrels[level-1] to each initial rel
477          * in joinrels[1].
478          */
479         foreach(r, joinrels[level - 1])
480         {
481                 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
482                 ListCell   *other_rels;
483
484                 if (level == 2)
485                         other_rels = lnext(r);          /* only consider remaining initial
486                                                                                  * rels */
487                 else
488                         other_rels = list_head(joinrels[1]);            /* consider all initial
489                                                                                                                  * rels */
490
491                 if (old_rel->joininfo != NIL || old_rel->has_eclass_joins ||
492                         has_join_restriction(root, old_rel))
493                 {
494                         /*
495                          * Note that if all available join clauses for this rel require
496                          * more than one other rel, we will fail to make any joins against
497                          * it here.  In most cases that's OK; it'll be considered by
498                          * "bushy plan" join code in a higher-level pass where we have
499                          * those other rels collected into a join rel.
500                          *
501                          * See also the last-ditch case below.
502                          */
503                         make_rels_by_clause_joins(root,
504                                                                           old_rel,
505                                                                           other_rels);
506                 }
507                 else
508                 {
509                         /*
510                          * Oops, we have a relation that is not joined to any other
511                          * relation, either directly or by join-order restrictions.
512                          * Cartesian product time.
513                          */
514                         make_rels_by_clauseless_joins(root,
515                                                                                   old_rel,
516                                                                                   other_rels);
517                 }
518         }
519
520         /*
521          * Now, consider "bushy plans" in which relations of k initial rels are
522          * joined to relations of level-k initial rels, for 2 <= k <= level-2.
523          *
524          * We only consider bushy-plan joins for pairs of rels where there is a
525          * suitable join clause (or join order restriction), in order to avoid
526          * unreasonable growth of planning time.
527          */
528         for (k = 2;; k++)
529         {
530                 int                     other_level = level - k;
531
532                 /*
533                  * Since make_join_rel(x, y) handles both x,y and y,x cases, we only
534                  * need to go as far as the halfway point.
535                  */
536                 if (k > other_level)
537                         break;
538
539                 foreach(r, joinrels[k])
540                 {
541                         RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
542                         ListCell   *other_rels;
543                         ListCell   *r2;
544
545                         /*
546                          * We can ignore clauseless joins here, *except* when they
547                          * participate in join-order restrictions --- then we might have
548                          * to force a bushy join plan.
549                          */
550                         if (old_rel->joininfo == NIL && !old_rel->has_eclass_joins &&
551                                 !has_join_restriction(root, old_rel))
552                                 continue;
553
554                         if (k == other_level)
555                                 other_rels = lnext(r);  /* only consider remaining rels */
556                         else
557                                 other_rels = list_head(joinrels[other_level]);
558
559                         for_each_cell(r2, other_rels)
560                         {
561                                 RelOptInfo *new_rel = (RelOptInfo *) lfirst(r2);
562
563                                 if (!bms_overlap(old_rel->relids, new_rel->relids))
564                                 {
565                                         /*
566                                          * OK, we can build a rel of the right level from this
567                                          * pair of rels.  Do so if there is at least one usable
568                                          * join clause or a relevant join restriction.
569                                          */
570                                         if (have_relevant_joinclause(root, old_rel, new_rel) ||
571                                                 have_join_order_restriction(root, old_rel, new_rel))
572                                         {
573                                                 (void) my_make_join_rel(root, old_rel, new_rel);
574                                         }
575                                 }
576                         }
577                 }
578         }
579
580         /*
581          * Last-ditch effort: if we failed to find any usable joins so far, force
582          * a set of cartesian-product joins to be generated.  This handles the
583          * special case where all the available rels have join clauses but we
584          * cannot use any of those clauses yet.  An example is
585          *
586          * SELECT * FROM a,b,c WHERE (a.f1 + b.f2 + c.f3) = 0;
587          *
588          * The join clause will be usable at level 3, but at level 2 we have no
589          * choice but to make cartesian joins.  We consider only left-sided and
590          * right-sided cartesian joins in this case (no bushy).
591          */
592         if (joinrels[level] == NIL)
593         {
594                 /*
595                  * This loop is just like the first one, except we always call
596                  * make_rels_by_clauseless_joins().
597                  */
598                 foreach(r, joinrels[level - 1])
599                 {
600                         RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
601                         ListCell   *other_rels;
602
603                         if (level == 2)
604                                 other_rels = lnext(r);  /* only consider remaining initial
605                                                                                  * rels */
606                         else
607                                 other_rels = list_head(joinrels[1]);    /* consider all initial
608                                                                                                                  * rels */
609
610                         make_rels_by_clauseless_joins(root,
611                                                                                   old_rel,
612                                                                                   other_rels);
613                 }
614
615                 /*----------
616                  * When special joins are involved, there may be no legal way
617                  * to make an N-way join for some values of N.  For example consider
618                  *
619                  * SELECT ... FROM t1 WHERE
620                  *       x IN (SELECT ... FROM t2,t3 WHERE ...) AND
621                  *       y IN (SELECT ... FROM t4,t5 WHERE ...)
622                  *
623                  * We will flatten this query to a 5-way join problem, but there are
624                  * no 4-way joins that join_is_legal() will consider legal.  We have
625                  * to accept failure at level 4 and go on to discover a workable
626                  * bushy plan at level 5.
627                  *
628                  * However, if there are no special joins then join_is_legal() should
629                  * never fail, and so the following sanity check is useful.
630                  *----------
631                  */
632                 if (joinrels[level] == NIL && root->join_info_list == NIL)
633                         elog(ERROR, "failed to build any %d-way joins", level);
634         }
635 }
636
637 /*
638  * src/backend/optimizer/path/joinrels.c
639  * static make_rels_by_clause_joins() を流用
640  * 
641  * 変更箇所
642  *  make_join_rel() の呼び出しをラップする、my_make_join_rel()の呼び出しに変更
643  */
644 /*
645  * make_rels_by_clause_joins
646  *        Build joins between the given relation 'old_rel' and other relations
647  *        that participate in join clauses that 'old_rel' also participates in
648  *        (or participate in join-order restrictions with it).
649  *        The join rels are returned in root->join_rel_level[join_cur_level].
650  *
651  * Note: at levels above 2 we will generate the same joined relation in
652  * multiple ways --- for example (a join b) join c is the same RelOptInfo as
653  * (b join c) join a, though the second case will add a different set of Paths
654  * to it.  This is the reason for using the join_rel_level mechanism, which
655  * automatically ensures that each new joinrel is only added to the list once.
656  *
657  * 'old_rel' is the relation entry for the relation to be joined
658  * 'other_rels': the first cell in a linked list containing the other
659  * rels to be considered for joining
660  *
661  * Currently, this is only used with initial rels in other_rels, but it
662  * will work for joining to joinrels too.
663  */
664 static void
665 make_rels_by_clause_joins(PlannerInfo *root,
666                                                   RelOptInfo *old_rel,
667                                                   ListCell *other_rels)
668 {
669         ListCell   *l;
670
671         for_each_cell(l, other_rels)
672         {
673                 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
674
675                 if (!bms_overlap(old_rel->relids, other_rel->relids) &&
676                         (have_relevant_joinclause(root, old_rel, other_rel) ||
677                          have_join_order_restriction(root, old_rel, other_rel)))
678                 {
679                         (void) my_make_join_rel(root, old_rel, other_rel);
680                 }
681         }
682 }
683
684 /*
685  * src/backend/optimizer/path/joinrels.c
686  * static make_rels_by_clauseless_joins() を流用
687  * 
688  * 変更箇所
689  *  make_join_rel() の呼び出しをラップする、my_make_join_rel()の呼び出しに変更
690  */
691 /*
692  * make_rels_by_clauseless_joins
693  *        Given a relation 'old_rel' and a list of other relations
694  *        'other_rels', create a join relation between 'old_rel' and each
695  *        member of 'other_rels' that isn't already included in 'old_rel'.
696  *        The join rels are returned in root->join_rel_level[join_cur_level].
697  *
698  * 'old_rel' is the relation entry for the relation to be joined
699  * 'other_rels': the first cell of a linked list containing the
700  * other rels to be considered for joining
701  *
702  * Currently, this is only used with initial rels in other_rels, but it would
703  * work for joining to joinrels too.
704  */
705 static void
706 make_rels_by_clauseless_joins(PlannerInfo *root,
707                                                           RelOptInfo *old_rel,
708                                                           ListCell *other_rels)
709 {
710         ListCell   *l;
711
712         for_each_cell(l, other_rels)
713         {
714                 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
715
716                 if (!bms_overlap(other_rel->relids, old_rel->relids))
717                 {
718                         (void) my_make_join_rel(root, old_rel, other_rel);
719                 }
720         }
721 }
722
723 /*
724  * src/backend/optimizer/path/joinrels.c
725  * static has_join_restriction() を流用
726  * 
727  * 変更箇所
728  *  なし
729  */
730 /*
731  * has_join_restriction
732  *              Detect whether the specified relation has join-order restrictions
733  *              due to being inside an outer join or an IN (sub-SELECT).
734  *
735  * Essentially, this tests whether have_join_order_restriction() could
736  * succeed with this rel and some other one.  It's OK if we sometimes
737  * say "true" incorrectly.      (Therefore, we don't bother with the relatively
738  * expensive has_legal_joinclause test.)
739  */
740 static bool
741 has_join_restriction(PlannerInfo *root, RelOptInfo *rel)
742 {
743         ListCell   *l;
744
745         foreach(l, root->join_info_list)
746         {
747                 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
748
749                 /* ignore full joins --- other mechanisms preserve their ordering */
750                 if (sjinfo->jointype == JOIN_FULL)
751                         continue;
752
753                 /* ignore if SJ is already contained in rel */
754                 if (bms_is_subset(sjinfo->min_lefthand, rel->relids) &&
755                         bms_is_subset(sjinfo->min_righthand, rel->relids))
756                         continue;
757
758                 /* restricted if it overlaps LHS or RHS, but doesn't contain SJ */
759                 if (bms_overlap(sjinfo->min_lefthand, rel->relids) ||
760                         bms_overlap(sjinfo->min_righthand, rel->relids))
761                         return true;
762         }
763
764         return false;
765 }