OSDN Git Service

Merge branch 'ut' into ut_suzuki
[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 "commands/prepare.h"
13 #include "miscadmin.h"
14 #include "nodes/nodeFuncs.h"
15 #include "optimizer/clauses.h"
16 #include "optimizer/cost.h"
17 #include "optimizer/geqo.h"
18 #include "optimizer/joininfo.h"
19 #include "optimizer/pathnode.h"
20 #include "optimizer/paths.h"
21 #include "optimizer/plancat.h"
22 #include "optimizer/planner.h"
23 #include "optimizer/prep.h"
24 #include "optimizer/restrictinfo.h"
25 #include "tcop/utility.h"
26 #include "utils/lsyscache.h"
27 #include "utils/memutils.h"
28
29 #ifdef PG_MODULE_MAGIC
30 PG_MODULE_MAGIC;
31 #endif
32
33 #if PG_VERSION_NUM < 90100
34 #error unsupported PostgreSQL version
35 #endif
36
37 #define BLOCK_COMMENT_START             "/*"
38 #define BLOCK_COMMENT_END               "*/"
39 #define HINT_COMMENT_KEYWORD    "+"
40 #define HINT_START                              BLOCK_COMMENT_START HINT_COMMENT_KEYWORD
41 #define HINT_END                                BLOCK_COMMENT_END
42
43 /* hint keywords */
44 #define HINT_SEQSCAN                    "SeqScan"
45 #define HINT_INDEXSCAN                  "IndexScan"
46 #define HINT_BITMAPSCAN                 "BitmapScan"
47 #define HINT_TIDSCAN                    "TidScan"
48 #define HINT_NOSEQSCAN                  "NoSeqScan"
49 #define HINT_NOINDEXSCAN                "NoIndexScan"
50 #define HINT_NOBITMAPSCAN               "NoBitmapScan"
51 #define HINT_NOTIDSCAN                  "NoTidScan"
52 #if PG_VERSION_NUM >= 90200
53 #define HINT_INDEXONLYSCAN              "IndexonlyScan"
54 #define HINT_NOINDEXONLYSCAN    "NoIndexonlyScan"
55 #endif
56 #define HINT_NESTLOOP                   "NestLoop"
57 #define HINT_MERGEJOIN                  "MergeJoin"
58 #define HINT_HASHJOIN                   "HashJoin"
59 #define HINT_NONESTLOOP                 "NoNestLoop"
60 #define HINT_NOMERGEJOIN                "NoMergeJoin"
61 #define HINT_NOHASHJOIN                 "NoHashJoin"
62 #define HINT_LEADING                    "Leading"
63 #define HINT_SET                                "Set"
64
65
66 #define HINT_ARRAY_DEFAULT_INITSIZE 8
67
68 #define parse_ereport(str, detail) \
69         ereport(pg_hint_plan_parse_messages, \
70                         (errmsg("hint syntax error at or near \"%s\"", (str)), \
71                          errdetail detail))
72
73 #define skip_space(str) \
74         while (isspace(*str)) \
75                 str++;
76
77 enum
78 {
79         ENABLE_SEQSCAN = 0x01,
80         ENABLE_INDEXSCAN = 0x02,
81         ENABLE_BITMAPSCAN = 0x04,
82         ENABLE_TIDSCAN = 0x08,
83 #if PG_VERSION_NUM >= 90200
84         ENABLE_INDEXONLYSCAN = 0x10
85 #endif
86 } SCAN_TYPE_BITS;
87
88 enum
89 {
90         ENABLE_NESTLOOP = 0x01,
91         ENABLE_MERGEJOIN = 0x02,
92         ENABLE_HASHJOIN = 0x04
93 } JOIN_TYPE_BITS;
94
95 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN \
96                                                 | ENABLE_TIDSCAN)
97 #if PG_VERSION_NUM >= 90200
98 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | ENABLE_BITMAPSCAN \
99                                                 | ENABLE_TIDSCAN | ENABLE_INDEXONLYSCAN)
100 #endif
101 #define ENABLE_ALL_JOIN (ENABLE_NESTLOOP | ENABLE_MERGEJOIN | ENABLE_HASHJOIN)
102 #define DISABLE_ALL_SCAN 0
103 #define DISABLE_ALL_JOIN 0
104
105 typedef struct Hint Hint;
106 typedef struct PlanHint PlanHint;
107
108 typedef Hint *(*HintCreateFunction) (const char *hint_str,
109                                                                          const char *keyword);
110 typedef void (*HintDeleteFunction) (Hint *hint);
111 typedef void (*HintDumpFunction) (Hint *hint, StringInfo buf);
112 typedef int (*HintCmpFunction) (const Hint *a, const Hint *b);
113 typedef const char *(*HintParseFunction) (Hint *hint, PlanHint *plan,
114                                                                                   Query *parse, const char *str);
115
116 /* hint types */
117 #define NUM_HINT_TYPE   4
118 typedef enum HintType
119 {
120         HINT_TYPE_SCAN_METHOD,
121         HINT_TYPE_JOIN_METHOD,
122         HINT_TYPE_LEADING,
123         HINT_TYPE_SET
124 } HintType;
125
126 /* hint status */
127 typedef enum HintStatus
128 {
129         HINT_STATE_NOTUSED = 0,         /* specified relation not used in query */
130         HINT_STATE_USED,                        /* hint is used */
131         HINT_STATE_DUPLICATION,         /* specified hint duplication */
132         HINT_STATE_ERROR                        /* execute error (parse error does not include
133                                                                  * it) */
134 } HintStatus;
135
136 #define hint_state_enabled(hint) ((hint)->base.state == HINT_STATE_NOTUSED || \
137                                                                   (hint)->base.state == HINT_STATE_USED)
138
139 /* common data for all hints. */
140 struct Hint
141 {
142         const char                 *hint_str;           /* must not do pfree */
143         const char                 *keyword;            /* must not do pfree */
144         HintType                        type;
145         HintStatus                      state;
146         HintDeleteFunction      delete_func;
147         HintDumpFunction        dump_func;
148         HintCmpFunction         cmp_func;
149         HintParseFunction       parser_func;
150 };
151
152 /* scan method hints */
153 typedef struct ScanMethodHint
154 {
155         Hint                    base;
156         char               *relname;
157         List               *indexnames;
158         unsigned char   enforce_mask;
159 } ScanMethodHint;
160
161 /* join method hints */
162 typedef struct JoinMethodHint
163 {
164         Hint                    base;
165         int                             nrels;
166         char              **relnames;
167         unsigned char   enforce_mask;
168         Relids                  joinrelids;
169 } JoinMethodHint;
170
171 /* join order hints */
172 typedef struct LeadingHint
173 {
174         Hint    base;
175         List   *relations;              /* relation names specified in Leading hint */
176 } LeadingHint;
177
178 /* change a run-time parameter hints */
179 typedef struct SetHint
180 {
181         Hint    base;
182         char   *name;                           /* name of variable */
183         char   *value;
184 } SetHint;
185
186 /*
187  * Describes a context of hint processing.
188  */
189 struct PlanHint
190 {
191         char               *hint_str;                   /* original hint string */
192
193         /* all hint */
194         int                             nall_hints;                     /* # of valid all hints */
195         int                             max_all_hints;          /* # of slots for all hints */
196         Hint              **all_hints;                  /* parsed all hints */
197
198         /* # of each hints */
199         int                             num_hints[NUM_HINT_TYPE];
200
201         /* for scan method hints */
202         ScanMethodHint **scan_hints;            /* parsed scan hints */
203         int                             init_scan_mask;         /* initial value scan parameter */
204         Index                   parent_relid;           /* inherit parent table relid */
205         ScanMethodHint *parent_hint;            /* inherit parent table scan hint */
206
207         /* for join method hints */
208         JoinMethodHint **join_hints;            /* parsed join hints */
209         int                             init_join_mask;         /* initial value join parameter */
210         List              **join_hint_level;
211
212         /* for Leading hint */
213         LeadingHint        *leading_hint;               /* parsed last specified Leading hint */
214
215         /* for Set hints */
216         SetHint           **set_hints;                  /* parsed Set hints */
217         GucContext              context;                        /* which GUC parameters can we set? */
218 };
219
220 /*
221  * Describes a hint parser module which is bound with particular hint keyword.
222  */
223 typedef struct HintParser
224 {
225         char                       *keyword;
226         HintCreateFunction      create_func;
227 } HintParser;
228
229 /* Module callbacks */
230 void            _PG_init(void);
231 void            _PG_fini(void);
232
233 static void pg_hint_plan_ProcessUtility(Node *parsetree,
234                                                                                 const char *queryString,
235                                                                                 ParamListInfo params, bool isTopLevel,
236                                                                                 DestReceiver *dest,
237                                                                                 char *completionTag);
238 static PlannedStmt *pg_hint_plan_planner(Query *parse, int cursorOptions,
239                                                                                  ParamListInfo boundParams);
240 static void pg_hint_plan_get_relation_info(PlannerInfo *root,
241                                                                                    Oid relationObjectId,
242                                                                                    bool inhparent, RelOptInfo *rel);
243 static RelOptInfo *pg_hint_plan_join_search(PlannerInfo *root,
244                                                                                         int levels_needed,
245                                                                                         List *initial_rels);
246
247 static Hint *ScanMethodHintCreate(const char *hint_str, const char *keyword);
248 static void ScanMethodHintDelete(ScanMethodHint *hint);
249 static void ScanMethodHintDump(ScanMethodHint *hint, StringInfo buf);
250 static int ScanMethodHintCmp(const ScanMethodHint *a, const ScanMethodHint *b);
251 static const char *ScanMethodHintParse(ScanMethodHint *hint, PlanHint *plan,
252                                                                            Query *parse, const char *str);
253 static Hint *JoinMethodHintCreate(const char *hint_str, const char *keyword);
254 static void JoinMethodHintDelete(JoinMethodHint *hint);
255 static void JoinMethodHintDump(JoinMethodHint *hint, StringInfo buf);
256 static int JoinMethodHintCmp(const JoinMethodHint *a, const JoinMethodHint *b);
257 static const char *JoinMethodHintParse(JoinMethodHint *hint, PlanHint *plan,
258                                                                            Query *parse, const char *str);
259 static Hint *LeadingHintCreate(const char *hint_str, const char *keyword);
260 static void LeadingHintDelete(LeadingHint *hint);
261 static void LeadingHintDump(LeadingHint *hint, StringInfo buf);
262 static int LeadingHintCmp(const LeadingHint *a, const LeadingHint *b);
263 static const char *LeadingHintParse(LeadingHint *hint, PlanHint *plan,
264                                                                         Query *parse, const char *str);
265 static Hint *SetHintCreate(const char *hint_str, const char *keyword);
266 static void SetHintDelete(SetHint *hint);
267 static void SetHintDump(SetHint *hint, StringInfo buf);
268 static int SetHintCmp(const SetHint *a, const SetHint *b);
269 static const char *SetHintParse(SetHint *hint, PlanHint *plan, Query *parse,
270                                                                 const char *str);
271
272 RelOptInfo *pg_hint_plan_standard_join_search(PlannerInfo *root,
273                                                                                           int levels_needed,
274                                                                                           List *initial_rels);
275 void pg_hint_plan_join_search_one_level(PlannerInfo *root, int level);
276 static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel,
277                                                                           ListCell *other_rels);
278 static void make_rels_by_clauseless_joins(PlannerInfo *root,
279                                                                                   RelOptInfo *old_rel,
280                                                                                   ListCell *other_rels);
281 static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
282 static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
283                                                                         Index rti, RangeTblEntry *rte);
284 static List *accumulate_append_subpath(List *subpaths, Path *path);
285 static void set_dummy_rel_pathlist(RelOptInfo *rel);
286 RelOptInfo *pg_hint_plan_make_join_rel(PlannerInfo *root, RelOptInfo *rel1,
287                                                                            RelOptInfo *rel2);
288
289
290 /* GUC variables */
291 static bool     pg_hint_plan_enable = true;
292 static bool     pg_hint_plan_debug_print = false;
293 static int      pg_hint_plan_parse_messages = INFO;
294
295 static const struct config_enum_entry parse_messages_level_options[] = {
296         {"debug", DEBUG2, true},
297         {"debug5", DEBUG5, false},
298         {"debug4", DEBUG4, false},
299         {"debug3", DEBUG3, false},
300         {"debug2", DEBUG2, false},
301         {"debug1", DEBUG1, false},
302         {"log", LOG, false},
303         {"info", INFO, false},
304         {"notice", NOTICE, false},
305         {"warning", WARNING, false},
306         {"error", ERROR, false},
307         /*
308          * {"fatal", FATAL, true},
309          * {"panic", PANIC, true},
310          */
311         {NULL, 0, false}
312 };
313
314 /* Saved hook values in case of unload */
315 static ProcessUtility_hook_type prev_ProcessUtility = NULL;
316 static planner_hook_type prev_planner = NULL;
317 static get_relation_info_hook_type prev_get_relation_info = NULL;
318 static join_search_hook_type prev_join_search = NULL;
319
320 /* フック関数をまたがって使用する情報を管理する */
321 static PlanHint *global = NULL;
322
323 /*
324  * EXECUTEコマンド実行時に、ステートメント名を格納する。
325  * その他のコマンドの場合は、NULLに設定する。
326  */
327 static char        *stmt_name = NULL;
328
329 static const HintParser parsers[] = {
330         {HINT_SEQSCAN, ScanMethodHintCreate},
331         {HINT_INDEXSCAN, ScanMethodHintCreate},
332         {HINT_BITMAPSCAN, ScanMethodHintCreate},
333         {HINT_TIDSCAN, ScanMethodHintCreate},
334         {HINT_NOSEQSCAN, ScanMethodHintCreate},
335         {HINT_NOINDEXSCAN, ScanMethodHintCreate},
336         {HINT_NOBITMAPSCAN, ScanMethodHintCreate},
337         {HINT_NOTIDSCAN, ScanMethodHintCreate},
338 #if PG_VERSION_NUM >= 90200
339         {HINT_INDEXONLYSCAN, ScanMethodHintCreate},
340         {HINT_NOINDEXONLYSCAN, ScanMethodHintCreate},
341 #endif
342         {HINT_NESTLOOP, JoinMethodHintCreate},
343         {HINT_MERGEJOIN, JoinMethodHintCreate},
344         {HINT_HASHJOIN, JoinMethodHintCreate},
345         {HINT_NONESTLOOP, JoinMethodHintCreate},
346         {HINT_NOMERGEJOIN, JoinMethodHintCreate},
347         {HINT_NOHASHJOIN, JoinMethodHintCreate},
348         {HINT_LEADING, LeadingHintCreate},
349         {HINT_SET, SetHintCreate},
350         {NULL, NULL}
351 };
352
353 /*
354  * Module load callbacks
355  */
356 void
357 _PG_init(void)
358 {
359         /* Define custom GUC variables. */
360         DefineCustomBoolVariable("pg_hint_plan.enable",
361                          "Instructions or hints to the planner using block comments.",
362                                                          NULL,
363                                                          &pg_hint_plan_enable,
364                                                          true,
365                                                          PGC_USERSET,
366                                                          0,
367                                                          NULL,
368                                                          NULL,
369                                                          NULL);
370
371         DefineCustomBoolVariable("pg_hint_plan.debug_print",
372                                                          "Logs each query's parse results of the hint.",
373                                                          NULL,
374                                                          &pg_hint_plan_debug_print,
375                                                          false,
376                                                          PGC_USERSET,
377                                                          0,
378                                                          NULL,
379                                                          NULL,
380                                                          NULL);
381
382         DefineCustomEnumVariable("pg_hint_plan.parse_messages",
383                                                          "Messege level of the parse error.",
384                                                          NULL,
385                                                          &pg_hint_plan_parse_messages,
386                                                          INFO,
387                                                          parse_messages_level_options,
388                                                          PGC_USERSET,
389                                                          0,
390                                                          NULL,
391                                                          NULL,
392                                                          NULL);
393
394         /* Install hooks. */
395         prev_ProcessUtility = ProcessUtility_hook;
396         ProcessUtility_hook = pg_hint_plan_ProcessUtility;
397         prev_planner = planner_hook;
398         planner_hook = pg_hint_plan_planner;
399         prev_get_relation_info = get_relation_info_hook;
400         get_relation_info_hook = pg_hint_plan_get_relation_info;
401         prev_join_search = join_search_hook;
402         join_search_hook = pg_hint_plan_join_search;
403 }
404
405 /*
406  * Module unload callback
407  * XXX never called
408  */
409 void
410 _PG_fini(void)
411 {
412         /* Uninstall hooks. */
413         ProcessUtility_hook = prev_ProcessUtility;
414         planner_hook = prev_planner;
415         get_relation_info_hook = prev_get_relation_info;
416         join_search_hook = prev_join_search;
417 }
418
419 /*
420  * create and delete functions the hint object
421  */
422
423 static Hint *
424 ScanMethodHintCreate(const char *hint_str, const char *keyword)
425 {
426         ScanMethodHint *hint;
427
428         hint = palloc(sizeof(ScanMethodHint));
429         hint->base.hint_str = hint_str;
430         hint->base.keyword = keyword;
431         hint->base.type = HINT_TYPE_SCAN_METHOD;
432         hint->base.state = HINT_STATE_NOTUSED;
433         hint->base.delete_func = (HintDeleteFunction) ScanMethodHintDelete;
434         hint->base.dump_func = (HintDumpFunction) ScanMethodHintDump;
435         hint->base.cmp_func = (HintCmpFunction) ScanMethodHintCmp;
436         hint->base.parser_func = (HintParseFunction) ScanMethodHintParse;
437         hint->relname = NULL;
438         hint->indexnames = NIL;
439         hint->enforce_mask = 0;
440
441         return (Hint *) hint;
442 }
443
444 static void
445 ScanMethodHintDelete(ScanMethodHint *hint)
446 {
447         if (!hint)
448                 return;
449
450         if (hint->relname)
451                 pfree(hint->relname);
452         list_free_deep(hint->indexnames);
453         pfree(hint);
454 }
455
456 static Hint *
457 JoinMethodHintCreate(const char *hint_str, const char *keyword)
458 {
459         JoinMethodHint *hint;
460
461         hint = palloc(sizeof(JoinMethodHint));
462         hint->base.hint_str = hint_str;
463         hint->base.keyword = keyword;
464         hint->base.type = HINT_TYPE_JOIN_METHOD;
465         hint->base.state = HINT_STATE_NOTUSED;
466         hint->base.delete_func = (HintDeleteFunction) JoinMethodHintDelete;
467         hint->base.dump_func = (HintDumpFunction) JoinMethodHintDump;
468         hint->base.cmp_func = (HintCmpFunction) JoinMethodHintCmp;
469         hint->base.parser_func = (HintParseFunction) JoinMethodHintParse;
470         hint->nrels = 0;
471         hint->relnames = NULL;
472         hint->enforce_mask = 0;
473         hint->joinrelids = NULL;
474
475         return (Hint *) hint;
476 }
477
478 static void
479 JoinMethodHintDelete(JoinMethodHint *hint)
480 {
481         if (!hint)
482                 return;
483
484         if (hint->relnames)
485         {
486                 int     i;
487
488                 for (i = 0; i < hint->nrels; i++)
489                         pfree(hint->relnames[i]);
490                 pfree(hint->relnames);
491         }
492         bms_free(hint->joinrelids);
493         pfree(hint);
494 }
495
496 static Hint *
497 LeadingHintCreate(const char *hint_str, const char *keyword)
498 {
499         LeadingHint        *hint;
500
501         hint = palloc(sizeof(LeadingHint));
502         hint->base.hint_str = hint_str;
503         hint->base.keyword = keyword;
504         hint->base.type = HINT_TYPE_LEADING;
505         hint->base.state = HINT_STATE_NOTUSED;
506         hint->base.delete_func = (HintDeleteFunction)LeadingHintDelete;
507         hint->base.dump_func = (HintDumpFunction) LeadingHintDump;
508         hint->base.cmp_func = (HintCmpFunction) LeadingHintCmp;
509         hint->base.parser_func = (HintParseFunction) LeadingHintParse;
510         hint->relations = NIL;
511
512         return (Hint *) hint;
513 }
514
515 static void
516 LeadingHintDelete(LeadingHint *hint)
517 {
518         if (!hint)
519                 return;
520
521         list_free_deep(hint->relations);
522         pfree(hint);
523 }
524
525 static Hint *
526 SetHintCreate(const char *hint_str, const char *keyword)
527 {
528         SetHint    *hint;
529
530         hint = palloc(sizeof(SetHint));
531         hint->base.hint_str = hint_str;
532         hint->base.keyword = keyword;
533         hint->base.type = HINT_TYPE_SET;
534         hint->base.state = HINT_STATE_NOTUSED;
535         hint->base.delete_func = (HintDeleteFunction) SetHintDelete;
536         hint->base.dump_func = (HintDumpFunction) SetHintDump;
537         hint->base.cmp_func = (HintCmpFunction) SetHintCmp;
538         hint->base.parser_func = (HintParseFunction) SetHintParse;
539         hint->name = NULL;
540         hint->value = NULL;
541
542         return (Hint *) hint;
543 }
544
545 static void
546 SetHintDelete(SetHint *hint)
547 {
548         if (!hint)
549                 return;
550
551         if (hint->name)
552                 pfree(hint->name);
553         if (hint->value)
554                 pfree(hint->value);
555         pfree(hint);
556 }
557
558 static PlanHint *
559 PlanHintCreate(void)
560 {
561         PlanHint   *hint;
562
563         hint = palloc(sizeof(PlanHint));
564         hint->hint_str = NULL;
565         hint->nall_hints = 0;
566         hint->max_all_hints = 0;
567         hint->all_hints = NULL;
568         memset(hint->num_hints, 0, sizeof(hint->num_hints));
569         hint->scan_hints = NULL;
570         hint->init_scan_mask = 0;
571         hint->parent_relid = 0;
572         hint->parent_hint = NULL;
573         hint->join_hints = NULL;
574         hint->init_join_mask = 0;
575         hint->join_hint_level = NULL;
576         hint->leading_hint = NULL;
577         hint->context = superuser() ? PGC_SUSET : PGC_USERSET;
578         hint->set_hints = NULL;
579
580         return hint;
581 }
582
583 static void
584 PlanHintDelete(PlanHint *hint)
585 {
586         int                     i;
587
588         if (!hint)
589                 return;
590
591         if (hint->hint_str)
592                 pfree(hint->hint_str);
593
594         for (i = 0; i < hint->num_hints[HINT_TYPE_SCAN_METHOD]; i++)
595                 hint->all_hints[i]->delete_func(hint->all_hints[i]);
596         if (hint->all_hints)
597                 pfree(hint->all_hints);
598 }
599
600 /*
601  * dump functions
602  */
603
604 static void
605 dump_quote_value(StringInfo buf, const char *value)
606 {
607         bool            need_quote = false;
608         const char *str;
609
610         for (str = value; *str != '\0'; str++)
611         {
612                 if (isspace(*str) || *str == ')' || *str == '"')
613                 {
614                         need_quote = true;
615                         appendStringInfoCharMacro(buf, '"');
616                         break;
617                 }
618         }
619
620         for (str = value; *str != '\0'; str++)
621         {
622                 if (*str == '"')
623                         appendStringInfoCharMacro(buf, '"');
624
625                 appendStringInfoCharMacro(buf, *str);
626         }
627
628         if (need_quote)
629                 appendStringInfoCharMacro(buf, '"');
630 }
631
632 static void
633 ScanMethodHintDump(ScanMethodHint *hint, StringInfo buf)
634 {
635         ListCell   *l;
636
637         appendStringInfo(buf, "%s(", hint->base.keyword);
638         dump_quote_value(buf, hint->relname);
639         foreach(l, hint->indexnames)
640         {
641                 appendStringInfoCharMacro(buf, ' ');
642                 dump_quote_value(buf, (char *) lfirst(l));
643         }
644         appendStringInfoString(buf, ")\n");
645 }
646
647 static void
648 JoinMethodHintDump(JoinMethodHint *hint, StringInfo buf)
649 {
650         int     i;
651
652         appendStringInfo(buf, "%s(", hint->base.keyword);
653         dump_quote_value(buf, hint->relnames[0]);
654         for (i = 1; i < hint->nrels; i++)
655         {
656                 appendStringInfoCharMacro(buf, ' ');
657                 dump_quote_value(buf, hint->relnames[i]);
658         }
659         appendStringInfoString(buf, ")\n");
660
661 }
662
663 static void
664 LeadingHintDump(LeadingHint *hint, StringInfo buf)
665 {
666         bool            is_first;
667         ListCell   *l;
668
669         appendStringInfo(buf, "%s(", HINT_LEADING);
670         is_first = true;
671         foreach(l, hint->relations)
672         {
673                 if (is_first)
674                         is_first = false;
675                 else
676                         appendStringInfoCharMacro(buf, ' ');
677
678                 dump_quote_value(buf, (char *) lfirst(l));
679         }
680
681         appendStringInfoString(buf, ")\n");
682 }
683
684 static void
685 SetHintDump(SetHint *hint, StringInfo buf)
686 {
687         appendStringInfo(buf, "%s(", HINT_SET);
688         dump_quote_value(buf, hint->name);
689         appendStringInfoCharMacro(buf, ' ');
690         dump_quote_value(buf, hint->value);
691         appendStringInfo(buf, ")\n");
692 }
693
694 static void
695 all_hint_dump(PlanHint *hint, StringInfo buf, const char *title,
696                           HintStatus state)
697 {
698         int     i;
699
700         appendStringInfo(buf, "%s:\n", title);
701         for (i = 0; i < hint->nall_hints; i++)
702         {
703                 if (hint->all_hints[i]->state != state)
704                         continue;
705
706                 hint->all_hints[i]->dump_func(hint->all_hints[i], buf);
707         }
708 }
709
710 static void
711 PlanHintDump(PlanHint *hint)
712 {
713         StringInfoData  buf;
714
715         if (!hint)
716         {
717                 elog(LOG, "pg_hint_plan:\nno hint");
718                 return;
719         }
720
721         initStringInfo(&buf);
722
723         appendStringInfoString(&buf, "pg_hint_plan:\n");
724         all_hint_dump(hint, &buf, "used hint", HINT_STATE_USED);
725         all_hint_dump(hint, &buf, "not used hint", HINT_STATE_NOTUSED);
726         all_hint_dump(hint, &buf, "duplication hint", HINT_STATE_DUPLICATION);
727         all_hint_dump(hint, &buf, "error hint", HINT_STATE_ERROR);
728
729         elog(LOG, "%s", buf.data);
730
731         pfree(buf.data);
732 }
733
734 /*
735  * compare functions
736  */
737
738 static int
739 RelnameCmp(const void *a, const void *b)
740 {
741         const char *relnamea = *((const char **) a);
742         const char *relnameb = *((const char **) b);
743
744         return strcmp(relnamea, relnameb);
745 }
746
747 static int
748 ScanMethodHintCmp(const ScanMethodHint *a, const ScanMethodHint *b)
749 {
750         return RelnameCmp(&a->relname, &b->relname);
751 }
752
753 static int
754 JoinMethodHintCmp(const JoinMethodHint *a, const JoinMethodHint *b)
755 {
756         int     i;
757
758         if (a->nrels != b->nrels)
759                 return a->nrels - b->nrels;
760
761         for (i = 0; i < a->nrels; i++)
762         {
763                 int     result;
764                 if ((result = RelnameCmp(&a->relnames[i], &b->relnames[i])) != 0)
765                         return result;
766         }
767
768         return 0;
769 }
770
771 static int
772 LeadingHintCmp(const LeadingHint *a, const LeadingHint *b)
773 {
774         return 0;
775 }
776
777 static int
778 SetHintCmp(const SetHint *a, const SetHint *b)
779 {
780         return strcmp(a->name, b->name);
781 }
782
783 static int
784 AllHintCmp(const void *a, const void *b, bool order)
785 {
786         const Hint *hinta = *((const Hint **) a);
787         const Hint *hintb = *((const Hint **) b);
788         int                     result = 0;
789
790         if (hinta->type != hintb->type)
791                 return hinta->type - hintb->type;
792
793         if ((result = hinta->cmp_func(hinta, hintb)) != 0 || !order)
794                 return result;
795
796         /* ヒント句で指定した順を返す */
797         return hinta->hint_str - hintb->hint_str;
798 }
799
800 static int
801 AllHintCmpIsOrder(const void *a, const void *b)
802 {
803         return AllHintCmp(a, b, true);
804 }
805
806 /*
807  * parse functions
808  */
809
810 static const char *
811 parse_keyword(const char *str, StringInfo buf)
812 {
813         skip_space(str);
814
815         while (!isspace(*str) && *str != '(' && *str != '\0')
816                 appendStringInfoCharMacro(buf, *str++);
817
818         return str;
819 }
820
821 static const char *
822 skip_opened_parenthesis(const char *str)
823 {
824         skip_space(str);
825
826         if (*str != '(')
827         {
828                 parse_ereport(str, ("Opened parenthesis is necessary."));
829                 return NULL;
830         }
831
832         str++;
833
834         return str;
835 }
836
837 static const char *
838 skip_closed_parenthesis(const char *str)
839 {
840         skip_space(str);
841
842         if (*str != ')')
843         {
844                 parse_ereport(str, ("Closed parenthesis is necessary."));
845                 return NULL;
846         }
847
848         str++;
849
850         return str;
851 }
852
853 /*
854  * 二重引用符で囲まれているかもしれないトークンを読み取り word 引数に palloc
855  * で確保したバッファに格納してそのポインタを返す。
856  *
857  * 正常にパースできた場合は残りの文字列の先頭位置を、異常があった場合は NULL を
858  * 返す。
859  */
860 static const char *
861 parse_quote_value(const char *str, char **word, char *value_type)
862 {
863         StringInfoData  buf;
864         bool                    in_quote;
865
866         /* 先頭のスペースは読み飛ばす。 */
867         skip_space(str);
868
869         initStringInfo(&buf);
870         if (*str == '"')
871         {
872                 str++;
873                 in_quote = true;
874         }
875         else
876                 in_quote = false;
877
878         while (true)
879         {
880                 if (in_quote)
881                 {
882                         /* 二重引用符が閉じられていない場合はパース中断 */
883                         if (*str == '\0')
884                         {
885                                 pfree(buf.data);
886                                 parse_ereport(str, ("Unterminated quoted %s.", value_type));
887                                 return NULL;
888                         }
889
890                         /*
891                          * エスケープ対象のダブルクウォートをスキップする。
892                          * もしブロックコメントの開始文字列や終了文字列もオブジェクト名とし
893                          * て使用したい場合は、/ と * もエスケープ対象とすることで使用できる
894                          * が、処理対象としていない。もしテーブル名にこれらの文字が含まれる
895                          * 場合は、エイリアスを指定する必要がある。
896                          */
897                         if (*str == '"')
898                         {
899                                 str++;
900                                 if (*str != '"')
901                                         break;
902                         }
903                 }
904                 else if (isspace(*str) || *str == ')' || *str == '"' || *str == '\0')
905                         break;
906
907                 appendStringInfoCharMacro(&buf, *str++);
908         }
909
910         if (buf.len == 0)
911         {
912                 char   *type;
913
914                 type = pstrdup(value_type);
915                 type[0] = toupper(type[0]);
916                 parse_ereport(str, ("%s is necessary.", type));
917
918                 pfree(buf.data);
919                 pfree(type);
920
921                 return NULL;
922         }
923
924         *word = buf.data;
925
926         return str;
927 }
928
929 static void
930 parse_hints(PlanHint *plan, Query *parse, const char *str)
931 {
932         StringInfoData  buf;
933         char               *head;
934
935         initStringInfo(&buf);
936         while (*str != '\0')
937         {
938                 const HintParser *parser;
939
940                 /* in error message, we output the comment including the keyword. */
941                 head = (char *) str;
942
943                 /* parse only the keyword of the hint. */
944                 resetStringInfo(&buf);
945                 str = parse_keyword(str, &buf);
946
947                 for (parser = parsers; parser->keyword != NULL; parser++)
948                 {
949                         char   *keyword = parser->keyword;
950                         Hint   *hint;
951
952                         if (strcasecmp(buf.data, keyword) != 0)
953                                 continue;
954
955                         hint = parser->create_func(head, keyword);
956
957                         /* parser of each hint does parse in a parenthesis. */
958                         if ((str = skip_opened_parenthesis(str)) == NULL ||
959                                 (str = hint->parser_func(hint, plan, parse, str)) == NULL ||
960                                 (str = skip_closed_parenthesis(str)) == NULL)
961                         {
962                                 hint->delete_func(hint);
963                                 pfree(buf.data);
964                                 return;
965                         }
966
967                         /*
968                          * 出来上がったヒント情報を追加。スロットが足りない場合は二倍に拡張する。
969                          */
970                         if (plan->nall_hints == 0)
971                         {
972                                 plan->max_all_hints = HINT_ARRAY_DEFAULT_INITSIZE;
973                                 plan->all_hints = palloc(sizeof(Hint *) * plan->max_all_hints);
974                         }
975                         else if (plan->nall_hints == plan->max_all_hints)
976                         {
977                                 plan->max_all_hints *= 2;
978                                 plan->all_hints = repalloc(plan->all_hints,
979                                                                                 sizeof(Hint *) * plan->max_all_hints);
980                         }
981
982                         plan->all_hints[plan->nall_hints] = hint;
983                         plan->nall_hints++;
984
985                         skip_space(str);
986
987                         break;
988                 }
989
990                 if (parser->keyword == NULL)
991                 {
992                         parse_ereport(head, ("Keyword \"%s\" does not exist.", buf.data));
993                         pfree(buf.data);
994                         return;
995                 }
996         }
997
998         pfree(buf.data);
999 }
1000
1001 /*
1002  * Do basic parsing of the query head comment.
1003  */
1004 static PlanHint *
1005 parse_head_comment(Query *parse)
1006 {
1007         const char *p;
1008         char       *head;
1009         char       *tail;
1010         int                     len;
1011         int                     i;
1012         PlanHint   *plan;
1013
1014         /* get client-supplied query string. */
1015         if (stmt_name)
1016         {
1017                 PreparedStatement  *entry;
1018
1019                 entry = FetchPreparedStatement(stmt_name, true);
1020                 p = entry->plansource->query_string;
1021         }
1022         else
1023                 p = debug_query_string;
1024
1025         if (p == NULL)
1026                 return NULL;
1027
1028         /* extract query head comment. */
1029         len = strlen(HINT_START);
1030         skip_space(p);
1031         if (strncmp(p, HINT_START, len))
1032                 return NULL;
1033
1034         head = (char *) p;
1035         p += len;
1036         skip_space(p);
1037
1038         /* find hint end keyword. */
1039         if ((tail = strstr(p, HINT_END)) == NULL)
1040         {
1041                 parse_ereport(head, ("Unterminated block comment."));
1042                 return NULL;
1043         }
1044
1045         /* 入れ子にしたブロックコメントはサポートしない */
1046         if ((head = strstr(p, BLOCK_COMMENT_START)) != NULL && head < tail)
1047         {
1048                 parse_ereport(head, ("Block comments nest doesn't supported."));
1049                 return NULL;
1050         }
1051
1052         /* ヒント句部分を切り出す */
1053         len = tail - p;
1054         head = palloc(len + 1);
1055         memcpy(head, p, len);
1056         head[len] = '\0';
1057         p = head;
1058
1059         plan = PlanHintCreate();
1060         plan->hint_str = head;
1061
1062         /* parse each hint. */
1063         parse_hints(plan, parse, p);
1064
1065         /* When nothing specified a hint, we free PlanHint and returns NULL. */
1066         if (plan->nall_hints == 0)
1067         {
1068                 PlanHintDelete(plan);
1069                 return NULL;
1070         }
1071
1072         /* パースしたヒントを並び替える */
1073         qsort(plan->all_hints, plan->nall_hints, sizeof(Hint *), AllHintCmpIsOrder);
1074
1075         /* 重複したヒントを検索する */
1076         for (i = 0; i < plan->nall_hints; i++)
1077         {
1078                 Hint   *hint = plan->all_hints[i];
1079
1080                 plan->num_hints[hint->type]++;
1081
1082                 if (i + 1 >= plan->nall_hints)
1083                         break;
1084
1085                 if (AllHintCmp(plan->all_hints + i, plan->all_hints + i + 1, false) ==
1086                         0)
1087                 {
1088                         const char *HintTypeName[] = {"scan method", "join method",
1089                                                                                   "leading", "set"};
1090
1091                         parse_ereport(plan->all_hints[i]->hint_str,
1092                                                   ("Conflict %s hint.", HintTypeName[hint->type]));
1093                         plan->all_hints[i]->state = HINT_STATE_DUPLICATION;
1094                 }
1095         }
1096
1097         plan->scan_hints = (ScanMethodHint **) plan->all_hints;
1098         plan->join_hints = (JoinMethodHint **) plan->all_hints +
1099                 plan->num_hints[HINT_TYPE_SCAN_METHOD];
1100         plan->leading_hint = (LeadingHint *) plan->all_hints[
1101                 plan->num_hints[HINT_TYPE_SCAN_METHOD] +
1102                 plan->num_hints[HINT_TYPE_JOIN_METHOD] +
1103                 plan->num_hints[HINT_TYPE_LEADING] - 1];
1104         plan->set_hints = (SetHint **) plan->all_hints +
1105                 plan->num_hints[HINT_TYPE_SCAN_METHOD] +
1106                 plan->num_hints[HINT_TYPE_JOIN_METHOD] +
1107                 plan->num_hints[HINT_TYPE_LEADING];
1108
1109         return plan;
1110 }
1111
1112 /*
1113  * スキャン方式ヒントのカッコ内をパースする
1114  */
1115 static const char *
1116 ScanMethodHintParse(ScanMethodHint *hint, PlanHint *plan, Query *parse,
1117                                         const char *str)
1118 {
1119         const char *keyword = hint->base.keyword;
1120
1121         /*
1122          * スキャン方式のヒントでリレーション名が読み取れない場合はヒント無効
1123          */
1124         if ((str = parse_quote_value(str, &hint->relname, "relation name")) == NULL)
1125                 return NULL;
1126
1127         skip_space(str);
1128
1129         /*
1130          * インデックスリストを受け付けるヒントであれば、インデックス参照をパース
1131          * する。
1132          */
1133         if (strcmp(keyword, HINT_INDEXSCAN) == 0 ||
1134 #if PG_VERSION_NUM >= 90200
1135                 strcmp(keyword, HINT_INDEXONLYSCAN) == 0 ||
1136 #endif
1137                 strcmp(keyword, HINT_BITMAPSCAN) == 0)
1138         {
1139                 while (*str != ')' && *str != '\0')
1140                 {
1141                         char       *indexname;
1142
1143                         str = parse_quote_value(str, &indexname, "index name");
1144                         if (str == NULL)
1145                                 return NULL;
1146
1147                         hint->indexnames = lappend(hint->indexnames, indexname);
1148                         skip_space(str);
1149                 }
1150         }
1151
1152         /*
1153          * ヒントごとに決まっている許容スキャン方式をビットマスクとして設定
1154          */
1155         if (strcasecmp(keyword, HINT_SEQSCAN) == 0)
1156                 hint->enforce_mask = ENABLE_SEQSCAN;
1157         else if (strcasecmp(keyword, HINT_INDEXSCAN) == 0)
1158                 hint->enforce_mask = ENABLE_INDEXSCAN;
1159         else if (strcasecmp(keyword, HINT_BITMAPSCAN) == 0)
1160                 hint->enforce_mask = ENABLE_BITMAPSCAN;
1161         else if (strcasecmp(keyword, HINT_TIDSCAN) == 0)
1162                 hint->enforce_mask = ENABLE_TIDSCAN;
1163 #if PG_VERSION_NUM >= 90200
1164         else if (strcasecmp(keyword, HINT_INDEXONLYSCAN) == 0)
1165                 hint->enforce_mask = ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN;
1166 #endif
1167         else if (strcasecmp(keyword, HINT_NOSEQSCAN) == 0)
1168                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_SEQSCAN;
1169         else if (strcasecmp(keyword, HINT_NOINDEXSCAN) == 0)
1170                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXSCAN;
1171         else if (strcasecmp(keyword, HINT_NOBITMAPSCAN) == 0)
1172                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_BITMAPSCAN;
1173         else if (strcasecmp(keyword, HINT_NOTIDSCAN) == 0)
1174                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_TIDSCAN;
1175 #if PG_VERSION_NUM >= 90200
1176         else if (strcasecmp(keyword, HINT_NOINDEXONLYSCAN) == 0)
1177                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXONLYSCAN;
1178 #endif
1179         else
1180         {
1181                 parse_ereport(str, ("Unrecognized hint keyword \"%s\".", keyword));
1182                 return NULL;
1183         }
1184
1185         return str;
1186 }
1187
1188 static const char *
1189 JoinMethodHintParse(JoinMethodHint *hint, PlanHint *plan, Query *parse,
1190                                         const char *str)
1191 {
1192         char       *relname;
1193         const char *keyword = hint->base.keyword;
1194
1195         skip_space(str);
1196
1197         hint->relnames = palloc(sizeof(char *));
1198
1199         while ((str = parse_quote_value(str, &relname, "relation name")) != NULL)
1200         {
1201                 hint->nrels++;
1202                 hint->relnames = repalloc(hint->relnames, sizeof(char *) * hint->nrels);
1203                 hint->relnames[hint->nrels - 1] = relname;
1204
1205                 skip_space(str);
1206                 if (*str == ')')
1207                         break;
1208         }
1209
1210         if (str == NULL)
1211                 return NULL;
1212
1213         /* Join 対象のテーブルは最低でも2つ指定する必要がある */
1214         if (hint->nrels < 2)
1215         {
1216                 parse_ereport(str, ("Specified relation more than two."));
1217                 hint->base.state = HINT_STATE_ERROR;
1218         }
1219
1220         /* テーブル名順にソートする */
1221         qsort(hint->relnames, hint->nrels, sizeof(char *), RelnameCmp);
1222
1223         if (strcasecmp(keyword, HINT_NESTLOOP) == 0)
1224                 hint->enforce_mask = ENABLE_NESTLOOP;
1225         else if (strcasecmp(keyword, HINT_MERGEJOIN) == 0)
1226                 hint->enforce_mask = ENABLE_MERGEJOIN;
1227         else if (strcasecmp(keyword, HINT_HASHJOIN) == 0)
1228                 hint->enforce_mask = ENABLE_HASHJOIN;
1229         else if (strcasecmp(keyword, HINT_NONESTLOOP) == 0)
1230                 hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_NESTLOOP;
1231         else if (strcasecmp(keyword, HINT_NOMERGEJOIN) == 0)
1232                 hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_MERGEJOIN;
1233         else if (strcasecmp(keyword, HINT_NOHASHJOIN) == 0)
1234                 hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_HASHJOIN;
1235         else
1236         {
1237                 parse_ereport(str, ("Unrecognized hint keyword \"%s\".", keyword));
1238                 return NULL;
1239         }
1240
1241         return str;
1242 }
1243
1244 static const char *
1245 LeadingHintParse(LeadingHint *hint, PlanHint *plan, Query *parse,
1246                                  const char *str)
1247 {
1248         skip_space(str);
1249
1250         while (*str != ')')
1251         {
1252                 char   *relname;
1253
1254                 if ((str = parse_quote_value(str, &relname, "relation name")) == NULL)
1255                         return NULL;
1256
1257                 hint->relations = lappend(hint->relations, relname);
1258
1259                 skip_space(str);
1260         }
1261
1262         /* テーブル指定が2つ未満の場合は、Leading ヒントはエラーとする */
1263         if (list_length(hint->relations) < 2)
1264         {
1265                 parse_ereport(hint->base.hint_str,
1266                                           ("In %s hint, specified relation name 2 or more.",
1267                                            HINT_LEADING));
1268                 hint->base.state = HINT_STATE_ERROR;
1269         }
1270
1271         return str;
1272 }
1273
1274 static const char *
1275 SetHintParse(SetHint *hint, PlanHint *plan, Query *parse, const char *str)
1276 {
1277         if ((str = parse_quote_value(str, &hint->name, "parameter name")) == NULL ||
1278                 (str = parse_quote_value(str, &hint->value, "parameter value")) == NULL)
1279                 return NULL;
1280
1281         return str;
1282 }
1283
1284 /*
1285  * set GUC parameter functions
1286  */
1287
1288 #if PG_VERSION_NUM < 90200
1289 static int
1290 set_config_option_wrapper(const char *name, const char *value,
1291                                                   GucContext context, GucSource source,
1292                                                   GucAction action, bool changeVal, int elevel)
1293 {
1294         int                             result = 0;
1295         MemoryContext   ccxt = CurrentMemoryContext;
1296
1297         PG_TRY();
1298         {
1299                 result = set_config_option(name, value, context, source,
1300                                                                    action, changeVal);
1301         }
1302         PG_CATCH();
1303         {
1304                 ErrorData          *errdata;
1305                 MemoryContext   ecxt;
1306
1307                 if (elevel >= ERROR)
1308                         PG_RE_THROW();
1309
1310                 ecxt = MemoryContextSwitchTo(ccxt);
1311                 errdata = CopyErrorData();
1312                 ereport(elevel, (errcode(errdata->sqlerrcode),
1313                                 errmsg("%s", errdata->message),
1314                                 errdata->detail ? errdetail("%s", errdata->detail) : 0,
1315                                 errdata->hint ? errhint("%s", errdata->hint) : 0));
1316                 FreeErrorData(errdata);
1317
1318                 MemoryContextSwitchTo(ecxt);
1319         }
1320         PG_END_TRY();
1321
1322         return result;
1323 }
1324
1325 #define set_config_option(name, value, context, source, \
1326                                                   action, changeVal, elevel) \
1327         set_config_option_wrapper(name, value, context, source, \
1328                                                           action, changeVal, elevel)
1329 #endif
1330
1331 static int
1332 set_config_options(SetHint **options, int noptions, GucContext context)
1333 {
1334         int     i;
1335         int     save_nestlevel;
1336
1337         save_nestlevel = NewGUCNestLevel();
1338
1339         for (i = 0; i < noptions; i++)
1340         {
1341                 SetHint    *hint = options[i];
1342                 int                     result;
1343
1344                 if (!hint_state_enabled(hint))
1345                         continue;
1346
1347                 result = set_config_option(hint->name, hint->value, context,
1348                                                                    PGC_S_SESSION, GUC_ACTION_SAVE, true,
1349                                                                    pg_hint_plan_parse_messages);
1350                 if (result != 0)
1351                         hint->base.state = HINT_STATE_USED;
1352                 else
1353                         hint->base.state = HINT_STATE_ERROR;
1354         }
1355
1356         return save_nestlevel;
1357 }
1358
1359 #define SET_CONFIG_OPTION(name, type_bits) \
1360         set_config_option((name), \
1361                 (mask & (type_bits)) ? "true" : "false", \
1362                 context, PGC_S_SESSION, GUC_ACTION_SAVE, true, ERROR)
1363
1364 static void
1365 set_scan_config_options(unsigned char enforce_mask, GucContext context)
1366 {
1367         unsigned char   mask;
1368
1369         if (enforce_mask == ENABLE_SEQSCAN || enforce_mask == ENABLE_INDEXSCAN ||
1370                 enforce_mask == ENABLE_BITMAPSCAN || enforce_mask == ENABLE_TIDSCAN
1371 #if PG_VERSION_NUM >= 90200
1372                 || enforce_mask == ENABLE_INDEXONLYSCAN
1373 #endif
1374                 )
1375                 mask = enforce_mask;
1376         else
1377                 mask = enforce_mask & global->init_scan_mask;
1378
1379         SET_CONFIG_OPTION("enable_seqscan", ENABLE_SEQSCAN);
1380         SET_CONFIG_OPTION("enable_indexscan", ENABLE_INDEXSCAN);
1381         SET_CONFIG_OPTION("enable_bitmapscan", ENABLE_BITMAPSCAN);
1382         SET_CONFIG_OPTION("enable_tidscan", ENABLE_TIDSCAN);
1383 #if PG_VERSION_NUM >= 90200
1384         SET_CONFIG_OPTION("enable_indexonlyscan", ENABLE_INDEXONLYSCAN);
1385 #endif
1386 }
1387
1388 static void
1389 set_join_config_options(unsigned char enforce_mask, GucContext context)
1390 {
1391         unsigned char   mask;
1392
1393         if (enforce_mask == ENABLE_NESTLOOP || enforce_mask == ENABLE_MERGEJOIN ||
1394                 enforce_mask == ENABLE_HASHJOIN)
1395                 mask = enforce_mask;
1396         else
1397                 mask = enforce_mask & global->init_scan_mask;
1398
1399         SET_CONFIG_OPTION("enable_nestloop", ENABLE_NESTLOOP);
1400         SET_CONFIG_OPTION("enable_mergejoin", ENABLE_MERGEJOIN);
1401         SET_CONFIG_OPTION("enable_hashjoin", ENABLE_HASHJOIN);
1402 }
1403
1404 /*
1405  * pg_hint_plan hook functions
1406  */
1407
1408 static void
1409 pg_hint_plan_ProcessUtility(Node *parsetree, const char *queryString,
1410                                                         ParamListInfo params, bool isTopLevel,
1411                                                         DestReceiver *dest, char *completionTag)
1412 {
1413         Node                               *node;
1414
1415         if (!pg_hint_plan_enable)
1416         {
1417                 if (prev_ProcessUtility)
1418                         (*prev_ProcessUtility) (parsetree, queryString, params,
1419                                                                         isTopLevel, dest, completionTag);
1420                 else
1421                         standard_ProcessUtility(parsetree, queryString, params,
1422                                                                         isTopLevel, dest, completionTag);
1423
1424                 return;
1425         }
1426
1427         node = parsetree;
1428         if (IsA(node, ExplainStmt))
1429         {
1430                 /*
1431                  * EXPLAIN対象のクエリのパースツリーを取得する
1432                  */
1433                 ExplainStmt        *stmt;
1434                 Query              *query;
1435
1436                 stmt = (ExplainStmt *) node;
1437
1438                 Assert(IsA(stmt->query, Query));
1439                 query = (Query *) stmt->query;
1440
1441                 if (query->commandType == CMD_UTILITY && query->utilityStmt != NULL)
1442                         node = query->utilityStmt;
1443         }
1444
1445         /*
1446          * EXECUTEコマンドならば、PREPARE時に指定されたクエリ文字列を取得し、ヒント
1447          * 句の候補として設定する
1448          */
1449         if (IsA(node, ExecuteStmt))
1450         {
1451                 ExecuteStmt        *stmt;
1452
1453                 stmt = (ExecuteStmt *) node;
1454                 stmt_name = stmt->name;
1455         }
1456
1457         if (stmt_name)
1458         {
1459                 PG_TRY();
1460                 {
1461                         if (prev_ProcessUtility)
1462                                 (*prev_ProcessUtility) (parsetree, queryString, params,
1463                                                                                 isTopLevel, dest, completionTag);
1464                         else
1465                                 standard_ProcessUtility(parsetree, queryString, params,
1466                                                                                 isTopLevel, dest, completionTag);
1467                 }
1468                 PG_CATCH();
1469                 {
1470                         stmt_name = NULL;
1471                         PG_RE_THROW();
1472                 }
1473                 PG_END_TRY();
1474
1475                 stmt_name = NULL;
1476
1477                 return;
1478         }
1479
1480         if (prev_ProcessUtility)
1481                 (*prev_ProcessUtility) (parsetree, queryString, params,
1482                                                                 isTopLevel, dest, completionTag);
1483         else
1484                 standard_ProcessUtility(parsetree, queryString, params,
1485                                                                 isTopLevel, dest, completionTag);
1486 }
1487
1488 static PlannedStmt *
1489 pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
1490 {
1491         int                             save_nestlevel;
1492         PlannedStmt        *result;
1493
1494         /*
1495          * hintが指定されない、または空のhintを指定された場合は通常のparser処理をお
1496          * こなう。
1497          * 他のフック関数で実行されるhint処理をスキップするために、global 変数をNULL
1498          * に設定しておく。
1499          */
1500         if (!pg_hint_plan_enable || (global = parse_head_comment(parse)) == NULL)
1501         {
1502                 global = NULL;
1503
1504                 if (prev_planner)
1505                         return (*prev_planner) (parse, cursorOptions, boundParams);
1506                 else
1507                         return standard_planner(parse, cursorOptions, boundParams);
1508         }
1509
1510         /* Set hint で指定されたGUCパラメータを設定する */
1511         save_nestlevel = set_config_options(global->set_hints,
1512                                                                                 global->num_hints[HINT_TYPE_SET],
1513                                                                                 global->context);
1514
1515         if (enable_seqscan)
1516                 global->init_scan_mask |= ENABLE_SEQSCAN;
1517         if (enable_indexscan)
1518                 global->init_scan_mask |= ENABLE_INDEXSCAN;
1519         if (enable_bitmapscan)
1520                 global->init_scan_mask |= ENABLE_BITMAPSCAN;
1521         if (enable_tidscan)
1522                 global->init_scan_mask |= ENABLE_TIDSCAN;
1523 #if PG_VERSION_NUM >= 90200
1524         if (enable_indexonlyscan)
1525                 global->init_scan_mask |= ENABLE_INDEXONLYSCAN;
1526 #endif
1527         if (enable_nestloop)
1528                 global->init_join_mask |= ENABLE_NESTLOOP;
1529         if (enable_mergejoin)
1530                 global->init_join_mask |= ENABLE_MERGEJOIN;
1531         if (enable_hashjoin)
1532                 global->init_join_mask |= ENABLE_HASHJOIN;
1533
1534         if (prev_planner)
1535                 result = (*prev_planner) (parse, cursorOptions, boundParams);
1536         else
1537                 result = standard_planner(parse, cursorOptions, boundParams);
1538
1539         /*
1540          * Restore the GUC variables we set above.
1541          */
1542         AtEOXact_GUC(true, save_nestlevel);
1543
1544         /*
1545          * Print hint if debugging.
1546          */
1547         if (pg_hint_plan_debug_print)
1548                 PlanHintDump(global);
1549
1550         PlanHintDelete(global);
1551         global = NULL;
1552
1553         return result;
1554 }
1555
1556 /*
1557  * aliasnameと一致するSCANヒントを探す
1558  */
1559 static ScanMethodHint *
1560 find_scan_hint(PlannerInfo *root, RelOptInfo *rel)
1561 {
1562         RangeTblEntry  *rte;
1563         int                             i;
1564
1565         /*
1566          * RELOPT_BASEREL でなければ、scan method ヒントが適用しない。
1567          * 子テーブルの場合はRELOPT_OTHER_MEMBER_RELとなるが、サポート対象外とする。
1568          * また、通常のリレーション以外は、スキャン方式を選択できない。
1569          */
1570         if (rel->reloptkind != RELOPT_BASEREL || rel->rtekind != RTE_RELATION)
1571                 return NULL;
1572
1573         rte = root->simple_rte_array[rel->relid];
1574
1575         /* 外部表はスキャン方式が選択できない。 */
1576         if (rte->relkind == RELKIND_FOREIGN_TABLE)
1577                 return NULL;
1578
1579         /*
1580          * スキャン方式のヒントのリストから、検索対象のリレーションと名称が一致する
1581          * ヒントを検索する。
1582          */
1583         for (i = 0; i < global->num_hints[HINT_TYPE_SCAN_METHOD]; i++)
1584         {
1585                 ScanMethodHint *hint = global->scan_hints[i];
1586
1587                 /* すでに無効となっているヒントは検索対象にしない。 */
1588                 if (!hint_state_enabled(hint))
1589                         continue;
1590
1591                 if (RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
1592                         return hint;
1593         }
1594
1595         return NULL;
1596 }
1597
1598 static void
1599 delete_indexes(ScanMethodHint *hint, RelOptInfo *rel)
1600 {
1601         ListCell           *cell;
1602         ListCell           *prev;
1603         ListCell           *next;
1604
1605         /*
1606          * We delete all the IndexOptInfo list and prevent you from being usable by
1607          * a scan.
1608          */
1609         if (hint->enforce_mask == ENABLE_SEQSCAN ||
1610                 hint->enforce_mask == ENABLE_TIDSCAN)
1611         {
1612                 list_free_deep(rel->indexlist);
1613                 rel->indexlist = NIL;
1614                 hint->base.state = HINT_STATE_USED;
1615
1616                 return;
1617         }
1618
1619         /*
1620          * When a list of indexes is not specified, we just use all indexes.
1621          */
1622         if (hint->indexnames == NIL)
1623                 return;
1624
1625         /*
1626          * Leaving only an specified index, we delete it from a IndexOptInfo list
1627          * other than it.
1628          */
1629         prev = NULL;
1630         for (cell = list_head(rel->indexlist); cell; cell = next)
1631         {
1632                 IndexOptInfo   *info = (IndexOptInfo *) lfirst(cell);
1633                 char               *indexname = get_rel_name(info->indexoid);
1634                 ListCell           *l;
1635                 bool                    use_index = false;
1636
1637                 next = lnext(cell);
1638
1639                 foreach(l, hint->indexnames)
1640                 {
1641                         if (RelnameCmp(&indexname, &lfirst(l)) == 0)
1642                         {
1643                                 use_index = true;
1644                                 break;
1645                         }
1646                 }
1647
1648                 if (!use_index)
1649                         rel->indexlist = list_delete_cell(rel->indexlist, cell, prev);
1650                 else
1651                         prev = cell;
1652
1653                 pfree(indexname);
1654         }
1655 }
1656
1657 static void
1658 pg_hint_plan_get_relation_info(PlannerInfo *root, Oid relationObjectId,
1659                                                            bool inhparent, RelOptInfo *rel)
1660 {
1661         ScanMethodHint *hint;
1662
1663         if (prev_get_relation_info)
1664                 (*prev_get_relation_info) (root, relationObjectId, inhparent, rel);
1665
1666         /* 有効なヒントが指定されなかった場合は処理をスキップする。 */
1667         if (!global)
1668                 return;
1669
1670         if (inhparent)
1671         {
1672                 /* store does relids of parent table. */
1673                 global->parent_relid = rel->relid;
1674         }
1675         else if (global->parent_relid != 0)
1676         {
1677                 /*
1678                  * We use the same GUC parameter if this table is the child table of a
1679                  * table called pg_hint_plan_get_relation_info just before that.
1680                  */
1681                 ListCell   *l;
1682
1683                 /* append_rel_list contains all append rels; ignore others */
1684                 foreach(l, root->append_rel_list)
1685                 {
1686                         AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
1687
1688                         /* This rel is child table. */
1689                         if (appinfo->parent_relid == global->parent_relid &&
1690                                 appinfo->child_relid == rel->relid)
1691                         {
1692                                 if (global->parent_hint)
1693                                         delete_indexes(global->parent_hint, rel);
1694
1695                                 return;
1696                         }
1697                 }
1698
1699                 /* This rel is not inherit table. */
1700                 global->parent_relid = 0;
1701                 global->parent_hint = NULL;
1702         }
1703
1704         /* scan hint が指定されない場合は、GUCパラメータをリセットする。 */
1705         if ((hint = find_scan_hint(root, rel)) == NULL)
1706         {
1707                 set_scan_config_options(global->init_scan_mask, global->context);
1708                 return;
1709         }
1710         set_scan_config_options(hint->enforce_mask, global->context);
1711         hint->base.state = HINT_STATE_USED;
1712         if (inhparent)
1713                 global->parent_hint = hint;
1714
1715         delete_indexes(hint, rel);
1716 }
1717
1718 /*
1719  * aliasnameがクエリ中に指定した別名と一致する場合は、そのインデックスを返し、一致
1720  * する別名がなければ0を返す。
1721  * aliasnameがクエリ中に複数回指定された場合は、-1を返す。
1722  */
1723 static int
1724 find_relid_aliasname(PlannerInfo *root, char *aliasname, List *initial_rels,
1725                                          const char *str)
1726 {
1727         int             i;
1728         Index   found = 0;
1729
1730         for (i = 1; i < root->simple_rel_array_size; i++)
1731         {
1732                 ListCell   *l;
1733
1734                 if (root->simple_rel_array[i] == NULL)
1735                         continue;
1736
1737                 Assert(i == root->simple_rel_array[i]->relid);
1738
1739                 if (RelnameCmp(&aliasname, &root->simple_rte_array[i]->eref->aliasname)
1740                         != 0)
1741                         continue;
1742
1743                 foreach(l, initial_rels)
1744                 {
1745                         RelOptInfo *rel = (RelOptInfo *) lfirst(l);
1746
1747                         if (rel->reloptkind == RELOPT_BASEREL)
1748                         {
1749                                 if (rel->relid != i)
1750                                         continue;
1751                         }
1752                         else
1753                         {
1754                                 Assert(rel->reloptkind == RELOPT_JOINREL);
1755
1756                                 if (!bms_is_member(i, rel->relids))
1757                                         continue;
1758                         }
1759
1760                         if (found != 0)
1761                         {
1762                                 parse_ereport(str,
1763                                                           ("Relation name \"%s\" is ambiguous.",
1764                                                            aliasname));
1765                                 return -1;
1766                         }
1767
1768                         found = i;
1769                         break;
1770                 }
1771
1772         }
1773
1774         return found;
1775 }
1776
1777 /*
1778  * relidビットマスクと一致するヒントを探す
1779  */
1780 static JoinMethodHint *
1781 find_join_hint(Relids joinrelids)
1782 {
1783         List       *join_hint;
1784         ListCell   *l;
1785
1786         join_hint = global->join_hint_level[bms_num_members(joinrelids)];
1787
1788         foreach(l, join_hint)
1789         {
1790                 JoinMethodHint *hint = (JoinMethodHint *) lfirst(l);
1791
1792                 if (bms_equal(joinrelids, hint->joinrelids))
1793                         return hint;
1794         }
1795
1796         return NULL;
1797 }
1798
1799 /*
1800  * 結合方式のヒントを使用しやすい構造に変換する。
1801  */
1802 static void
1803 transform_join_hints(PlanHint *plan, PlannerInfo *root, int nbaserel,
1804                 List *initial_rels, JoinMethodHint **join_method_hints)
1805 {
1806         int                             i;
1807         int                             relid;
1808         LeadingHint        *lhint;
1809         Relids                  joinrelids;
1810         int                             njoinrels;
1811         ListCell           *l;
1812
1813         for (i = 0; i < plan->num_hints[HINT_TYPE_JOIN_METHOD]; i++)
1814         {
1815                 JoinMethodHint *hint = plan->join_hints[i];
1816                 int     j;
1817
1818                 if (!hint_state_enabled(hint) || hint->nrels > nbaserel)
1819                         continue;
1820
1821                 bms_free(hint->joinrelids);
1822                 hint->joinrelids = NULL;
1823                 relid = 0;
1824                 for (j = 0; j < hint->nrels; j++)
1825                 {
1826                         char   *relname = hint->relnames[j];
1827
1828                         relid = find_relid_aliasname(root, relname, initial_rels,
1829                                                                                  hint->base.hint_str);
1830
1831                         if (relid == -1)
1832                                 hint->base.state = HINT_STATE_ERROR;
1833
1834                         if (relid <= 0)
1835                                 break;
1836
1837                         if (bms_is_member(relid, hint->joinrelids))
1838                         {
1839                                 parse_ereport(hint->base.hint_str,
1840                                                           ("Relation name \"%s\" is duplicate.", relname));
1841                                 hint->base.state = HINT_STATE_ERROR;
1842                                 break;
1843                         }
1844
1845                         hint->joinrelids = bms_add_member(hint->joinrelids, relid);
1846                 }
1847
1848                 if (relid <= 0 || hint->base.state == HINT_STATE_ERROR)
1849                         continue;
1850
1851                 plan->join_hint_level[hint->nrels] =
1852                         lappend(plan->join_hint_level[hint->nrels], hint);
1853         }
1854
1855         /*
1856          * 有効なLeading ヒントが指定されている場合は、結合順にあわせてjoin method hint
1857          * のフォーマットに変換する。
1858          */
1859         if (plan->num_hints[HINT_TYPE_LEADING] == 0)
1860                 return;
1861
1862         lhint = plan->leading_hint;
1863         if (!hint_state_enabled(lhint))
1864                 return;
1865
1866         /* Leading hint は、全ての join 方式が有効な hint として登録する */
1867         joinrelids = NULL;
1868         njoinrels = 0;
1869         foreach(l, lhint->relations)
1870         {
1871                 char   *relname = (char *)lfirst(l);
1872                 JoinMethodHint *hint;
1873
1874                 relid =
1875                         find_relid_aliasname(root, relname, initial_rels, plan->hint_str);
1876
1877                 if (relid == -1)
1878                 {
1879                         bms_free(joinrelids);
1880                         return;
1881                 }
1882
1883                 if (relid == 0)
1884                         continue;
1885
1886                 if (bms_is_member(relid, joinrelids))
1887                 {
1888                         parse_ereport(lhint->base.hint_str,
1889                                                   ("Relation name \"%s\" is duplicate.", relname));
1890                         lhint->base.state = HINT_STATE_ERROR;
1891                         bms_free(joinrelids);
1892                         return;
1893                 }
1894
1895                 joinrelids = bms_add_member(joinrelids, relid);
1896                 njoinrels++;
1897
1898                 if (njoinrels < 2)
1899                         continue;
1900
1901                 hint = find_join_hint(joinrelids);
1902                 if (hint == NULL)
1903                 {
1904                         /*
1905                          * Here relnames is not set, since Relids bitmap is sufficient to
1906                          * control paths of this query afterwards.
1907                          */
1908                         hint = (JoinMethodHint *) JoinMethodHintCreate(lhint->base.hint_str,
1909                                                                                                                    HINT_LEADING);
1910                         hint->base.state = HINT_STATE_USED;
1911                         hint->nrels = njoinrels;
1912                         hint->enforce_mask = ENABLE_ALL_JOIN;
1913                         hint->joinrelids = bms_copy(joinrelids);
1914                 }
1915
1916                 join_method_hints[njoinrels] = hint;
1917
1918                 if (njoinrels >= nbaserel)
1919                         break;
1920         }
1921
1922         bms_free(joinrelids);
1923
1924         if (njoinrels < 2)
1925                 return;
1926
1927         for (i = 2; i <= njoinrels; i++)
1928         {
1929                 /* Leading で指定した組み合わせ以外の join hint を削除する */
1930                 list_free(plan->join_hint_level[i]);
1931
1932                 plan->join_hint_level[i] = lappend(NIL, join_method_hints[i]);
1933         }
1934
1935         if (hint_state_enabled(lhint))
1936                 set_join_config_options(DISABLE_ALL_JOIN, global->context);
1937
1938         lhint->base.state = HINT_STATE_USED;
1939
1940 }
1941
1942 /*
1943  * set_plain_rel_pathlist
1944  *        Build access paths for a plain relation (no subquery, no inheritance)
1945  *
1946  * This function was copied and edited from set_plain_rel_pathlist() in
1947  * src/backend/optimizer/path/allpaths.c
1948  */
1949 static void
1950 set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1951 {
1952         /* Consider sequential scan */
1953         add_path(rel, create_seqscan_path(root, rel));
1954
1955         /* Consider index scans */
1956         create_index_paths(root, rel);
1957
1958         /* Consider TID scans */
1959         create_tidscan_paths(root, rel);
1960
1961         /* Now find the cheapest of the paths for this rel */
1962         set_cheapest(rel);
1963 }
1964
1965 static void
1966 rebuild_scan_path(PlanHint *plan, PlannerInfo *root, int level,
1967                                   List *initial_rels)
1968 {
1969         ListCell   *l;
1970
1971         foreach(l, initial_rels)
1972         {
1973                 RelOptInfo         *rel = (RelOptInfo *) lfirst(l);
1974                 RangeTblEntry  *rte;
1975                 ScanMethodHint *hint;
1976
1977                 /*
1978                  * スキャン方式が選択できるリレーションのみ、スキャンパスを再生成
1979                  * する。
1980                  */
1981                 if (rel->reloptkind != RELOPT_BASEREL || rel->rtekind != RTE_RELATION)
1982                         continue;
1983
1984                 rte = root->simple_rte_array[rel->relid];
1985
1986                 /* 外部表はスキャン方式が選択できない。 */
1987                 if (rte->relkind == RELKIND_FOREIGN_TABLE)
1988                         continue;
1989
1990                 /*
1991                  * scan method hint が指定されていなければ、初期値のGUCパラメータでscan
1992                  * path を再生成する。
1993                  */
1994                 if ((hint = find_scan_hint(root, rel)) == NULL)
1995                         set_scan_config_options(plan->init_scan_mask, plan->context);
1996                 else
1997                 {
1998                         set_scan_config_options(hint->enforce_mask, plan->context);
1999                         hint->base.state = HINT_STATE_USED;
2000                 }
2001
2002                 list_free_deep(rel->pathlist);
2003                 rel->pathlist = NIL;
2004                 if (rte->inh)
2005                 {
2006                         /* It's an "append relation", process accordingly */
2007                         set_append_rel_pathlist(root, rel, rel->relid, rte);
2008                 }
2009                 else
2010                 {
2011                         set_plain_rel_pathlist(root, rel, rte);
2012                 }
2013         }
2014
2015         /*
2016          * Restore the GUC variables we set above.
2017          */
2018         set_scan_config_options(plan->init_scan_mask, plan->context);
2019 }
2020
2021 /*
2022  * make_join_rel() をラップする関数
2023  *
2024  * ヒントにしたがって、enabele_* パラメータを変更した上で、make_join_rel()を
2025  * 呼び出す。
2026  */
2027 static RelOptInfo *
2028 make_join_rel_wrapper(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
2029 {
2030         Relids                  joinrelids;
2031         JoinMethodHint *hint;
2032         RelOptInfo         *rel;
2033         int                             save_nestlevel;
2034
2035         joinrelids = bms_union(rel1->relids, rel2->relids);
2036         hint = find_join_hint(joinrelids);
2037         bms_free(joinrelids);
2038
2039         if (!hint)
2040                 return pg_hint_plan_make_join_rel(root, rel1, rel2);
2041
2042         save_nestlevel = NewGUCNestLevel();
2043
2044         set_join_config_options(hint->enforce_mask, global->context);
2045
2046         rel = pg_hint_plan_make_join_rel(root, rel1, rel2);
2047         hint->base.state = HINT_STATE_USED;
2048
2049         /*
2050          * Restore the GUC variables we set above.
2051          */
2052         AtEOXact_GUC(true, save_nestlevel);
2053
2054         return rel;
2055 }
2056
2057 static int
2058 get_num_baserels(List *initial_rels)
2059 {
2060         int                     nbaserel = 0;
2061         ListCell   *l;
2062
2063         foreach(l, initial_rels)
2064         {
2065                 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
2066
2067                 if (rel->reloptkind == RELOPT_BASEREL)
2068                         nbaserel++;
2069                 else if (rel->reloptkind ==RELOPT_JOINREL)
2070                         nbaserel+= bms_num_members(rel->relids);
2071                 else
2072                 {
2073                         /* other values not expected here */
2074                         elog(ERROR, "unrecognized reloptkind type: %d", rel->reloptkind);
2075                 }
2076         }
2077
2078         return nbaserel;
2079 }
2080
2081 static RelOptInfo *
2082 pg_hint_plan_join_search(PlannerInfo *root, int levels_needed,
2083                                                  List *initial_rels)
2084 {
2085         JoinMethodHint **join_method_hints;
2086         int                     nbaserel;
2087         RelOptInfo *rel;
2088         int                     i;
2089
2090         /*
2091          * pg_hint_planが無効、または有効なヒントが1つも指定されなかった場合は、標準
2092          * の処理を行う。
2093          */
2094         if (!global)
2095         {
2096                 if (prev_join_search)
2097                         return (*prev_join_search) (root, levels_needed, initial_rels);
2098                 else if (enable_geqo && levels_needed >= geqo_threshold)
2099                         return geqo(root, levels_needed, initial_rels);
2100                 else
2101                         return standard_join_search(root, levels_needed, initial_rels);
2102         }
2103
2104         /* We apply scan method hint rebuild scan path. */
2105         rebuild_scan_path(global, root, levels_needed, initial_rels);
2106
2107         /*
2108          * GEQOを使用する条件を満たした場合は、GEQOを用いた結合方式の検索を行う。
2109          * このとき、スキャン方式のヒントとSetヒントのみが有効になり、結合方式や結合
2110          * 順序はヒント句は無効になりGEQOのアルゴリズムで決定される。
2111          */
2112         if (enable_geqo && levels_needed >= geqo_threshold)
2113                 return geqo(root, levels_needed, initial_rels);
2114
2115         nbaserel = get_num_baserels(initial_rels);
2116         global->join_hint_level = palloc0(sizeof(List *) * (nbaserel + 1));
2117         join_method_hints = palloc0(sizeof(JoinMethodHint *) * (nbaserel + 1));
2118
2119         transform_join_hints(global, root, nbaserel, initial_rels,
2120                                                  join_method_hints);
2121
2122         rel = pg_hint_plan_standard_join_search(root, levels_needed, initial_rels);
2123
2124         for (i = 2; i <= nbaserel; i++)
2125         {
2126                 list_free(global->join_hint_level[i]);
2127
2128                 /* free Leading hint only */
2129                 if (join_method_hints[i] != NULL &&
2130                         join_method_hints[i]->enforce_mask == ENABLE_ALL_JOIN)
2131                         JoinMethodHintDelete(join_method_hints[i]);
2132         }
2133         pfree(global->join_hint_level);
2134         pfree(join_method_hints);
2135
2136         if (global->num_hints[HINT_TYPE_LEADING] > 0 &&
2137                 hint_state_enabled(global->leading_hint))
2138                 set_join_config_options(global->init_join_mask, global->context);
2139
2140         return rel;
2141 }
2142
2143 /*
2144  * set_rel_pathlist
2145  *        Build access paths for a base relation
2146  *
2147  * This function was copied and edited from set_rel_pathlist() in
2148  * src/backend/optimizer/path/allpaths.c
2149  */
2150 static void
2151 set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
2152                                  Index rti, RangeTblEntry *rte)
2153 {
2154         if (rte->inh)
2155         {
2156                 /* It's an "append relation", process accordingly */
2157                 set_append_rel_pathlist(root, rel, rti, rte);
2158         }
2159         else
2160         {
2161                 if (rel->rtekind == RTE_RELATION)
2162                 {
2163                         if (rte->relkind == RELKIND_RELATION)
2164                         {
2165                                 /* Plain relation */
2166                                 set_plain_rel_pathlist(root, rel, rte);
2167                         }
2168                         else
2169                                 elog(ERROR, "unexpected relkind: %c", rte->relkind);
2170                 }
2171                 else
2172                         elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
2173         }
2174 }
2175
2176 #define standard_join_search pg_hint_plan_standard_join_search
2177 #define join_search_one_level pg_hint_plan_join_search_one_level
2178 #define make_join_rel make_join_rel_wrapper
2179 #include "core.c"
2180
2181 #undef make_join_rel
2182 #define make_join_rel pg_hint_plan_make_join_rel
2183 #define add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype, sjinfo, restrictlist) \
2184 do { \
2185         ScanMethodHint *hint = NULL; \
2186         if ((hint = find_scan_hint((root), (innerrel))) != NULL) \
2187         { \
2188                 set_scan_config_options(hint->enforce_mask, global->context); \
2189                 hint->base.state = HINT_STATE_USED; \
2190         } \
2191         add_paths_to_joinrel((root), (joinrel), (outerrel), (innerrel), (jointype), (sjinfo), (restrictlist)); \
2192         if (hint != NULL) \
2193                 set_scan_config_options(global->init_scan_mask, global->context); \
2194 } while(0)
2195 #include "make_join_rel.c"