OSDN Git Service

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