1 /*-------------------------------------------------------------------------
4 * Track statement execution in current/last transaction.
6 * Copyright (c) 2011, PostgreSQL Global Development Group
9 * contrib/pg_hint_plan/pg_hint_plan.c
11 *-------------------------------------------------------------------------
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"
24 #ifdef PG_MODULE_MAGIC
28 #define HASH_ENTRIES 201
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
41 typedef struct tidlist
47 typedef struct hash_entry
50 unsigned char enforce_mask;
51 struct hash_entry *next;
54 static HashEntry *hashent[HASH_ENTRIES];
56 static bool (*org_cost_hook)(CostHookType type, PlannerInfo *root, Path *path1, Path *path2);
58 static bool print_log = false;
59 static bool tweak_enabled = true;
61 /* Module callbacks */
64 Datum pg_add_hint(PG_FUNCTION_ARGS);
65 Datum pg_clear_hint(PG_FUNCTION_ARGS);
66 Datum pg_dump_hint(PG_FUNCTION_ARGS);
67 Datum pg_enable_hint(bool arg, bool *isnull);
68 Datum pg_enable_log(bool arg, bool *isnull);
71 static char *rels_str(PlannerInfo *root, Path *path);
72 static void dump_rels(char *label, PlannerInfo *root, Path *path, bool found, bool enabled);
73 static void dump_joinrels(char *label, PlannerInfo *root, Path *inpath, Path *outpath, bool found, bool enabled);
74 static bool my_cost_hook(CostHookType type, PlannerInfo *root, Path *path1, Path *path2);
76 static void free_hashent(HashEntry *head);
77 static unsigned int calc_hash(TidList *tidlist);
79 static HashEntry *search_ent(TidList *tidlist);
82 /* Join Method Hints */
83 typedef struct RelIdInfo
90 typedef struct JoinHint
95 unsigned char enforce_mask;
98 typedef struct GucVariables
101 bool enable_indexscan;
102 bool enable_bitmapscan;
106 bool enable_nestloop;
107 bool enable_material;
108 bool enable_mergejoin;
109 bool enable_hashjoin;
112 static void backup_guc(GucVariables *backup);
113 static void restore_guc(GucVariables *backup);
114 static void set_guc(unsigned char enforce_mask);
115 static void build_join_hints(PlannerInfo *root, int level, List *initial_rels);
116 static RelOptInfo *my_make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2);
117 static RelOptInfo *my_join_search(PlannerInfo *root, int levels_needed,
119 static void my_join_search_one_level(PlannerInfo *root, int level);
120 static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel, ListCell *other_rels);
121 static void make_rels_by_clauseless_joins(PlannerInfo *root, RelOptInfo *old_rel, ListCell *other_rels);
122 static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
124 static join_search_hook_type org_join_search = NULL;
125 static List **join_hint_level = NULL;
127 PG_FUNCTION_INFO_V1(pg_add_hint);
128 PG_FUNCTION_INFO_V1(pg_clear_hint);
131 * Module load callbacks
139 org_cost_hook = cost_hook;
140 cost_hook = my_cost_hook;
142 org_join_search = join_search_hook;
143 join_search_hook = my_join_search;
145 for (i = 0 ; i < HASH_ENTRIES ; i++)
150 * Module unload callback
158 cost_hook = org_cost_hook;
160 join_search_hook = org_join_search;
162 for (i = 0 ; i < HASH_ENTRIES ; i++)
164 free_hashent(hashent[i]);
171 char *rels_str(PlannerInfo *root, Path *path)
178 if (path->pathtype == T_Invalid) return strdup("");
180 tmpbms = bms_copy(path->parent->relids);
183 while ((relid = bms_first_member(tmpbms)) >= 0)
186 snprintf(idbuf, sizeof(idbuf), first ? "%d" : ", %d",
187 root->simple_rte_array[relid]->relid);
188 if (strlen(buf) + strlen(idbuf) < sizeof(buf))
197 static int oidsortcmp(const void *a, const void *b)
199 const Oid oida = *((const Oid *)a);
200 const Oid oidb = *((const Oid *)b);
206 static TidList *maketidlist(PlannerInfo *root, Path *path1, Path *path2)
209 Path *paths[2] = {path1, path2};
213 TidList *ret = (TidList *)malloc(sizeof(TidList));
215 for (i = 0 ; i < 2 ; i++)
217 if (paths[i] != NULL)
218 nrels += bms_num_members(paths[i]->parent->relids);
222 ret->oids = (Oid *)malloc(nrels * sizeof(Oid));
224 for (i = 0 ; i < 2 ; i++)
228 if (paths[i] == NULL) continue;
230 tmpbms= bms_copy(paths[i]->parent->relids);
232 while ((relid = bms_first_member(tmpbms)) >= 0)
233 ret->oids[j++] = root->simple_rte_array[relid]->relid;
237 qsort(ret->oids, nrels, sizeof(Oid), oidsortcmp);
242 static void free_tidlist(TidList *tidlist)
253 static void dump_rels(char *label, PlannerInfo *root, Path *path, bool found, bool enabled)
257 if (!print_log) return;
258 relsstr = rels_str(root, path);
259 ereport(INFO, (errmsg_internal("SCAN: %04d: %s for relation %s (%s, %s)\n",
261 found ? "found" : "not found",
262 enabled ? "enabled" : "disabled")));
267 void dump_joinrels(char *label, PlannerInfo *root, Path *inpath, Path *outpath,
268 bool found, bool enabled)
270 char *irelstr, *orelstr;
272 if (!print_log) return;
273 irelstr = rels_str(root, inpath);
274 orelstr = rels_str(root, outpath);
276 ereport(INFO, (errmsg_internal("JOIN: %04d: %s for relation ((%s),(%s)) (%s, %s)\n",
277 J++, label, irelstr, orelstr,
278 found ? "found" : "not found",
279 enabled ? "enabled" : "disabled")));
285 bool my_cost_hook(CostHookType type, PlannerInfo *root, Path *path1, Path *path2)
295 case COSTHOOK_seqscan:
296 return enable_seqscan;
297 case COSTHOOK_indexscan:
298 return enable_indexscan;
299 case COSTHOOK_bitmapscan:
300 return enable_bitmapscan;
301 case COSTHOOK_tidscan:
302 return enable_tidscan;
303 case COSTHOOK_nestloop:
304 return enable_nestloop;
305 case COSTHOOK_mergejoin:
306 return enable_mergejoin;
307 case COSTHOOK_hashjoin:
308 return enable_hashjoin;
310 ereport(LOG, (errmsg_internal("Unknown cost type")));
316 case COSTHOOK_seqscan:
317 tidlist = maketidlist(root, path1, path2);
318 ent = search_ent(tidlist);
319 free_tidlist(tidlist);
320 ret = (ent ? (ent->enforce_mask & ENABLE_SEQSCAN) :
322 dump_rels("cost_seqscan", root, path1, ent != NULL, ret);
324 case COSTHOOK_indexscan:
325 tidlist = maketidlist(root, path1, path2);
326 ent = search_ent(tidlist);
327 free_tidlist(tidlist);
328 ret = (ent ? (ent->enforce_mask & ENABLE_INDEXSCAN) :
330 dump_rels("cost_indexscan", root, path1, ent != NULL, ret);
332 case COSTHOOK_bitmapscan:
333 if (path1->pathtype != T_BitmapHeapScan)
336 ret = enable_bitmapscan;
340 tidlist = maketidlist(root, path1, path2);
341 ent = search_ent(tidlist);
342 free_tidlist(tidlist);
343 ret = (ent ? (ent->enforce_mask & ENABLE_BITMAPSCAN) :
346 dump_rels("cost_bitmapscan", root, path1, ent != NULL, ret);
349 case COSTHOOK_tidscan:
350 tidlist = maketidlist(root, path1, path2);
351 ent = search_ent(tidlist);
352 free_tidlist(tidlist);
353 ret = (ent ? (ent->enforce_mask & ENABLE_TIDSCAN) :
355 dump_rels("cost_tidscan", root, path1, ent != NULL, ret);
357 case COSTHOOK_nestloop:
358 tidlist = maketidlist(root, path1, path2);
359 ent = search_ent(tidlist);
360 free_tidlist(tidlist);
361 ret = (ent ? (ent->enforce_mask & ENABLE_NESTLOOP) :
363 dump_joinrels("cost_nestloop", root, path1, path2,
366 case COSTHOOK_mergejoin:
367 tidlist = maketidlist(root, path1, path2);
368 ent = search_ent(tidlist);
369 free_tidlist(tidlist);
370 ret = (ent ? (ent->enforce_mask & ENABLE_MERGEJOIN) :
372 dump_joinrels("cost_mergejoin", root, path1, path2,
375 case COSTHOOK_hashjoin:
376 tidlist = maketidlist(root, path1, path2);
377 ent = search_ent(tidlist);
378 free_tidlist(tidlist);
379 ret = (ent ? (ent->enforce_mask & ENABLE_HASHJOIN) :
381 dump_joinrels("cost_hashjoin", root, path1, path2,
385 ereport(LOG, (errmsg_internal("Unknown cost type")));
393 static void free_hashent(HashEntry *head)
395 HashEntry *next = head;
399 HashEntry *last = next;
400 if (next->tidlist.oids != NULL) free(next->tidlist.oids);
406 static HashEntry *parse_tidlist(char **str)
410 Oid tid[20]; /* ^^; */
415 while (isdigit(**str) && ntids < 20)
418 while (isdigit(**str)) (*str)++;
420 if (len >= 8) return NULL;
421 strncpy(tidstr, p0, len);
424 /* Tis 0 is valid? I don't know :-p */
425 if ((tid[ntids++] = atoi(tidstr)) == 0) return NULL;
427 if (**str == ',') (*str)++;
431 qsort(tid, ntids, sizeof(Oid), oidsortcmp);
432 ret = (HashEntry*)malloc(sizeof(HashEntry));
434 ret->enforce_mask = 0;
435 ret->tidlist.nrels = ntids;
436 ret->tidlist.oids = (Oid *)malloc(ntids * sizeof(Oid));
437 for (i = 0 ; i < ntids ; i++)
438 ret->tidlist.oids[i] = tid[i];
442 static int parse_phrase(HashEntry **head, char **str)
444 char *cmds[] = {"seq", "index", "nest", "merge", "hash", NULL};
445 unsigned char masks[] = {ENABLE_SEQSCAN, ENABLE_INDEXSCAN|ENABLE_BITMAPSCAN,
446 ENABLE_NESTLOOP, ENABLE_MERGEJOIN, ENABLE_HASHJOIN};
449 HashEntry *ent = NULL;
452 bool not_use = false;
455 while (isalpha(**str) || **str == '_') (*str)++;
457 if (**str != '(' || len >= 12) return 0;
458 strncpy(req, p0, len);
460 if (strncmp("no_", req, 3) == 0)
463 memmove(req, req + 3, len - 3 + 1);
465 for (cmd = 0 ; cmds[cmd] && strcmp(cmds[cmd], req) ; cmd++);
466 if (cmds[cmd] == NULL) return 0;
468 if ((ent = parse_tidlist(str)) == NULL) return 0;
469 if (*(*str)++ != ')') return 0;
470 if (**str != 0 && **str != ';') return 0;
471 if (**str == ';') (*str)++;
472 ent->enforce_mask = not_use ? ~masks[cmd] : masks[cmd];
480 static HashEntry* parse_top(char* str)
482 HashEntry *head = NULL;
483 HashEntry *ent = NULL;
485 if (!parse_phrase(&head, &str))
494 if (!parse_phrase(&ent->next, &str))
505 static bool ent_matches(TidList *key, HashEntry *ent2)
509 if (key->nrels != ent2->tidlist.nrels)
512 for (i = 0 ; i < key->nrels ; i++)
513 if (key->oids[i] != ent2->tidlist.oids[i])
519 static unsigned int calc_hash(TidList *tidlist)
521 unsigned int hash = 0;
524 for (i = 0 ; i < tidlist->nrels ; i++)
527 for (j = 0 ; j < sizeof(Oid) ; j++)
528 hash = hash * 2 + ((tidlist->oids[i] >> (j * 8)) & 0xff);
531 return hash % HASH_ENTRIES;
536 static HashEntry *search_ent(TidList *tidlist)
539 if (tidlist == NULL) return NULL;
541 ent = hashent[calc_hash(tidlist)];
544 if (ent_matches(tidlist, ent))
554 pg_add_hint(PG_FUNCTION_ARGS)
556 HashEntry *ret = NULL;
561 ereport(ERROR, (errmsg_internal("No argument")));
563 str = text_to_cstring(PG_GETARG_TEXT_PP(0));
565 ret = parse_top(str);
568 ereport(ERROR, (errmsg_internal("Parse Error")));
572 HashEntry *etmp = NULL;
573 HashEntry *next = NULL;
574 int hash = calc_hash(&ret->tidlist);
575 while (hashent[hash] && ent_matches(&ret->tidlist, hashent[hash]))
577 etmp = hashent[hash]->next;
578 hashent[hash]->next = NULL;
579 free_hashent(hashent[hash]);
580 hashent[hash] = etmp;
583 etmp = hashent[hash];
584 while (etmp && etmp->next)
586 if (ent_matches(&ret->tidlist, etmp->next))
588 HashEntry *etmp2 = etmp->next->next;
589 etmp->next->next = NULL;
590 free_hashent(etmp->next);
598 ret->next = hashent[hash];
606 pg_clear_hint(PG_FUNCTION_ARGS)
611 for (i = 0 ; i < HASH_ENTRIES ; i++)
613 free_hashent(hashent[i]);
622 pg_enable_hint(bool arg, bool *isnull)
629 pg_enable_log(bool arg, bool *isnull)
635 static int putsbuf(char **p, char *bottom, char *str)
637 while (*p < bottom && *str)
645 static void dump_ent(HashEntry *ent, char **p, char *bottom)
647 static char typesigs[] = "SIBTNMH";
648 char sigs[sizeof(typesigs)];
651 if (!putsbuf(p, bottom, "[(")) return;
652 for (i = 0 ; i < ent->tidlist.nrels ; i++)
654 if (i && !putsbuf(p, bottom, ", ")) return;
655 if (*p >= bottom) return;
656 *p += snprintf(*p, bottom - *p, "%d", ent->tidlist.oids[i]);
658 if (!putsbuf(p, bottom, "), ")) return;
659 strcpy(sigs, typesigs);
660 for (i = 0 ; i < 7 ; i++) /* Magic number here! */
662 if(((1<<i) & ent->enforce_mask) == 0)
663 sigs[i] += 'a' - 'A';
665 if (!putsbuf(p, bottom, sigs)) return;
666 if (!putsbuf(p, bottom, "]")) return;
670 pg_dump_hint(PG_FUNCTION_ARGS)
672 char buf[16384]; /* ^^; */
673 char *bottom = buf + sizeof(buf);
678 memset(buf, 0, sizeof(buf));
679 for (i = 0 ; i < HASH_ENTRIES ; i++)
683 HashEntry *ent = hashent[i];
689 putsbuf(&p, bottom, ", ");
691 dump_ent(ent, &p, bottom);
696 if (p >= bottom) p--;
699 PG_RETURN_CSTRING(cstring_to_text(buf));
703 * pg_add_hint()で登録した個別のヒントを、使用しやすい構造に変換する。
706 set_relids(HashEntry *ent, RelIdInfo **relids, int nrels)
712 hint = palloc(sizeof(JoinHint));
713 hint->joinrelids = NULL;
714 hint->relidinfos = NIL;
716 for (i = 0; i < ent->tidlist.nrels; i++)
718 for (j = 0; j < nrels; j++)
720 if (ent->tidlist.oids[i] == relids[j]->oid)
722 hint->relidinfos = lappend(hint->relidinfos, relids[j]);
724 bms_add_member(hint->joinrelids, relids[j]->relid);
731 list_free(hint->relidinfos);
737 hint->nrels = ent->tidlist.nrels;
738 hint->enforce_mask = ent->enforce_mask;
744 * pg_add_hint()で登録したヒントから、今回のクエリで使用するもののみ抽出し、
748 build_join_hints(PlannerInfo *root, int level, List *initial_rels)
755 relids = palloc(sizeof(RelIdInfo *) * root->simple_rel_array_size);
761 foreach(l, initial_rels)
763 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
764 elog_node_display(INFO, "initial_rels", rel, true);
766 elog_node_display(INFO, "root", root, true);
767 elog(INFO, "%s(simple_rel_array_size:%d, level:%d, query_level:%d, parent_root:%p)",
768 __func__, root->simple_rel_array_size, level, root->query_level, root->parent_root);
771 for (i = 0, nrels = 0; i < root->simple_rel_array_size; i++)
773 if (root->simple_rel_array[i] == NULL)
776 relids[nrels] = palloc(sizeof(RelIdInfo));
778 Assert(i == root->simple_rel_array[i]->relid);
780 relids[nrels]->relid = i;
781 relids[nrels]->oid = root->simple_rte_array[i]->relid;
782 relids[nrels]->eref = root->simple_rte_array[i]->eref;
783 //elog(INFO, "%d:%d:%d:%s", i, relids[nrels]->relid, relids[nrels]->oid, relids[nrels]->eref->aliasname);
788 join_hint_level = palloc0(sizeof(List *) * (root->simple_rel_array_size));
790 for (i = 0; i < HASH_ENTRIES; i++)
794 for (next = hashent[i]; next; next = next->next)
797 if (!(next->enforce_mask & ENABLE_HASHJOIN) &&
798 !(next->enforce_mask & ENABLE_NESTLOOP) &&
799 !(next->enforce_mask & ENABLE_MERGEJOIN))
802 if ((hint = set_relids(next, relids, nrels)) == NULL)
805 lv = bms_num_members(hint->joinrelids);
806 join_hint_level[lv] = lappend(join_hint_level[lv], hint);
812 backup_guc(GucVariables *backup)
814 backup->enable_seqscan = enable_seqscan;
815 backup->enable_indexscan = enable_indexscan;
816 backup->enable_bitmapscan = enable_bitmapscan;
817 backup->enable_tidscan = enable_tidscan;
818 backup->enable_sort = enable_sort;
819 backup->enable_hashagg = enable_hashagg;
820 backup->enable_nestloop = enable_nestloop;
821 backup->enable_material = enable_material;
822 backup->enable_mergejoin = enable_mergejoin;
823 backup->enable_hashjoin = enable_hashjoin;
827 restore_guc(GucVariables *backup)
829 enable_seqscan = backup->enable_seqscan;
830 enable_indexscan = backup->enable_indexscan;
831 enable_bitmapscan = backup->enable_bitmapscan;
832 enable_tidscan = backup->enable_tidscan;
833 enable_sort = backup->enable_sort;
834 enable_hashagg = backup->enable_hashagg;
835 enable_nestloop = backup->enable_nestloop;
836 enable_material = backup->enable_material;
837 enable_mergejoin = backup->enable_mergejoin;
838 enable_hashjoin = backup->enable_hashjoin;
842 set_guc(unsigned char enforce_mask)
844 enable_mergejoin = enforce_mask & ENABLE_MERGEJOIN ? true : false;
845 enable_hashjoin = enforce_mask & ENABLE_HASHJOIN ? true : false;
846 enable_nestloop = enforce_mask & ENABLE_NESTLOOP ? true : false;
850 * relidビットマスクと一致するヒントを探す
853 find_join_hint(Relids joinrelids)
858 join_hint = join_hint_level[bms_num_members(joinrelids)];
859 foreach(l, join_hint)
861 JoinHint *hint = (JoinHint *) lfirst(l);
862 if (bms_equal(joinrelids, hint->joinrelids))
870 * src/backend/optimizer/path/joinrels.c
871 * export make_join_rel() をラップする関数
873 * ヒントにしたがって、enabele_* パラメータを変更した上で、make_join_rel()を
877 my_make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
884 joinrelids = bms_union(rel1->relids, rel2->relids);
885 hint = find_join_hint(joinrelids);
886 bms_free(joinrelids);
891 set_guc(hint->enforce_mask);
894 rel = make_join_rel(root, rel1, rel2);
903 * PostgreSQL 本体から流用した関数
907 * src/backend/optimizer/path/allpaths.c
908 * export standard_join_search() を流用
911 * build_join_hints() の呼び出しを追加
914 * standard_join_search
915 * Find possible joinpaths for a query by successively finding ways
916 * to join component relations into join relations.
918 * 'levels_needed' is the number of iterations needed, ie, the number of
919 * independent jointree items in the query. This is > 1.
921 * 'initial_rels' is a list of RelOptInfo nodes for each independent
922 * jointree item. These are the components to be joined together.
923 * Note that levels_needed == list_length(initial_rels).
925 * Returns the final level of join relations, i.e., the relation that is
926 * the result of joining all the original relations together.
927 * At least one implementation path must be provided for this relation and
928 * all required sub-relations.
930 * To support loadable plugins that modify planner behavior by changing the
931 * join searching algorithm, we provide a hook variable that lets a plugin
932 * replace or supplement this function. Any such hook must return the same
933 * final join relation as the standard code would, but it might have a
934 * different set of implementation paths attached, and only the sub-joinrels
935 * needed for these paths need have been instantiated.
937 * Note to plugin authors: the functions invoked during standard_join_search()
938 * modify root->join_rel_list and root->join_rel_hash. If you want to do more
939 * than one join-order search, you'll probably need to save and restore the
940 * original states of those data structures. See geqo_eval() for an example.
943 my_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
949 * This function cannot be invoked recursively within any one planning
950 * problem, so join_rel_level[] can't be in use already.
952 Assert(root->join_rel_level == NULL);
955 * We employ a simple "dynamic programming" algorithm: we first find all
956 * ways to build joins of two jointree items, then all ways to build joins
957 * of three items (from two-item joins and single items), then four-item
958 * joins, and so on until we have considered all ways to join all the
959 * items into one rel.
961 * root->join_rel_level[j] is a list of all the j-item rels. Initially we
962 * set root->join_rel_level[1] to represent all the single-jointree-item
965 root->join_rel_level = (List **) palloc0((levels_needed + 1) * sizeof(List *));
967 root->join_rel_level[1] = initial_rels;
969 build_join_hints(root, levels_needed, initial_rels);
971 for (lev = 2; lev <= levels_needed; lev++)
976 * Determine all possible pairs of relations to be joined at this
977 * level, and build paths for making each one from every available
978 * pair of lower-level relations.
980 my_join_search_one_level(root, lev);
983 * Do cleanup work on each just-processed rel.
985 foreach(lc, root->join_rel_level[lev])
987 rel = (RelOptInfo *) lfirst(lc);
989 /* Find and save the cheapest paths for this rel */
992 #ifdef OPTIMIZER_DEBUG
993 debug_print_rel(root, rel);
999 * We should have a single rel at the final level.
1001 if (root->join_rel_level[levels_needed] == NIL)
1002 elog(ERROR, "failed to build any %d-way joins", levels_needed);
1003 Assert(list_length(root->join_rel_level[levels_needed]) == 1);
1005 rel = (RelOptInfo *) linitial(root->join_rel_level[levels_needed]);
1007 root->join_rel_level = NULL;
1013 * src/backend/optimizer/path/joinrels.c
1014 * static join_search_one_level() を流用
1017 * make_join_rel() の呼び出しをラップする、my_make_join_rel()の呼び出しに変更
1020 * join_search_one_level
1021 * Consider ways to produce join relations containing exactly 'level'
1022 * jointree items. (This is one step of the dynamic-programming method
1023 * embodied in standard_join_search.) Join rel nodes for each feasible
1024 * combination of lower-level rels are created and returned in a list.
1025 * Implementation paths are created for each such joinrel, too.
1027 * level: level of rels we want to make this time
1028 * root->join_rel_level[j], 1 <= j < level, is a list of rels containing j items
1030 * The result is returned in root->join_rel_level[level].
1033 my_join_search_one_level(PlannerInfo *root, int level)
1035 List **joinrels = root->join_rel_level;
1039 Assert(joinrels[level] == NIL);
1041 /* Set join_cur_level so that new joinrels are added to proper list */
1042 root->join_cur_level = level;
1045 * First, consider left-sided and right-sided plans, in which rels of
1046 * exactly level-1 member relations are joined against initial relations.
1047 * We prefer to join using join clauses, but if we find a rel of level-1
1048 * members that has no join clauses, we will generate Cartesian-product
1049 * joins against all initial rels not already contained in it.
1051 * In the first pass (level == 2), we try to join each initial rel to each
1052 * initial rel that appears later in joinrels[1]. (The mirror-image joins
1053 * are handled automatically by make_join_rel.) In later passes, we try
1054 * to join rels of size level-1 from joinrels[level-1] to each initial rel
1057 foreach(r, joinrels[level - 1])
1059 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1060 ListCell *other_rels;
1063 other_rels = lnext(r); /* only consider remaining initial
1066 other_rels = list_head(joinrels[1]); /* consider all initial
1069 if (old_rel->joininfo != NIL || old_rel->has_eclass_joins ||
1070 has_join_restriction(root, old_rel))
1073 * Note that if all available join clauses for this rel require
1074 * more than one other rel, we will fail to make any joins against
1075 * it here. In most cases that's OK; it'll be considered by
1076 * "bushy plan" join code in a higher-level pass where we have
1077 * those other rels collected into a join rel.
1079 * See also the last-ditch case below.
1081 make_rels_by_clause_joins(root,
1088 * Oops, we have a relation that is not joined to any other
1089 * relation, either directly or by join-order restrictions.
1090 * Cartesian product time.
1092 make_rels_by_clauseless_joins(root,
1099 * Now, consider "bushy plans" in which relations of k initial rels are
1100 * joined to relations of level-k initial rels, for 2 <= k <= level-2.
1102 * We only consider bushy-plan joins for pairs of rels where there is a
1103 * suitable join clause (or join order restriction), in order to avoid
1104 * unreasonable growth of planning time.
1108 int other_level = level - k;
1111 * Since make_join_rel(x, y) handles both x,y and y,x cases, we only
1112 * need to go as far as the halfway point.
1114 if (k > other_level)
1117 foreach(r, joinrels[k])
1119 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1120 ListCell *other_rels;
1124 * We can ignore clauseless joins here, *except* when they
1125 * participate in join-order restrictions --- then we might have
1126 * to force a bushy join plan.
1128 if (old_rel->joininfo == NIL && !old_rel->has_eclass_joins &&
1129 !has_join_restriction(root, old_rel))
1132 if (k == other_level)
1133 other_rels = lnext(r); /* only consider remaining rels */
1135 other_rels = list_head(joinrels[other_level]);
1137 for_each_cell(r2, other_rels)
1139 RelOptInfo *new_rel = (RelOptInfo *) lfirst(r2);
1141 if (!bms_overlap(old_rel->relids, new_rel->relids))
1144 * OK, we can build a rel of the right level from this
1145 * pair of rels. Do so if there is at least one usable
1146 * join clause or a relevant join restriction.
1148 if (have_relevant_joinclause(root, old_rel, new_rel) ||
1149 have_join_order_restriction(root, old_rel, new_rel))
1151 (void) my_make_join_rel(root, old_rel, new_rel);
1159 * Last-ditch effort: if we failed to find any usable joins so far, force
1160 * a set of cartesian-product joins to be generated. This handles the
1161 * special case where all the available rels have join clauses but we
1162 * cannot use any of those clauses yet. An example is
1164 * SELECT * FROM a,b,c WHERE (a.f1 + b.f2 + c.f3) = 0;
1166 * The join clause will be usable at level 3, but at level 2 we have no
1167 * choice but to make cartesian joins. We consider only left-sided and
1168 * right-sided cartesian joins in this case (no bushy).
1170 if (joinrels[level] == NIL)
1173 * This loop is just like the first one, except we always call
1174 * make_rels_by_clauseless_joins().
1176 foreach(r, joinrels[level - 1])
1178 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1179 ListCell *other_rels;
1182 other_rels = lnext(r); /* only consider remaining initial
1185 other_rels = list_head(joinrels[1]); /* consider all initial
1188 make_rels_by_clauseless_joins(root,
1194 * When special joins are involved, there may be no legal way
1195 * to make an N-way join for some values of N. For example consider
1197 * SELECT ... FROM t1 WHERE
1198 * x IN (SELECT ... FROM t2,t3 WHERE ...) AND
1199 * y IN (SELECT ... FROM t4,t5 WHERE ...)
1201 * We will flatten this query to a 5-way join problem, but there are
1202 * no 4-way joins that join_is_legal() will consider legal. We have
1203 * to accept failure at level 4 and go on to discover a workable
1204 * bushy plan at level 5.
1206 * However, if there are no special joins then join_is_legal() should
1207 * never fail, and so the following sanity check is useful.
1210 if (joinrels[level] == NIL && root->join_info_list == NIL)
1211 elog(ERROR, "failed to build any %d-way joins", level);
1216 * src/backend/optimizer/path/joinrels.c
1217 * static make_rels_by_clause_joins() を流用
1220 * make_join_rel() の呼び出しをラップする、my_make_join_rel()の呼び出しに変更
1223 * make_rels_by_clause_joins
1224 * Build joins between the given relation 'old_rel' and other relations
1225 * that participate in join clauses that 'old_rel' also participates in
1226 * (or participate in join-order restrictions with it).
1227 * The join rels are returned in root->join_rel_level[join_cur_level].
1229 * Note: at levels above 2 we will generate the same joined relation in
1230 * multiple ways --- for example (a join b) join c is the same RelOptInfo as
1231 * (b join c) join a, though the second case will add a different set of Paths
1232 * to it. This is the reason for using the join_rel_level mechanism, which
1233 * automatically ensures that each new joinrel is only added to the list once.
1235 * 'old_rel' is the relation entry for the relation to be joined
1236 * 'other_rels': the first cell in a linked list containing the other
1237 * rels to be considered for joining
1239 * Currently, this is only used with initial rels in other_rels, but it
1240 * will work for joining to joinrels too.
1243 make_rels_by_clause_joins(PlannerInfo *root,
1244 RelOptInfo *old_rel,
1245 ListCell *other_rels)
1249 for_each_cell(l, other_rels)
1251 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
1253 if (!bms_overlap(old_rel->relids, other_rel->relids) &&
1254 (have_relevant_joinclause(root, old_rel, other_rel) ||
1255 have_join_order_restriction(root, old_rel, other_rel)))
1257 (void) my_make_join_rel(root, old_rel, other_rel);
1263 * src/backend/optimizer/path/joinrels.c
1264 * static make_rels_by_clauseless_joins() を流用
1267 * make_join_rel() の呼び出しをラップする、my_make_join_rel()の呼び出しに変更
1270 * make_rels_by_clauseless_joins
1271 * Given a relation 'old_rel' and a list of other relations
1272 * 'other_rels', create a join relation between 'old_rel' and each
1273 * member of 'other_rels' that isn't already included in 'old_rel'.
1274 * The join rels are returned in root->join_rel_level[join_cur_level].
1276 * 'old_rel' is the relation entry for the relation to be joined
1277 * 'other_rels': the first cell of a linked list containing the
1278 * other rels to be considered for joining
1280 * Currently, this is only used with initial rels in other_rels, but it would
1281 * work for joining to joinrels too.
1284 make_rels_by_clauseless_joins(PlannerInfo *root,
1285 RelOptInfo *old_rel,
1286 ListCell *other_rels)
1290 for_each_cell(l, other_rels)
1292 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
1294 if (!bms_overlap(other_rel->relids, old_rel->relids))
1296 (void) my_make_join_rel(root, old_rel, other_rel);
1302 * src/backend/optimizer/path/joinrels.c
1303 * static has_join_restriction() を流用
1309 * has_join_restriction
1310 * Detect whether the specified relation has join-order restrictions
1311 * due to being inside an outer join or an IN (sub-SELECT).
1313 * Essentially, this tests whether have_join_order_restriction() could
1314 * succeed with this rel and some other one. It's OK if we sometimes
1315 * say "true" incorrectly. (Therefore, we don't bother with the relatively
1316 * expensive has_legal_joinclause test.)
1319 has_join_restriction(PlannerInfo *root, RelOptInfo *rel)
1323 foreach(l, root->join_info_list)
1325 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
1327 /* ignore full joins --- other mechanisms preserve their ordering */
1328 if (sjinfo->jointype == JOIN_FULL)
1331 /* ignore if SJ is already contained in rel */
1332 if (bms_is_subset(sjinfo->min_lefthand, rel->relids) &&
1333 bms_is_subset(sjinfo->min_righthand, rel->relids))
1336 /* restricted if it overlaps LHS or RHS, but doesn't contain SJ */
1337 if (bms_overlap(sjinfo->min_lefthand, rel->relids) ||
1338 bms_overlap(sjinfo->min_righthand, rel->relids))