OSDN Git Service

Scan方式制御機能を追加
[pghintplan/pg_hint_plan.git] / pg_hint_plan.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_hint_plan.c
4  *                do instructions or hints to the planner using C-style block comments
5  *                of the SQL.
6  *
7  * Copyright (c) 2012, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
8  *
9  *-------------------------------------------------------------------------
10  */
11 #include "postgres.h"
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"
21
22 #ifdef PG_MODULE_MAGIC
23 PG_MODULE_MAGIC;
24 #endif
25
26 #if PG_VERSION_NUM != 90200
27 #error unsupported PostgreSQL version
28 #endif
29
30 #define HINT_START      "/*"
31 #define HINT_END        "*/"
32
33 /* hint keywords */
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"
50
51 #if PG_VERSION_NUM >= 90200
52 #define HINT_INDEXONLYSCAN              "IndexonlyScan"
53 #define HINT_NOINDEXONLYSCAN    "NoIndexonlyScan"
54 #endif
55
56 #define HINT_ARRAY_DEFAULT_INITSIZE 8
57
58 #define parse_ereport(str, detail) \
59         ereport(pg_hint_plan_parse_message, \
60                         (errmsg("hint syntax error at or near \"%s\"", (str)), \
61                          errdetail detail))
62
63 #define skip_space(str) \
64         while (isspace(*str)) \
65                 str++;
66
67 enum
68 {
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
76 } TYPE_BITS;
77
78 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN \
79                                                 | ENABLE_TIDSCAN)
80 #define ENABLE_ALL_JOIN (ENABLE_NESTLOOP | ENABLE_MERGEJOIN | ENABLE_HASHJOIN)
81
82 /* scan method hints */
83 typedef struct ScanHint
84 {
85         const char         *opt_str;            /* must not do pfree */
86         char               *relname;
87         List               *indexnames;
88         unsigned char   enforce_mask;
89 } ScanHint;
90
91 /* join method hints */
92 typedef struct JoinHint
93 {
94         const char         *opt_str;            /* must not do pfree */
95         int                             nrels;
96         char              **relnames;
97         unsigned char   enforce_mask;
98         Relids                  joinrelids;
99 } JoinHint;
100
101 /* change a run-time parameter hints */
102 typedef struct SetHint
103 {
104         char   *name;                           /* name of variable */
105         char   *value;
106 } SetHint;
107
108 typedef struct PlanHint
109 {
110         char       *hint_str;
111
112         int                     nscan_hints;
113         int                     max_scan_hints;
114         ScanHint  **scan_hints;
115
116         int                     njoin_hints;
117         int                     max_join_hints;
118         JoinHint  **join_hints;
119
120         int                     nlevel;
121         List      **join_hint_level;
122
123         List       *leading;
124
125         GucContext      context;
126         List       *set_hints;
127 } PlanHint;
128
129 typedef const char *(*HintParserFunction) (PlanHint *plan, Query *parse, char *keyword, const char *str);
130
131 typedef struct HintParser
132 {
133         char   *keyword;
134         bool    have_paren;
135         HintParserFunction      hint_parser;
136 } HintParser;
137
138 /* Module callbacks */
139 void            _PG_init(void);
140 void            _PG_fini(void);
141
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,
147                                                                   List *initial_rels);
148
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);
152 #ifdef NOT_USED
153 static const char *Ordered(PlanHint *plan, Query *parse, char *keyword, const char *str);
154 #endif
155
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);
161
162
163 /* GUC variables */
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;
167
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},
175         {"log", LOG, false},
176         {"info", INFO, false},
177         {"notice", NOTICE, false},
178         {"warning", WARNING, false},
179         {"error", ERROR, false},
180         /*
181         {"fatal", FATAL, true},
182         {"panic", PANIC, true},
183          */
184         {NULL, 0, false}
185 };
186
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;
191
192 /* フック関数をまたがって使用する情報を管理する */
193 static PlanHint *global = NULL;
194
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},
207 #endif
208         {HINT_SET, true, ParseSet},
209         {NULL, false, NULL},
210 };
211
212 /*
213  * Module load callbacks
214  */
215 void
216 _PG_init(void)
217 {
218         /* Define custom GUC variables. */
219         DefineCustomBoolVariable("pg_hint_plan.enable",
220                          "Instructions or hints to the planner using block comments.",
221                                                          NULL,
222                                                          &pg_hint_plan_enable,
223                                                          true,
224                                                          PGC_USERSET,
225                                                          0,
226                                                          NULL,
227                                                          NULL,
228                                                          NULL);
229
230         DefineCustomBoolVariable("pg_hint_plan.debug_print",
231                                                          "Logs each query's parse results of the hint.",
232                                                          NULL,
233                                                          &pg_hint_plan_debug_print,
234                                                          false,
235                                                          PGC_USERSET,
236                                                          0,
237                                                          NULL,
238                                                          NULL,
239                                                          NULL);
240
241         DefineCustomEnumVariable("pg_hint_plan.parse_message",
242                                                          "Messege level of the parse error.",
243                                                          NULL,
244                                                          &pg_hint_plan_parse_message,
245                                                          INFO,
246                                                          parse_message_level_options,
247                                                          PGC_USERSET,
248                                                          0,
249                                                          NULL,
250                                                          NULL,
251                                                          NULL);
252
253         /* Install hooks. */
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;
260 }
261
262 /*
263  * Module unload callback
264  */
265 void
266 _PG_fini(void)
267 {
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;
272 }
273
274 static ScanHint *
275 ScanHintCreate(void)
276 {
277         ScanHint           *hint;
278
279         hint = palloc(sizeof(ScanHint));
280         hint->opt_str = NULL;
281         hint->relname = NULL;
282         hint->indexnames = NIL;
283         hint->enforce_mask = 0;
284
285         return hint;
286 }
287
288 static void
289 ScanHintDelete(ScanHint *hint)
290 {
291         if (!hint)
292                 return;
293
294         if (hint->relname)
295                 pfree(hint->relname);
296         list_free_deep(hint->indexnames);
297         pfree(hint);
298 }
299
300 static JoinHint *
301 JoinHintCreate(void)
302 {
303         JoinHint   *hint;
304
305         hint = palloc(sizeof(JoinHint));
306         hint->opt_str = NULL;
307         hint->nrels = 0;
308         hint->relnames = NULL;
309         hint->enforce_mask = 0;
310         hint->joinrelids = NULL;
311
312         return hint;
313 }
314
315 static void
316 JoinHintDelete(JoinHint *hint)
317 {
318         if (!hint)
319                 return;
320
321         if (hint->relnames)
322         {
323                 int     i;
324
325                 for (i = 0; i < hint->nrels; i++)
326                         pfree(hint->relnames[i]);
327                 pfree(hint->relnames);
328         }
329         bms_free(hint->joinrelids);
330         pfree(hint);
331 }
332
333 static SetHint *
334 SetHintCreate(void)
335 {
336         SetHint    *hint;
337
338         hint = palloc(sizeof(SetHint));
339         hint->name = NULL;
340         hint->value = NULL;
341
342         return hint;
343 }
344
345 static void
346 SetHintDelete(SetHint *hint)
347 {
348         if (!hint)
349                 return;
350
351         if (hint->name)
352                 pfree(hint->name);
353         if (hint->value)
354                 pfree(hint->value);
355         pfree(hint);
356 }
357
358 static PlanHint *
359 PlanHintCreate(void)
360 {
361         PlanHint   *hint;
362
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;
371         hint->nlevel = 0;
372         hint->join_hint_level = NULL;
373         hint->leading = NIL;
374         hint->context = superuser() ? PGC_SUSET : PGC_USERSET;
375         hint->set_hints = NIL;
376
377         return hint;
378 }
379
380 static void
381 PlanHintDelete(PlanHint *hint)
382 {
383         ListCell   *l;
384         int                     i;
385
386         if (!hint)
387                 return;
388
389         if (hint->hint_str)
390                 pfree(hint->hint_str);
391
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);
396
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);
401
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);
406
407         list_free_deep(hint->leading);
408
409         foreach(l, hint->set_hints)
410                 SetHintDelete((SetHint *) lfirst(l));
411         list_free(hint->set_hints);
412
413         pfree(hint);
414 }
415
416 static bool
417 PlanHintIsempty(PlanHint *hint)
418 {
419         if (hint->nscan_hints == 0 &&
420                 hint->njoin_hints == 0 &&
421                 hint->leading == NIL &&
422                 hint->set_hints == NIL)
423                 return true;
424
425         return false;
426 }
427
428 // TODO オブジェクト名のクォート処理を追加
429 static void
430 PlanHintDump(PlanHint *hint)
431 {
432         StringInfoData  buf;
433         ListCell           *l;
434         int                             i;
435         bool                    is_first = true;
436
437         if (!hint)
438         {
439                 elog(INFO, "no hint");
440                 return;
441         }
442
443         initStringInfo(&buf);
444         appendStringInfo(&buf, "/*\n");
445         for (i = 0; i < hint->nscan_hints; i++)
446         {
447                 ScanHint   *h = hint->scan_hints[i];
448                 ListCell   *n;
449                 switch(h->enforce_mask)
450                 {
451                         case(ENABLE_SEQSCAN):
452                                 appendStringInfo(&buf, "%s(", HINT_SEQSCAN);
453                                 break;
454                         case(ENABLE_INDEXSCAN):
455                                 appendStringInfo(&buf, "%s(", HINT_INDEXSCAN);
456                                 break;
457                         case(ENABLE_BITMAPSCAN):
458                                 appendStringInfo(&buf, "%s(", HINT_BITMAPSCAN);
459                                 break;
460                         case(ENABLE_TIDSCAN):
461                                 appendStringInfo(&buf, "%s(", HINT_TIDSCAN);
462                                 break;
463                         case(ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN | ENABLE_TIDSCAN):
464                                 appendStringInfo(&buf, "%s(", HINT_NOSEQSCAN);
465                                 break;
466                         case(ENABLE_SEQSCAN | ENABLE_BITMAPSCAN | ENABLE_TIDSCAN):
467                                 appendStringInfo(&buf, "%s(", HINT_NOINDEXSCAN);
468                                 break;
469                         case(ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_TIDSCAN):
470                                 appendStringInfo(&buf, "%s(", HINT_NOBITMAPSCAN);
471                                 break;
472                         case(ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN):
473                                 appendStringInfo(&buf, "%s(", HINT_NOTIDSCAN);
474                                 break;
475                         default:
476                                 appendStringInfoString(&buf, "\?\?\?(");
477                                 break;
478                 }
479                 appendStringInfo(&buf, "%s", h->relname);
480                 foreach(n, h->indexnames)
481                         appendStringInfo(&buf, " %s", (char *) lfirst(n));
482                 appendStringInfoString(&buf, ")\n");
483         }
484
485         for (i = 0; i < hint->njoin_hints; i++)
486         {
487                 JoinHint   *h = hint->join_hints[i];
488                 int                     i;
489                 switch(h->enforce_mask)
490                 {
491                         case(ENABLE_NESTLOOP):
492                                 appendStringInfo(&buf, "%s(", HINT_NESTLOOP);
493                                 break;
494                         case(ENABLE_MERGEJOIN):
495                                 appendStringInfo(&buf, "%s(", HINT_MERGEJOIN);
496                                 break;
497                         case(ENABLE_HASHJOIN):
498                                 appendStringInfo(&buf, "%s(", HINT_HASHJOIN);
499                                 break;
500                         case(ENABLE_ALL_JOIN ^ ENABLE_NESTLOOP):
501                                 appendStringInfo(&buf, "%s(", HINT_NONESTLOOP);
502                                 break;
503                         case(ENABLE_ALL_JOIN ^ ENABLE_MERGEJOIN):
504                                 appendStringInfo(&buf, "%s(", HINT_NOMERGEJOIN);
505                                 break;
506                         case(ENABLE_ALL_JOIN ^ ENABLE_HASHJOIN):
507                                 appendStringInfo(&buf, "%s(", HINT_NOHASHJOIN);
508                                 break;
509                         case(ENABLE_ALL_JOIN):
510                                 continue;
511                         default:
512                                 appendStringInfoString(&buf, "\?\?\?(");
513                                 break;
514                 }
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");
519         }
520
521         foreach(l, hint->set_hints)
522         {
523                 SetHint    *h = (SetHint *) lfirst(l);
524                 appendStringInfo(&buf, "%s(%s %s)\n", HINT_SET, h->name, h->value);
525         }
526
527         foreach(l, hint->leading)
528         {
529                 if (is_first)
530                 {
531                         appendStringInfo(&buf, "%s(%s", HINT_LEADING, (char *)lfirst(l));
532                         is_first = false;
533                 }
534                 else
535                         appendStringInfo(&buf, " %s", (char *)lfirst(l));
536         }
537         if (!is_first)
538                 appendStringInfoString(&buf, ")\n");
539
540         appendStringInfoString(&buf, "*/");
541
542         elog(INFO, "%s", buf.data);
543
544         pfree(buf.data);
545 }
546
547 static int
548 RelnameCmp(const void *a, const void *b)
549 {
550         const char *relnamea = *((const char **) a);
551         const char *relnameb = *((const char **) b);
552
553         return strcmp(relnamea, relnameb);
554 }
555
556 static int
557 ScanHintCmp(const void *a, const void *b, bool order)
558 {
559         const ScanHint     *hinta = *((const ScanHint **) a);
560         const ScanHint     *hintb = *((const ScanHint **) b);
561         int                                     result;
562
563         if ((result = strcmp(hinta->relname, hintb->relname)) != 0)
564                 return result;
565
566         /* ヒント句で指定した順を返す */
567         if (order)
568                 return hinta->opt_str - hintb->opt_str;
569         else
570                 return 0;
571 }
572
573 static int
574 ScanHintCmpIsOrder(const void *a, const void *b)
575 {
576         return ScanHintCmp(a, b, true);
577 }
578
579 static int
580 JoinHintCmp(const void *a, const void *b, bool order)
581 {
582         const JoinHint     *hinta = *((const JoinHint **) a);
583         const JoinHint     *hintb = *((const JoinHint **) b);
584
585         if (hinta->nrels == hintb->nrels)
586         {
587                 int     i;
588                 for (i = 0; i < hinta->nrels; i++)
589                 {
590                         int     result;
591                         if ((result = strcmp(hinta->relnames[i], hintb->relnames[i])) != 0)
592                                 return result;
593                 }
594
595                 /* ヒント句で指定した順を返す */
596                 if (order)
597                         return hinta->opt_str - hintb->opt_str;
598                 else
599                         return 0;
600         }
601
602         return hinta->nrels - hintb->nrels;
603 }
604
605 static int
606 JoinHintCmpIsOrder(const void *a, const void *b)
607 {
608         return JoinHintCmp(a, b, true);
609 }
610
611 static int
612 set_config_options(List *options, GucContext context)
613 {
614         ListCell   *l;
615         int                     save_nestlevel;
616         int                     result = 1;
617
618         save_nestlevel = NewGUCNestLevel();
619
620         foreach(l, options)
621         {
622                 SetHint    *hint = (SetHint *) lfirst(l);
623
624                 if (result > 0)
625                         result = set_config_option(hint->name, hint->value, context,
626                                                 PGC_S_SESSION, GUC_ACTION_SAVE, true,
627                                                 pg_hint_plan_parse_message);
628         }
629
630         return save_nestlevel;
631 }
632
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)
637
638 static void
639 set_join_config_options(unsigned char enforce_mask, GucContext context)
640 {
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);
644 }
645
646 static void
647 set_scan_config_options(unsigned char enforce_mask, GucContext context)
648 {
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);
655 #endif
656 }
657
658 /*
659  * parse functions
660  */
661
662 static const char *
663 parse_keyword(const char *str, StringInfo buf)
664 {
665         skip_space(str);
666
667         while (!isspace(*str) && *str != '(' && *str != '\0')
668                 appendStringInfoChar(buf, *str++);
669
670         return str;
671 }
672
673 static const char *
674 skip_opened_parenthesis(const char *str)
675 {
676         skip_space(str);
677
678         if (*str != '(')
679         {
680                 parse_ereport(str, ("Opened parenthesis is necessary."));
681                 return NULL;
682         }
683
684         str++;
685
686         return str;
687 }
688
689 static const char *
690 skip_closed_parenthesis(const char *str)
691 {
692         skip_space(str);
693
694         if (*str != ')')
695         {
696                 parse_ereport(str, ("Closed parenthesis is necessary."));
697                 return NULL;
698         }
699
700         str++;
701
702         return str;
703 }
704
705 static const char *
706 parse_quote_value(const char *str, char **word, char *value_type)
707 {
708         StringInfoData  buf;
709         bool                    in_quote;
710
711         skip_space(str);
712
713         initStringInfo(&buf);
714         if (*str == '"')
715         {
716                 str++;
717                 in_quote = true;
718         }
719         else
720         {
721                 /*
722                  * 1文字目以降の制限の適用
723                  */
724                 if (!isalpha(*str) && *str != '_')
725                 {
726                         pfree(buf.data);
727                         parse_ereport(str, ("Need for %s to be quoted.", value_type));
728                         return NULL;
729                 }
730
731                 in_quote = false;
732                 appendStringInfoCharMacro(&buf, *str++);
733         }
734
735         while (true)
736         {
737                 if (in_quote)
738                 {
739                         if (*str == '\0')
740                         {
741                                 pfree(buf.data);
742                                 parse_ereport(str, ("Unterminated quoted %s.", value_type));
743                                 return NULL;
744                         }
745
746                         /*
747                          * エスケープ対象をスキップする。
748                          * TODO エスケープ対象の仕様にあわせた処理を行う。
749                          */
750                         if(*str == '"')
751                         {
752                                 str++;
753                                 if (*str != '"')
754                                         break;
755                         }
756                 }
757                 else
758                 {
759                         /*
760                          * 2文字目以降の制限の適用
761                          */
762                         if (!isalnum(*str) && *str != '_' && *str != '$')
763                                 break;
764                 }
765
766                 appendStringInfoCharMacro(&buf, *str++);
767         }
768
769         if (buf.len == 0)
770         {
771                 pfree(buf.data);
772                 parse_ereport(str, ("%s is necessary.", value_type));
773                 return NULL;
774         }
775
776         *word = buf.data;
777
778         return str;
779 }
780
781 static const char *
782 skip_option_delimiter(const char *str)
783 {
784         const char *p = str;
785
786         skip_space(str);
787
788         if (str == p)
789         {
790                 parse_ereport(str, ("Must be specified space."));
791                 return NULL;
792         }
793
794         return str;
795 }
796
797 static bool
798 parse_hints(PlanHint *plan, Query *parse, const char *str)
799 {
800         StringInfoData  buf;
801         char               *head;
802
803         initStringInfo(&buf);
804         while (*str != '\0')
805         {
806                 const HintParser *parser;
807
808                 /* in error message, we output the comment including the keyword. */
809                 head = (char *) str;
810
811                 /* parse only the keyword of the hint. */
812                 resetStringInfo(&buf);
813                 str = parse_keyword(str, &buf);
814
815                 for (parser = parsers; parser->keyword != NULL; parser++)
816                 {
817                         char   *keyword = parser->keyword;
818
819                         if (strcasecmp(buf.data, keyword) != 0)
820                                 continue;
821
822                         if (parser->have_paren)
823                         {
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)
828                                 {
829                                         pfree(buf.data);
830                                         return false;
831                                 }
832                         }
833                         else
834                         {
835                                 if ((str = parser->hint_parser(plan, parse, keyword, str)) == NULL)
836                                 {
837                                         pfree(buf.data);
838                                         return false;
839                                 }
840
841                                 /*
842                                  * 直前のヒントに括弧の指定がなければ次のヒントの間に空白が必要
843                                  */
844                                 if (!isspace(*str) && *str == '\0')
845                                         parse_ereport(str, ("Delimiter of the hint is necessary."));
846                         }
847
848                         skip_space(str);
849
850                         break;
851                 }
852
853                 if (parser->keyword == NULL)
854                 {
855                         parse_ereport(head, ("Keyword \"%s\" does not exist.", buf.data));
856                         pfree(buf.data);
857                         return false;
858                 }
859         }
860
861         pfree(buf.data);
862
863         return true;
864 }
865
866 /*
867  * Do basic parsing of the query head comment.
868  */
869 static PlanHint *
870 parse_head_comment(Query *parse)
871 {
872         const char         *p;
873         char               *head;
874         char               *tail;
875         int                             len;
876         int                             i;
877         PlanHint           *plan;
878
879         /* get client-supplied query string. */
880         p = debug_query_string;
881         if (p == NULL)
882                 return NULL;
883
884
885         /* extract query head comment. */
886         len = strlen(HINT_START);
887         skip_space(p);
888         if (strncmp(p, HINT_START, len))
889                 return NULL;
890
891         p += len;
892         skip_space(p);
893
894         if ((tail = strstr(p, HINT_END)) == NULL)
895                 elog(ERROR, "unterminated /* comment at or near \"%s\"",
896                          debug_query_string);
897
898         /* 入れ子にしたブロックコメントはサポートしない */
899         if ((head = strstr(p, HINT_START)) != NULL && head < tail)
900                 parse_ereport(head, ("block comments nest doesn't supported"));
901
902         /* ヒント句部分を切り出す */
903         len = tail - p;
904         head = palloc(len + 1);
905         memcpy(head, p, len);
906         head[len] = '\0';
907         p = head;
908
909         plan = PlanHintCreate();
910         plan->hint_str = head;
911
912         /* parse each hint. */
913         if (!parse_hints(plan, parse, p))
914                 return plan;
915
916         /* 重複したScan条件をを除外する */
917         qsort(plan->scan_hints, plan->nscan_hints, sizeof(ScanHint *), ScanHintCmpIsOrder);
918         for (i = 0; i < plan->nscan_hints - 1;)
919         {
920                 int     result = ScanHintCmp(plan->scan_hints + i,
921                                                 plan->scan_hints + i + 1, false);
922                 if (result != 0)
923                         i++;
924                 else
925                 {
926                         /* 後で指定したヒントを有効にする */
927                         plan->nscan_hints--;
928                         memmove(plan->scan_hints + i, plan->scan_hints + i + 1,
929                                         sizeof(ScanHint *) * (plan->nscan_hints - i));
930                 }
931         }
932
933         /* 重複したJoin条件をを除外する */
934         qsort(plan->join_hints, plan->njoin_hints, sizeof(JoinHint *), JoinHintCmpIsOrder);
935         for (i = 0; i < plan->njoin_hints - 1;)
936         {
937                 int     result = JoinHintCmp(plan->join_hints + i,
938                                                 plan->join_hints + i + 1, false);
939                 if (result != 0)
940                         i++;
941                 else
942                 {
943                         /* 後で指定したヒントを有効にする */
944                         plan->njoin_hints--;
945                         memmove(plan->join_hints + i, plan->join_hints + i + 1,
946                                         sizeof(JoinHint *) * (plan->njoin_hints - i));
947                 }
948         }
949
950         return plan;
951 }
952
953 static const char *
954 parse_scan_method(PlanHint *plan, Query *parse, char *keyword, const char *str)
955 {
956         ScanHint   *hint;
957
958         hint = ScanHintCreate();
959         hint->opt_str = str;
960
961         if ((str = parse_quote_value(str, &hint->relname, "ralation name")) == NULL)
962         {
963                 ScanHintDelete(hint);
964                 return NULL;
965         }
966
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;
983         else
984         {
985                 elog(ERROR, "unrecognized hint keyword \"%s\"", keyword);
986                 return NULL;
987         }
988
989         if (plan->nscan_hints == 0)
990         {
991                 plan->max_scan_hints = HINT_ARRAY_DEFAULT_INITSIZE;
992                 plan->scan_hints = palloc(sizeof(JoinHint *) * plan->max_scan_hints);
993         }
994         else if (plan->nscan_hints == plan->max_scan_hints)
995         {
996                 plan->max_scan_hints *= 2;
997                 plan->scan_hints = repalloc(plan->scan_hints,
998                                                                 sizeof(JoinHint *) * plan->max_scan_hints);
999         }
1000
1001         plan->scan_hints[plan->nscan_hints] = hint;
1002         plan->nscan_hints++;
1003
1004         return str;
1005 }
1006
1007 static const char *
1008 ParseScanMethod(PlanHint *plan, Query *parse, char *keyword, const char *str)
1009 {
1010         ScanHint   *hint;
1011
1012         if ((str = parse_scan_method(plan, parse, keyword, str)) == NULL)
1013                 return NULL;
1014
1015         hint = plan->scan_hints[plan->nscan_hints - 1];
1016
1017         skip_space(str);
1018         if (*str != ')')
1019         {
1020                 parse_ereport(str, ("Closed parenthesis is necessary."));
1021                 plan->nscan_hints--;
1022                 ScanHintDelete(hint);
1023                 return NULL;
1024         }
1025
1026         return str;
1027 }
1028
1029 static const char *
1030 ParseIndexScanMethod(PlanHint *plan, Query *parse, char *keyword, const char *str)
1031 {
1032         char       *indexname;
1033         ScanHint   *hint;
1034
1035         if ((str = parse_scan_method(plan, parse, keyword, str)) == NULL)
1036                 return NULL;
1037
1038         hint = plan->scan_hints[plan->nscan_hints - 1];
1039
1040         /* インデックス参照をパースする。 */
1041         while (true)
1042         {
1043                 // TODO 直前のオブジェクト名がクウォート処理されていた場合の処理を実装
1044                 skip_space(str);
1045                 if (*str == ')')
1046                         break;
1047
1048                 if ((str = parse_quote_value(str, &indexname, "index name")) == NULL)
1049                 {
1050                         plan->nscan_hints--;
1051                         ScanHintDelete(hint);
1052                         return NULL;
1053                 }
1054
1055                 hint->indexnames = lappend(hint->indexnames, indexname);
1056         }
1057
1058         return str;
1059 }
1060
1061 static const char *
1062 ParseSet(PlanHint *plan, Query *parse, char *keyword, const char *str)
1063 {
1064         SetHint    *hint;
1065
1066         hint = SetHintCreate();
1067
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)
1071         {
1072                 SetHintDelete(hint);
1073                 return NULL;
1074         }
1075
1076         skip_space(str);
1077         if (*str != ')')
1078         {
1079                 parse_ereport(str, ("Closed parenthesis is necessary."));
1080                 SetHintDelete(hint);
1081                 return NULL;
1082         }
1083         plan->set_hints = lappend(plan->set_hints, hint);
1084
1085         return str;
1086 }
1087
1088 #ifdef NOT_USED
1089 /*
1090  * Oracle の ORDERD ヒントの実装
1091  */
1092 static const char *
1093 Ordered(PlanHint *plan, Query *parse, char *keyword, const char *str)
1094 {
1095         SetHint    *hint;
1096
1097         hint = SetHintCreate();
1098         hint->name = pstrdup("join_collapse_limit");
1099         hint->value = pstrdup("1");
1100         plan->set_hints = lappend(plan->set_hints, hint);
1101
1102         return str;
1103 }
1104 #endif
1105
1106 static PlannedStmt *
1107 pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
1108 {
1109         int                             save_nestlevel;
1110         PlannedStmt        *result;
1111
1112         /*
1113          * hintが指定されない、または空のhintを指定された場合は通常のparser処理をお
1114          * こなう。
1115          * 他のフック関数で実行されるhint処理をスキップするために、global 変数をNULL
1116          * に設定しておく。
1117          */
1118         if (!pg_hint_plan_enable ||
1119                 (global = parse_head_comment(parse)) == NULL ||
1120                 PlanHintIsempty(global))
1121         {
1122                 PlanHintDelete(global);
1123                 global = NULL;
1124
1125                 if (prev_planner_hook)
1126                         return (*prev_planner_hook) (parse, cursorOptions, boundParams);
1127                 else
1128                         return standard_planner(parse, cursorOptions, boundParams);
1129         }
1130
1131         /* Set hint で指定されたGUCパラメータを設定する */
1132         save_nestlevel = set_config_options(global->set_hints, global->context);
1133
1134         if (global->leading != NIL)
1135                 set_join_config_options(0, global->context);
1136
1137         /*
1138          * TODO ビュー定義で指定したテーブル数が1つの場合にもこのタイミングでGUCを変更する必
1139          * 要がある。
1140          */
1141         if (list_length(parse->rtable) == 1 &&
1142                 ((RangeTblEntry *) linitial(parse->rtable))->rtekind == RTE_RELATION)
1143         {
1144                 int     i;
1145                 RangeTblEntry  *rte = linitial(parse->rtable);
1146                 
1147                 for (i = 0; i < global->nscan_hints; i++)
1148                 {
1149                         ScanHint           *hint = global->scan_hints[i];
1150
1151                         if (strcmp(hint->relname, rte->eref->aliasname) != 0)
1152                                 parse_ereport(hint->opt_str, ("Relation \"%s\" does not exist.", hint->relname));
1153
1154                         set_scan_config_options(hint->enforce_mask, global->context);
1155                 }
1156         }
1157
1158         if (prev_planner_hook)
1159                 result = (*prev_planner_hook) (parse, cursorOptions, boundParams);
1160         else
1161                 result = standard_planner(parse, cursorOptions, boundParams);
1162
1163         /*
1164          * Restore the GUC variables we set above.
1165          */
1166         AtEOXact_GUC(true, save_nestlevel);
1167
1168         if (pg_hint_plan_debug_print)
1169         {
1170                 PlanHintDump(global);
1171                 //elog_node_display(INFO, "rtable", parse->rtable, true);
1172         }
1173
1174         PlanHintDelete(global);
1175         global = NULL;
1176
1177         return result;
1178 }
1179
1180 /*
1181  * aliasnameと一致するSCANヒントを探す
1182  */
1183 static ScanHint *
1184 find_scan_hint(RangeTblEntry *rte)
1185 {
1186         int     i;
1187
1188         for (i = 0; i < global->nscan_hints; i++)
1189         {
1190                 ScanHint   *hint = global->scan_hints[i];
1191
1192                 if (strcmp(rte->eref->aliasname, hint->relname) == 0)
1193                         return hint;
1194         }
1195
1196         return NULL;
1197 }
1198
1199 static void
1200 pg_hint_plan_get_relation_info(PlannerInfo *root, Oid relationObjectId,
1201                                                                  bool inhparent, RelOptInfo *rel)
1202 {
1203         ScanHint   *hint;
1204         ListCell   *cell;
1205         ListCell   *prev;
1206         ListCell   *next;
1207
1208         if (prev_get_relation_info)
1209                 (*prev_get_relation_info) (root, relationObjectId, inhparent, rel);
1210
1211         /* 有効なヒントが指定されなかった場合は処理をスキップする。 */
1212         if (!global)
1213                 return;
1214
1215         if (rel->reloptkind != RELOPT_BASEREL)
1216                 return;
1217
1218         if ((hint = find_scan_hint(root->simple_rte_array[rel->relid])) == NULL)
1219                 return;
1220
1221         /* インデックスを全て削除し、スキャンに使えなくする */
1222         if (hint->enforce_mask == ENABLE_SEQSCAN)
1223         {
1224                 list_free_deep(rel->indexlist);
1225                 rel->indexlist = NIL;
1226
1227                 return;
1228         }
1229
1230         /* 後でパスを作り直すため、ここではなにもしない */
1231         if (hint->indexnames == NULL)
1232                 return;
1233
1234         /* 指定されたインデックスのみをのこす */
1235         prev = NULL;
1236         for (cell = list_head(rel->indexlist); cell; cell = next)
1237         {
1238                 IndexOptInfo   *info = (IndexOptInfo *) lfirst(cell);
1239                 char               *indexname = get_rel_name(info->indexoid);
1240                 ListCell           *l;
1241                 bool                    use_index = false;
1242
1243                 next = lnext(cell);
1244
1245                 foreach(l, hint->indexnames)
1246                 {
1247                         if (strcmp(indexname, lfirst(l)) == 0)
1248                         {
1249                                 use_index = true;
1250                                 break;
1251                         }
1252                 }
1253
1254                 if (!use_index)
1255                         rel->indexlist = list_delete_cell(rel->indexlist, cell, prev);
1256                 else
1257                         prev = cell;
1258
1259                 pfree(indexname);
1260         }
1261 }
1262
1263 static Index
1264 scan_relid_aliasname(PlannerInfo *root, char *aliasname, bool check_ambiguous, const char *str)
1265 {
1266         // TODO refnameRangeTblEntry を参考
1267         int             i;
1268         Index   find = 0;
1269
1270         for (i = 1; i < root->simple_rel_array_size; i++)
1271         {
1272                 if (root->simple_rel_array[i] == NULL)
1273                         continue;
1274
1275                 Assert(i == root->simple_rel_array[i]->relid);
1276
1277                 if (strcmp(aliasname, root->simple_rte_array[i]->eref->aliasname) != 0)
1278                         continue;
1279
1280                 if (!check_ambiguous)
1281                         return i;
1282
1283                 if (find)
1284                         parse_ereport(str, ("relation name \"%s\" is ambiguous", aliasname));
1285
1286                 find = i;
1287         }
1288
1289         return find;
1290 }
1291
1292 /*
1293  * relidビットマスクと一致するヒントを探す
1294  */
1295 static JoinHint *
1296 scan_join_hint(Relids joinrelids)
1297 {
1298         List       *join_hint;
1299         ListCell   *l;
1300
1301         join_hint = global->join_hint_level[bms_num_members(joinrelids)];
1302         foreach(l, join_hint)
1303         {
1304                 JoinHint   *hint = (JoinHint *) lfirst(l);
1305                 if (bms_equal(joinrelids, hint->joinrelids))
1306                         return hint;
1307         }
1308
1309         return NULL;
1310 }
1311
1312 /*
1313  * ヒントを使用しやすい構造に変換する。
1314  */
1315 static void
1316 rebuild_join_hints(PlanHint *plan, PlannerInfo *root, int level, List *initial_rels)
1317 {
1318         int                     i;
1319         ListCell   *l;
1320         Relids          joinrelids;
1321         int                     njoinrels;
1322
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++)
1326         {
1327                 JoinHint   *hint = plan->join_hints[i];
1328                 int                     j;
1329                 Index           relid = 0;
1330
1331                 for (j = 0; j < hint->nrels; j++)
1332                 {
1333                         char   *relname = hint->relnames[j];
1334
1335                         relid = scan_relid_aliasname(root, relname, true, hint->opt_str);
1336                         if (relid == 0)
1337                         {
1338                                 parse_ereport(hint->opt_str, ("Relation \"%s\" does not exist.", relname));
1339                                 break;
1340                         }
1341
1342                         hint->joinrelids = bms_add_member(hint->joinrelids, relid);
1343                 }
1344
1345                 if (relid == 0)
1346                         continue;
1347
1348                 plan->join_hint_level[hint->nrels] =
1349                         lappend(plan->join_hint_level[hint->nrels], hint);
1350         }
1351
1352         /* Leading hint は、全ての join 方式が有効な hint として登録する */
1353         joinrelids = NULL;
1354         njoinrels = 0;
1355         foreach(l, plan->leading)
1356         {
1357                 char       *relname = (char *)lfirst(l);
1358                 JoinHint   *hint;
1359
1360                 i = scan_relid_aliasname(root, relname, true, plan->hint_str);
1361                 if (i == 0)
1362                 {
1363                         parse_ereport(plan->hint_str, ("Relation \"%s\" does not exist.", relname));
1364                         list_free_deep(plan->leading);
1365                         plan->leading = NIL;
1366                         break;
1367                 }
1368
1369                 joinrelids = bms_add_member(joinrelids, i);
1370                 njoinrels++;
1371
1372                 if (njoinrels < 2)
1373                         continue;
1374
1375                 if (njoinrels > plan->nlevel)
1376                 {
1377                         parse_ereport(plan->hint_str, ("In %s hint, specified relation name %d or less.", HINT_LEADING, plan->nlevel));
1378                         break;
1379                 }
1380
1381                 /* Leading で指定した組み合わせ以外の join hint を削除する */
1382                 hint = scan_join_hint(joinrelids);
1383                 list_free(plan->join_hint_level[njoinrels]);
1384                 if (hint)
1385                         plan->join_hint_level[njoinrels] = lappend(NIL, hint);
1386                 else
1387                 {
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);
1393
1394                         if (plan->njoin_hints == 0)
1395                         {
1396                                 plan->max_join_hints = HINT_ARRAY_DEFAULT_INITSIZE;
1397                                 plan->join_hints = palloc(sizeof(JoinHint *) * plan->max_join_hints);
1398                         }
1399                         else if (plan->njoin_hints == plan->max_join_hints)
1400                         {
1401                                 plan->max_join_hints *= 2;
1402                                 plan->join_hints = repalloc(plan->join_hints,
1403                                                                         sizeof(JoinHint *) * plan->max_join_hints);
1404                         }
1405
1406                         plan->join_hints[plan->njoin_hints] = hint;
1407                         plan->njoin_hints++;
1408                 }
1409         }
1410
1411         bms_free(joinrelids);
1412 }
1413
1414 static void
1415 rebuild_scan_path(PlanHint *plan, PlannerInfo *root, int level, List *initial_rels)
1416 {
1417         int     i;
1418         int     save_nestlevel = 0;
1419
1420         for (i = 0; i < plan->nscan_hints; i++)
1421         {
1422                 ScanHint   *hint = plan->scan_hints[i];
1423                 ListCell   *l;
1424
1425                 if (hint->enforce_mask == ENABLE_SEQSCAN)
1426                         continue;
1427
1428                 foreach(l, initial_rels)
1429                 {
1430                         RelOptInfo         *rel = (RelOptInfo *) lfirst(l);
1431                         RangeTblEntry  *rte = root->simple_rte_array[rel->relid];
1432
1433                         if (rel->reloptkind != RELOPT_BASEREL ||
1434                                 strcmp(hint->relname, rte->eref->aliasname) != 0)
1435                                 continue;
1436
1437                         if (save_nestlevel != 0)
1438                                 save_nestlevel = NewGUCNestLevel();
1439
1440                         /*
1441                          * TODO ヒントで指定されたScan方式が最安価でない場合のみ、Pathを生成
1442                          * しなおす
1443                          */
1444                         set_scan_config_options(hint->enforce_mask, plan->context);
1445
1446                         rel->pathlist = NIL;    // TODO 解放
1447                         set_plain_rel_pathlist(root, rel, rte);
1448
1449                         break;
1450                 }
1451         }
1452
1453         /*
1454          * Restore the GUC variables we set above.
1455          */
1456         if (save_nestlevel != 0)
1457                 AtEOXact_GUC(true, save_nestlevel);
1458 }
1459
1460 /*
1461  * src/backend/optimizer/path/joinrels.c
1462  * export make_join_rel() をラップする関数
1463  * 
1464  * ヒントにしたがって、enabele_* パラメータを変更した上で、make_join_rel()を
1465  * 呼び出す。
1466  */
1467 static RelOptInfo *
1468 pg_hint_plan_make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
1469 {
1470         Relids                  joinrelids;
1471         JoinHint           *hint;
1472         RelOptInfo         *rel;
1473         int                             save_nestlevel;
1474
1475         joinrelids = bms_union(rel1->relids, rel2->relids);
1476         hint = scan_join_hint(joinrelids);
1477         bms_free(joinrelids);
1478
1479         if (!hint)
1480                 return make_join_rel(root, rel1, rel2);
1481
1482         save_nestlevel = NewGUCNestLevel();
1483
1484         set_join_config_options(hint->enforce_mask, global->context);
1485
1486         rel = make_join_rel(root, rel1, rel2);
1487
1488         /*
1489          * Restore the GUC variables we set above.
1490          */
1491         AtEOXact_GUC(true, save_nestlevel);
1492
1493         return rel;
1494 }
1495
1496 static RelOptInfo *_standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels);
1497 static RelOptInfo *
1498 pg_hint_plan_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
1499 {
1500         /* 有効なヒントが指定されなかった場合は本来の処理を実行する。 */
1501         if (!global)
1502         {
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);
1507                 else
1508                         return standard_join_search(root, levels_needed, initial_rels);
1509         }
1510
1511         return _standard_join_search(root, levels_needed, initial_rels);
1512 }
1513
1514 /*
1515  * PostgreSQL 本体から流用した関数
1516  */
1517
1518 /*
1519  * src/backend/optimizer/path/allpaths.c
1520  * export standard_join_search() を流用
1521  * 
1522  * 変更箇所
1523  *  rebuild_join_hints() と rebuild_scan_path() の呼び出しを追加
1524  */
1525 /*
1526  * standard_join_search
1527  *        Find possible joinpaths for a query by successively finding ways
1528  *        to join component relations into join relations.
1529  *
1530  * 'levels_needed' is the number of iterations needed, ie, the number of
1531  *              independent jointree items in the query.  This is > 1.
1532  *
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).
1536  *
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.
1541  *
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.
1548  *
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.
1553  */
1554 static RelOptInfo *
1555 _standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
1556 {
1557         int                     lev;
1558         RelOptInfo *rel;
1559
1560         /*
1561          * This function cannot be invoked recursively within any one planning
1562          * problem, so join_rel_level[] can't be in use already.
1563          */
1564         Assert(root->join_rel_level == NULL);
1565
1566         /*
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.
1572          *
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
1575          * relations.
1576          */
1577         root->join_rel_level = (List **) palloc0((levels_needed + 1) * sizeof(List *));
1578
1579         root->join_rel_level[1] = initial_rels;
1580
1581         rebuild_join_hints(global, root, levels_needed, initial_rels);
1582         rebuild_scan_path(global, root, levels_needed, initial_rels);
1583
1584         for (lev = 2; lev <= levels_needed; lev++)
1585         {
1586                 ListCell   *lc;
1587
1588                 /*
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.
1592                  */
1593                 my_join_search_one_level(root, lev);
1594
1595                 /*
1596                  * Do cleanup work on each just-processed rel.
1597                  */
1598                 foreach(lc, root->join_rel_level[lev])
1599                 {
1600                         rel = (RelOptInfo *) lfirst(lc);
1601
1602                         /* Find and save the cheapest paths for this rel */
1603                         set_cheapest(rel);
1604
1605 #ifdef OPTIMIZER_DEBUG
1606                         debug_print_rel(root, rel);
1607 #endif
1608                 }
1609         }
1610
1611         /*
1612          * We should have a single rel at the final level.
1613          */
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);
1617
1618         rel = (RelOptInfo *) linitial(root->join_rel_level[levels_needed]);
1619
1620         root->join_rel_level = NULL;
1621
1622         return rel;
1623 }
1624
1625 /*
1626  * src/backend/optimizer/path/joinrels.c
1627  * join_search_one_level() を流用
1628  * 
1629  * 変更箇所
1630  *  make_join_rel() の呼び出しをラップする、pg_hint_plan_make_join_rel()の呼び出しに変更
1631  */
1632 /*
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.
1639  *
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
1642  *
1643  * The result is returned in root->join_rel_level[level].
1644  */
1645 static void
1646 my_join_search_one_level(PlannerInfo *root, int level)
1647 {
1648         List      **joinrels = root->join_rel_level;
1649         ListCell   *r;
1650         int                     k;
1651
1652         Assert(joinrels[level] == NIL);
1653
1654         /* Set join_cur_level so that new joinrels are added to proper list */
1655         root->join_cur_level = level;
1656
1657         /*
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.
1663          *
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
1668          * in joinrels[1].
1669          */
1670         foreach(r, joinrels[level - 1])
1671         {
1672                 RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1673                 ListCell   *other_rels;
1674
1675                 if (level == 2)
1676                         other_rels = lnext(r);          /* only consider remaining initial
1677                                                                                  * rels */
1678                 else
1679                         other_rels = list_head(joinrels[1]);            /* consider all initial
1680                                                                                                                  * rels */
1681
1682                 if (old_rel->joininfo != NIL || old_rel->has_eclass_joins ||
1683                         has_join_restriction(root, old_rel))
1684                 {
1685                         /*
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.
1691                          *
1692                          * See also the last-ditch case below.
1693                          */
1694                         make_rels_by_clause_joins(root,
1695                                                                           old_rel,
1696                                                                           other_rels);
1697                 }
1698                 else
1699                 {
1700                         /*
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.
1704                          */
1705                         make_rels_by_clauseless_joins(root,
1706                                                                                   old_rel,
1707                                                                                   other_rels);
1708                 }
1709         }
1710
1711         /*
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.
1714          *
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.
1718          */
1719         for (k = 2;; k++)
1720         {
1721                 int                     other_level = level - k;
1722
1723                 /*
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.
1726                  */
1727                 if (k > other_level)
1728                         break;
1729
1730                 foreach(r, joinrels[k])
1731                 {
1732                         RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1733                         ListCell   *other_rels;
1734                         ListCell   *r2;
1735
1736                         /*
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.
1740                          */
1741                         if (old_rel->joininfo == NIL && !old_rel->has_eclass_joins &&
1742                                 !has_join_restriction(root, old_rel))
1743                                 continue;
1744
1745                         if (k == other_level)
1746                                 other_rels = lnext(r);  /* only consider remaining rels */
1747                         else
1748                                 other_rels = list_head(joinrels[other_level]);
1749
1750                         for_each_cell(r2, other_rels)
1751                         {
1752                                 RelOptInfo *new_rel = (RelOptInfo *) lfirst(r2);
1753
1754                                 if (!bms_overlap(old_rel->relids, new_rel->relids))
1755                                 {
1756                                         /*
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.
1760                                          */
1761                                         if (have_relevant_joinclause(root, old_rel, new_rel) ||
1762                                                 have_join_order_restriction(root, old_rel, new_rel))
1763                                         {
1764                                                 (void) pg_hint_plan_make_join_rel(root, old_rel, new_rel);
1765                                         }
1766                                 }
1767                         }
1768                 }
1769         }
1770
1771         /*
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
1776          *
1777          * SELECT * FROM a,b,c WHERE (a.f1 + b.f2 + c.f3) = 0;
1778          *
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).
1782          */
1783         if (joinrels[level] == NIL)
1784         {
1785                 /*
1786                  * This loop is just like the first one, except we always call
1787                  * make_rels_by_clauseless_joins().
1788                  */
1789                 foreach(r, joinrels[level - 1])
1790                 {
1791                         RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
1792                         ListCell   *other_rels;
1793
1794                         if (level == 2)
1795                                 other_rels = lnext(r);  /* only consider remaining initial
1796                                                                                  * rels */
1797                         else
1798                                 other_rels = list_head(joinrels[1]);    /* consider all initial
1799                                                                                                                  * rels */
1800
1801                         make_rels_by_clauseless_joins(root,
1802                                                                                   old_rel,
1803                                                                                   other_rels);
1804                 }
1805
1806                 /*----------
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
1809                  *
1810                  * SELECT ... FROM t1 WHERE
1811                  *       x IN (SELECT ... FROM t2,t3 WHERE ...) AND
1812                  *       y IN (SELECT ... FROM t4,t5 WHERE ...)
1813                  *
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.
1818                  *
1819                  * However, if there are no special joins then join_is_legal() should
1820                  * never fail, and so the following sanity check is useful.
1821                  *----------
1822                  */
1823                 if (joinrels[level] == NIL && root->join_info_list == NIL)
1824                         elog(ERROR, "failed to build any %d-way joins", level);
1825         }
1826 }
1827
1828 /*
1829  * src/backend/optimizer/path/joinrels.c
1830  * static make_rels_by_clause_joins() を流用
1831  * 
1832  * 変更箇所
1833  *  make_join_rel() の呼び出しをラップする、pg_hint_plan_make_join_rel()の呼び出しに変更
1834  */
1835 /*
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].
1841  *
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.
1847  *
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
1851  *
1852  * Currently, this is only used with initial rels in other_rels, but it
1853  * will work for joining to joinrels too.
1854  */
1855 static void
1856 make_rels_by_clause_joins(PlannerInfo *root,
1857                                                   RelOptInfo *old_rel,
1858                                                   ListCell *other_rels)
1859 {
1860         ListCell   *l;
1861
1862         for_each_cell(l, other_rels)
1863         {
1864                 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
1865
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)))
1869                 {
1870                         (void) pg_hint_plan_make_join_rel(root, old_rel, other_rel);
1871                 }
1872         }
1873 }
1874
1875 /*
1876  * src/backend/optimizer/path/joinrels.c
1877  * static make_rels_by_clauseless_joins() を流用
1878  * 
1879  * 変更箇所
1880  *  make_join_rel() の呼び出しをラップする、pg_hint_plan_make_join_rel()の呼び出しに変更
1881  */
1882 /*
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].
1888  *
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
1892  *
1893  * Currently, this is only used with initial rels in other_rels, but it would
1894  * work for joining to joinrels too.
1895  */
1896 static void
1897 make_rels_by_clauseless_joins(PlannerInfo *root,
1898                                                           RelOptInfo *old_rel,
1899                                                           ListCell *other_rels)
1900 {
1901         ListCell   *l;
1902
1903         for_each_cell(l, other_rels)
1904         {
1905                 RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
1906
1907                 if (!bms_overlap(other_rel->relids, old_rel->relids))
1908                 {
1909                         (void) pg_hint_plan_make_join_rel(root, old_rel, other_rel);
1910                 }
1911         }
1912 }
1913
1914 /*
1915  * src/backend/optimizer/path/joinrels.c
1916  * static has_join_restriction() を流用
1917  * 
1918  * 変更箇所
1919  *  なし
1920  */
1921 /*
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).
1925  *
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.)
1930  */
1931 static bool
1932 has_join_restriction(PlannerInfo *root, RelOptInfo *rel)
1933 {
1934         ListCell   *l;
1935
1936         foreach(l, root->join_info_list)
1937         {
1938                 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
1939
1940                 /* ignore full joins --- other mechanisms preserve their ordering */
1941                 if (sjinfo->jointype == JOIN_FULL)
1942                         continue;
1943
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))
1947                         continue;
1948
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))
1952                         return true;
1953         }
1954
1955         return false;
1956 }
1957
1958 /*
1959  * src/backend/optimizer/path/allpaths.c
1960  * static set_plain_rel_pathlist() を流用
1961  * 
1962  * 変更箇所
1963  *  なし
1964  */
1965 /*
1966  * set_plain_rel_pathlist
1967  *        Build access paths for a plain relation (no subquery, no inheritance)
1968  */
1969 static void
1970 set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1971 {
1972         /* Consider sequential scan */
1973         add_path(rel, create_seqscan_path(root, rel));
1974
1975         /* Consider index scans */
1976         create_index_paths(root, rel);
1977
1978         /* Consider TID scans */
1979         create_tidscan_paths(root, rel);
1980
1981         /* Now find the cheapest of the paths for this rel */
1982         set_cheapest(rel);
1983 }