OSDN Git Service

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