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