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