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 *ParseSet(PlanHint *plan, Query *parse, char *keyword, const char *str);
153 static const char *Ordered(PlanHint *plan, Query *parse, char *keyword, const char *str);
156 static void my_join_search_one_level(PlannerInfo *root, int level);
157 static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel, ListCell *other_rels);
158 static void make_rels_by_clauseless_joins(PlannerInfo *root, RelOptInfo *old_rel, ListCell *other_rels);
159 static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
160 static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte);
164 static bool pg_hint_plan_enable = true;
165 static bool pg_hint_plan_debug_print = false;
166 static int pg_hint_plan_parse_message = INFO;
168 static const struct config_enum_entry parse_message_level_options[] = {
169 {"debug", DEBUG2, true},
170 {"debug5", DEBUG5, false},
171 {"debug4", DEBUG4, false},
172 {"debug3", DEBUG3, false},
173 {"debug2", DEBUG2, false},
174 {"debug1", DEBUG1, false},
176 {"info", INFO, false},
177 {"notice", NOTICE, false},
178 {"warning", WARNING, false},
179 {"error", ERROR, false},
181 {"fatal", FATAL, true},
182 {"panic", PANIC, true},
187 /* Saved hook values in case of unload */
188 static planner_hook_type prev_planner_hook = NULL;
189 static get_relation_info_hook_type prev_get_relation_info = NULL;
190 static join_search_hook_type prev_join_search = NULL;
192 /* フック関数をまたがって使用する情報を管理する */
193 static PlanHint *global = NULL;
195 static const HintParser parsers[] = {
196 {HINT_SEQSCAN, true, ParseScanMethod},
197 {HINT_INDEXSCAN, true, ParseIndexScanMethod},
198 {HINT_BITMAPSCAN, true, ParseIndexScanMethod},
199 {HINT_TIDSCAN, true, ParseScanMethod},
200 {HINT_NOSEQSCAN, true, ParseScanMethod},
201 {HINT_NOINDEXSCAN, true, ParseScanMethod},
202 {HINT_NOBITMAPSCAN, true, ParseScanMethod},
203 {HINT_NOTIDSCAN, true, ParseScanMethod},
204 #if PG_VERSION_NUM >= 90200
205 {HINT_INDEXONLYSCAN, true, ParseIndexScanMethod},
206 {HINT_NOINDEXONLYSCAN, true, ParseIndexScanMethod},
208 {HINT_SET, true, ParseSet},
213 * Module load callbacks
218 /* Define custom GUC variables. */
219 DefineCustomBoolVariable("pg_hint_plan.enable",
220 "Instructions or hints to the planner using block comments.",
222 &pg_hint_plan_enable,
230 DefineCustomBoolVariable("pg_hint_plan.debug_print",
231 "Logs each query's parse results of the hint.",
233 &pg_hint_plan_debug_print,
241 DefineCustomEnumVariable("pg_hint_plan.parse_message",
242 "Messege level of the parse error.",
244 &pg_hint_plan_parse_message,
246 parse_message_level_options,
254 prev_planner_hook = planner_hook;
255 planner_hook = pg_hint_plan_planner;
256 prev_get_relation_info = get_relation_info_hook;
257 get_relation_info_hook = pg_hint_plan_get_relation_info;
258 prev_join_search = join_search_hook;
259 join_search_hook = pg_hint_plan_join_search;
263 * Module unload callback
268 /* Uninstall hooks. */
269 planner_hook = prev_planner_hook;
270 get_relation_info_hook = prev_get_relation_info;
271 join_search_hook = prev_join_search;
279 hint = palloc(sizeof(ScanHint));
280 hint->opt_str = NULL;
281 hint->relname = NULL;
282 hint->indexnames = NIL;
283 hint->enforce_mask = 0;
289 ScanHintDelete(ScanHint *hint)
295 pfree(hint->relname);
296 list_free_deep(hint->indexnames);
305 hint = palloc(sizeof(JoinHint));
306 hint->opt_str = NULL;
308 hint->relnames = NULL;
309 hint->enforce_mask = 0;
310 hint->joinrelids = NULL;
316 JoinHintDelete(JoinHint *hint)
325 for (i = 0; i < hint->nrels; i++)
326 pfree(hint->relnames[i]);
327 pfree(hint->relnames);
329 bms_free(hint->joinrelids);
338 hint = palloc(sizeof(SetHint));
346 SetHintDelete(SetHint *hint)
363 hint = palloc(sizeof(PlanHint));
364 hint->hint_str = NULL;
365 hint->nscan_hints = 0;
366 hint->max_scan_hints = 0;
367 hint->scan_hints = NULL;
368 hint->njoin_hints = 0;
369 hint->max_join_hints = 0;
370 hint->join_hints = NULL;
372 hint->join_hint_level = NULL;
374 hint->context = superuser() ? PGC_SUSET : PGC_USERSET;
375 hint->set_hints = NIL;
381 PlanHintDelete(PlanHint *hint)
390 pfree(hint->hint_str);
392 for (i = 0; i < hint->nscan_hints; i++)
393 ScanHintDelete(hint->scan_hints[i]);
394 if (hint->scan_hints)
395 pfree(hint->scan_hints);
397 for (i = 0; i < hint->njoin_hints; i++)
398 JoinHintDelete(hint->join_hints[i]);
399 if (hint->join_hints)
400 pfree(hint->join_hints);
402 for (i = 2; i <= hint->nlevel; i++)
403 list_free(hint->join_hint_level[i]);
404 if (hint->join_hint_level)
405 pfree(hint->join_hint_level);
407 list_free_deep(hint->leading);
409 foreach(l, hint->set_hints)
410 SetHintDelete((SetHint *) lfirst(l));
411 list_free(hint->set_hints);
417 PlanHintIsempty(PlanHint *hint)
419 if (hint->nscan_hints == 0 &&
420 hint->njoin_hints == 0 &&
421 hint->leading == NIL &&
422 hint->set_hints == NIL)
428 // TODO オブジェクト名のクォート処理を追加
430 PlanHintDump(PlanHint *hint)
435 bool is_first = true;
439 elog(INFO, "no hint");
443 initStringInfo(&buf);
444 appendStringInfo(&buf, "/*\n");
445 for (i = 0; i < hint->nscan_hints; i++)
447 ScanHint *h = hint->scan_hints[i];
449 switch(h->enforce_mask)
451 case(ENABLE_SEQSCAN):
452 appendStringInfo(&buf, "%s(", HINT_SEQSCAN);
454 case(ENABLE_INDEXSCAN):
455 appendStringInfo(&buf, "%s(", HINT_INDEXSCAN);
457 case(ENABLE_BITMAPSCAN):
458 appendStringInfo(&buf, "%s(", HINT_BITMAPSCAN);
460 case(ENABLE_TIDSCAN):
461 appendStringInfo(&buf, "%s(", HINT_TIDSCAN);
463 case(ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN | ENABLE_TIDSCAN):
464 appendStringInfo(&buf, "%s(", HINT_NOSEQSCAN);
466 case(ENABLE_SEQSCAN | ENABLE_BITMAPSCAN | ENABLE_TIDSCAN):
467 appendStringInfo(&buf, "%s(", HINT_NOINDEXSCAN);
469 case(ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_TIDSCAN):
470 appendStringInfo(&buf, "%s(", HINT_NOBITMAPSCAN);
472 case(ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN):
473 appendStringInfo(&buf, "%s(", HINT_NOTIDSCAN);
476 appendStringInfoString(&buf, "\?\?\?(");
479 appendStringInfo(&buf, "%s", h->relname);
480 foreach(n, h->indexnames)
481 appendStringInfo(&buf, " %s", (char *) lfirst(n));
482 appendStringInfoString(&buf, ")\n");
485 for (i = 0; i < hint->njoin_hints; i++)
487 JoinHint *h = hint->join_hints[i];
489 switch(h->enforce_mask)
491 case(ENABLE_NESTLOOP):
492 appendStringInfo(&buf, "%s(", HINT_NESTLOOP);
494 case(ENABLE_MERGEJOIN):
495 appendStringInfo(&buf, "%s(", HINT_MERGEJOIN);
497 case(ENABLE_HASHJOIN):
498 appendStringInfo(&buf, "%s(", HINT_HASHJOIN);
500 case(ENABLE_ALL_JOIN ^ ENABLE_NESTLOOP):
501 appendStringInfo(&buf, "%s(", HINT_NONESTLOOP);
503 case(ENABLE_ALL_JOIN ^ ENABLE_MERGEJOIN):
504 appendStringInfo(&buf, "%s(", HINT_NOMERGEJOIN);
506 case(ENABLE_ALL_JOIN ^ ENABLE_HASHJOIN):
507 appendStringInfo(&buf, "%s(", HINT_NOHASHJOIN);
509 case(ENABLE_ALL_JOIN):
512 appendStringInfoString(&buf, "\?\?\?(");
515 appendStringInfo(&buf, "%s", h->relnames[0]);
516 for (i = 1; i < h->nrels; i++)
517 appendStringInfo(&buf, " %s", h->relnames[i]);
518 appendStringInfoString(&buf, ")\n");
521 foreach(l, hint->set_hints)
523 SetHint *h = (SetHint *) lfirst(l);
524 appendStringInfo(&buf, "%s(%s %s)\n", HINT_SET, h->name, h->value);
527 foreach(l, hint->leading)
531 appendStringInfo(&buf, "%s(%s", HINT_LEADING, (char *)lfirst(l));
535 appendStringInfo(&buf, " %s", (char *)lfirst(l));
538 appendStringInfoString(&buf, ")\n");
540 appendStringInfoString(&buf, "*/");
542 elog(INFO, "%s", buf.data);
548 RelnameCmp(const void *a, const void *b)
550 const char *relnamea = *((const char **) a);
551 const char *relnameb = *((const char **) b);
553 return strcmp(relnamea, relnameb);
557 ScanHintCmp(const void *a, const void *b, bool order)
559 const ScanHint *hinta = *((const ScanHint **) a);
560 const ScanHint *hintb = *((const ScanHint **) b);
563 if ((result = strcmp(hinta->relname, hintb->relname)) != 0)
568 return hinta->opt_str - hintb->opt_str;
574 ScanHintCmpIsOrder(const void *a, const void *b)
576 return ScanHintCmp(a, b, true);
580 JoinHintCmp(const void *a, const void *b, bool order)
582 const JoinHint *hinta = *((const JoinHint **) a);
583 const JoinHint *hintb = *((const JoinHint **) b);
585 if (hinta->nrels == hintb->nrels)
588 for (i = 0; i < hinta->nrels; i++)
591 if ((result = strcmp(hinta->relnames[i], hintb->relnames[i])) != 0)
597 return hinta->opt_str - hintb->opt_str;
602 return hinta->nrels - hintb->nrels;
606 JoinHintCmpIsOrder(const void *a, const void *b)
608 return JoinHintCmp(a, b, true);
612 set_config_options(List *options, GucContext context)
618 save_nestlevel = NewGUCNestLevel();
622 SetHint *hint = (SetHint *) lfirst(l);
625 result = set_config_option(hint->name, hint->value, context,
626 PGC_S_SESSION, GUC_ACTION_SAVE, true,
627 pg_hint_plan_parse_message);
630 return save_nestlevel;
633 #define SET_CONFIG_OPTION(name, enforce_mask, type_bits) \
634 set_config_option((name), \
635 ((enforce_mask) & (type_bits)) ? "true" : "false", \
636 context, PGC_S_SESSION, GUC_ACTION_SAVE, true, ERROR)
639 set_join_config_options(unsigned char enforce_mask, GucContext context)
641 SET_CONFIG_OPTION("enable_nestloop", enforce_mask, ENABLE_NESTLOOP);
642 SET_CONFIG_OPTION("enable_mergejoin", enforce_mask, ENABLE_MERGEJOIN);
643 SET_CONFIG_OPTION("enable_hashjoin", enforce_mask, ENABLE_HASHJOIN);
647 set_scan_config_options(unsigned char enforce_mask, GucContext context)
649 SET_CONFIG_OPTION("enable_seqscan", enforce_mask, ENABLE_SEQSCAN);
650 SET_CONFIG_OPTION("enable_indexscan", enforce_mask, ENABLE_INDEXSCAN);
651 SET_CONFIG_OPTION("enable_bitmapscan", enforce_mask, ENABLE_BITMAPSCAN);
652 SET_CONFIG_OPTION("enable_tidscan", enforce_mask, ENABLE_TIDSCAN);
653 #if PG_VERSION_NUM >= 90200
654 SET_CONFIG_OPTION("enable_indexonlyscan", enforce_mask, ENABLE_INDEXSCAN);
663 parse_keyword(const char *str, StringInfo buf)
667 while (!isspace(*str) && *str != '(' && *str != '\0')
668 appendStringInfoChar(buf, *str++);
674 skip_opened_parenthesis(const char *str)
680 parse_ereport(str, ("Opened parenthesis is necessary."));
690 skip_closed_parenthesis(const char *str)
696 parse_ereport(str, ("Closed parenthesis is necessary."));
706 parse_quote_value(const char *str, char **word, char *value_type)
713 initStringInfo(&buf);
724 if (!isalpha(*str) && *str != '_')
727 parse_ereport(str, ("Need for %s to be quoted.", value_type));
732 appendStringInfoCharMacro(&buf, *str++);
742 parse_ereport(str, ("Unterminated quoted %s.", value_type));
748 * TODO エスケープ対象の仕様にあわせた処理を行う。
762 if (!isalnum(*str) && *str != '_' && *str != '$')
766 appendStringInfoCharMacro(&buf, *str++);
772 parse_ereport(str, ("%s is necessary.", value_type));
782 skip_option_delimiter(const char *str)
790 parse_ereport(str, ("Must be specified space."));
798 parse_hints(PlanHint *plan, Query *parse, const char *str)
803 initStringInfo(&buf);
806 const HintParser *parser;
808 /* in error message, we output the comment including the keyword. */
811 /* parse only the keyword of the hint. */
812 resetStringInfo(&buf);
813 str = parse_keyword(str, &buf);
815 for (parser = parsers; parser->keyword != NULL; parser++)
817 char *keyword = parser->keyword;
819 if (strcasecmp(buf.data, keyword) != 0)
822 if (parser->have_paren)
824 /* parser of each hint does parse in a parenthesis. */
825 if ((str = skip_opened_parenthesis(str)) == NULL ||
826 (str = parser->hint_parser(plan, parse, keyword, str)) == NULL ||
827 (str = skip_closed_parenthesis(str)) == NULL)
835 if ((str = parser->hint_parser(plan, parse, keyword, str)) == NULL)
842 * 直前のヒントに括弧の指定がなければ次のヒントの間に空白が必要
844 if (!isspace(*str) && *str == '\0')
845 parse_ereport(str, ("Delimiter of the hint is necessary."));
853 if (parser->keyword == NULL)
855 parse_ereport(head, ("Keyword \"%s\" does not exist.", buf.data));
867 * Do basic parsing of the query head comment.
870 parse_head_comment(Query *parse)
879 /* get client-supplied query string. */
880 p = debug_query_string;
885 /* extract query head comment. */
886 len = strlen(HINT_START);
888 if (strncmp(p, HINT_START, len))
894 if ((tail = strstr(p, HINT_END)) == NULL)
895 elog(ERROR, "unterminated /* comment at or near \"%s\"",
898 /* 入れ子にしたブロックコメントはサポートしない */
899 if ((head = strstr(p, HINT_START)) != NULL && head < tail)
900 parse_ereport(head, ("block comments nest doesn't supported"));
904 head = palloc(len + 1);
905 memcpy(head, p, len);
909 plan = PlanHintCreate();
910 plan->hint_str = head;
912 /* parse each hint. */
913 if (!parse_hints(plan, parse, p))
916 /* 重複したScan条件をを除外する */
917 qsort(plan->scan_hints, plan->nscan_hints, sizeof(ScanHint *), ScanHintCmpIsOrder);
918 for (i = 0; i < plan->nscan_hints - 1;)
920 int result = ScanHintCmp(plan->scan_hints + i,
921 plan->scan_hints + i + 1, false);
926 /* 後で指定したヒントを有効にする */
928 memmove(plan->scan_hints + i, plan->scan_hints + i + 1,
929 sizeof(ScanHint *) * (plan->nscan_hints - i));
933 /* 重複したJoin条件をを除外する */
934 qsort(plan->join_hints, plan->njoin_hints, sizeof(JoinHint *), JoinHintCmpIsOrder);
935 for (i = 0; i < plan->njoin_hints - 1;)
937 int result = JoinHintCmp(plan->join_hints + i,
938 plan->join_hints + i + 1, false);
943 /* 後で指定したヒントを有効にする */
945 memmove(plan->join_hints + i, plan->join_hints + i + 1,
946 sizeof(JoinHint *) * (plan->njoin_hints - i));
954 parse_scan_method(PlanHint *plan, Query *parse, char *keyword, const char *str)
958 hint = ScanHintCreate();
961 if ((str = parse_quote_value(str, &hint->relname, "ralation name")) == NULL)
963 ScanHintDelete(hint);
967 if (strcasecmp(keyword, HINT_SEQSCAN) == 0)
968 hint->enforce_mask = ENABLE_SEQSCAN;
969 else if (strcasecmp(keyword, HINT_INDEXSCAN) == 0)
970 hint->enforce_mask = ENABLE_INDEXSCAN;
971 else if (strcasecmp(keyword, HINT_BITMAPSCAN) == 0)
972 hint->enforce_mask = ENABLE_BITMAPSCAN;
973 else if (strcasecmp(keyword, HINT_TIDSCAN) == 0)
974 hint->enforce_mask = ENABLE_TIDSCAN;
975 else if (strcasecmp(keyword, HINT_NOSEQSCAN) == 0)
976 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_SEQSCAN;
977 else if (strcasecmp(keyword, HINT_NOINDEXSCAN) == 0)
978 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXSCAN;
979 else if (strcasecmp(keyword, HINT_NOBITMAPSCAN) == 0)
980 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_BITMAPSCAN;
981 else if (strcasecmp(keyword, HINT_NOTIDSCAN) == 0)
982 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_TIDSCAN;
985 elog(ERROR, "unrecognized hint keyword \"%s\"", keyword);
989 if (plan->nscan_hints == 0)
991 plan->max_scan_hints = HINT_ARRAY_DEFAULT_INITSIZE;
992 plan->scan_hints = palloc(sizeof(JoinHint *) * plan->max_scan_hints);
994 else if (plan->nscan_hints == plan->max_scan_hints)
996 plan->max_scan_hints *= 2;
997 plan->scan_hints = repalloc(plan->scan_hints,
998 sizeof(JoinHint *) * plan->max_scan_hints);
1001 plan->scan_hints[plan->nscan_hints] = hint;
1002 plan->nscan_hints++;
1008 ParseScanMethod(PlanHint *plan, Query *parse, char *keyword, const char *str)
1012 if ((str = parse_scan_method(plan, parse, keyword, str)) == NULL)
1015 hint = plan->scan_hints[plan->nscan_hints - 1];
1020 parse_ereport(str, ("Closed parenthesis is necessary."));
1021 plan->nscan_hints--;
1022 ScanHintDelete(hint);
1030 ParseIndexScanMethod(PlanHint *plan, Query *parse, char *keyword, const char *str)
1035 if ((str = parse_scan_method(plan, parse, keyword, str)) == NULL)
1038 hint = plan->scan_hints[plan->nscan_hints - 1];
1040 /* インデックス参照をパースする。 */
1043 // TODO 直前のオブジェクト名がクウォート処理されていた場合の処理を実装
1048 if ((str = parse_quote_value(str, &indexname, "index name")) == NULL)
1050 plan->nscan_hints--;
1051 ScanHintDelete(hint);
1055 hint->indexnames = lappend(hint->indexnames, indexname);
1062 ParseSet(PlanHint *plan, Query *parse, char *keyword, const char *str)
1066 hint = SetHintCreate();
1068 if ((str = parse_quote_value(str, &hint->name, "parameter name")) == NULL ||
1069 (str = skip_option_delimiter(str)) == NULL ||
1070 (str = parse_quote_value(str, &hint->value, "parameter value")) == NULL)
1072 SetHintDelete(hint);
1079 parse_ereport(str, ("Closed parenthesis is necessary."));
1080 SetHintDelete(hint);
1083 plan->set_hints = lappend(plan->set_hints, hint);
1090 * Oracle の ORDERD ヒントの実装
1093 Ordered(PlanHint *plan, Query *parse, char *keyword, const char *str)
1097 hint = SetHintCreate();
1098 hint->name = pstrdup("join_collapse_limit");
1099 hint->value = pstrdup("1");
1100 plan->set_hints = lappend(plan->set_hints, hint);
1106 static PlannedStmt *
1107 pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
1110 PlannedStmt *result;
1113 * hintが指定されない、または空のhintを指定された場合は通常のparser処理をお
1115 * 他のフック関数で実行されるhint処理をスキップするために、global 変数をNULL
1118 if (!pg_hint_plan_enable ||
1119 (global = parse_head_comment(parse)) == NULL ||
1120 PlanHintIsempty(global))
1122 PlanHintDelete(global);
1125 if (prev_planner_hook)
1126 return (*prev_planner_hook) (parse, cursorOptions, boundParams);
1128 return standard_planner(parse, cursorOptions, boundParams);
1131 /* Set hint で指定されたGUCパラメータを設定する */
1132 save_nestlevel = set_config_options(global->set_hints, global->context);
1134 if (global->leading != NIL)
1135 set_join_config_options(0, global->context);
1138 * TODO ビュー定義で指定したテーブル数が1つの場合にもこのタイミングでGUCを変更する必
1141 if (list_length(parse->rtable) == 1 &&
1142 ((RangeTblEntry *) linitial(parse->rtable))->rtekind == RTE_RELATION)
1145 RangeTblEntry *rte = linitial(parse->rtable);
1147 for (i = 0; i < global->nscan_hints; i++)
1149 ScanHint *hint = global->scan_hints[i];
1151 if (strcmp(hint->relname, rte->eref->aliasname) != 0)
1152 parse_ereport(hint->opt_str, ("Relation \"%s\" does not exist.", hint->relname));
1154 set_scan_config_options(hint->enforce_mask, global->context);
1158 if (prev_planner_hook)
1159 result = (*prev_planner_hook) (parse, cursorOptions, boundParams);
1161 result = standard_planner(parse, cursorOptions, boundParams);
1164 * Restore the GUC variables we set above.
1166 AtEOXact_GUC(true, save_nestlevel);
1168 if (pg_hint_plan_debug_print)
1170 PlanHintDump(global);
1171 //elog_node_display(INFO, "rtable", parse->rtable, true);
1174 PlanHintDelete(global);
1181 * aliasnameと一致するSCANヒントを探す
1184 find_scan_hint(RangeTblEntry *rte)
1188 for (i = 0; i < global->nscan_hints; i++)
1190 ScanHint *hint = global->scan_hints[i];
1192 if (strcmp(rte->eref->aliasname, hint->relname) == 0)
1200 pg_hint_plan_get_relation_info(PlannerInfo *root, Oid relationObjectId,
1201 bool inhparent, RelOptInfo *rel)
1208 if (prev_get_relation_info)
1209 (*prev_get_relation_info) (root, relationObjectId, inhparent, rel);
1211 /* 有効なヒントが指定されなかった場合は処理をスキップする。 */
1215 if (rel->reloptkind != RELOPT_BASEREL)
1218 if ((hint = find_scan_hint(root->simple_rte_array[rel->relid])) == NULL)
1221 /* インデックスを全て削除し、スキャンに使えなくする */
1222 if (hint->enforce_mask == ENABLE_SEQSCAN)
1224 list_free_deep(rel->indexlist);
1225 rel->indexlist = NIL;
1230 /* 後でパスを作り直すため、ここではなにもしない */
1231 if (hint->indexnames == NULL)
1234 /* 指定されたインデックスのみをのこす */
1236 for (cell = list_head(rel->indexlist); cell; cell = next)
1238 IndexOptInfo *info = (IndexOptInfo *) lfirst(cell);
1239 char *indexname = get_rel_name(info->indexoid);
1241 bool use_index = false;
1245 foreach(l, hint->indexnames)
1247 if (strcmp(indexname, lfirst(l)) == 0)
1255 rel->indexlist = list_delete_cell(rel->indexlist, cell, prev);
1264 scan_relid_aliasname(PlannerInfo *root, char *aliasname, bool check_ambiguous, const char *str)
1266 // TODO refnameRangeTblEntry を参考
1270 for (i = 1; i < root->simple_rel_array_size; i++)
1272 if (root->simple_rel_array[i] == NULL)
1275 Assert(i == root->simple_rel_array[i]->relid);
1277 if (strcmp(aliasname, root->simple_rte_array[i]->eref->aliasname) != 0)
1280 if (!check_ambiguous)
1284 parse_ereport(str, ("relation name \"%s\" is ambiguous", aliasname));
1293 * relidビットマスクと一致するヒントを探す
1296 scan_join_hint(Relids joinrelids)
1301 join_hint = global->join_hint_level[bms_num_members(joinrelids)];
1302 foreach(l, join_hint)
1304 JoinHint *hint = (JoinHint *) lfirst(l);
1305 if (bms_equal(joinrelids, hint->joinrelids))
1313 * ヒントを使用しやすい構造に変換する。
1316 rebuild_join_hints(PlanHint *plan, PlannerInfo *root, int level, List *initial_rels)
1323 plan->nlevel = root->simple_rel_array_size - 1;
1324 plan->join_hint_level = palloc0(sizeof(List *) * (root->simple_rel_array_size));
1325 for (i = 0; i < plan->njoin_hints; i++)
1327 JoinHint *hint = plan->join_hints[i];
1331 for (j = 0; j < hint->nrels; j++)
1333 char *relname = hint->relnames[j];
1335 relid = scan_relid_aliasname(root, relname, true, hint->opt_str);
1338 parse_ereport(hint->opt_str, ("Relation \"%s\" does not exist.", relname));
1342 hint->joinrelids = bms_add_member(hint->joinrelids, relid);
1348 plan->join_hint_level[hint->nrels] =
1349 lappend(plan->join_hint_level[hint->nrels], hint);
1352 /* Leading hint は、全ての join 方式が有効な hint として登録する */
1355 foreach(l, plan->leading)
1357 char *relname = (char *)lfirst(l);
1360 i = scan_relid_aliasname(root, relname, true, plan->hint_str);
1363 parse_ereport(plan->hint_str, ("Relation \"%s\" does not exist.", relname));
1364 list_free_deep(plan->leading);
1365 plan->leading = NIL;
1369 joinrelids = bms_add_member(joinrelids, i);
1375 if (njoinrels > plan->nlevel)
1377 parse_ereport(plan->hint_str, ("In %s hint, specified relation name %d or less.", HINT_LEADING, plan->nlevel));
1381 /* Leading で指定した組み合わせ以外の join hint を削除する */
1382 hint = scan_join_hint(joinrelids);
1383 list_free(plan->join_hint_level[njoinrels]);
1385 plan->join_hint_level[njoinrels] = lappend(NIL, hint);
1388 hint = JoinHintCreate();
1389 hint->nrels = njoinrels;
1390 hint->enforce_mask = ENABLE_ALL_JOIN;
1391 hint->joinrelids = bms_copy(joinrelids);
1392 plan->join_hint_level[njoinrels] = lappend(NIL, hint);
1394 if (plan->njoin_hints == 0)
1396 plan->max_join_hints = HINT_ARRAY_DEFAULT_INITSIZE;
1397 plan->join_hints = palloc(sizeof(JoinHint *) * plan->max_join_hints);
1399 else if (plan->njoin_hints == plan->max_join_hints)
1401 plan->max_join_hints *= 2;
1402 plan->join_hints = repalloc(plan->join_hints,
1403 sizeof(JoinHint *) * plan->max_join_hints);
1406 plan->join_hints[plan->njoin_hints] = hint;
1407 plan->njoin_hints++;
1411 bms_free(joinrelids);
1415 rebuild_scan_path(PlanHint *plan, PlannerInfo *root, int level, List *initial_rels)
1418 int save_nestlevel = 0;
1420 for (i = 0; i < plan->nscan_hints; i++)
1422 ScanHint *hint = plan->scan_hints[i];
1425 if (hint->enforce_mask == ENABLE_SEQSCAN)
1428 foreach(l, initial_rels)
1430 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
1431 RangeTblEntry *rte = root->simple_rte_array[rel->relid];
1433 if (rel->reloptkind != RELOPT_BASEREL ||
1434 strcmp(hint->relname, rte->eref->aliasname) != 0)
1437 if (save_nestlevel != 0)
1438 save_nestlevel = NewGUCNestLevel();
1441 * TODO ヒントで指定されたScan方式が最安価でない場合のみ、Pathを生成
1444 set_scan_config_options(hint->enforce_mask, plan->context);
1446 rel->pathlist = NIL; // TODO 解放
1447 set_plain_rel_pathlist(root, rel, rte);
1454 * Restore the GUC variables we set above.
1456 if (save_nestlevel != 0)
1457 AtEOXact_GUC(true, save_nestlevel);
1461 * src/backend/optimizer/path/joinrels.c
1462 * export make_join_rel() をラップする関数
1464 * ヒントにしたがって、enabele_* パラメータを変更した上で、make_join_rel()を
1468 pg_hint_plan_make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
1475 joinrelids = bms_union(rel1->relids, rel2->relids);
1476 hint = scan_join_hint(joinrelids);
1477 bms_free(joinrelids);
1480 return make_join_rel(root, rel1, rel2);
1482 save_nestlevel = NewGUCNestLevel();
1484 set_join_config_options(hint->enforce_mask, global->context);
1486 rel = make_join_rel(root, rel1, rel2);
1489 * Restore the GUC variables we set above.
1491 AtEOXact_GUC(true, save_nestlevel);
1496 static RelOptInfo *_standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels);
1498 pg_hint_plan_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
1500 /* 有効なヒントが指定されなかった場合は本来の処理を実行する。 */
1503 if (prev_join_search)
1504 return (*prev_join_search) (root, levels_needed, initial_rels);
1505 else if (enable_geqo && levels_needed >= geqo_threshold)
1506 return geqo(root, levels_needed, initial_rels);
1508 return standard_join_search(root, levels_needed, initial_rels);
1511 return _standard_join_search(root, levels_needed, initial_rels);
1515 * PostgreSQL 本体から流用した関数
1519 * src/backend/optimizer/path/allpaths.c
1520 * export standard_join_search() を流用
1523 * rebuild_join_hints() と rebuild_scan_path() の呼び出しを追加
1526 * standard_join_search
1527 * Find possible joinpaths for a query by successively finding ways
1528 * to join component relations into join relations.
1530 * 'levels_needed' is the number of iterations needed, ie, the number of
1531 * independent jointree items in the query. This is > 1.
1533 * 'initial_rels' is a list of RelOptInfo nodes for each independent
1534 * jointree item. These are the components to be joined together.
1535 * Note that levels_needed == list_length(initial_rels).
1537 * Returns the final level of join relations, i.e., the relation that is
1538 * the result of joining all the original relations together.
1539 * At least one implementation path must be provided for this relation and
1540 * all required sub-relations.
1542 * To support loadable plugins that modify planner behavior by changing the
1543 * join searching algorithm, we provide a hook variable that lets a plugin
1544 * replace or supplement this function. Any such hook must return the same
1545 * final join relation as the standard code would, but it might have a
1546 * different set of implementation paths attached, and only the sub-joinrels
1547 * needed for these paths need have been instantiated.
1549 * Note to plugin authors: the functions invoked during standard_join_search()
1550 * modify root->join_rel_list and root->join_rel_hash. If you want to do more
1551 * than one join-order search, you'll probably need to save and restore the
1552 * original states of those data structures. See geqo_eval() for an example.
1555 _standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
1561 * This function cannot be invoked recursively within any one planning
1562 * problem, so join_rel_level[] can't be in use already.
1564 Assert(root->join_rel_level == NULL);
1567 * We employ a simple "dynamic programming" algorithm: we first find all
1568 * ways to build joins of two jointree items, then all ways to build joins
1569 * of three items (from two-item joins and single items), then four-item
1570 * joins, and so on until we have considered all ways to join all the
1571 * items into one rel.
1573 * root->join_rel_level[j] is a list of all the j-item rels. Initially we
1574 * set root->join_rel_level[1] to represent all the single-jointree-item
1577 root->join_rel_level = (List **) palloc0((levels_needed + 1) * sizeof(List *));
1579 root->join_rel_level[1] = initial_rels;
1581 rebuild_join_hints(global, root, levels_needed, initial_rels);
1582 rebuild_scan_path(global, root, levels_needed, initial_rels);
1584 for (lev = 2; lev <= levels_needed; lev++)
1589 * Determine all possible pairs of relations to be joined at this
1590 * level, and build paths for making each one from every available
1591 * pair of lower-level relations.
1593 my_join_search_one_level(root, lev);
1596 * Do cleanup work on each just-processed rel.
1598 foreach(lc, root->join_rel_level[lev])
1600 rel = (RelOptInfo *) lfirst(lc);
1602 /* Find and save the cheapest paths for this rel */
1605 #ifdef OPTIMIZER_DEBUG
1606 debug_print_rel(root, rel);
1612 * We should have a single rel at the final level.
1614 if (root->join_rel_level[levels_needed] == NIL)
1615 elog(ERROR, "failed to build any %d-way joins", levels_needed);
1616 Assert(list_length(root->join_rel_level[levels_needed]) == 1);
1618 rel = (RelOptInfo *) linitial(root->join_rel_level[levels_needed]);
1620 root->join_rel_level = NULL;
1626 * src/backend/optimizer/path/joinrels.c
1627 * join_search_one_level() を流用
1630 * make_join_rel() の呼び出しをラップする、pg_hint_plan_make_join_rel()の呼び出しに変更
1633 * join_search_one_level
1634 * Consider ways to produce join relations containing exactly 'level'
1635 * jointree items. (This is one step of the dynamic-programming method
1636 * embodied in standard_join_search.) Join rel nodes for each feasible
1637 * combination of lower-level rels are created and returned in a list.
1638 * Implementation paths are created for each such joinrel, too.
1640 * level: level of rels we want to make this time
1641 * root->join_rel_level[j], 1 <= j < level, is a list of rels containing j items
1643 * The result is returned in root->join_rel_level[level].
1646 my_join_search_one_level(PlannerInfo *root, int level)
1648 List **joinrels = root->join_rel_level;
1652 Assert(joinrels[level] == NIL);
1654 /* Set join_cur_level so that new joinrels are added to proper list */
1655 root->join_cur_level = level;
1658 * First, consider left-sided and right-sided plans, in which rels of
1659 * exactly level-1 member relations are joined against initial relations.
1660 * We prefer to join using join clauses, but if we find a rel of level-1
1661 * members that has no join clauses, we will generate Cartesian-product
1662 * joins against all initial rels not already contained in it.
1664 * In the first pass (level == 2), we try to join each initial rel to each
1665 * initial rel that appears later in joinrels[1]. (The mirror-image joins
1666 * are handled automatically by make_join_rel.) In later passes, we try
1667 * to join rels of size level-1 from joinrels[level-1] to each initial rel
1670 foreach(r, joinrels[level - 1])
1672 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1673 ListCell *other_rels;
1676 other_rels = lnext(r); /* only consider remaining initial
1679 other_rels = list_head(joinrels[1]); /* consider all initial
1682 if (old_rel->joininfo != NIL || old_rel->has_eclass_joins ||
1683 has_join_restriction(root, old_rel))
1686 * Note that if all available join clauses for this rel require
1687 * more than one other rel, we will fail to make any joins against
1688 * it here. In most cases that's OK; it'll be considered by
1689 * "bushy plan" join code in a higher-level pass where we have
1690 * those other rels collected into a join rel.
1692 * See also the last-ditch case below.
1694 make_rels_by_clause_joins(root,
1701 * Oops, we have a relation that is not joined to any other
1702 * relation, either directly or by join-order restrictions.
1703 * Cartesian product time.
1705 make_rels_by_clauseless_joins(root,
1712 * Now, consider "bushy plans" in which relations of k initial rels are
1713 * joined to relations of level-k initial rels, for 2 <= k <= level-2.
1715 * We only consider bushy-plan joins for pairs of rels where there is a
1716 * suitable join clause (or join order restriction), in order to avoid
1717 * unreasonable growth of planning time.
1721 int other_level = level - k;
1724 * Since make_join_rel(x, y) handles both x,y and y,x cases, we only
1725 * need to go as far as the halfway point.
1727 if (k > other_level)
1730 foreach(r, joinrels[k])
1732 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1733 ListCell *other_rels;
1737 * We can ignore clauseless joins here, *except* when they
1738 * participate in join-order restrictions --- then we might have
1739 * to force a bushy join plan.
1741 if (old_rel->joininfo == NIL && !old_rel->has_eclass_joins &&
1742 !has_join_restriction(root, old_rel))
1745 if (k == other_level)
1746 other_rels = lnext(r); /* only consider remaining rels */
1748 other_rels = list_head(joinrels[other_level]);
1750 for_each_cell(r2, other_rels)
1752 RelOptInfo *new_rel = (RelOptInfo *) lfirst(r2);
1754 if (!bms_overlap(old_rel->relids, new_rel->relids))
1757 * OK, we can build a rel of the right level from this
1758 * pair of rels. Do so if there is at least one usable
1759 * join clause or a relevant join restriction.
1761 if (have_relevant_joinclause(root, old_rel, new_rel) ||
1762 have_join_order_restriction(root, old_rel, new_rel))
1764 (void) pg_hint_plan_make_join_rel(root, old_rel, new_rel);
1772 * Last-ditch effort: if we failed to find any usable joins so far, force
1773 * a set of cartesian-product joins to be generated. This handles the
1774 * special case where all the available rels have join clauses but we
1775 * cannot use any of those clauses yet. An example is
1777 * SELECT * FROM a,b,c WHERE (a.f1 + b.f2 + c.f3) = 0;
1779 * The join clause will be usable at level 3, but at level 2 we have no
1780 * choice but to make cartesian joins. We consider only left-sided and
1781 * right-sided cartesian joins in this case (no bushy).
1783 if (joinrels[level] == NIL)
1786 * This loop is just like the first one, except we always call
1787 * make_rels_by_clauseless_joins().
1789 foreach(r, joinrels[level - 1])
1791 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1792 ListCell *other_rels;
1795 other_rels = lnext(r); /* only consider remaining initial
1798 other_rels = list_head(joinrels[1]); /* consider all initial
1801 make_rels_by_clauseless_joins(root,
1807 * When special joins are involved, there may be no legal way
1808 * to make an N-way join for some values of N. For example consider
1810 * SELECT ... FROM t1 WHERE
1811 * x IN (SELECT ... FROM t2,t3 WHERE ...) AND
1812 * y IN (SELECT ... FROM t4,t5 WHERE ...)
1814 * We will flatten this query to a 5-way join problem, but there are
1815 * no 4-way joins that join_is_legal() will consider legal. We have
1816 * to accept failure at level 4 and go on to discover a workable
1817 * bushy plan at level 5.
1819 * However, if there are no special joins then join_is_legal() should
1820 * never fail, and so the following sanity check is useful.
1823 if (joinrels[level] == NIL && root->join_info_list == NIL)
1824 elog(ERROR, "failed to build any %d-way joins", level);
1829 * src/backend/optimizer/path/joinrels.c
1830 * static make_rels_by_clause_joins() を流用
1833 * make_join_rel() の呼び出しをラップする、pg_hint_plan_make_join_rel()の呼び出しに変更
1836 * make_rels_by_clause_joins
1837 * Build joins between the given relation 'old_rel' and other relations
1838 * that participate in join clauses that 'old_rel' also participates in
1839 * (or participate in join-order restrictions with it).
1840 * The join rels are returned in root->join_rel_level[join_cur_level].
1842 * Note: at levels above 2 we will generate the same joined relation in
1843 * multiple ways --- for example (a join b) join c is the same RelOptInfo as
1844 * (b join c) join a, though the second case will add a different set of Paths
1845 * to it. This is the reason for using the join_rel_level mechanism, which
1846 * automatically ensures that each new joinrel is only added to the list once.
1848 * 'old_rel' is the relation entry for the relation to be joined
1849 * 'other_rels': the first cell in a linked list containing the other
1850 * rels to be considered for joining
1852 * Currently, this is only used with initial rels in other_rels, but it
1853 * will work for joining to joinrels too.
1856 make_rels_by_clause_joins(PlannerInfo *root,
1857 RelOptInfo *old_rel,
1858 ListCell *other_rels)
1862 for_each_cell(l, other_rels)
1864 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
1866 if (!bms_overlap(old_rel->relids, other_rel->relids) &&
1867 (have_relevant_joinclause(root, old_rel, other_rel) ||
1868 have_join_order_restriction(root, old_rel, other_rel)))
1870 (void) pg_hint_plan_make_join_rel(root, old_rel, other_rel);
1876 * src/backend/optimizer/path/joinrels.c
1877 * static make_rels_by_clauseless_joins() を流用
1880 * make_join_rel() の呼び出しをラップする、pg_hint_plan_make_join_rel()の呼び出しに変更
1883 * make_rels_by_clauseless_joins
1884 * Given a relation 'old_rel' and a list of other relations
1885 * 'other_rels', create a join relation between 'old_rel' and each
1886 * member of 'other_rels' that isn't already included in 'old_rel'.
1887 * The join rels are returned in root->join_rel_level[join_cur_level].
1889 * 'old_rel' is the relation entry for the relation to be joined
1890 * 'other_rels': the first cell of a linked list containing the
1891 * other rels to be considered for joining
1893 * Currently, this is only used with initial rels in other_rels, but it would
1894 * work for joining to joinrels too.
1897 make_rels_by_clauseless_joins(PlannerInfo *root,
1898 RelOptInfo *old_rel,
1899 ListCell *other_rels)
1903 for_each_cell(l, other_rels)
1905 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
1907 if (!bms_overlap(other_rel->relids, old_rel->relids))
1909 (void) pg_hint_plan_make_join_rel(root, old_rel, other_rel);
1915 * src/backend/optimizer/path/joinrels.c
1916 * static has_join_restriction() を流用
1922 * has_join_restriction
1923 * Detect whether the specified relation has join-order restrictions
1924 * due to being inside an outer join or an IN (sub-SELECT).
1926 * Essentially, this tests whether have_join_order_restriction() could
1927 * succeed with this rel and some other one. It's OK if we sometimes
1928 * say "true" incorrectly. (Therefore, we don't bother with the relatively
1929 * expensive has_legal_joinclause test.)
1932 has_join_restriction(PlannerInfo *root, RelOptInfo *rel)
1936 foreach(l, root->join_info_list)
1938 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
1940 /* ignore full joins --- other mechanisms preserve their ordering */
1941 if (sjinfo->jointype == JOIN_FULL)
1944 /* ignore if SJ is already contained in rel */
1945 if (bms_is_subset(sjinfo->min_lefthand, rel->relids) &&
1946 bms_is_subset(sjinfo->min_righthand, rel->relids))
1949 /* restricted if it overlaps LHS or RHS, but doesn't contain SJ */
1950 if (bms_overlap(sjinfo->min_lefthand, rel->relids) ||
1951 bms_overlap(sjinfo->min_righthand, rel->relids))
1959 * src/backend/optimizer/path/allpaths.c
1960 * static set_plain_rel_pathlist() を流用
1966 * set_plain_rel_pathlist
1967 * Build access paths for a plain relation (no subquery, no inheritance)
1970 set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1972 /* Consider sequential scan */
1973 add_path(rel, create_seqscan_path(root, rel));
1975 /* Consider index scans */
1976 create_index_paths(root, rel);
1978 /* Consider TID scans */
1979 create_tidscan_paths(root, rel);
1981 /* Now find the cheapest of the paths for this rel */