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 #if PG_VERSION_NUM >= 90200
31 #include "catalog/pg_class.h"
32 #endif
33
34 #ifdef PG_MODULE_MAGIC
35 PG_MODULE_MAGIC;
36 #endif
37
38 #if PG_VERSION_NUM < 90100
39 #error unsupported PostgreSQL version
40 #endif
41
42 #define BLOCK_COMMENT_START             "/*"
43 #define BLOCK_COMMENT_END               "*/"
44 #define HINT_COMMENT_KEYWORD    "+"
45 #define HINT_START                              BLOCK_COMMENT_START HINT_COMMENT_KEYWORD
46 #define HINT_END                                BLOCK_COMMENT_END
47
48 /* hint keywords */
49 #define HINT_SEQSCAN                    "SeqScan"
50 #define HINT_INDEXSCAN                  "IndexScan"
51 #define HINT_BITMAPSCAN                 "BitmapScan"
52 #define HINT_TIDSCAN                    "TidScan"
53 #define HINT_NOSEQSCAN                  "NoSeqScan"
54 #define HINT_NOINDEXSCAN                "NoIndexScan"
55 #define HINT_NOBITMAPSCAN               "NoBitmapScan"
56 #define HINT_NOTIDSCAN                  "NoTidScan"
57 #if PG_VERSION_NUM >= 90200
58 #define HINT_INDEXONLYSCAN              "IndexOnlyScan"
59 #define HINT_NOINDEXONLYSCAN    "NoIndexOnlyScan"
60 #endif
61 #define HINT_NESTLOOP                   "NestLoop"
62 #define HINT_MERGEJOIN                  "MergeJoin"
63 #define HINT_HASHJOIN                   "HashJoin"
64 #define HINT_NONESTLOOP                 "NoNestLoop"
65 #define HINT_NOMERGEJOIN                "NoMergeJoin"
66 #define HINT_NOHASHJOIN                 "NoHashJoin"
67 #define HINT_LEADING                    "Leading"
68 #define HINT_SET                                "Set"
69
70 #define HINT_ARRAY_DEFAULT_INITSIZE 8
71
72 #define parse_ereport(str, detail) \
73         ereport(pg_hint_plan_parse_messages, \
74                         (errmsg("hint syntax error at or near \"%s\"", (str)), \
75                          errdetail detail))
76
77 #define skip_space(str) \
78         while (isspace(*str)) \
79                 str++;
80
81 enum
82 {
83         ENABLE_SEQSCAN = 0x01,
84         ENABLE_INDEXSCAN = 0x02,
85         ENABLE_BITMAPSCAN = 0x04,
86         ENABLE_TIDSCAN = 0x08,
87 #if PG_VERSION_NUM >= 90200
88         ENABLE_INDEXONLYSCAN = 0x10
89 #endif
90 } SCAN_TYPE_BITS;
91
92 enum
93 {
94         ENABLE_NESTLOOP = 0x01,
95         ENABLE_MERGEJOIN = 0x02,
96         ENABLE_HASHJOIN = 0x04
97 } JOIN_TYPE_BITS;
98
99 #if PG_VERSION_NUM >= 90200
100 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | \
101                                                  ENABLE_BITMAPSCAN | ENABLE_TIDSCAN | \
102                                                  ENABLE_INDEXONLYSCAN)
103 #else
104 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | \
105                                                  ENABLE_BITMAPSCAN | ENABLE_TIDSCAN)
106 #endif
107 #define ENABLE_ALL_JOIN (ENABLE_NESTLOOP | ENABLE_MERGEJOIN | ENABLE_HASHJOIN)
108 #define DISABLE_ALL_SCAN 0
109 #define DISABLE_ALL_JOIN 0
110
111 typedef struct Hint Hint;
112 typedef struct HintState HintState;
113
114 typedef Hint *(*HintCreateFunction) (const char *hint_str,
115                                                                          const char *keyword);
116 typedef void (*HintDeleteFunction) (Hint *hint);
117 typedef void (*HintDumpFunction) (Hint *hint, StringInfo buf);
118 typedef int (*HintCmpFunction) (const Hint *a, const Hint *b);
119 typedef const char *(*HintParseFunction) (Hint *hint, HintState *hstate,
120                                                                                   Query *parse, const char *str);
121
122 /* hint types */
123 #define NUM_HINT_TYPE   4
124 typedef enum HintType
125 {
126         HINT_TYPE_SCAN_METHOD,
127         HINT_TYPE_JOIN_METHOD,
128         HINT_TYPE_LEADING,
129         HINT_TYPE_SET
130 } HintType;
131
132 static const char *HintTypeName[] = {
133         "scan method",
134         "join method",
135         "leading",
136         "set"
137 };
138
139 /* hint status */
140 typedef enum HintStatus
141 {
142         HINT_STATE_NOTUSED = 0,         /* specified relation not used in query */
143         HINT_STATE_USED,                        /* hint is used */
144         HINT_STATE_DUPLICATION,         /* specified hint duplication */
145         HINT_STATE_ERROR                        /* execute error (parse error does not include
146                                                                  * it) */
147 } HintStatus;
148
149 #define hint_state_enabled(hint) ((hint)->base.state == HINT_STATE_NOTUSED || \
150                                                                   (hint)->base.state == HINT_STATE_USED)
151
152 /* common data for all hints. */
153 struct Hint
154 {
155         const char                 *hint_str;           /* must not do pfree */
156         const char                 *keyword;            /* must not do pfree */
157         HintType                        type;
158         HintStatus                      state;
159         HintDeleteFunction      delete_func;
160         HintDumpFunction        dump_func;
161         HintCmpFunction         cmp_func;
162         HintParseFunction       parser_func;
163 };
164
165 /* scan method hints */
166 typedef struct ScanMethodHint
167 {
168         Hint                    base;
169         char               *relname;
170         List               *indexnames;
171         unsigned char   enforce_mask;
172 } ScanMethodHint;
173
174 /* join method hints */
175 typedef struct JoinMethodHint
176 {
177         Hint                    base;
178         int                             nrels;
179         char              **relnames;
180         unsigned char   enforce_mask;
181         Relids                  joinrelids;
182 } JoinMethodHint;
183
184 /* join order hints */
185 typedef struct LeadingHint
186 {
187         Hint    base;
188         List   *relations;              /* relation names specified in Leading hint */
189 } LeadingHint;
190
191 /* change a run-time parameter hints */
192 typedef struct SetHint
193 {
194         Hint    base;
195         char   *name;                           /* name of variable */
196         char   *value;
197         List   *words;
198 } SetHint;
199
200 /*
201  * Describes a context of hint processing.
202  */
203 struct HintState
204 {
205         char               *hint_str;                   /* original hint string */
206
207         /* all hint */
208         int                             nall_hints;                     /* # of valid all hints */
209         int                             max_all_hints;          /* # of slots for all hints */
210         Hint              **all_hints;                  /* parsed all hints */
211
212         /* # of each hints */
213         int                             num_hints[NUM_HINT_TYPE];
214
215         /* for scan method hints */
216         ScanMethodHint **scan_hints;            /* parsed scan hints */
217         int                             init_scan_mask;         /* initial value scan parameter */
218         Index                   parent_relid;           /* inherit parent table relid */
219         ScanMethodHint *parent_hint;            /* inherit parent table scan hint */
220
221         /* for join method hints */
222         JoinMethodHint **join_hints;            /* parsed join hints */
223         int                             init_join_mask;         /* initial value join parameter */
224         List              **join_hint_level;
225
226         /* for Leading hint */
227         LeadingHint        *leading_hint;               /* parsed last specified Leading hint */
228
229         /* for Set hints */
230         SetHint           **set_hints;                  /* parsed Set hints */
231         GucContext              context;                        /* which GUC parameters can we set? */
232 };
233
234 /*
235  * Describes a hint parser module which is bound with particular hint keyword.
236  */
237 typedef struct HintParser
238 {
239         char                       *keyword;
240         HintCreateFunction      create_func;
241 } HintParser;
242
243 /* Module callbacks */
244 void            _PG_init(void);
245 void            _PG_fini(void);
246
247 static void push_hint(HintState *hstate);
248 static void pop_hint(void);
249
250 static void pg_hint_plan_ProcessUtility(Node *parsetree,
251                                                                                 const char *queryString,
252                                                                                 ParamListInfo params, bool isTopLevel,
253                                                                                 DestReceiver *dest,
254                                                                                 char *completionTag);
255 static PlannedStmt *pg_hint_plan_planner(Query *parse, int cursorOptions,
256                                                                                  ParamListInfo boundParams);
257 static void pg_hint_plan_get_relation_info(PlannerInfo *root,
258                                                                                    Oid relationObjectId,
259                                                                                    bool inhparent, RelOptInfo *rel);
260 static RelOptInfo *pg_hint_plan_join_search(PlannerInfo *root,
261                                                                                         int levels_needed,
262                                                                                         List *initial_rels);
263
264 static Hint *ScanMethodHintCreate(const char *hint_str, const char *keyword);
265 static void ScanMethodHintDelete(ScanMethodHint *hint);
266 static void ScanMethodHintDump(ScanMethodHint *hint, StringInfo buf);
267 static int ScanMethodHintCmp(const ScanMethodHint *a, const ScanMethodHint *b);
268 static const char *ScanMethodHintParse(ScanMethodHint *hint, HintState *hstate,
269                                                                            Query *parse, const char *str);
270 static Hint *JoinMethodHintCreate(const char *hint_str, const char *keyword);
271 static void JoinMethodHintDelete(JoinMethodHint *hint);
272 static void JoinMethodHintDump(JoinMethodHint *hint, StringInfo buf);
273 static int JoinMethodHintCmp(const JoinMethodHint *a, const JoinMethodHint *b);
274 static const char *JoinMethodHintParse(JoinMethodHint *hint, HintState *hstate,
275                                                                            Query *parse, const char *str);
276 static Hint *LeadingHintCreate(const char *hint_str, const char *keyword);
277 static void LeadingHintDelete(LeadingHint *hint);
278 static void LeadingHintDump(LeadingHint *hint, StringInfo buf);
279 static int LeadingHintCmp(const LeadingHint *a, const LeadingHint *b);
280 static const char *LeadingHintParse(LeadingHint *hint, HintState *hstate,
281                                                                         Query *parse, const char *str);
282 static Hint *SetHintCreate(const char *hint_str, const char *keyword);
283 static void SetHintDelete(SetHint *hint);
284 static void SetHintDump(SetHint *hint, StringInfo buf);
285 static int SetHintCmp(const SetHint *a, const SetHint *b);
286 static const char *SetHintParse(SetHint *hint, HintState *hstate, Query *parse,
287                                                                 const char *str);
288
289 RelOptInfo *pg_hint_plan_standard_join_search(PlannerInfo *root,
290                                                                                           int levels_needed,
291                                                                                           List *initial_rels);
292 void pg_hint_plan_join_search_one_level(PlannerInfo *root, int level);
293 static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel,
294                                                                           ListCell *other_rels);
295 static void make_rels_by_clauseless_joins(PlannerInfo *root,
296                                                                                   RelOptInfo *old_rel,
297                                                                                   ListCell *other_rels);
298 static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
299 static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
300                                                                         Index rti, RangeTblEntry *rte);
301 #if PG_VERSION_NUM >= 90200
302 static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
303                                                    List *live_childrels,
304                                                    List *all_child_pathkeys);
305 #endif
306 static List *accumulate_append_subpath(List *subpaths, Path *path);
307 #if PG_VERSION_NUM < 90200
308 static void set_dummy_rel_pathlist(RelOptInfo *rel);
309 #endif
310 RelOptInfo *pg_hint_plan_make_join_rel(PlannerInfo *root, RelOptInfo *rel1,
311                                                                            RelOptInfo *rel2);
312
313 /* GUC variables */
314 static bool     pg_hint_plan_enable_hint = true;
315 static bool     pg_hint_plan_debug_print = false;
316 static int      pg_hint_plan_parse_messages = INFO;
317
318 static const struct config_enum_entry parse_messages_level_options[] = {
319         {"debug", DEBUG2, true},
320         {"debug5", DEBUG5, false},
321         {"debug4", DEBUG4, false},
322         {"debug3", DEBUG3, false},
323         {"debug2", DEBUG2, false},
324         {"debug1", DEBUG1, false},
325         {"log", LOG, false},
326         {"info", INFO, false},
327         {"notice", NOTICE, false},
328         {"warning", WARNING, false},
329         {"error", ERROR, false},
330         /*
331          * {"fatal", FATAL, true},
332          * {"panic", PANIC, true},
333          */
334         {NULL, 0, false}
335 };
336
337 /* Saved hook values in case of unload */
338 static ProcessUtility_hook_type prev_ProcessUtility = NULL;
339 static planner_hook_type prev_planner = NULL;
340 static get_relation_info_hook_type prev_get_relation_info = NULL;
341 static join_search_hook_type prev_join_search = NULL;
342
343 /* Hold reference to currently active hint */
344 static HintState *current_hint = NULL;
345
346 /*
347  * List of hint contexts.  We treat the head of the list as the Top of the
348  * context stack, so current_hint always points the first element of this list.
349  */
350 static List *HintStateStack = NIL;
351
352 /*
353  * Holds statement name during executing EXECUTE command.  NULL for other
354  * statements.
355  */
356 static char        *stmt_name = NULL;
357
358 static const HintParser parsers[] = {
359         {HINT_SEQSCAN, ScanMethodHintCreate},
360         {HINT_INDEXSCAN, ScanMethodHintCreate},
361         {HINT_BITMAPSCAN, ScanMethodHintCreate},
362         {HINT_TIDSCAN, ScanMethodHintCreate},
363         {HINT_NOSEQSCAN, ScanMethodHintCreate},
364         {HINT_NOINDEXSCAN, ScanMethodHintCreate},
365         {HINT_NOBITMAPSCAN, ScanMethodHintCreate},
366         {HINT_NOTIDSCAN, ScanMethodHintCreate},
367 #if PG_VERSION_NUM >= 90200
368         {HINT_INDEXONLYSCAN, ScanMethodHintCreate},
369         {HINT_NOINDEXONLYSCAN, ScanMethodHintCreate},
370 #endif
371         {HINT_NESTLOOP, JoinMethodHintCreate},
372         {HINT_MERGEJOIN, JoinMethodHintCreate},
373         {HINT_HASHJOIN, JoinMethodHintCreate},
374         {HINT_NONESTLOOP, JoinMethodHintCreate},
375         {HINT_NOMERGEJOIN, JoinMethodHintCreate},
376         {HINT_NOHASHJOIN, JoinMethodHintCreate},
377         {HINT_LEADING, LeadingHintCreate},
378         {HINT_SET, SetHintCreate},
379         {NULL, NULL}
380 };
381
382 /*
383  * Module load callbacks
384  */
385 void
386 _PG_init(void)
387 {
388         /* Define custom GUC variables. */
389         DefineCustomBoolVariable("pg_hint_plan.enable_hint",
390                          "Force planner to use plans specified in the hint comment preceding to the query.",
391                                                          NULL,
392                                                          &pg_hint_plan_enable_hint,
393                                                          true,
394                                                          PGC_USERSET,
395                                                          0,
396                                                          NULL,
397                                                          NULL,
398                                                          NULL);
399
400         DefineCustomBoolVariable("pg_hint_plan.debug_print",
401                                                          "Logs results of hint parsing.",
402                                                          NULL,
403                                                          &pg_hint_plan_debug_print,
404                                                          false,
405                                                          PGC_USERSET,
406                                                          0,
407                                                          NULL,
408                                                          NULL,
409                                                          NULL);
410
411         DefineCustomEnumVariable("pg_hint_plan.parse_messages",
412                                                          "Message level of parse errors.",
413                                                          NULL,
414                                                          &pg_hint_plan_parse_messages,
415                                                          INFO,
416                                                          parse_messages_level_options,
417                                                          PGC_USERSET,
418                                                          0,
419                                                          NULL,
420                                                          NULL,
421                                                          NULL);
422
423         /* Install hooks. */
424         prev_ProcessUtility = ProcessUtility_hook;
425         ProcessUtility_hook = pg_hint_plan_ProcessUtility;
426         prev_planner = planner_hook;
427         planner_hook = pg_hint_plan_planner;
428         prev_get_relation_info = get_relation_info_hook;
429         get_relation_info_hook = pg_hint_plan_get_relation_info;
430         prev_join_search = join_search_hook;
431         join_search_hook = pg_hint_plan_join_search;
432 }
433
434 /*
435  * Module unload callback
436  * XXX never called
437  */
438 void
439 _PG_fini(void)
440 {
441         /* Uninstall hooks. */
442         ProcessUtility_hook = prev_ProcessUtility;
443         planner_hook = prev_planner;
444         get_relation_info_hook = prev_get_relation_info;
445         join_search_hook = prev_join_search;
446 }
447
448 /*
449  * create and delete functions the hint object
450  */
451
452 static Hint *
453 ScanMethodHintCreate(const char *hint_str, const char *keyword)
454 {
455         ScanMethodHint *hint;
456
457         hint = palloc(sizeof(ScanMethodHint));
458         hint->base.hint_str = hint_str;
459         hint->base.keyword = keyword;
460         hint->base.type = HINT_TYPE_SCAN_METHOD;
461         hint->base.state = HINT_STATE_NOTUSED;
462         hint->base.delete_func = (HintDeleteFunction) ScanMethodHintDelete;
463         hint->base.dump_func = (HintDumpFunction) ScanMethodHintDump;
464         hint->base.cmp_func = (HintCmpFunction) ScanMethodHintCmp;
465         hint->base.parser_func = (HintParseFunction) ScanMethodHintParse;
466         hint->relname = NULL;
467         hint->indexnames = NIL;
468         hint->enforce_mask = 0;
469
470         return (Hint *) hint;
471 }
472
473 static void
474 ScanMethodHintDelete(ScanMethodHint *hint)
475 {
476         if (!hint)
477                 return;
478
479         if (hint->relname)
480                 pfree(hint->relname);
481         list_free_deep(hint->indexnames);
482         pfree(hint);
483 }
484
485 static Hint *
486 JoinMethodHintCreate(const char *hint_str, const char *keyword)
487 {
488         JoinMethodHint *hint;
489
490         hint = palloc(sizeof(JoinMethodHint));
491         hint->base.hint_str = hint_str;
492         hint->base.keyword = keyword;
493         hint->base.type = HINT_TYPE_JOIN_METHOD;
494         hint->base.state = HINT_STATE_NOTUSED;
495         hint->base.delete_func = (HintDeleteFunction) JoinMethodHintDelete;
496         hint->base.dump_func = (HintDumpFunction) JoinMethodHintDump;
497         hint->base.cmp_func = (HintCmpFunction) JoinMethodHintCmp;
498         hint->base.parser_func = (HintParseFunction) JoinMethodHintParse;
499         hint->nrels = 0;
500         hint->relnames = NULL;
501         hint->enforce_mask = 0;
502         hint->joinrelids = NULL;
503
504         return (Hint *) hint;
505 }
506
507 static void
508 JoinMethodHintDelete(JoinMethodHint *hint)
509 {
510         if (!hint)
511                 return;
512
513         if (hint->relnames)
514         {
515                 int     i;
516
517                 for (i = 0; i < hint->nrels; i++)
518                         pfree(hint->relnames[i]);
519                 pfree(hint->relnames);
520         }
521         bms_free(hint->joinrelids);
522         pfree(hint);
523 }
524
525 static Hint *
526 LeadingHintCreate(const char *hint_str, const char *keyword)
527 {
528         LeadingHint        *hint;
529
530         hint = palloc(sizeof(LeadingHint));
531         hint->base.hint_str = hint_str;
532         hint->base.keyword = keyword;
533         hint->base.type = HINT_TYPE_LEADING;
534         hint->base.state = HINT_STATE_NOTUSED;
535         hint->base.delete_func = (HintDeleteFunction)LeadingHintDelete;
536         hint->base.dump_func = (HintDumpFunction) LeadingHintDump;
537         hint->base.cmp_func = (HintCmpFunction) LeadingHintCmp;
538         hint->base.parser_func = (HintParseFunction) LeadingHintParse;
539         hint->relations = NIL;
540
541         return (Hint *) hint;
542 }
543
544 static void
545 LeadingHintDelete(LeadingHint *hint)
546 {
547         if (!hint)
548                 return;
549
550         list_free_deep(hint->relations);
551         pfree(hint);
552 }
553
554 static Hint *
555 SetHintCreate(const char *hint_str, const char *keyword)
556 {
557         SetHint    *hint;
558
559         hint = palloc(sizeof(SetHint));
560         hint->base.hint_str = hint_str;
561         hint->base.keyword = keyword;
562         hint->base.type = HINT_TYPE_SET;
563         hint->base.state = HINT_STATE_NOTUSED;
564         hint->base.delete_func = (HintDeleteFunction) SetHintDelete;
565         hint->base.dump_func = (HintDumpFunction) SetHintDump;
566         hint->base.cmp_func = (HintCmpFunction) SetHintCmp;
567         hint->base.parser_func = (HintParseFunction) SetHintParse;
568         hint->name = NULL;
569         hint->value = NULL;
570         hint->words = NIL;
571
572         return (Hint *) hint;
573 }
574
575 static void
576 SetHintDelete(SetHint *hint)
577 {
578         if (!hint)
579                 return;
580
581         if (hint->name)
582                 pfree(hint->name);
583         if (hint->value)
584                 pfree(hint->value);
585         if (hint->words)
586                 list_free(hint->words);
587         pfree(hint);
588 }
589
590 static HintState *
591 HintStateCreate(void)
592 {
593         HintState   *hstate;
594
595         hstate = palloc(sizeof(HintState));
596         hstate->hint_str = NULL;
597         hstate->nall_hints = 0;
598         hstate->max_all_hints = 0;
599         hstate->all_hints = NULL;
600         memset(hstate->num_hints, 0, sizeof(hstate->num_hints));
601         hstate->scan_hints = NULL;
602         hstate->init_scan_mask = 0;
603         hstate->parent_relid = 0;
604         hstate->parent_hint = NULL;
605         hstate->join_hints = NULL;
606         hstate->init_join_mask = 0;
607         hstate->join_hint_level = NULL;
608         hstate->leading_hint = NULL;
609         hstate->context = superuser() ? PGC_SUSET : PGC_USERSET;
610         hstate->set_hints = NULL;
611
612         return hstate;
613 }
614
615 static void
616 HintStateDelete(HintState *hstate)
617 {
618         int                     i;
619
620         if (!hstate)
621                 return;
622
623         if (hstate->hint_str)
624                 pfree(hstate->hint_str);
625
626         for (i = 0; i < hstate->num_hints[HINT_TYPE_SCAN_METHOD]; i++)
627                 hstate->all_hints[i]->delete_func(hstate->all_hints[i]);
628         if (hstate->all_hints)
629                 pfree(hstate->all_hints);
630 }
631
632 /*
633  * dump functions
634  */
635
636 static void
637 dump_quote_value(StringInfo buf, const char *value)
638 {
639         bool            need_quote = false;
640         const char *str;
641
642         for (str = value; *str != '\0'; str++)
643         {
644                 if (isspace(*str) || *str == ')' || *str == '"')
645                 {
646                         need_quote = true;
647                         appendStringInfoCharMacro(buf, '"');
648                         break;
649                 }
650         }
651
652         for (str = value; *str != '\0'; str++)
653         {
654                 if (*str == '"')
655                         appendStringInfoCharMacro(buf, '"');
656
657                 appendStringInfoCharMacro(buf, *str);
658         }
659
660         if (need_quote)
661                 appendStringInfoCharMacro(buf, '"');
662 }
663
664 static void
665 ScanMethodHintDump(ScanMethodHint *hint, StringInfo buf)
666 {
667         ListCell   *l;
668
669         appendStringInfo(buf, "%s(", hint->base.keyword);
670         if (hint->relname != NULL)
671         {
672                 dump_quote_value(buf, hint->relname);
673                 foreach(l, hint->indexnames)
674                 {
675                         appendStringInfoCharMacro(buf, ' ');
676                         dump_quote_value(buf, (char *) lfirst(l));
677                 }
678         }
679         appendStringInfoString(buf, ")\n");
680 }
681
682 static void
683 JoinMethodHintDump(JoinMethodHint *hint, StringInfo buf)
684 {
685         int     i;
686
687         appendStringInfo(buf, "%s(", hint->base.keyword);
688         if (hint->relnames != NULL)
689         {
690                 dump_quote_value(buf, hint->relnames[0]);
691                 for (i = 1; i < hint->nrels; i++)
692                 {
693                         appendStringInfoCharMacro(buf, ' ');
694                         dump_quote_value(buf, hint->relnames[i]);
695                 }
696         }
697         appendStringInfoString(buf, ")\n");
698
699 }
700
701 static void
702 LeadingHintDump(LeadingHint *hint, StringInfo buf)
703 {
704         bool            is_first;
705         ListCell   *l;
706
707         appendStringInfo(buf, "%s(", HINT_LEADING);
708         is_first = true;
709         foreach(l, hint->relations)
710         {
711                 if (is_first)
712                         is_first = false;
713                 else
714                         appendStringInfoCharMacro(buf, ' ');
715
716                 dump_quote_value(buf, (char *) lfirst(l));
717         }
718
719         appendStringInfoString(buf, ")\n");
720 }
721
722 static void
723 SetHintDump(SetHint *hint, StringInfo buf)
724 {
725         bool            is_first = true;
726         ListCell   *l;
727
728         appendStringInfo(buf, "%s(", HINT_SET);
729         foreach(l, hint->words)
730         {
731                 if (is_first)
732                         is_first = false;
733                 else
734                         appendStringInfoCharMacro(buf, ' ');
735
736                 dump_quote_value(buf, (char *) lfirst(l));
737         }
738         appendStringInfo(buf, ")\n");
739 }
740
741 static void
742 all_hint_dump(HintState *hstate, StringInfo buf, const char *title,
743                           HintStatus state)
744 {
745         int     i;
746
747         appendStringInfo(buf, "%s:\n", title);
748         for (i = 0; i < hstate->nall_hints; i++)
749         {
750                 if (hstate->all_hints[i]->state != state)
751                         continue;
752
753                 hstate->all_hints[i]->dump_func(hstate->all_hints[i], buf);
754         }
755 }
756
757 static void
758 HintStateDump(HintState *hstate)
759 {
760         StringInfoData  buf;
761
762         if (!hstate)
763         {
764                 elog(LOG, "pg_hint_plan:\nno hint");
765                 return;
766         }
767
768         initStringInfo(&buf);
769
770         appendStringInfoString(&buf, "pg_hint_plan:\n");
771         all_hint_dump(hstate, &buf, "used hint", HINT_STATE_USED);
772         all_hint_dump(hstate, &buf, "not used hint", HINT_STATE_NOTUSED);
773         all_hint_dump(hstate, &buf, "duplication hint", HINT_STATE_DUPLICATION);
774         all_hint_dump(hstate, &buf, "error hint", HINT_STATE_ERROR);
775
776         elog(LOG, "%s", buf.data);
777
778         pfree(buf.data);
779 }
780
781 /*
782  * compare functions
783  */
784
785 static int
786 RelnameCmp(const void *a, const void *b)
787 {
788         const char *relnamea = *((const char **) a);
789         const char *relnameb = *((const char **) b);
790
791         return strcmp(relnamea, relnameb);
792 }
793
794 static int
795 ScanMethodHintCmp(const ScanMethodHint *a, const ScanMethodHint *b)
796 {
797         return RelnameCmp(&a->relname, &b->relname);
798 }
799
800 static int
801 JoinMethodHintCmp(const JoinMethodHint *a, const JoinMethodHint *b)
802 {
803         int     i;
804
805         if (a->nrels != b->nrels)
806                 return a->nrels - b->nrels;
807
808         for (i = 0; i < a->nrels; i++)
809         {
810                 int     result;
811                 if ((result = RelnameCmp(&a->relnames[i], &b->relnames[i])) != 0)
812                         return result;
813         }
814
815         return 0;
816 }
817
818 static int
819 LeadingHintCmp(const LeadingHint *a, const LeadingHint *b)
820 {
821         return 0;
822 }
823
824 static int
825 SetHintCmp(const SetHint *a, const SetHint *b)
826 {
827         return strcmp(a->name, b->name);
828 }
829
830 static int
831 HintCmp(const void *a, const void *b)
832 {
833         const Hint *hinta = *((const Hint **) a);
834         const Hint *hintb = *((const Hint **) b);
835
836         if (hinta->type != hintb->type)
837                 return hinta->type - hintb->type;
838         if (hinta->state == HINT_STATE_ERROR)
839                 return -1;
840         if (hintb->state == HINT_STATE_ERROR)
841                 return 1;
842         return hinta->cmp_func(hinta, hintb);
843 }
844
845 /*
846  * Returns byte offset of hint b from hint a.  If hint a was specified before
847  * b, positive value is returned.
848  */
849 static int
850 HintCmpWithPos(const void *a, const void *b)
851 {
852         const Hint *hinta = *((const Hint **) a);
853         const Hint *hintb = *((const Hint **) b);
854         int             result;
855
856         result = HintCmp(a, b);
857         if (result == 0)
858                 result = hinta->hint_str - hintb->hint_str;
859
860         return result;
861 }
862
863 /*
864  * parse functions
865  */
866 static const char *
867 parse_keyword(const char *str, StringInfo buf)
868 {
869         skip_space(str);
870
871         while (!isspace(*str) && *str != '(' && *str != '\0')
872                 appendStringInfoCharMacro(buf, *str++);
873
874         return str;
875 }
876
877 static const char *
878 skip_opened_parenthesis(const char *str)
879 {
880         skip_space(str);
881
882         if (*str != '(')
883         {
884                 parse_ereport(str, ("Opening parenthesis is necessary."));
885                 return NULL;
886         }
887
888         str++;
889
890         return str;
891 }
892
893 static const char *
894 skip_closed_parenthesis(const char *str)
895 {
896         skip_space(str);
897
898         if (*str != ')')
899         {
900                 parse_ereport(str, ("Closing parenthesis is necessary."));
901                 return NULL;
902         }
903
904         str++;
905
906         return str;
907 }
908
909 /*
910  * Parse a token from str, and store malloc'd copy into word.  A token can be
911  * quoted with '"'.  Return value is pointer to unparsed portion of original
912  * string, or NULL if an error occurred.
913  *
914  * Parsed token is truncated within NAMEDATALEN-1 bytes, when truncate is true.
915  */
916 static const char *
917 parse_quote_value(const char *str, char **word, bool truncate)
918 {
919         StringInfoData  buf;
920         bool                    in_quote;
921
922         /* Skip leading spaces. */
923         skip_space(str);
924
925         initStringInfo(&buf);
926         if (*str == '"')
927         {
928                 str++;
929                 in_quote = true;
930         }
931         else
932                 in_quote = false;
933
934         while (true)
935         {
936                 if (in_quote)
937                 {
938                         /* Double quotation must be closed. */
939                         if (*str == '\0')
940                         {
941                                 pfree(buf.data);
942                                 parse_ereport(str, ("Unterminated quoted string."));
943                                 return NULL;
944                         }
945
946                         /*
947                          * Skip escaped double quotation.
948                          *
949                          * We don't allow slash-asterisk and asterisk-slash (delimiters of
950                          * block comments) to be an object name, so users must specify
951                          * alias for such object names.
952                          *
953                          * Those special names can be allowed if we care escaped slashes
954                          * and asterisks, but we don't.
955                          */
956                         if (*str == '"')
957                         {
958                                 str++;
959                                 if (*str != '"')
960                                         break;
961                         }
962                 }
963                 else if (isspace(*str) || *str == ')' || *str == '"' || *str == '\0')
964                         break;
965
966                 appendStringInfoCharMacro(&buf, *str++);
967         }
968
969         if (buf.len == 0)
970         {
971                 parse_ereport(str, ("Zero-length delimited string."));
972
973                 pfree(buf.data);
974
975                 return NULL;
976         }
977
978         /* Truncate name if it's too long */
979         if (truncate)
980                 truncate_identifier(buf.data, strlen(buf.data), true);
981
982         *word = buf.data;
983
984         return str;
985 }
986
987 static const char *
988 parse_parentheses(const char *str, List **name_list, HintType type)
989 {
990         char   *name;
991         bool    truncate = true;
992
993         if ((str = skip_opened_parenthesis(str)) == NULL)
994                 return NULL;
995
996         skip_space(str);
997
998         /* Store words in a parenthesis in a list. */
999         while(*str != ')' && *str != '\0')
1000         {
1001                 if ((str = parse_quote_value(str, &name, truncate)) == NULL)
1002                 {
1003                         list_free(*name_list);
1004                         return NULL;
1005                 }
1006
1007                 *name_list = lappend(*name_list, name);
1008                 skip_space(str);
1009
1010                 if (type == HINT_TYPE_SET)
1011                 {
1012                         truncate = false;
1013                 }
1014         }
1015
1016         if ((str = skip_closed_parenthesis(str)) == NULL)
1017                 return NULL;
1018         return str;
1019 }
1020
1021 static void
1022 parse_hints(HintState *hstate, Query *parse, const char *str)
1023 {
1024         StringInfoData  buf;
1025         char               *head;
1026
1027         initStringInfo(&buf);
1028         while (*str != '\0')
1029         {
1030                 const HintParser *parser;
1031
1032                 /* in error message, we output the comment including the keyword. */
1033                 head = (char *) str;
1034
1035                 /* parse only the keyword of the hint. */
1036                 resetStringInfo(&buf);
1037                 str = parse_keyword(str, &buf);
1038
1039                 for (parser = parsers; parser->keyword != NULL; parser++)
1040                 {
1041                         char   *keyword = parser->keyword;
1042                         Hint   *hint;
1043
1044                         if (strcasecmp(buf.data, keyword) != 0)
1045                                 continue;
1046
1047                         hint = parser->create_func(head, keyword);
1048
1049                         /* parser of each hint does parse in a parenthesis. */
1050                         if ((str = hint->parser_func(hint, hstate, parse, str)) == NULL)
1051                         {
1052                                 hint->delete_func(hint);
1053                                 pfree(buf.data);
1054                                 return;
1055                         }
1056
1057                         /*
1058                          * Add hint information into all_hints array.  If we don't have
1059                          * enough space, double the array.
1060                          */
1061                         if (hstate->nall_hints == 0)
1062                         {
1063                                 hstate->max_all_hints = HINT_ARRAY_DEFAULT_INITSIZE;
1064                                 hstate->all_hints = (Hint **)
1065                                         palloc(sizeof(Hint *) * hstate->max_all_hints);
1066                         }
1067                         else if (hstate->nall_hints == hstate->max_all_hints)
1068                         {
1069                                 hstate->max_all_hints *= 2;
1070                                 hstate->all_hints = (Hint **)
1071                                         repalloc(hstate->all_hints,
1072                                                          sizeof(Hint *) * hstate->max_all_hints);
1073                         }
1074
1075                         hstate->all_hints[hstate->nall_hints] = hint;
1076                         hstate->nall_hints++;
1077
1078                         skip_space(str);
1079
1080                         break;
1081                 }
1082
1083                 if (parser->keyword == NULL)
1084                 {
1085                         parse_ereport(head,
1086                                                   ("Unrecognized hint keyword \"%s\".", buf.data));
1087                         pfree(buf.data);
1088                         return;
1089                 }
1090         }
1091
1092         pfree(buf.data);
1093 }
1094
1095 /*
1096  * Do basic parsing of the query head comment.
1097  */
1098 static HintState *
1099 parse_head_comment(Query *parse)
1100 {
1101         const char *p;
1102         char       *head;
1103         char       *tail;
1104         int                     len;
1105         int                     i;
1106         HintState   *hstate;
1107
1108         /* get client-supplied query string. */
1109         if (stmt_name)
1110         {
1111                 PreparedStatement  *entry;
1112
1113                 entry = FetchPreparedStatement(stmt_name, true);
1114                 p = entry->plansource->query_string;
1115         }
1116         else
1117                 p = debug_query_string;
1118
1119         if (p == NULL)
1120                 return NULL;
1121
1122         /* extract query head comment. */
1123         len = strlen(HINT_START);
1124         skip_space(p);
1125         if (strncmp(p, HINT_START, len))
1126                 return NULL;
1127
1128         head = (char *) p;
1129         p += len;
1130         skip_space(p);
1131
1132         /* find hint end keyword. */
1133         if ((tail = strstr(p, HINT_END)) == NULL)
1134         {
1135                 parse_ereport(head, ("Unterminated block comment."));
1136                 return NULL;
1137         }
1138
1139         /* We don't support nested block comments. */
1140         if ((head = strstr(p, BLOCK_COMMENT_START)) != NULL && head < tail)
1141         {
1142                 parse_ereport(head, ("Nested block comments are not supported."));
1143                 return NULL;
1144         }
1145
1146         /* Make a copy of hint. */
1147         len = tail - p;
1148         head = palloc(len + 1);
1149         memcpy(head, p, len);
1150         head[len] = '\0';
1151         p = head;
1152
1153         hstate = HintStateCreate();
1154         hstate->hint_str = head;
1155
1156         /* parse each hint. */
1157         parse_hints(hstate, parse, p);
1158
1159         /* When nothing specified a hint, we free HintState and returns NULL. */
1160         if (hstate->nall_hints == 0)
1161         {
1162                 HintStateDelete(hstate);
1163                 return NULL;
1164         }
1165
1166         /* Sort hints in order of original position. */
1167         qsort(hstate->all_hints, hstate->nall_hints, sizeof(Hint *),
1168                   HintCmpWithPos);
1169
1170         /* Count up hints per hint-type. */
1171         for (i = 0; i < hstate->nall_hints; i++)
1172         {
1173                 Hint   *cur_hint = hstate->all_hints[i];
1174                 hstate->num_hints[cur_hint->type]++;
1175         }
1176
1177         /*
1178          * If we have hints which are specified for an object, mark preceding one
1179          * as 'duplicated' to ignore it in planner phase.
1180          * We need to pass address of hint pointers, because HintCmp has
1181          * been designed to be used with qsort.
1182          */
1183         for (i = 0; i < hstate->nall_hints - 1; i++)
1184         {
1185                 Hint   *cur_hint = hstate->all_hints[i];
1186                 Hint   *next_hint = hstate->all_hints[i + 1];
1187
1188                 if (HintCmp(&cur_hint, &next_hint) == 0)
1189                 {
1190                         parse_ereport(cur_hint->hint_str,
1191                                                   ("Conflict %s hint.", HintTypeName[cur_hint->type]));
1192                         cur_hint->state = HINT_STATE_DUPLICATION;
1193                 }
1194         }
1195
1196         /*
1197          * Make sure that per-type array pointers point proper position in the
1198          * array which consists of all hints.
1199          */
1200         hstate->scan_hints = (ScanMethodHint **) hstate->all_hints;
1201         hstate->join_hints = (JoinMethodHint **) hstate->all_hints +
1202                 hstate->num_hints[HINT_TYPE_SCAN_METHOD];
1203         hstate->leading_hint = (LeadingHint *) hstate->all_hints[
1204                 hstate->num_hints[HINT_TYPE_SCAN_METHOD] +
1205                 hstate->num_hints[HINT_TYPE_JOIN_METHOD] +
1206                 hstate->num_hints[HINT_TYPE_LEADING] - 1];
1207         hstate->set_hints = (SetHint **) hstate->all_hints +
1208                 hstate->num_hints[HINT_TYPE_SCAN_METHOD] +
1209                 hstate->num_hints[HINT_TYPE_JOIN_METHOD] +
1210                 hstate->num_hints[HINT_TYPE_LEADING];
1211
1212         return hstate;
1213 }
1214
1215 /*
1216  * Parse inside of parentheses of scan-method hints.
1217  */
1218 static const char *
1219 ScanMethodHintParse(ScanMethodHint *hint, HintState *hstate, Query *parse,
1220                                         const char *str)
1221 {
1222         const char *keyword = hint->base.keyword;
1223         List       *name_list = NIL;
1224         int                     length;
1225
1226         if ((str = parse_parentheses(str, &name_list, hint->base.type)) == NULL)
1227                 return NULL;
1228
1229         /* Parse relation name and index name(s) if given hint accepts. */
1230         length = list_length(name_list);
1231         if (length > 0)
1232         {
1233                 hint->relname = linitial(name_list);
1234                 hint->indexnames = list_delete_first(name_list);
1235
1236                 /* check the kerword to need the only relation. */
1237                 if (strcmp(keyword, HINT_INDEXSCAN) != 0 &&
1238 #if PG_VERSION_NUM >= 90200
1239                         strcmp(keyword, HINT_INDEXONLYSCAN) != 0 &&
1240 #endif
1241                         strcmp(keyword, HINT_BITMAPSCAN) != 0 &&
1242                         length != 1)
1243                 {
1244                         parse_ereport(str,
1245                                                   ("%s hint requires only one relation.",
1246                                                    hint->base.keyword));
1247                         hint->base.state = HINT_STATE_ERROR;
1248                         return str;
1249                 }
1250         }
1251         else
1252         {
1253                 parse_ereport(str,
1254                                           ("%s hint requires a relation.",
1255                                            hint->base.keyword));
1256                 hint->base.state = HINT_STATE_ERROR;
1257                 return str;
1258         }
1259
1260         /* Set a bit for specified hint. */
1261         if (strcasecmp(keyword, HINT_SEQSCAN) == 0)
1262                 hint->enforce_mask = ENABLE_SEQSCAN;
1263         else if (strcasecmp(keyword, HINT_INDEXSCAN) == 0)
1264                 hint->enforce_mask = ENABLE_INDEXSCAN;
1265         else if (strcasecmp(keyword, HINT_BITMAPSCAN) == 0)
1266                 hint->enforce_mask = ENABLE_BITMAPSCAN;
1267         else if (strcasecmp(keyword, HINT_TIDSCAN) == 0)
1268                 hint->enforce_mask = ENABLE_TIDSCAN;
1269         else if (strcasecmp(keyword, HINT_NOSEQSCAN) == 0)
1270                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_SEQSCAN;
1271         else if (strcasecmp(keyword, HINT_NOINDEXSCAN) == 0)
1272                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXSCAN;
1273         else if (strcasecmp(keyword, HINT_NOBITMAPSCAN) == 0)
1274                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_BITMAPSCAN;
1275         else if (strcasecmp(keyword, HINT_NOTIDSCAN) == 0)
1276                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_TIDSCAN;
1277 #if PG_VERSION_NUM >= 90200
1278         else if (strcasecmp(keyword, HINT_INDEXONLYSCAN) == 0)
1279                 hint->enforce_mask = ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN;
1280         else if (strcasecmp(keyword, HINT_NOINDEXONLYSCAN) == 0)
1281                 hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXONLYSCAN;
1282 #endif
1283         else
1284         {
1285                 parse_ereport(str, ("Unrecognized hint keyword \"%s\".", keyword));
1286                 return NULL;
1287         }
1288
1289         return str;
1290 }
1291
1292 static const char *
1293 JoinMethodHintParse(JoinMethodHint *hint, HintState *hstate, Query *parse,
1294                                         const char *str)
1295 {
1296         const char *keyword = hint->base.keyword;
1297         List       *name_list = NIL;
1298
1299         if ((str = parse_parentheses(str, &name_list, hint->base.type)) == NULL)
1300                 return NULL;
1301
1302         hint->nrels = list_length(name_list);
1303
1304         if (hint->nrels > 0)
1305         {
1306                 ListCell   *l;
1307                 int                     i = 0;
1308
1309                 /* save the data on the list in array of join hint struct. */
1310                 hint->relnames = palloc(sizeof(char *) * hint->nrels);
1311                 foreach (l, name_list)
1312                 {
1313                         hint->relnames[i] = lfirst(l);
1314                         i++;
1315                 }
1316         }
1317
1318         list_free(name_list);
1319
1320         /* A join hint requires at least two relations to be specified. */
1321         if (hint->nrels < 2)
1322         {
1323                 parse_ereport(str,
1324                                           ("%s hint requires at least two relations.",
1325                                            hint->base.keyword));
1326                 hint->base.state = HINT_STATE_ERROR;
1327                 return str;
1328         }
1329
1330         /* Sort hints in alphabetical order of relation names. */
1331         qsort(hint->relnames, hint->nrels, sizeof(char *), RelnameCmp);
1332
1333         if (strcasecmp(keyword, HINT_NESTLOOP) == 0)
1334                 hint->enforce_mask = ENABLE_NESTLOOP;
1335         else if (strcasecmp(keyword, HINT_MERGEJOIN) == 0)
1336                 hint->enforce_mask = ENABLE_MERGEJOIN;
1337         else if (strcasecmp(keyword, HINT_HASHJOIN) == 0)
1338                 hint->enforce_mask = ENABLE_HASHJOIN;
1339         else if (strcasecmp(keyword, HINT_NONESTLOOP) == 0)
1340                 hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_NESTLOOP;
1341         else if (strcasecmp(keyword, HINT_NOMERGEJOIN) == 0)
1342                 hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_MERGEJOIN;
1343         else if (strcasecmp(keyword, HINT_NOHASHJOIN) == 0)
1344                 hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_HASHJOIN;
1345         else
1346         {
1347                 parse_ereport(str, ("Unrecognized hint keyword \"%s\".", keyword));
1348                 return NULL;
1349         }
1350
1351         return str;
1352 }
1353
1354 static const char *
1355 LeadingHintParse(LeadingHint *hint, HintState *hstate, Query *parse,
1356                                  const char *str)
1357 {
1358         List   *name_list = NIL;
1359
1360         if ((str = parse_parentheses(str, &name_list, hint->base.type)) == NULL)
1361                 return NULL;
1362
1363         hint->relations = name_list;
1364
1365         /* A Leading hint requires at least two relations to be specified. */
1366         if (list_length(hint->relations) < 2)
1367         {
1368                 parse_ereport(hint->base.hint_str,
1369                                           ("%s hint requires at least two relations.",
1370                                            HINT_LEADING));
1371                 hint->base.state = HINT_STATE_ERROR;
1372         }
1373
1374         return str;
1375 }
1376
1377 static const char *
1378 SetHintParse(SetHint *hint, HintState *hstate, Query *parse, const char *str)
1379 {
1380         List   *name_list = NIL;
1381
1382         if ((str = parse_parentheses(str, &name_list, hint->base.type)) == NULL)
1383                 return NULL;
1384
1385         hint->words = name_list;
1386
1387         /* need only parameter's name and parameter's value to set GUC parameter. */
1388         if (list_length(name_list) == 2)
1389         {
1390                 hint->name = linitial(name_list);
1391                 hint->value = lsecond(name_list);
1392         }
1393         else
1394         {
1395                 parse_ereport(hint->base.hint_str,
1396                                           ("%s hint requires two relations.",
1397                                            HINT_SET));
1398                 hint->base.state = HINT_STATE_ERROR;
1399         }
1400
1401         return str;
1402 }
1403
1404 /*
1405  * set GUC parameter functions
1406  */
1407
1408 static int
1409 set_config_option_wrapper(const char *name, const char *value,
1410                                                   GucContext context, GucSource source,
1411                                                   GucAction action, bool changeVal, int elevel)
1412 {
1413         int                             result = 0;
1414         MemoryContext   ccxt = CurrentMemoryContext;
1415
1416         PG_TRY();
1417         {
1418 #if PG_VERSION_NUM >= 90200
1419                 result = set_config_option(name, value, context, source,
1420                                                                    action, changeVal, 0);
1421 #else
1422                 result = set_config_option(name, value, context, source,
1423                                                                    action, changeVal);
1424 #endif
1425         }
1426         PG_CATCH();
1427         {
1428                 ErrorData          *errdata;
1429
1430                 /* Save error info */
1431                 MemoryContextSwitchTo(ccxt);
1432                 errdata = CopyErrorData();
1433                 FlushErrorState();
1434
1435                 ereport(elevel, (errcode(errdata->sqlerrcode),
1436                                 errmsg("%s", errdata->message),
1437                                 errdata->detail ? errdetail("%s", errdata->detail) : 0,
1438                                 errdata->hint ? errhint("%s", errdata->hint) : 0));
1439                 FreeErrorData(errdata);
1440         }
1441         PG_END_TRY();
1442
1443         return result;
1444 }
1445
1446 static int
1447 set_config_options(SetHint **options, int noptions, GucContext context)
1448 {
1449         int     i;
1450         int     save_nestlevel;
1451
1452         save_nestlevel = NewGUCNestLevel();
1453
1454         for (i = 0; i < noptions; i++)
1455         {
1456                 SetHint    *hint = options[i];
1457                 int                     result;
1458
1459                 if (!hint_state_enabled(hint))
1460                         continue;
1461
1462                 result = set_config_option_wrapper(hint->name, hint->value, context,
1463                                                                                    PGC_S_SESSION, GUC_ACTION_SAVE, true,
1464                                                                                    pg_hint_plan_parse_messages);
1465                 if (result != 0)
1466                         hint->base.state = HINT_STATE_USED;
1467                 else
1468                         hint->base.state = HINT_STATE_ERROR;
1469         }
1470
1471         return save_nestlevel;
1472 }
1473
1474 #define SET_CONFIG_OPTION(name, type_bits) \
1475         set_config_option_wrapper((name), \
1476                 (mask & (type_bits)) ? "true" : "false", \
1477                 context, PGC_S_SESSION, GUC_ACTION_SAVE, true, ERROR)
1478
1479 static void
1480 set_scan_config_options(unsigned char enforce_mask, GucContext context)
1481 {
1482         unsigned char   mask;
1483
1484         if (enforce_mask == ENABLE_SEQSCAN || enforce_mask == ENABLE_INDEXSCAN ||
1485                 enforce_mask == ENABLE_BITMAPSCAN || enforce_mask == ENABLE_TIDSCAN
1486 #if PG_VERSION_NUM >= 90200
1487                 || enforce_mask == (ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN)
1488 #endif
1489                 )
1490                 mask = enforce_mask;
1491         else
1492                 mask = enforce_mask & current_hint->init_scan_mask;
1493
1494         SET_CONFIG_OPTION("enable_seqscan", ENABLE_SEQSCAN);
1495         SET_CONFIG_OPTION("enable_indexscan", ENABLE_INDEXSCAN);
1496         SET_CONFIG_OPTION("enable_bitmapscan", ENABLE_BITMAPSCAN);
1497         SET_CONFIG_OPTION("enable_tidscan", ENABLE_TIDSCAN);
1498 #if PG_VERSION_NUM >= 90200
1499         SET_CONFIG_OPTION("enable_indexonlyscan", ENABLE_INDEXONLYSCAN);
1500 #endif
1501 }
1502
1503 static void
1504 set_join_config_options(unsigned char enforce_mask, GucContext context)
1505 {
1506         unsigned char   mask;
1507
1508         if (enforce_mask == ENABLE_NESTLOOP || enforce_mask == ENABLE_MERGEJOIN ||
1509                 enforce_mask == ENABLE_HASHJOIN)
1510                 mask = enforce_mask;
1511         else
1512                 mask = enforce_mask & current_hint->init_join_mask;
1513
1514         SET_CONFIG_OPTION("enable_nestloop", ENABLE_NESTLOOP);
1515         SET_CONFIG_OPTION("enable_mergejoin", ENABLE_MERGEJOIN);
1516         SET_CONFIG_OPTION("enable_hashjoin", ENABLE_HASHJOIN);
1517 }
1518
1519 /*
1520  * pg_hint_plan hook functions
1521  */
1522
1523 static void
1524 pg_hint_plan_ProcessUtility(Node *parsetree, const char *queryString,
1525                                                         ParamListInfo params, bool isTopLevel,
1526                                                         DestReceiver *dest, char *completionTag)
1527 {
1528         Node                               *node;
1529
1530         if (!pg_hint_plan_enable_hint)
1531         {
1532                 if (prev_ProcessUtility)
1533                         (*prev_ProcessUtility) (parsetree, queryString, params,
1534                                                                         isTopLevel, dest, completionTag);
1535                 else
1536                         standard_ProcessUtility(parsetree, queryString, params,
1537                                                                         isTopLevel, dest, completionTag);
1538
1539                 return;
1540         }
1541
1542         node = parsetree;
1543         if (IsA(node, ExplainStmt))
1544         {
1545                 /*
1546                  * Draw out parse tree of actual query from Query struct of EXPLAIN
1547                  * statement.
1548                  */
1549                 ExplainStmt        *stmt;
1550                 Query              *query;
1551
1552                 stmt = (ExplainStmt *) node;
1553
1554                 Assert(IsA(stmt->query, Query));
1555                 query = (Query *) stmt->query;
1556
1557                 if (query->commandType == CMD_UTILITY && query->utilityStmt != NULL)
1558                         node = query->utilityStmt;
1559         }
1560
1561         /*
1562          * If the query was a EXECUTE or CREATE TABLE AS EXECUTE, get query string
1563          * specified to preceding PREPARE command to use it as source of hints.
1564          */
1565         if (IsA(node, ExecuteStmt))
1566         {
1567                 ExecuteStmt        *stmt;
1568
1569                 stmt = (ExecuteStmt *) node;
1570                 stmt_name = stmt->name;
1571         }
1572 #if PG_VERSION_NUM >= 90200
1573         /*
1574          * CREATE AS EXECUTE behavior has changed since 9.2, so we must handle it
1575          * specially here.
1576          */
1577         if (IsA(node, CreateTableAsStmt))
1578         {
1579                 CreateTableAsStmt          *stmt;
1580                 Query              *query;
1581
1582                 stmt = (CreateTableAsStmt *) node;
1583                 Assert(IsA(stmt->query, Query));
1584                 query = (Query *) stmt->query;
1585
1586                 if (query->commandType == CMD_UTILITY &&
1587                         IsA(query->utilityStmt, ExecuteStmt))
1588                 {
1589                         ExecuteStmt *estmt = (ExecuteStmt *) query->utilityStmt;
1590                         stmt_name = estmt->name;
1591                 }
1592         }
1593 #endif
1594         if (stmt_name)
1595         {
1596                 PG_TRY();
1597                 {
1598                         if (prev_ProcessUtility)
1599                                 (*prev_ProcessUtility) (parsetree, queryString, params,
1600                                                                                 isTopLevel, dest, completionTag);
1601                         else
1602                                 standard_ProcessUtility(parsetree, queryString, params,
1603                                                                                 isTopLevel, dest, completionTag);
1604                 }
1605                 PG_CATCH();
1606                 {
1607                         stmt_name = NULL;
1608                         PG_RE_THROW();
1609                 }
1610                 PG_END_TRY();
1611
1612                 stmt_name = NULL;
1613
1614                 return;
1615         }
1616
1617         if (prev_ProcessUtility)
1618                 (*prev_ProcessUtility) (parsetree, queryString, params,
1619                                                                 isTopLevel, dest, completionTag);
1620         else
1621                 standard_ProcessUtility(parsetree, queryString, params,
1622                                                                 isTopLevel, dest, completionTag);
1623 }
1624
1625 /*
1626  * Push a hint into hint stack which is implemented with List struct.  Head of
1627  * list is top of stack.
1628  */
1629 static void
1630 push_hint(HintState *hstate)
1631 {
1632         /* Prepend new hint to the list means pushing to stack. */
1633         HintStateStack = lcons(hstate, HintStateStack);
1634
1635         /* Pushed hint is the one which should be used hereafter. */
1636         current_hint = hstate;
1637 }
1638
1639 /* Pop a hint from hint stack.  Popped hint is automatically discarded. */
1640 static void
1641 pop_hint(void)
1642 {
1643         /* Hint stack must not be empty. */
1644         if(HintStateStack == NIL)
1645                 elog(ERROR, "hint stack is empty");
1646
1647         /*
1648          * Take a hint at the head from the list, and free it.  Switch current_hint
1649          * to point new head (NULL if the list is empty).
1650          */
1651         HintStateStack = list_delete_first(HintStateStack);
1652         HintStateDelete(current_hint);
1653         if(HintStateStack == NIL)
1654                 current_hint = NULL;
1655         else
1656                 current_hint = (HintState *) lfirst(list_head(HintStateStack));
1657 }
1658
1659 static PlannedStmt *
1660 pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
1661 {
1662         int                             save_nestlevel;
1663         PlannedStmt        *result;
1664         HintState          *hstate;
1665
1666         /*
1667          * Use standard planner if pg_hint_plan is disabled.  Other hook functions
1668          * try to change plan with current_hint if any, so set it to NULL.
1669          */
1670         if (!pg_hint_plan_enable_hint)
1671         {
1672                 current_hint = NULL;
1673
1674                 if (prev_planner)
1675                         return (*prev_planner) (parse, cursorOptions, boundParams);
1676                 else
1677                         return standard_planner(parse, cursorOptions, boundParams);
1678         }
1679
1680         /* Create hint struct from parse tree. */
1681         hstate = parse_head_comment(parse);
1682
1683         /*
1684          * Use standard planner if the statement has not valid hint.  Other hook
1685          * functions try to change plan with current_hint if any, so set it to
1686          * NULL.
1687          */
1688         if (!hstate)
1689         {
1690                 current_hint = NULL;
1691
1692                 if (prev_planner)
1693                         return (*prev_planner) (parse, cursorOptions, boundParams);
1694                 else
1695                         return standard_planner(parse, cursorOptions, boundParams);
1696         }
1697
1698         /*
1699          * Push new hint struct to the hint stack to disable previous hint context.
1700          */
1701         push_hint(hstate);
1702
1703         /* Set GUC parameters which are specified with Set hint. */
1704         save_nestlevel = set_config_options(current_hint->set_hints,
1705                                                                                 current_hint->num_hints[HINT_TYPE_SET],
1706                                                                                 current_hint->context);
1707
1708         if (enable_seqscan)
1709                 current_hint->init_scan_mask |= ENABLE_SEQSCAN;
1710         if (enable_indexscan)
1711                 current_hint->init_scan_mask |= ENABLE_INDEXSCAN;
1712         if (enable_bitmapscan)
1713                 current_hint->init_scan_mask |= ENABLE_BITMAPSCAN;
1714         if (enable_tidscan)
1715                 current_hint->init_scan_mask |= ENABLE_TIDSCAN;
1716 #if PG_VERSION_NUM >= 90200
1717         if (enable_indexonlyscan)
1718                 current_hint->init_scan_mask |= ENABLE_INDEXONLYSCAN;
1719 #endif
1720         if (enable_nestloop)
1721                 current_hint->init_join_mask |= ENABLE_NESTLOOP;
1722         if (enable_mergejoin)
1723                 current_hint->init_join_mask |= ENABLE_MERGEJOIN;
1724         if (enable_hashjoin)
1725                 current_hint->init_join_mask |= ENABLE_HASHJOIN;
1726
1727         /*
1728          * Use PG_TRY mechanism to recover GUC parameters and current_hint to the
1729          * state when this planner started when error occurred in planner.
1730          */
1731         PG_TRY();
1732         {
1733                 if (prev_planner)
1734                         result = (*prev_planner) (parse, cursorOptions, boundParams);
1735                 else
1736                         result = standard_planner(parse, cursorOptions, boundParams);
1737         }
1738         PG_CATCH();
1739         {
1740                 /*
1741                  * Rollback changes of GUC parameters, and pop current hint context
1742                  * from hint stack to rewind the state.
1743                  */
1744                 AtEOXact_GUC(true, save_nestlevel);
1745                 pop_hint();
1746                 PG_RE_THROW();
1747         }
1748         PG_END_TRY();
1749
1750         /* Print hint in debug mode. */
1751         if (pg_hint_plan_debug_print)
1752                 HintStateDump(current_hint);
1753
1754         /*
1755          * Rollback changes of GUC parameters, and pop current hint context from
1756          * hint stack to rewind the state.
1757          */
1758         AtEOXact_GUC(true, save_nestlevel);
1759         pop_hint();
1760
1761         return result;
1762 }
1763
1764 /*
1765  * Return scan method hint which matches given aliasname.
1766  */
1767 static ScanMethodHint *
1768 find_scan_hint(PlannerInfo *root, RelOptInfo *rel)
1769 {
1770         RangeTblEntry  *rte;
1771         int                             i;
1772
1773         /*
1774          * We can't apply scan method hint if the relation is:
1775          *   - not a base relation
1776          *   - not an ordinary relation (such as join and subquery)
1777          */
1778         if (rel->reloptkind != RELOPT_BASEREL || rel->rtekind != RTE_RELATION)
1779                 return NULL;
1780
1781         rte = root->simple_rte_array[rel->relid];
1782
1783         /* We can't force scan method of foreign tables */
1784         if (rte->relkind == RELKIND_FOREIGN_TABLE)
1785                 return NULL;
1786
1787         /* Find scan method hint, which matches given names, from the list. */
1788         for (i = 0; i < current_hint->num_hints[HINT_TYPE_SCAN_METHOD]; i++)
1789         {
1790                 ScanMethodHint *hint = current_hint->scan_hints[i];
1791
1792                 /* We ignore disabled hints. */
1793                 if (!hint_state_enabled(hint))
1794                         continue;
1795
1796                 if (RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
1797                         return hint;
1798         }
1799
1800         return NULL;
1801 }
1802
1803 static void
1804 delete_indexes(ScanMethodHint *hint, RelOptInfo *rel)
1805 {
1806         ListCell           *cell;
1807         ListCell           *prev;
1808         ListCell           *next;
1809
1810         /*
1811          * We delete all the IndexOptInfo list and prevent you from being usable by
1812          * a scan.
1813          */
1814         if (hint->enforce_mask == ENABLE_SEQSCAN ||
1815                 hint->enforce_mask == ENABLE_TIDSCAN)
1816         {
1817                 list_free_deep(rel->indexlist);
1818                 rel->indexlist = NIL;
1819                 hint->base.state = HINT_STATE_USED;
1820
1821                 return;
1822         }
1823
1824         /*
1825          * When a list of indexes is not specified, we just use all indexes.
1826          */
1827         if (hint->indexnames == NIL)
1828                 return;
1829
1830         /*
1831          * Leaving only an specified index, we delete it from a IndexOptInfo list
1832          * other than it.
1833          */
1834         prev = NULL;
1835         for (cell = list_head(rel->indexlist); cell; cell = next)
1836         {
1837                 IndexOptInfo   *info = (IndexOptInfo *) lfirst(cell);
1838                 char               *indexname = get_rel_name(info->indexoid);
1839                 ListCell           *l;
1840                 bool                    use_index = false;
1841
1842                 next = lnext(cell);
1843
1844                 foreach(l, hint->indexnames)
1845                 {
1846                         if (RelnameCmp(&indexname, &lfirst(l)) == 0)
1847                         {
1848                                 use_index = true;
1849                                 break;
1850                         }
1851                 }
1852
1853                 if (!use_index)
1854                         rel->indexlist = list_delete_cell(rel->indexlist, cell, prev);
1855                 else
1856                         prev = cell;
1857
1858                 pfree(indexname);
1859         }
1860 }
1861
1862 static void
1863 pg_hint_plan_get_relation_info(PlannerInfo *root, Oid relationObjectId,
1864                                                            bool inhparent, RelOptInfo *rel)
1865 {
1866         ScanMethodHint *hint;
1867
1868         if (prev_get_relation_info)
1869                 (*prev_get_relation_info) (root, relationObjectId, inhparent, rel);
1870
1871         /* Do nothing if we don't have valid hint in this context. */
1872         if (!current_hint)
1873                 return;
1874
1875         if (inhparent)
1876         {
1877                 /* store does relids of parent table. */
1878                 current_hint->parent_relid = rel->relid;
1879         }
1880         else if (current_hint->parent_relid != 0)
1881         {
1882                 /*
1883                  * We use the same GUC parameter if this table is the child table of a
1884                  * table called pg_hint_plan_get_relation_info just before that.
1885                  */
1886                 ListCell   *l;
1887
1888                 /* append_rel_list contains all append rels; ignore others */
1889                 foreach(l, root->append_rel_list)
1890                 {
1891                         AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
1892
1893                         /* This rel is child table. */
1894                         if (appinfo->parent_relid == current_hint->parent_relid &&
1895                                 appinfo->child_relid == rel->relid)
1896                         {
1897                                 if (current_hint->parent_hint)
1898                                         delete_indexes(current_hint->parent_hint, rel);
1899
1900                                 return;
1901                         }
1902                 }
1903
1904                 /* This rel is not inherit table. */
1905                 current_hint->parent_relid = 0;
1906                 current_hint->parent_hint = NULL;
1907         }
1908
1909         /*
1910          * If scan method hint was given, reset GUC parameters which control
1911          * planner behavior about choosing scan methods.
1912          */
1913         if ((hint = find_scan_hint(root, rel)) == NULL)
1914         {
1915                 set_scan_config_options(current_hint->init_scan_mask,
1916                                                                 current_hint->context);
1917                 return;
1918         }
1919         set_scan_config_options(hint->enforce_mask, current_hint->context);
1920         hint->base.state = HINT_STATE_USED;
1921         if (inhparent)
1922                 current_hint->parent_hint = hint;
1923
1924         delete_indexes(hint, rel);
1925 }
1926
1927 /*
1928  * Return index of relation which matches given aliasname, or 0 if not found.
1929  * If same aliasname was used multiple times in a query, return -1.
1930  */
1931 static int
1932 find_relid_aliasname(PlannerInfo *root, char *aliasname, List *initial_rels,
1933                                          const char *str)
1934 {
1935         int             i;
1936         Index   found = 0;
1937
1938         for (i = 1; i < root->simple_rel_array_size; i++)
1939         {
1940                 ListCell   *l;
1941
1942                 if (root->simple_rel_array[i] == NULL)
1943                         continue;
1944
1945                 Assert(i == root->simple_rel_array[i]->relid);
1946
1947                 if (RelnameCmp(&aliasname,
1948                                            &root->simple_rte_array[i]->eref->aliasname) != 0)
1949                         continue;
1950
1951                 foreach(l, initial_rels)
1952                 {
1953                         RelOptInfo *rel = (RelOptInfo *) lfirst(l);
1954
1955                         if (rel->reloptkind == RELOPT_BASEREL)
1956                         {
1957                                 if (rel->relid != i)
1958                                         continue;
1959                         }
1960                         else
1961                         {
1962                                 Assert(rel->reloptkind == RELOPT_JOINREL);
1963
1964                                 if (!bms_is_member(i, rel->relids))
1965                                         continue;
1966                         }
1967
1968                         if (found != 0)
1969                         {
1970                                 parse_ereport(str,
1971                                                           ("Relation name \"%s\" is ambiguous.",
1972                                                            aliasname));
1973                                 return -1;
1974                         }
1975
1976                         found = i;
1977                         break;
1978                 }
1979
1980         }
1981
1982         return found;
1983 }
1984
1985 /*
1986  * Return join hint which matches given joinrelids.
1987  */
1988 static JoinMethodHint *
1989 find_join_hint(Relids joinrelids)
1990 {
1991         List       *join_hint;
1992         ListCell   *l;
1993
1994         join_hint = current_hint->join_hint_level[bms_num_members(joinrelids)];
1995
1996         foreach(l, join_hint)
1997         {
1998                 JoinMethodHint *hint = (JoinMethodHint *) lfirst(l);
1999
2000                 if (bms_equal(joinrelids, hint->joinrelids))
2001                         return hint;
2002         }
2003
2004         return NULL;
2005 }
2006
2007 /*
2008  * Transform join method hint into handy form.
2009  *
2010  *   - create bitmap of relids from alias names, to make it easier to check
2011  *     whether a join path matches a join method hint.
2012  *   - add join method hints which are necessary to enforce join order
2013  *     specified by Leading hint
2014  */
2015 static void
2016 transform_join_hints(HintState *hstate, PlannerInfo *root, int nbaserel,
2017                 List *initial_rels, JoinMethodHint **join_method_hints)
2018 {
2019         int                             i;
2020         int                             relid;
2021         LeadingHint        *lhint;
2022         Relids                  joinrelids;
2023         int                             njoinrels;
2024         ListCell           *l;
2025
2026         /*
2027          * Create bitmap of relids from alias names for each join method hint.
2028          * Bitmaps are more handy than strings in join searching.
2029          */
2030         for (i = 0; i < hstate->num_hints[HINT_TYPE_JOIN_METHOD]; i++)
2031         {
2032                 JoinMethodHint *hint = hstate->join_hints[i];
2033                 int     j;
2034
2035                 if (!hint_state_enabled(hint) || hint->nrels > nbaserel)
2036                         continue;
2037
2038                 bms_free(hint->joinrelids);
2039                 hint->joinrelids = NULL;
2040                 relid = 0;
2041                 for (j = 0; j < hint->nrels; j++)
2042                 {
2043                         char   *relname = hint->relnames[j];
2044
2045                         relid = find_relid_aliasname(root, relname, initial_rels,
2046                                                                                  hint->base.hint_str);
2047
2048                         if (relid == -1)
2049                                 hint->base.state = HINT_STATE_ERROR;
2050
2051                         if (relid <= 0)
2052                                 break;
2053
2054                         if (bms_is_member(relid, hint->joinrelids))
2055                         {
2056                                 parse_ereport(hint->base.hint_str,
2057                                                           ("Relation name \"%s\" is duplicated.", relname));
2058                                 hint->base.state = HINT_STATE_ERROR;
2059                                 break;
2060                         }
2061
2062                         hint->joinrelids = bms_add_member(hint->joinrelids, relid);
2063                 }
2064
2065                 if (relid <= 0 || hint->base.state == HINT_STATE_ERROR)
2066                         continue;
2067
2068                 hstate->join_hint_level[hint->nrels] =
2069                         lappend(hstate->join_hint_level[hint->nrels], hint);
2070         }
2071
2072         /* Do nothing if no Leading hint was supplied. */
2073         if (hstate->num_hints[HINT_TYPE_LEADING] == 0)
2074                 return;
2075
2076         /* Do nothing if Leading hint is invalid. */
2077         lhint = hstate->leading_hint;
2078         if (!hint_state_enabled(lhint))
2079                 return;
2080
2081         /*
2082          * We need join method hints which fit specified join order in every join
2083          * level.  For example, Leading(A B C) virtually requires following join
2084          * method hints, if no join method hint supplied:
2085          *   - level 1: none
2086          *   - level 2: NestLoop(A B), MergeJoin(A B), HashJoin(A B)
2087          *   - level 3: NestLoop(A B C), MergeJoin(A B C), HashJoin(A B C)
2088          *
2089          * If we already have join method hint which fits specified join order in
2090          * that join level, we leave it as-is and don't add new hints.
2091          */
2092         joinrelids = NULL;
2093         njoinrels = 0;
2094         foreach(l, lhint->relations)
2095         {
2096                 char   *relname = (char *)lfirst(l);
2097                 JoinMethodHint *hint;
2098
2099                 /*
2100                  * Find relid of the relation which has given name.  If we have the
2101                  * name given in Leading hint multiple times in the join, nothing to
2102                  * do.
2103                  */
2104                 relid = find_relid_aliasname(root, relname, initial_rels,
2105                                                                          hstate->hint_str);
2106                 if (relid == -1)
2107                 {
2108                         bms_free(joinrelids);
2109                         return;
2110                 }
2111                 if (relid == 0)
2112                         continue;
2113
2114                 /* Found relid must not be in joinrelids. */
2115                 if (bms_is_member(relid, joinrelids))
2116                 {
2117                         parse_ereport(lhint->base.hint_str,
2118                                                   ("Relation name \"%s\" is duplicated.", relname));
2119                         lhint->base.state = HINT_STATE_ERROR;
2120                         bms_free(joinrelids);
2121                         return;
2122                 }
2123
2124                 /* Create bitmap of relids for current join level. */
2125                 joinrelids = bms_add_member(joinrelids, relid);
2126                 njoinrels++;
2127
2128                 /* We never have join method hint for single relation. */
2129                 if (njoinrels < 2)
2130                         continue;
2131
2132                 /*
2133                  * If we don't have join method hint, create new one for the
2134                  * join combination with all join methods are enabled.
2135                  */
2136                 hint = find_join_hint(joinrelids);
2137                 if (hint == NULL)
2138                 {
2139                         /*
2140                          * Here relnames is not set, since Relids bitmap is sufficient to
2141                          * control paths of this query afterward.
2142                          */
2143                         hint = (JoinMethodHint *) JoinMethodHintCreate(lhint->base.hint_str,
2144                                                                                                                    HINT_LEADING);
2145                         hint->base.state = HINT_STATE_USED;
2146                         hint->nrels = njoinrels;
2147                         hint->enforce_mask = ENABLE_ALL_JOIN;
2148                         hint->joinrelids = bms_copy(joinrelids);
2149                 }
2150
2151                 join_method_hints[njoinrels] = hint;
2152
2153                 if (njoinrels >= nbaserel)
2154                         break;
2155         }
2156
2157         bms_free(joinrelids);
2158
2159         if (njoinrels < 2)
2160                 return;
2161
2162         /*
2163          * Delete all join hints which have different combination from Leading
2164          * hint.
2165          */
2166         for (i = 2; i <= njoinrels; i++)
2167         {
2168                 list_free(hstate->join_hint_level[i]);
2169
2170                 hstate->join_hint_level[i] = lappend(NIL, join_method_hints[i]);
2171         }
2172
2173         if (hint_state_enabled(lhint))
2174                 set_join_config_options(DISABLE_ALL_JOIN, current_hint->context);
2175
2176         lhint->base.state = HINT_STATE_USED;
2177
2178 }
2179
2180 /*
2181  * set_plain_rel_pathlist
2182  *        Build access paths for a plain relation (no subquery, no inheritance)
2183  *
2184  * This function was copied and edited from set_plain_rel_pathlist() in
2185  * src/backend/optimizer/path/allpaths.c
2186  */
2187 static void
2188 set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
2189 {
2190         /* Consider sequential scan */
2191 #if PG_VERSION_NUM >= 90200
2192         add_path(rel, create_seqscan_path(root, rel, NULL));
2193 #else
2194         add_path(rel, create_seqscan_path(root, rel));
2195 #endif
2196
2197         /* Consider index scans */
2198         create_index_paths(root, rel);
2199
2200         /* Consider TID scans */
2201         create_tidscan_paths(root, rel);
2202
2203         /* Now find the cheapest of the paths for this rel */
2204         set_cheapest(rel);
2205 }
2206
2207 static void
2208 rebuild_scan_path(HintState *hstate, PlannerInfo *root, int level,
2209                                   List *initial_rels)
2210 {
2211         ListCell   *l;
2212
2213         foreach(l, initial_rels)
2214         {
2215                 RelOptInfo         *rel = (RelOptInfo *) lfirst(l);
2216                 RangeTblEntry  *rte;
2217                 ScanMethodHint *hint;
2218
2219                 /* Skip relations which we can't choose scan method. */
2220                 if (rel->reloptkind != RELOPT_BASEREL || rel->rtekind != RTE_RELATION)
2221                         continue;
2222
2223                 rte = root->simple_rte_array[rel->relid];
2224
2225                 /* We can't force scan method of foreign tables */
2226                 if (rte->relkind == RELKIND_FOREIGN_TABLE)
2227                         continue;
2228
2229                 /*
2230                  * Create scan paths with GUC parameters which are at the beginning of
2231                  * planner if scan method hint is not specified, otherwise use
2232                  * specified hints and mark the hint as used.
2233                  */
2234                 if ((hint = find_scan_hint(root, rel)) == NULL)
2235                         set_scan_config_options(hstate->init_scan_mask,
2236                                                                         hstate->context);
2237                 else
2238                 {
2239                         set_scan_config_options(hint->enforce_mask, hstate->context);
2240                         hint->base.state = HINT_STATE_USED;
2241                 }
2242
2243                 list_free_deep(rel->pathlist);
2244                 rel->pathlist = NIL;
2245                 if (rte->inh)
2246                 {
2247                         /* It's an "append relation", process accordingly */
2248                         set_append_rel_pathlist(root, rel, rel->relid, rte);
2249                 }
2250                 else
2251                 {
2252                         set_plain_rel_pathlist(root, rel, rte);
2253                 }
2254         }
2255
2256         /*
2257          * Restore the GUC variables we set above.
2258          */
2259         set_scan_config_options(hstate->init_scan_mask, hstate->context);
2260 }
2261
2262 /*
2263  * wrapper of make_join_rel()
2264  *
2265  * call make_join_rel() after changing enable_* parameters according to given
2266  * hints.
2267  */
2268 static RelOptInfo *
2269 make_join_rel_wrapper(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
2270 {
2271         Relids                  joinrelids;
2272         JoinMethodHint *hint;
2273         RelOptInfo         *rel;
2274         int                             save_nestlevel;
2275
2276         joinrelids = bms_union(rel1->relids, rel2->relids);
2277         hint = find_join_hint(joinrelids);
2278         bms_free(joinrelids);
2279
2280         if (!hint)
2281                 return pg_hint_plan_make_join_rel(root, rel1, rel2);
2282
2283         save_nestlevel = NewGUCNestLevel();
2284
2285         set_join_config_options(hint->enforce_mask, current_hint->context);
2286
2287         rel = pg_hint_plan_make_join_rel(root, rel1, rel2);
2288         hint->base.state = HINT_STATE_USED;
2289
2290         /*
2291          * Restore the GUC variables we set above.
2292          */
2293         AtEOXact_GUC(true, save_nestlevel);
2294
2295         return rel;
2296 }
2297
2298 static int
2299 get_num_baserels(List *initial_rels)
2300 {
2301         int                     nbaserel = 0;
2302         ListCell   *l;
2303
2304         foreach(l, initial_rels)
2305         {
2306                 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
2307
2308                 if (rel->reloptkind == RELOPT_BASEREL)
2309                         nbaserel++;
2310                 else if (rel->reloptkind ==RELOPT_JOINREL)
2311                         nbaserel+= bms_num_members(rel->relids);
2312                 else
2313                 {
2314                         /* other values not expected here */
2315                         elog(ERROR, "unrecognized reloptkind type: %d", rel->reloptkind);
2316                 }
2317         }
2318
2319         return nbaserel;
2320 }
2321
2322 static RelOptInfo *
2323 pg_hint_plan_join_search(PlannerInfo *root, int levels_needed,
2324                                                  List *initial_rels)
2325 {
2326         JoinMethodHint **join_method_hints;
2327         int                     nbaserel;
2328         RelOptInfo *rel;
2329         int                     i;
2330
2331         /*
2332          * Use standard planner (or geqo planner) if pg_hint_plan is disabled or no
2333          * valid hint is supplied.
2334          */
2335         if (!current_hint)
2336         {
2337                 if (prev_join_search)
2338                         return (*prev_join_search) (root, levels_needed, initial_rels);
2339                 else if (enable_geqo && levels_needed >= geqo_threshold)
2340                         return geqo(root, levels_needed, initial_rels);
2341                 else
2342                         return standard_join_search(root, levels_needed, initial_rels);
2343         }
2344
2345         /* We apply scan method hint rebuild scan path. */
2346         rebuild_scan_path(current_hint, root, levels_needed, initial_rels);
2347
2348         /*
2349          * In the case using GEQO, only scan method hints and Set hints have
2350          * effect.  Join method and join order is not controllable by hints.
2351          */
2352         if (enable_geqo && levels_needed >= geqo_threshold)
2353                 return geqo(root, levels_needed, initial_rels);
2354
2355         nbaserel = get_num_baserels(initial_rels);
2356         current_hint->join_hint_level = palloc0(sizeof(List *) * (nbaserel + 1));
2357         join_method_hints = palloc0(sizeof(JoinMethodHint *) * (nbaserel + 1));
2358
2359         transform_join_hints(current_hint, root, nbaserel, initial_rels,
2360                                                  join_method_hints);
2361
2362         rel = pg_hint_plan_standard_join_search(root, levels_needed, initial_rels);
2363
2364         for (i = 2; i <= nbaserel; i++)
2365         {
2366                 list_free(current_hint->join_hint_level[i]);
2367
2368                 /* free Leading hint only */
2369                 if (join_method_hints[i] != NULL &&
2370                         join_method_hints[i]->enforce_mask == ENABLE_ALL_JOIN)
2371                         JoinMethodHintDelete(join_method_hints[i]);
2372         }
2373         pfree(current_hint->join_hint_level);
2374         pfree(join_method_hints);
2375
2376         if (current_hint->num_hints[HINT_TYPE_LEADING] > 0 &&
2377                 hint_state_enabled(current_hint->leading_hint))
2378                 set_join_config_options(current_hint->init_join_mask,
2379                                                                 current_hint->context);
2380
2381         return rel;
2382 }
2383
2384 /*
2385  * set_rel_pathlist
2386  *        Build access paths for a base relation
2387  *
2388  * This function was copied and edited from set_rel_pathlist() in
2389  * src/backend/optimizer/path/allpaths.c
2390  */
2391 static void
2392 set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
2393                                  Index rti, RangeTblEntry *rte)
2394 {
2395 #if PG_VERSION_NUM >= 90200
2396         if (IS_DUMMY_REL(rel))
2397         {
2398                 /* We already proved the relation empty, so nothing more to do */
2399         }
2400         else if (rte->inh)
2401 #else
2402         if (rte->inh)
2403 #endif
2404         {
2405                 /* It's an "append relation", process accordingly */
2406                 set_append_rel_pathlist(root, rel, rti, rte);
2407         }
2408         else
2409         {
2410                 if (rel->rtekind == RTE_RELATION)
2411                 {
2412                         if (rte->relkind == RELKIND_RELATION)
2413                         {
2414                                 /* Plain relation */
2415                                 set_plain_rel_pathlist(root, rel, rte);
2416                         }
2417                         else
2418                                 elog(ERROR, "unexpected relkind: %c", rte->relkind);
2419                 }
2420                 else
2421                         elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
2422         }
2423 }
2424
2425 #define standard_join_search pg_hint_plan_standard_join_search
2426 #define join_search_one_level pg_hint_plan_join_search_one_level
2427 #define make_join_rel make_join_rel_wrapper
2428 #include "core.c"
2429
2430 #undef make_join_rel
2431 #define make_join_rel pg_hint_plan_make_join_rel
2432 #define add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype, sjinfo, restrictlist) \
2433 do { \
2434         ScanMethodHint *hint = NULL; \
2435         if ((hint = find_scan_hint((root), (innerrel))) != NULL) \
2436         { \
2437                 set_scan_config_options(hint->enforce_mask, current_hint->context); \
2438                 hint->base.state = HINT_STATE_USED; \
2439         } \
2440         add_paths_to_joinrel((root), (joinrel), (outerrel), (innerrel), (jointype), (sjinfo), (restrictlist)); \
2441         if (hint != NULL) \
2442                 set_scan_config_options(current_hint->init_scan_mask, current_hint->context); \
2443 } while(0)
2444 #include "make_join_rel.c"