1 /*-------------------------------------------------------------------------
4 * do instructions or hints to the planner using C-style block comments
7 * Copyright (c) 2012, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
9 *-------------------------------------------------------------------------
12 #include "miscadmin.h"
13 #include "optimizer/geqo.h"
14 #include "optimizer/joininfo.h"
15 #include "optimizer/pathnode.h"
16 #include "optimizer/paths.h"
17 #include "optimizer/plancat.h"
18 #include "optimizer/planner.h"
19 #include "tcop/tcopprot.h"
20 #include "utils/lsyscache.h"
22 #ifdef PG_MODULE_MAGIC
26 #if PG_VERSION_NUM != 90200
27 #error unsupported PostgreSQL version
30 #define HINT_START "/*"
34 #define HINT_SEQSCAN "SeqScan"
35 #define HINT_INDEXSCAN "IndexScan"
36 #define HINT_BITMAPSCAN "BitmapScan"
37 #define HINT_TIDSCAN "TidScan"
38 #define HINT_NOSEQSCAN "NoSeqScan"
39 #define HINT_NOINDEXSCAN "NoIndexScan"
40 #define HINT_NOBITMAPSCAN "NoBitmapScan"
41 #define HINT_NOTIDSCAN "NoTidScan"
42 #define HINT_NESTLOOP "NestLoop"
43 #define HINT_MERGEJOIN "MergeJoin"
44 #define HINT_HASHJOIN "HashJoin"
45 #define HINT_NONESTLOOP "NoNestLoop"
46 #define HINT_NOMERGEJOIN "NoMergeJoin"
47 #define HINT_NOHASHJOIN "NoHashJoin"
48 #define HINT_LEADING "Leading"
49 #define HINT_SET "Set"
51 #if PG_VERSION_NUM >= 90200
52 #define HINT_INDEXONLYSCAN "IndexonlyScan"
53 #define HINT_NOINDEXONLYSCAN "NoIndexonlyScan"
56 #define HINT_ARRAY_DEFAULT_INITSIZE 8
58 #define parse_ereport(str, detail) \
59 ereport(pg_hint_plan_parse_message, \
60 (errmsg("hint syntax error at or near \"%s\"", (str)), \
63 #define skip_space(str) \
64 while (isspace(*str)) \
69 ENABLE_SEQSCAN = 0x01,
70 ENABLE_INDEXSCAN = 0x02,
71 ENABLE_BITMAPSCAN = 0x04,
72 ENABLE_TIDSCAN = 0x08,
73 ENABLE_NESTLOOP = 0x10,
74 ENABLE_MERGEJOIN = 0x20,
75 ENABLE_HASHJOIN = 0x40
78 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN \
80 #define ENABLE_ALL_JOIN (ENABLE_NESTLOOP | ENABLE_MERGEJOIN | ENABLE_HASHJOIN)
82 /* scan method hints */
83 typedef struct ScanHint
85 const char *opt_str; /* must not do pfree */
88 unsigned char enforce_mask;
91 /* join method hints */
92 typedef struct JoinHint
94 const char *opt_str; /* must not do pfree */
97 unsigned char enforce_mask;
101 /* change a run-time parameter hints */
102 typedef struct SetHint
104 char *name; /* name of variable */
108 typedef struct PlanHint
114 ScanHint **scan_hints;
118 JoinHint **join_hints;
121 List **join_hint_level;
129 typedef const char *(*HintParserFunction) (PlanHint *plan, Query *parse, char *keyword, const char *str);
131 typedef struct HintParser
135 HintParserFunction hint_parser;
138 /* Module callbacks */
142 static PlannedStmt *pg_hint_plan_planner(Query *parse, int cursorOptions,
143 ParamListInfo boundParams);
144 static void pg_hint_plan_get_relation_info(PlannerInfo *root, Oid relationObjectId,
145 bool inhparent, RelOptInfo *rel);
146 static RelOptInfo *pg_hint_plan_join_search(PlannerInfo *root, int levels_needed,
149 static const char *ParseScanMethod(PlanHint *plan, Query *parse, char *keyword, const char *str);
150 static const char *ParseIndexScanMethod(PlanHint *plan, Query *parse, char *keyword, const char *str);
151 static const char *ParseJoinMethod(PlanHint *plan, Query *parse, char *keyword, const char *str);
152 static const char *ParseLeading(PlanHint *plan, Query *parse, char *keyword, const char *str);
153 static const char *ParseSet(PlanHint *plan, Query *parse, char *keyword, const char *str);
155 static const char *Ordered(PlanHint *plan, Query *parse, char *keyword, const char *str);
158 static void my_join_search_one_level(PlannerInfo *root, int level);
159 static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel, ListCell *other_rels);
160 static void make_rels_by_clauseless_joins(PlannerInfo *root, RelOptInfo *old_rel, ListCell *other_rels);
161 static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
162 static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte);
166 static bool pg_hint_plan_enable = true;
167 static bool pg_hint_plan_debug_print = false;
168 static int pg_hint_plan_parse_message = INFO;
170 static const struct config_enum_entry parse_message_level_options[] = {
171 {"debug", DEBUG2, true},
172 {"debug5", DEBUG5, false},
173 {"debug4", DEBUG4, false},
174 {"debug3", DEBUG3, false},
175 {"debug2", DEBUG2, false},
176 {"debug1", DEBUG1, false},
178 {"info", INFO, false},
179 {"notice", NOTICE, false},
180 {"warning", WARNING, false},
181 {"error", ERROR, false},
183 {"fatal", FATAL, true},
184 {"panic", PANIC, true},
189 /* Saved hook values in case of unload */
190 static planner_hook_type prev_planner_hook = NULL;
191 static get_relation_info_hook_type prev_get_relation_info = NULL;
192 static join_search_hook_type prev_join_search = NULL;
194 /* フック関数をまたがって使用する情報を管理する */
195 static PlanHint *global = NULL;
197 static const HintParser parsers[] = {
198 {HINT_SEQSCAN, true, ParseScanMethod},
199 {HINT_INDEXSCAN, true, ParseIndexScanMethod},
200 {HINT_BITMAPSCAN, true, ParseIndexScanMethod},
201 {HINT_TIDSCAN, true, ParseScanMethod},
202 {HINT_NOSEQSCAN, true, ParseScanMethod},
203 {HINT_NOINDEXSCAN, true, ParseScanMethod},
204 {HINT_NOBITMAPSCAN, true, ParseScanMethod},
205 {HINT_NOTIDSCAN, true, ParseScanMethod},
206 #if PG_VERSION_NUM >= 90200
207 {HINT_INDEXONLYSCAN, true, ParseIndexScanMethod},
208 {HINT_NOINDEXONLYSCAN, true, ParseIndexScanMethod},
210 {HINT_NESTLOOP, true, ParseJoinMethod},
211 {HINT_MERGEJOIN, true, ParseJoinMethod},
212 {HINT_HASHJOIN, true, ParseJoinMethod},
213 {HINT_NONESTLOOP, true, ParseJoinMethod},
214 {HINT_NOMERGEJOIN, true, ParseJoinMethod},
215 {HINT_NOHASHJOIN, true, ParseJoinMethod},
216 {HINT_LEADING, true, ParseLeading},
217 {HINT_SET, true, ParseSet},
222 * Module load callbacks
227 /* Define custom GUC variables. */
228 DefineCustomBoolVariable("pg_hint_plan.enable",
229 "Instructions or hints to the planner using block comments.",
231 &pg_hint_plan_enable,
239 DefineCustomBoolVariable("pg_hint_plan.debug_print",
240 "Logs each query's parse results of the hint.",
242 &pg_hint_plan_debug_print,
250 DefineCustomEnumVariable("pg_hint_plan.parse_message",
251 "Messege level of the parse error.",
253 &pg_hint_plan_parse_message,
255 parse_message_level_options,
263 prev_planner_hook = planner_hook;
264 planner_hook = pg_hint_plan_planner;
265 prev_get_relation_info = get_relation_info_hook;
266 get_relation_info_hook = pg_hint_plan_get_relation_info;
267 prev_join_search = join_search_hook;
268 join_search_hook = pg_hint_plan_join_search;
272 * Module unload callback
277 /* Uninstall hooks. */
278 planner_hook = prev_planner_hook;
279 get_relation_info_hook = prev_get_relation_info;
280 join_search_hook = prev_join_search;
288 hint = palloc(sizeof(ScanHint));
289 hint->opt_str = NULL;
290 hint->relname = NULL;
291 hint->indexnames = NIL;
292 hint->enforce_mask = 0;
298 ScanHintDelete(ScanHint *hint)
304 pfree(hint->relname);
305 list_free_deep(hint->indexnames);
314 hint = palloc(sizeof(JoinHint));
315 hint->opt_str = NULL;
317 hint->relnames = NULL;
318 hint->enforce_mask = 0;
319 hint->joinrelids = NULL;
325 JoinHintDelete(JoinHint *hint)
334 for (i = 0; i < hint->nrels; i++)
335 pfree(hint->relnames[i]);
336 pfree(hint->relnames);
338 bms_free(hint->joinrelids);
347 hint = palloc(sizeof(SetHint));
355 SetHintDelete(SetHint *hint)
372 hint = palloc(sizeof(PlanHint));
373 hint->hint_str = NULL;
374 hint->nscan_hints = 0;
375 hint->max_scan_hints = 0;
376 hint->scan_hints = NULL;
377 hint->njoin_hints = 0;
378 hint->max_join_hints = 0;
379 hint->join_hints = NULL;
381 hint->join_hint_level = NULL;
383 hint->context = superuser() ? PGC_SUSET : PGC_USERSET;
384 hint->set_hints = NIL;
390 PlanHintDelete(PlanHint *hint)
399 pfree(hint->hint_str);
401 for (i = 0; i < hint->nscan_hints; i++)
402 ScanHintDelete(hint->scan_hints[i]);
403 if (hint->scan_hints)
404 pfree(hint->scan_hints);
406 for (i = 0; i < hint->njoin_hints; i++)
407 JoinHintDelete(hint->join_hints[i]);
408 if (hint->join_hints)
409 pfree(hint->join_hints);
411 for (i = 2; i <= hint->nlevel; i++)
412 list_free(hint->join_hint_level[i]);
413 if (hint->join_hint_level)
414 pfree(hint->join_hint_level);
416 list_free_deep(hint->leading);
418 foreach(l, hint->set_hints)
419 SetHintDelete((SetHint *) lfirst(l));
420 list_free(hint->set_hints);
426 PlanHintIsempty(PlanHint *hint)
428 if (hint->nscan_hints == 0 &&
429 hint->njoin_hints == 0 &&
430 hint->leading == NIL &&
431 hint->set_hints == NIL)
437 // TODO オブジェクト名のクォート処理を追加
439 PlanHintDump(PlanHint *hint)
444 bool is_first = true;
448 elog(INFO, "no hint");
452 initStringInfo(&buf);
453 appendStringInfo(&buf, "/*\n");
454 for (i = 0; i < hint->nscan_hints; i++)
456 ScanHint *h = hint->scan_hints[i];
458 switch(h->enforce_mask)
460 case(ENABLE_SEQSCAN):
461 appendStringInfo(&buf, "%s(", HINT_SEQSCAN);
463 case(ENABLE_INDEXSCAN):
464 appendStringInfo(&buf, "%s(", HINT_INDEXSCAN);
466 case(ENABLE_BITMAPSCAN):
467 appendStringInfo(&buf, "%s(", HINT_BITMAPSCAN);
469 case(ENABLE_TIDSCAN):
470 appendStringInfo(&buf, "%s(", HINT_TIDSCAN);
472 case(ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN | ENABLE_TIDSCAN):
473 appendStringInfo(&buf, "%s(", HINT_NOSEQSCAN);
475 case(ENABLE_SEQSCAN | ENABLE_BITMAPSCAN | ENABLE_TIDSCAN):
476 appendStringInfo(&buf, "%s(", HINT_NOINDEXSCAN);
478 case(ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_TIDSCAN):
479 appendStringInfo(&buf, "%s(", HINT_NOBITMAPSCAN);
481 case(ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN):
482 appendStringInfo(&buf, "%s(", HINT_NOTIDSCAN);
485 appendStringInfoString(&buf, "\?\?\?(");
488 appendStringInfo(&buf, "%s", h->relname);
489 foreach(n, h->indexnames)
490 appendStringInfo(&buf, " %s", (char *) lfirst(n));
491 appendStringInfoString(&buf, ")\n");
494 for (i = 0; i < hint->njoin_hints; i++)
496 JoinHint *h = hint->join_hints[i];
498 switch(h->enforce_mask)
500 case(ENABLE_NESTLOOP):
501 appendStringInfo(&buf, "%s(", HINT_NESTLOOP);
503 case(ENABLE_MERGEJOIN):
504 appendStringInfo(&buf, "%s(", HINT_MERGEJOIN);
506 case(ENABLE_HASHJOIN):
507 appendStringInfo(&buf, "%s(", HINT_HASHJOIN);
509 case(ENABLE_ALL_JOIN ^ ENABLE_NESTLOOP):
510 appendStringInfo(&buf, "%s(", HINT_NONESTLOOP);
512 case(ENABLE_ALL_JOIN ^ ENABLE_MERGEJOIN):
513 appendStringInfo(&buf, "%s(", HINT_NOMERGEJOIN);
515 case(ENABLE_ALL_JOIN ^ ENABLE_HASHJOIN):
516 appendStringInfo(&buf, "%s(", HINT_NOHASHJOIN);
518 case(ENABLE_ALL_JOIN):
521 appendStringInfoString(&buf, "\?\?\?(");
524 appendStringInfo(&buf, "%s", h->relnames[0]);
525 for (i = 1; i < h->nrels; i++)
526 appendStringInfo(&buf, " %s", h->relnames[i]);
527 appendStringInfoString(&buf, ")\n");
530 foreach(l, hint->set_hints)
532 SetHint *h = (SetHint *) lfirst(l);
533 appendStringInfo(&buf, "%s(%s %s)\n", HINT_SET, h->name, h->value);
536 foreach(l, hint->leading)
540 appendStringInfo(&buf, "%s(%s", HINT_LEADING, (char *)lfirst(l));
544 appendStringInfo(&buf, " %s", (char *)lfirst(l));
547 appendStringInfoString(&buf, ")\n");
549 appendStringInfoString(&buf, "*/");
551 elog(INFO, "%s", buf.data);
557 RelnameCmp(const void *a, const void *b)
559 const char *relnamea = *((const char **) a);
560 const char *relnameb = *((const char **) b);
562 return strcmp(relnamea, relnameb);
566 ScanHintCmp(const void *a, const void *b, bool order)
568 const ScanHint *hinta = *((const ScanHint **) a);
569 const ScanHint *hintb = *((const ScanHint **) b);
572 if ((result = strcmp(hinta->relname, hintb->relname)) != 0)
577 return hinta->opt_str - hintb->opt_str;
583 ScanHintCmpIsOrder(const void *a, const void *b)
585 return ScanHintCmp(a, b, true);
589 JoinHintCmp(const void *a, const void *b, bool order)
591 const JoinHint *hinta = *((const JoinHint **) a);
592 const JoinHint *hintb = *((const JoinHint **) b);
594 if (hinta->nrels == hintb->nrels)
597 for (i = 0; i < hinta->nrels; i++)
600 if ((result = strcmp(hinta->relnames[i], hintb->relnames[i])) != 0)
606 return hinta->opt_str - hintb->opt_str;
611 return hinta->nrels - hintb->nrels;
615 JoinHintCmpIsOrder(const void *a, const void *b)
617 return JoinHintCmp(a, b, true);
621 set_config_options(List *options, GucContext context)
627 save_nestlevel = NewGUCNestLevel();
631 SetHint *hint = (SetHint *) lfirst(l);
634 result = set_config_option(hint->name, hint->value, context,
635 PGC_S_SESSION, GUC_ACTION_SAVE, true,
636 pg_hint_plan_parse_message);
639 return save_nestlevel;
642 #define SET_CONFIG_OPTION(name, enforce_mask, type_bits) \
643 set_config_option((name), \
644 ((enforce_mask) & (type_bits)) ? "true" : "false", \
645 context, PGC_S_SESSION, GUC_ACTION_SAVE, true, ERROR)
648 set_join_config_options(unsigned char enforce_mask, GucContext context)
650 SET_CONFIG_OPTION("enable_nestloop", enforce_mask, ENABLE_NESTLOOP);
651 SET_CONFIG_OPTION("enable_mergejoin", enforce_mask, ENABLE_MERGEJOIN);
652 SET_CONFIG_OPTION("enable_hashjoin", enforce_mask, ENABLE_HASHJOIN);
656 set_scan_config_options(unsigned char enforce_mask, GucContext context)
658 SET_CONFIG_OPTION("enable_seqscan", enforce_mask, ENABLE_SEQSCAN);
659 SET_CONFIG_OPTION("enable_indexscan", enforce_mask, ENABLE_INDEXSCAN);
660 SET_CONFIG_OPTION("enable_bitmapscan", enforce_mask, ENABLE_BITMAPSCAN);
661 SET_CONFIG_OPTION("enable_tidscan", enforce_mask, ENABLE_TIDSCAN);
662 #if PG_VERSION_NUM >= 90200
663 SET_CONFIG_OPTION("enable_indexonlyscan", enforce_mask, ENABLE_INDEXSCAN);
672 parse_keyword(const char *str, StringInfo buf)
676 while (!isspace(*str) && *str != '(' && *str != '\0')
677 appendStringInfoChar(buf, *str++);
683 skip_opened_parenthesis(const char *str)
689 parse_ereport(str, ("Opened parenthesis is necessary."));
699 skip_closed_parenthesis(const char *str)
705 parse_ereport(str, ("Closed parenthesis is necessary."));
715 parse_quote_value(const char *str, char **word, char *value_type)
722 initStringInfo(&buf);
733 if (!isalpha(*str) && *str != '_')
736 parse_ereport(str, ("Need for %s to be quoted.", value_type));
741 appendStringInfoCharMacro(&buf, *str++);
751 parse_ereport(str, ("Unterminated quoted %s.", value_type));
757 * TODO エスケープ対象の仕様にあわせた処理を行う。
771 if (!isalnum(*str) && *str != '_' && *str != '$')
775 appendStringInfoCharMacro(&buf, *str++);
781 parse_ereport(str, ("%s is necessary.", value_type));
791 skip_option_delimiter(const char *str)
799 parse_ereport(str, ("Must be specified space."));
807 parse_hints(PlanHint *plan, Query *parse, const char *str)
812 initStringInfo(&buf);
815 const HintParser *parser;
817 /* in error message, we output the comment including the keyword. */
820 /* parse only the keyword of the hint. */
821 resetStringInfo(&buf);
822 str = parse_keyword(str, &buf);
824 for (parser = parsers; parser->keyword != NULL; parser++)
826 char *keyword = parser->keyword;
828 if (strcasecmp(buf.data, keyword) != 0)
831 if (parser->have_paren)
833 /* parser of each hint does parse in a parenthesis. */
834 if ((str = skip_opened_parenthesis(str)) == NULL ||
835 (str = parser->hint_parser(plan, parse, keyword, str)) == NULL ||
836 (str = skip_closed_parenthesis(str)) == NULL)
844 if ((str = parser->hint_parser(plan, parse, keyword, str)) == NULL)
851 * 直前のヒントに括弧の指定がなければ次のヒントの間に空白が必要
853 if (!isspace(*str) && *str == '\0')
854 parse_ereport(str, ("Delimiter of the hint is necessary."));
862 if (parser->keyword == NULL)
864 parse_ereport(head, ("Keyword \"%s\" does not exist.", buf.data));
876 * Do basic parsing of the query head comment.
879 parse_head_comment(Query *parse)
888 /* get client-supplied query string. */
889 p = debug_query_string;
894 /* extract query head comment. */
895 len = strlen(HINT_START);
897 if (strncmp(p, HINT_START, len))
903 if ((tail = strstr(p, HINT_END)) == NULL)
904 elog(ERROR, "unterminated /* comment at or near \"%s\"",
907 /* 入れ子にしたブロックコメントはサポートしない */
908 if ((head = strstr(p, HINT_START)) != NULL && head < tail)
909 parse_ereport(head, ("block comments nest doesn't supported"));
913 head = palloc(len + 1);
914 memcpy(head, p, len);
918 plan = PlanHintCreate();
919 plan->hint_str = head;
921 /* parse each hint. */
922 if (!parse_hints(plan, parse, p))
925 /* 重複したScan条件をを除外する */
926 qsort(plan->scan_hints, plan->nscan_hints, sizeof(ScanHint *), ScanHintCmpIsOrder);
927 for (i = 0; i < plan->nscan_hints - 1;)
929 int result = ScanHintCmp(plan->scan_hints + i,
930 plan->scan_hints + i + 1, false);
935 /* 後で指定したヒントを有効にする */
937 memmove(plan->scan_hints + i, plan->scan_hints + i + 1,
938 sizeof(ScanHint *) * (plan->nscan_hints - i));
942 /* 重複したJoin条件をを除外する */
943 qsort(plan->join_hints, plan->njoin_hints, sizeof(JoinHint *), JoinHintCmpIsOrder);
944 for (i = 0; i < plan->njoin_hints - 1;)
946 int result = JoinHintCmp(plan->join_hints + i,
947 plan->join_hints + i + 1, false);
952 /* 後で指定したヒントを有効にする */
954 memmove(plan->join_hints + i, plan->join_hints + i + 1,
955 sizeof(JoinHint *) * (plan->njoin_hints - i));
963 parse_scan_method(PlanHint *plan, Query *parse, char *keyword, const char *str)
967 hint = ScanHintCreate();
970 if ((str = parse_quote_value(str, &hint->relname, "ralation name")) == NULL)
972 ScanHintDelete(hint);
976 if (strcasecmp(keyword, HINT_SEQSCAN) == 0)
977 hint->enforce_mask = ENABLE_SEQSCAN;
978 else if (strcasecmp(keyword, HINT_INDEXSCAN) == 0)
979 hint->enforce_mask = ENABLE_INDEXSCAN;
980 else if (strcasecmp(keyword, HINT_BITMAPSCAN) == 0)
981 hint->enforce_mask = ENABLE_BITMAPSCAN;
982 else if (strcasecmp(keyword, HINT_TIDSCAN) == 0)
983 hint->enforce_mask = ENABLE_TIDSCAN;
984 else if (strcasecmp(keyword, HINT_NOSEQSCAN) == 0)
985 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_SEQSCAN;
986 else if (strcasecmp(keyword, HINT_NOINDEXSCAN) == 0)
987 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXSCAN;
988 else if (strcasecmp(keyword, HINT_NOBITMAPSCAN) == 0)
989 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_BITMAPSCAN;
990 else if (strcasecmp(keyword, HINT_NOTIDSCAN) == 0)
991 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_TIDSCAN;
994 elog(ERROR, "unrecognized hint keyword \"%s\"", keyword);
998 if (plan->nscan_hints == 0)
1000 plan->max_scan_hints = HINT_ARRAY_DEFAULT_INITSIZE;
1001 plan->scan_hints = palloc(sizeof(JoinHint *) * plan->max_scan_hints);
1003 else if (plan->nscan_hints == plan->max_scan_hints)
1005 plan->max_scan_hints *= 2;
1006 plan->scan_hints = repalloc(plan->scan_hints,
1007 sizeof(JoinHint *) * plan->max_scan_hints);
1010 plan->scan_hints[plan->nscan_hints] = hint;
1011 plan->nscan_hints++;
1017 ParseScanMethod(PlanHint *plan, Query *parse, char *keyword, const char *str)
1021 if ((str = parse_scan_method(plan, parse, keyword, str)) == NULL)
1024 hint = plan->scan_hints[plan->nscan_hints - 1];
1029 parse_ereport(str, ("Closed parenthesis is necessary."));
1030 plan->nscan_hints--;
1031 ScanHintDelete(hint);
1039 ParseIndexScanMethod(PlanHint *plan, Query *parse, char *keyword, const char *str)
1044 if ((str = parse_scan_method(plan, parse, keyword, str)) == NULL)
1047 hint = plan->scan_hints[plan->nscan_hints - 1];
1049 /* インデックス参照をパースする。 */
1052 // TODO 直前のオブジェクト名がクウォート処理されていた場合の処理を実装
1057 if ((str = parse_quote_value(str, &indexname, "index name")) == NULL)
1059 plan->nscan_hints--;
1060 ScanHintDelete(hint);
1064 hint->indexnames = lappend(hint->indexnames, indexname);
1071 ParseJoinMethod(PlanHint *plan, Query *parse, char *keyword, const char *str)
1078 hint = JoinHintCreate();
1079 hint->opt_str = str;
1080 hint->relnames = palloc(sizeof(char *));
1082 while ((str = parse_quote_value(str, &relname, "table name")) != NULL)
1085 hint->relnames = repalloc(hint->relnames, sizeof(char *) * hint->nrels);
1086 hint->relnames[hint->nrels - 1] = relname;
1095 JoinHintDelete(hint);
1099 /* Join 対象のテーブルは最低でも2つ指定する必要がある */
1100 if (hint->nrels < 2)
1102 JoinHintDelete(hint);
1103 parse_ereport(str, ("Specified relation more than two."));
1108 qsort(hint->relnames, hint->nrels, sizeof(char *), RelnameCmp);
1110 if (strcasecmp(keyword, HINT_NESTLOOP) == 0)
1111 hint->enforce_mask = ENABLE_NESTLOOP;
1112 else if (strcasecmp(keyword, HINT_MERGEJOIN) == 0)
1113 hint->enforce_mask = ENABLE_MERGEJOIN;
1114 else if (strcasecmp(keyword, HINT_HASHJOIN) == 0)
1115 hint->enforce_mask = ENABLE_HASHJOIN;
1116 else if (strcasecmp(keyword, HINT_NONESTLOOP) == 0)
1117 hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_NESTLOOP;
1118 else if (strcasecmp(keyword, HINT_NOMERGEJOIN) == 0)
1119 hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_MERGEJOIN;
1120 else if (strcasecmp(keyword, HINT_NOHASHJOIN) == 0)
1121 hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_HASHJOIN;
1123 elog(ERROR, "unrecognized hint keyword \"%s\"", keyword);
1125 if (plan->njoin_hints == 0)
1127 plan->max_join_hints = HINT_ARRAY_DEFAULT_INITSIZE;
1128 plan->join_hints = palloc(sizeof(JoinHint *) * plan->max_join_hints);
1130 else if (plan->njoin_hints == plan->max_join_hints)
1132 plan->max_join_hints *= 2;
1133 plan->join_hints = repalloc(plan->join_hints,
1134 sizeof(JoinHint *) * plan->max_join_hints);
1137 plan->join_hints[plan->njoin_hints] = hint;
1138 plan->njoin_hints++;
1144 ParseLeading(PlanHint *plan, Query *parse, char *keyword, const char *str)
1149 * すでに指定済みの場合は、後で指定したヒントが有効にするため、登録済みの
1152 list_free_deep(plan->leading);
1153 plan->leading = NIL;
1155 while ((str = parse_quote_value(str, &relname, "relation name")) != NULL)
1159 plan->leading = lappend(plan->leading, relname);
1168 parse_ereport(str, ("Must be specified space."));
1173 /* テーブル指定が1つのみの場合は、ヒントを無効にし、パースを続ける */
1174 if (list_length(plan->leading) == 1)
1176 parse_ereport(str, ("In %s hint, specified relation name 2 or more.", HINT_LEADING));
1177 list_free_deep(plan->leading);
1178 plan->leading = NIL;
1185 ParseSet(PlanHint *plan, Query *parse, char *keyword, const char *str)
1189 hint = SetHintCreate();
1191 if ((str = parse_quote_value(str, &hint->name, "parameter name")) == NULL ||
1192 (str = skip_option_delimiter(str)) == NULL ||
1193 (str = parse_quote_value(str, &hint->value, "parameter value")) == NULL)
1195 SetHintDelete(hint);
1202 parse_ereport(str, ("Closed parenthesis is necessary."));
1203 SetHintDelete(hint);
1206 plan->set_hints = lappend(plan->set_hints, hint);
1213 * Oracle の ORDERD ヒントの実装
1216 Ordered(PlanHint *plan, Query *parse, char *keyword, const char *str)
1220 hint = SetHintCreate();
1221 hint->name = pstrdup("join_collapse_limit");
1222 hint->value = pstrdup("1");
1223 plan->set_hints = lappend(plan->set_hints, hint);
1229 static PlannedStmt *
1230 pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
1233 PlannedStmt *result;
1236 * hintが指定されない、または空のhintを指定された場合は通常のparser処理をお
1238 * 他のフック関数で実行されるhint処理をスキップするために、global 変数をNULL
1241 if (!pg_hint_plan_enable ||
1242 (global = parse_head_comment(parse)) == NULL ||
1243 PlanHintIsempty(global))
1245 PlanHintDelete(global);
1248 if (prev_planner_hook)
1249 return (*prev_planner_hook) (parse, cursorOptions, boundParams);
1251 return standard_planner(parse, cursorOptions, boundParams);
1254 /* Set hint で指定されたGUCパラメータを設定する */
1255 save_nestlevel = set_config_options(global->set_hints, global->context);
1257 if (global->leading != NIL)
1258 set_join_config_options(0, global->context);
1261 * TODO ビュー定義で指定したテーブル数が1つの場合にもこのタイミングでGUCを変更する必
1264 if (list_length(parse->rtable) == 1 &&
1265 ((RangeTblEntry *) linitial(parse->rtable))->rtekind == RTE_RELATION)
1268 RangeTblEntry *rte = linitial(parse->rtable);
1270 for (i = 0; i < global->nscan_hints; i++)
1272 ScanHint *hint = global->scan_hints[i];
1274 if (strcmp(hint->relname, rte->eref->aliasname) != 0)
1275 parse_ereport(hint->opt_str, ("Relation \"%s\" does not exist.", hint->relname));
1277 set_scan_config_options(hint->enforce_mask, global->context);
1281 if (prev_planner_hook)
1282 result = (*prev_planner_hook) (parse, cursorOptions, boundParams);
1284 result = standard_planner(parse, cursorOptions, boundParams);
1287 * Restore the GUC variables we set above.
1289 AtEOXact_GUC(true, save_nestlevel);
1291 if (pg_hint_plan_debug_print)
1293 PlanHintDump(global);
1294 //elog_node_display(INFO, "rtable", parse->rtable, true);
1297 PlanHintDelete(global);
1304 * aliasnameと一致するSCANヒントを探す
1307 find_scan_hint(RangeTblEntry *rte)
1311 for (i = 0; i < global->nscan_hints; i++)
1313 ScanHint *hint = global->scan_hints[i];
1315 if (strcmp(rte->eref->aliasname, hint->relname) == 0)
1323 pg_hint_plan_get_relation_info(PlannerInfo *root, Oid relationObjectId,
1324 bool inhparent, RelOptInfo *rel)
1331 if (prev_get_relation_info)
1332 (*prev_get_relation_info) (root, relationObjectId, inhparent, rel);
1334 /* 有効なヒントが指定されなかった場合は処理をスキップする。 */
1338 if (rel->reloptkind != RELOPT_BASEREL)
1341 if ((hint = find_scan_hint(root->simple_rte_array[rel->relid])) == NULL)
1344 /* インデックスを全て削除し、スキャンに使えなくする */
1345 if (hint->enforce_mask == ENABLE_SEQSCAN)
1347 list_free_deep(rel->indexlist);
1348 rel->indexlist = NIL;
1353 /* 後でパスを作り直すため、ここではなにもしない */
1354 if (hint->indexnames == NULL)
1357 /* 指定されたインデックスのみをのこす */
1359 for (cell = list_head(rel->indexlist); cell; cell = next)
1361 IndexOptInfo *info = (IndexOptInfo *) lfirst(cell);
1362 char *indexname = get_rel_name(info->indexoid);
1364 bool use_index = false;
1368 foreach(l, hint->indexnames)
1370 if (strcmp(indexname, lfirst(l)) == 0)
1378 rel->indexlist = list_delete_cell(rel->indexlist, cell, prev);
1387 scan_relid_aliasname(PlannerInfo *root, char *aliasname, bool check_ambiguous, const char *str)
1389 // TODO refnameRangeTblEntry を参考
1393 for (i = 1; i < root->simple_rel_array_size; i++)
1395 if (root->simple_rel_array[i] == NULL)
1398 Assert(i == root->simple_rel_array[i]->relid);
1400 if (strcmp(aliasname, root->simple_rte_array[i]->eref->aliasname) != 0)
1403 if (!check_ambiguous)
1407 parse_ereport(str, ("relation name \"%s\" is ambiguous", aliasname));
1416 * relidビットマスクと一致するヒントを探す
1419 scan_join_hint(Relids joinrelids)
1424 join_hint = global->join_hint_level[bms_num_members(joinrelids)];
1425 foreach(l, join_hint)
1427 JoinHint *hint = (JoinHint *) lfirst(l);
1428 if (bms_equal(joinrelids, hint->joinrelids))
1436 * ヒントを使用しやすい構造に変換する。
1439 rebuild_join_hints(PlanHint *plan, PlannerInfo *root, int level, List *initial_rels)
1446 plan->nlevel = root->simple_rel_array_size - 1;
1447 plan->join_hint_level = palloc0(sizeof(List *) * (root->simple_rel_array_size));
1448 for (i = 0; i < plan->njoin_hints; i++)
1450 JoinHint *hint = plan->join_hints[i];
1454 for (j = 0; j < hint->nrels; j++)
1456 char *relname = hint->relnames[j];
1458 relid = scan_relid_aliasname(root, relname, true, hint->opt_str);
1461 parse_ereport(hint->opt_str, ("Relation \"%s\" does not exist.", relname));
1465 hint->joinrelids = bms_add_member(hint->joinrelids, relid);
1471 plan->join_hint_level[hint->nrels] =
1472 lappend(plan->join_hint_level[hint->nrels], hint);
1475 /* Leading hint は、全ての join 方式が有効な hint として登録する */
1478 foreach(l, plan->leading)
1480 char *relname = (char *)lfirst(l);
1483 i = scan_relid_aliasname(root, relname, true, plan->hint_str);
1486 parse_ereport(plan->hint_str, ("Relation \"%s\" does not exist.", relname));
1487 list_free_deep(plan->leading);
1488 plan->leading = NIL;
1492 joinrelids = bms_add_member(joinrelids, i);
1498 if (njoinrels > plan->nlevel)
1500 parse_ereport(plan->hint_str, ("In %s hint, specified relation name %d or less.", HINT_LEADING, plan->nlevel));
1504 /* Leading で指定した組み合わせ以外の join hint を削除する */
1505 hint = scan_join_hint(joinrelids);
1506 list_free(plan->join_hint_level[njoinrels]);
1508 plan->join_hint_level[njoinrels] = lappend(NIL, hint);
1511 hint = JoinHintCreate();
1512 hint->nrels = njoinrels;
1513 hint->enforce_mask = ENABLE_ALL_JOIN;
1514 hint->joinrelids = bms_copy(joinrelids);
1515 plan->join_hint_level[njoinrels] = lappend(NIL, hint);
1517 if (plan->njoin_hints == 0)
1519 plan->max_join_hints = HINT_ARRAY_DEFAULT_INITSIZE;
1520 plan->join_hints = palloc(sizeof(JoinHint *) * plan->max_join_hints);
1522 else if (plan->njoin_hints == plan->max_join_hints)
1524 plan->max_join_hints *= 2;
1525 plan->join_hints = repalloc(plan->join_hints,
1526 sizeof(JoinHint *) * plan->max_join_hints);
1529 plan->join_hints[plan->njoin_hints] = hint;
1530 plan->njoin_hints++;
1534 bms_free(joinrelids);
1538 rebuild_scan_path(PlanHint *plan, PlannerInfo *root, int level, List *initial_rels)
1541 int save_nestlevel = 0;
1543 for (i = 0; i < plan->nscan_hints; i++)
1545 ScanHint *hint = plan->scan_hints[i];
1548 if (hint->enforce_mask == ENABLE_SEQSCAN)
1551 foreach(l, initial_rels)
1553 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
1554 RangeTblEntry *rte = root->simple_rte_array[rel->relid];
1556 if (rel->reloptkind != RELOPT_BASEREL ||
1557 strcmp(hint->relname, rte->eref->aliasname) != 0)
1560 if (save_nestlevel != 0)
1561 save_nestlevel = NewGUCNestLevel();
1564 * TODO ヒントで指定されたScan方式が最安価でない場合のみ、Pathを生成
1567 set_scan_config_options(hint->enforce_mask, plan->context);
1569 rel->pathlist = NIL; // TODO 解放
1570 set_plain_rel_pathlist(root, rel, rte);
1577 * Restore the GUC variables we set above.
1579 if (save_nestlevel != 0)
1580 AtEOXact_GUC(true, save_nestlevel);
1584 * src/backend/optimizer/path/joinrels.c
1585 * export make_join_rel() をラップする関数
1587 * ヒントにしたがって、enabele_* パラメータを変更した上で、make_join_rel()を
1591 pg_hint_plan_make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
1598 joinrelids = bms_union(rel1->relids, rel2->relids);
1599 hint = scan_join_hint(joinrelids);
1600 bms_free(joinrelids);
1603 return make_join_rel(root, rel1, rel2);
1605 save_nestlevel = NewGUCNestLevel();
1607 set_join_config_options(hint->enforce_mask, global->context);
1609 rel = make_join_rel(root, rel1, rel2);
1612 * Restore the GUC variables we set above.
1614 AtEOXact_GUC(true, save_nestlevel);
1619 static RelOptInfo *_standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels);
1621 pg_hint_plan_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
1623 /* 有効なヒントが指定されなかった場合は本来の処理を実行する。 */
1626 if (prev_join_search)
1627 return (*prev_join_search) (root, levels_needed, initial_rels);
1628 else if (enable_geqo && levels_needed >= geqo_threshold)
1629 return geqo(root, levels_needed, initial_rels);
1631 return standard_join_search(root, levels_needed, initial_rels);
1634 return _standard_join_search(root, levels_needed, initial_rels);
1638 * PostgreSQL 本体から流用した関数
1642 * src/backend/optimizer/path/allpaths.c
1643 * export standard_join_search() を流用
1646 * rebuild_join_hints() と rebuild_scan_path() の呼び出しを追加
1649 * standard_join_search
1650 * Find possible joinpaths for a query by successively finding ways
1651 * to join component relations into join relations.
1653 * 'levels_needed' is the number of iterations needed, ie, the number of
1654 * independent jointree items in the query. This is > 1.
1656 * 'initial_rels' is a list of RelOptInfo nodes for each independent
1657 * jointree item. These are the components to be joined together.
1658 * Note that levels_needed == list_length(initial_rels).
1660 * Returns the final level of join relations, i.e., the relation that is
1661 * the result of joining all the original relations together.
1662 * At least one implementation path must be provided for this relation and
1663 * all required sub-relations.
1665 * To support loadable plugins that modify planner behavior by changing the
1666 * join searching algorithm, we provide a hook variable that lets a plugin
1667 * replace or supplement this function. Any such hook must return the same
1668 * final join relation as the standard code would, but it might have a
1669 * different set of implementation paths attached, and only the sub-joinrels
1670 * needed for these paths need have been instantiated.
1672 * Note to plugin authors: the functions invoked during standard_join_search()
1673 * modify root->join_rel_list and root->join_rel_hash. If you want to do more
1674 * than one join-order search, you'll probably need to save and restore the
1675 * original states of those data structures. See geqo_eval() for an example.
1678 _standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
1684 * This function cannot be invoked recursively within any one planning
1685 * problem, so join_rel_level[] can't be in use already.
1687 Assert(root->join_rel_level == NULL);
1690 * We employ a simple "dynamic programming" algorithm: we first find all
1691 * ways to build joins of two jointree items, then all ways to build joins
1692 * of three items (from two-item joins and single items), then four-item
1693 * joins, and so on until we have considered all ways to join all the
1694 * items into one rel.
1696 * root->join_rel_level[j] is a list of all the j-item rels. Initially we
1697 * set root->join_rel_level[1] to represent all the single-jointree-item
1700 root->join_rel_level = (List **) palloc0((levels_needed + 1) * sizeof(List *));
1702 root->join_rel_level[1] = initial_rels;
1704 rebuild_join_hints(global, root, levels_needed, initial_rels);
1705 rebuild_scan_path(global, root, levels_needed, initial_rels);
1707 for (lev = 2; lev <= levels_needed; lev++)
1712 * Determine all possible pairs of relations to be joined at this
1713 * level, and build paths for making each one from every available
1714 * pair of lower-level relations.
1716 my_join_search_one_level(root, lev);
1719 * Do cleanup work on each just-processed rel.
1721 foreach(lc, root->join_rel_level[lev])
1723 rel = (RelOptInfo *) lfirst(lc);
1725 /* Find and save the cheapest paths for this rel */
1728 #ifdef OPTIMIZER_DEBUG
1729 debug_print_rel(root, rel);
1735 * We should have a single rel at the final level.
1737 if (root->join_rel_level[levels_needed] == NIL)
1738 elog(ERROR, "failed to build any %d-way joins", levels_needed);
1739 Assert(list_length(root->join_rel_level[levels_needed]) == 1);
1741 rel = (RelOptInfo *) linitial(root->join_rel_level[levels_needed]);
1743 root->join_rel_level = NULL;
1749 * src/backend/optimizer/path/joinrels.c
1750 * join_search_one_level() を流用
1753 * make_join_rel() の呼び出しをラップする、pg_hint_plan_make_join_rel()の呼び出しに変更
1756 * join_search_one_level
1757 * Consider ways to produce join relations containing exactly 'level'
1758 * jointree items. (This is one step of the dynamic-programming method
1759 * embodied in standard_join_search.) Join rel nodes for each feasible
1760 * combination of lower-level rels are created and returned in a list.
1761 * Implementation paths are created for each such joinrel, too.
1763 * level: level of rels we want to make this time
1764 * root->join_rel_level[j], 1 <= j < level, is a list of rels containing j items
1766 * The result is returned in root->join_rel_level[level].
1769 my_join_search_one_level(PlannerInfo *root, int level)
1771 List **joinrels = root->join_rel_level;
1775 Assert(joinrels[level] == NIL);
1777 /* Set join_cur_level so that new joinrels are added to proper list */
1778 root->join_cur_level = level;
1781 * First, consider left-sided and right-sided plans, in which rels of
1782 * exactly level-1 member relations are joined against initial relations.
1783 * We prefer to join using join clauses, but if we find a rel of level-1
1784 * members that has no join clauses, we will generate Cartesian-product
1785 * joins against all initial rels not already contained in it.
1787 * In the first pass (level == 2), we try to join each initial rel to each
1788 * initial rel that appears later in joinrels[1]. (The mirror-image joins
1789 * are handled automatically by make_join_rel.) In later passes, we try
1790 * to join rels of size level-1 from joinrels[level-1] to each initial rel
1793 foreach(r, joinrels[level - 1])
1795 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1796 ListCell *other_rels;
1799 other_rels = lnext(r); /* only consider remaining initial
1802 other_rels = list_head(joinrels[1]); /* consider all initial
1805 if (old_rel->joininfo != NIL || old_rel->has_eclass_joins ||
1806 has_join_restriction(root, old_rel))
1809 * Note that if all available join clauses for this rel require
1810 * more than one other rel, we will fail to make any joins against
1811 * it here. In most cases that's OK; it'll be considered by
1812 * "bushy plan" join code in a higher-level pass where we have
1813 * those other rels collected into a join rel.
1815 * See also the last-ditch case below.
1817 make_rels_by_clause_joins(root,
1824 * Oops, we have a relation that is not joined to any other
1825 * relation, either directly or by join-order restrictions.
1826 * Cartesian product time.
1828 make_rels_by_clauseless_joins(root,
1835 * Now, consider "bushy plans" in which relations of k initial rels are
1836 * joined to relations of level-k initial rels, for 2 <= k <= level-2.
1838 * We only consider bushy-plan joins for pairs of rels where there is a
1839 * suitable join clause (or join order restriction), in order to avoid
1840 * unreasonable growth of planning time.
1844 int other_level = level - k;
1847 * Since make_join_rel(x, y) handles both x,y and y,x cases, we only
1848 * need to go as far as the halfway point.
1850 if (k > other_level)
1853 foreach(r, joinrels[k])
1855 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1856 ListCell *other_rels;
1860 * We can ignore clauseless joins here, *except* when they
1861 * participate in join-order restrictions --- then we might have
1862 * to force a bushy join plan.
1864 if (old_rel->joininfo == NIL && !old_rel->has_eclass_joins &&
1865 !has_join_restriction(root, old_rel))
1868 if (k == other_level)
1869 other_rels = lnext(r); /* only consider remaining rels */
1871 other_rels = list_head(joinrels[other_level]);
1873 for_each_cell(r2, other_rels)
1875 RelOptInfo *new_rel = (RelOptInfo *) lfirst(r2);
1877 if (!bms_overlap(old_rel->relids, new_rel->relids))
1880 * OK, we can build a rel of the right level from this
1881 * pair of rels. Do so if there is at least one usable
1882 * join clause or a relevant join restriction.
1884 if (have_relevant_joinclause(root, old_rel, new_rel) ||
1885 have_join_order_restriction(root, old_rel, new_rel))
1887 (void) pg_hint_plan_make_join_rel(root, old_rel, new_rel);
1895 * Last-ditch effort: if we failed to find any usable joins so far, force
1896 * a set of cartesian-product joins to be generated. This handles the
1897 * special case where all the available rels have join clauses but we
1898 * cannot use any of those clauses yet. An example is
1900 * SELECT * FROM a,b,c WHERE (a.f1 + b.f2 + c.f3) = 0;
1902 * The join clause will be usable at level 3, but at level 2 we have no
1903 * choice but to make cartesian joins. We consider only left-sided and
1904 * right-sided cartesian joins in this case (no bushy).
1906 if (joinrels[level] == NIL)
1909 * This loop is just like the first one, except we always call
1910 * make_rels_by_clauseless_joins().
1912 foreach(r, joinrels[level - 1])
1914 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1915 ListCell *other_rels;
1918 other_rels = lnext(r); /* only consider remaining initial
1921 other_rels = list_head(joinrels[1]); /* consider all initial
1924 make_rels_by_clauseless_joins(root,
1930 * When special joins are involved, there may be no legal way
1931 * to make an N-way join for some values of N. For example consider
1933 * SELECT ... FROM t1 WHERE
1934 * x IN (SELECT ... FROM t2,t3 WHERE ...) AND
1935 * y IN (SELECT ... FROM t4,t5 WHERE ...)
1937 * We will flatten this query to a 5-way join problem, but there are
1938 * no 4-way joins that join_is_legal() will consider legal. We have
1939 * to accept failure at level 4 and go on to discover a workable
1940 * bushy plan at level 5.
1942 * However, if there are no special joins then join_is_legal() should
1943 * never fail, and so the following sanity check is useful.
1946 if (joinrels[level] == NIL && root->join_info_list == NIL)
1947 elog(ERROR, "failed to build any %d-way joins", level);
1952 * src/backend/optimizer/path/joinrels.c
1953 * static make_rels_by_clause_joins() を流用
1956 * make_join_rel() の呼び出しをラップする、pg_hint_plan_make_join_rel()の呼び出しに変更
1959 * make_rels_by_clause_joins
1960 * Build joins between the given relation 'old_rel' and other relations
1961 * that participate in join clauses that 'old_rel' also participates in
1962 * (or participate in join-order restrictions with it).
1963 * The join rels are returned in root->join_rel_level[join_cur_level].
1965 * Note: at levels above 2 we will generate the same joined relation in
1966 * multiple ways --- for example (a join b) join c is the same RelOptInfo as
1967 * (b join c) join a, though the second case will add a different set of Paths
1968 * to it. This is the reason for using the join_rel_level mechanism, which
1969 * automatically ensures that each new joinrel is only added to the list once.
1971 * 'old_rel' is the relation entry for the relation to be joined
1972 * 'other_rels': the first cell in a linked list containing the other
1973 * rels to be considered for joining
1975 * Currently, this is only used with initial rels in other_rels, but it
1976 * will work for joining to joinrels too.
1979 make_rels_by_clause_joins(PlannerInfo *root,
1980 RelOptInfo *old_rel,
1981 ListCell *other_rels)
1985 for_each_cell(l, other_rels)
1987 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
1989 if (!bms_overlap(old_rel->relids, other_rel->relids) &&
1990 (have_relevant_joinclause(root, old_rel, other_rel) ||
1991 have_join_order_restriction(root, old_rel, other_rel)))
1993 (void) pg_hint_plan_make_join_rel(root, old_rel, other_rel);
1999 * src/backend/optimizer/path/joinrels.c
2000 * static make_rels_by_clauseless_joins() を流用
2003 * make_join_rel() の呼び出しをラップする、pg_hint_plan_make_join_rel()の呼び出しに変更
2006 * make_rels_by_clauseless_joins
2007 * Given a relation 'old_rel' and a list of other relations
2008 * 'other_rels', create a join relation between 'old_rel' and each
2009 * member of 'other_rels' that isn't already included in 'old_rel'.
2010 * The join rels are returned in root->join_rel_level[join_cur_level].
2012 * 'old_rel' is the relation entry for the relation to be joined
2013 * 'other_rels': the first cell of a linked list containing the
2014 * other rels to be considered for joining
2016 * Currently, this is only used with initial rels in other_rels, but it would
2017 * work for joining to joinrels too.
2020 make_rels_by_clauseless_joins(PlannerInfo *root,
2021 RelOptInfo *old_rel,
2022 ListCell *other_rels)
2026 for_each_cell(l, other_rels)
2028 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
2030 if (!bms_overlap(other_rel->relids, old_rel->relids))
2032 (void) pg_hint_plan_make_join_rel(root, old_rel, other_rel);
2038 * src/backend/optimizer/path/joinrels.c
2039 * static has_join_restriction() を流用
2045 * has_join_restriction
2046 * Detect whether the specified relation has join-order restrictions
2047 * due to being inside an outer join or an IN (sub-SELECT).
2049 * Essentially, this tests whether have_join_order_restriction() could
2050 * succeed with this rel and some other one. It's OK if we sometimes
2051 * say "true" incorrectly. (Therefore, we don't bother with the relatively
2052 * expensive has_legal_joinclause test.)
2055 has_join_restriction(PlannerInfo *root, RelOptInfo *rel)
2059 foreach(l, root->join_info_list)
2061 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
2063 /* ignore full joins --- other mechanisms preserve their ordering */
2064 if (sjinfo->jointype == JOIN_FULL)
2067 /* ignore if SJ is already contained in rel */
2068 if (bms_is_subset(sjinfo->min_lefthand, rel->relids) &&
2069 bms_is_subset(sjinfo->min_righthand, rel->relids))
2072 /* restricted if it overlaps LHS or RHS, but doesn't contain SJ */
2073 if (bms_overlap(sjinfo->min_lefthand, rel->relids) ||
2074 bms_overlap(sjinfo->min_righthand, rel->relids))
2082 * src/backend/optimizer/path/allpaths.c
2083 * static set_plain_rel_pathlist() を流用
2089 * set_plain_rel_pathlist
2090 * Build access paths for a plain relation (no subquery, no inheritance)
2093 set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
2095 /* Consider sequential scan */
2096 add_path(rel, create_seqscan_path(root, rel));
2098 /* Consider index scans */
2099 create_index_paths(root, rel);
2101 /* Consider TID scans */
2102 create_tidscan_paths(root, rel);
2104 /* Now find the cheapest of the paths for this rel */