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-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
8  *
9  *-------------------------------------------------------------------------
10  */
11 #include "postgres.h"
12 #include "catalog/pg_collation.h"
13 #include "catalog/pg_index.h"
14 #include "commands/prepare.h"
15 #include "mb/pg_wchar.h"
16 #include "miscadmin.h"
17 #include "nodes/nodeFuncs.h"
18 #include "optimizer/clauses.h"
19 #include "optimizer/cost.h"
20 #include "optimizer/geqo.h"
21 #include "optimizer/joininfo.h"
22 #include "optimizer/pathnode.h"
23 #include "optimizer/paths.h"
24 #include "optimizer/plancat.h"
25 #include "optimizer/planner.h"
26 #include "optimizer/prep.h"
27 #include "optimizer/restrictinfo.h"
28 #include "parser/scansup.h"
29 #include "tcop/utility.h"
30 #include "utils/builtins.h"
31 #include "utils/lsyscache.h"
32 #include "utils/memutils.h"
33 #include "utils/rel.h"
34 #include "utils/syscache.h"
35 #if PG_VERSION_NUM >= 90200
36 #include "catalog/pg_class.h"
37 #endif
38
39 #ifdef PG_MODULE_MAGIC
40 PG_MODULE_MAGIC;
41 #endif
42
43 #if PG_VERSION_NUM < 90100
44 #error unsupported PostgreSQL version
45 #endif
46
47 #define BLOCK_COMMENT_START             "/*"
48 #define BLOCK_COMMENT_END               "*/"
49 #define HINT_COMMENT_KEYWORD    "+"
50 #define HINT_START                              BLOCK_COMMENT_START HINT_COMMENT_KEYWORD
51 #define HINT_END                                BLOCK_COMMENT_END
52
53 /* hint keywords */
54 #define HINT_SEQSCAN                    "SeqScan"
55 #define HINT_INDEXSCAN                  "IndexScan"
56 #define HINT_INDEXSCANREGEXP    "IndexScanRegexp"
57 #define HINT_BITMAPSCAN                 "BitmapScan"
58 #define HINT_BITMAPSCANREGEXP   "BitmapScanRegexp"
59 #define HINT_TIDSCAN                    "TidScan"
60 #define HINT_NOSEQSCAN                  "NoSeqScan"
61 #define HINT_NOINDEXSCAN                "NoIndexScan"
62 #define HINT_NOBITMAPSCAN               "NoBitmapScan"
63 #define HINT_NOTIDSCAN                  "NoTidScan"
64 #if PG_VERSION_NUM >= 90200
65 #define HINT_INDEXONLYSCAN              "IndexOnlyScan"
66 #define HINT_INDEXONLYSCANREGEXP        "IndexOnlyScanRegexp"
67 #define HINT_NOINDEXONLYSCAN    "NoIndexOnlyScan"
68 #endif
69 #define HINT_NESTLOOP                   "NestLoop"
70 #define HINT_MERGEJOIN                  "MergeJoin"
71 #define HINT_HASHJOIN                   "HashJoin"
72 #define HINT_NONESTLOOP                 "NoNestLoop"
73 #define HINT_NOMERGEJOIN                "NoMergeJoin"
74 #define HINT_NOHASHJOIN                 "NoHashJoin"
75 #define HINT_LEADING                    "Leading"
76 #define HINT_SET                                "Set"
77
78 #define HINT_ARRAY_DEFAULT_INITSIZE 8
79
80 #define hint_ereport(str, detail) \
81         ereport(pg_hint_plan_parse_messages, \
82                         (errmsg("hint syntax error at or near \"%s\"", (str)), \
83                          errdetail detail))
84
85 #define skip_space(str) \
86         while (isspace(*str)) \
87                 str++;
88
89 enum
90 {
91         ENABLE_SEQSCAN = 0x01,
92         ENABLE_INDEXSCAN = 0x02,
93         ENABLE_BITMAPSCAN = 0x04,
94         ENABLE_TIDSCAN = 0x08,
95 #if PG_VERSION_NUM >= 90200
96         ENABLE_INDEXONLYSCAN = 0x10
97 #endif
98 } SCAN_TYPE_BITS;
99
100 enum
101 {
102         ENABLE_NESTLOOP = 0x01,
103         ENABLE_MERGEJOIN = 0x02,
104         ENABLE_HASHJOIN = 0x04
105 } JOIN_TYPE_BITS;
106
107 #if PG_VERSION_NUM >= 90200
108 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | \
109                                                  ENABLE_BITMAPSCAN | ENABLE_TIDSCAN | \
110                                                  ENABLE_INDEXONLYSCAN)
111 #else
112 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | \
113                                                  ENABLE_BITMAPSCAN | ENABLE_TIDSCAN)
114 #endif
115 #define ENABLE_ALL_JOIN (ENABLE_NESTLOOP | ENABLE_MERGEJOIN | ENABLE_HASHJOIN)
116 #define DISABLE_ALL_SCAN 0
117 #define DISABLE_ALL_JOIN 0
118
119 /* hint keyword of enum type*/
120 typedef enum HintKeyword
121 {
122         HINT_KEYWORD_SEQSCAN,
123         HINT_KEYWORD_INDEXSCAN,
124         HINT_KEYWORD_INDEXSCANREGEXP,
125         HINT_KEYWORD_BITMAPSCAN,
126         HINT_KEYWORD_BITMAPSCANREGEXP,
127         HINT_KEYWORD_TIDSCAN,
128         HINT_KEYWORD_NOSEQSCAN,
129         HINT_KEYWORD_NOINDEXSCAN,
130         HINT_KEYWORD_NOBITMAPSCAN,
131         HINT_KEYWORD_NOTIDSCAN,
132 #if PG_VERSION_NUM >= 90200
133         HINT_KEYWORD_INDEXONLYSCAN,
134         HINT_KEYWORD_INDEXONLYSCANREGEXP,
135         HINT_KEYWORD_NOINDEXONLYSCAN,
136 #endif
137         HINT_KEYWORD_NESTLOOP,
138         HINT_KEYWORD_MERGEJOIN,
139         HINT_KEYWORD_HASHJOIN,
140         HINT_KEYWORD_NONESTLOOP,
141         HINT_KEYWORD_NOMERGEJOIN,
142         HINT_KEYWORD_NOHASHJOIN,
143         HINT_KEYWORD_LEADING,
144         HINT_KEYWORD_SET,
145         HINT_KEYWORD_UNRECOGNIZED
146 } HintKeyword;
147
148 typedef struct Hint Hint;
149 typedef struct HintState HintState;
150
151 typedef Hint *(*HintCreateFunction) (const char *hint_str,
152                                                                          const char *keyword,
153                                                                          HintKeyword hint_keyword);
154 typedef void (*HintDeleteFunction) (Hint *hint);
155 typedef void (*HintDescFunction) (Hint *hint, StringInfo buf);
156 typedef int (*HintCmpFunction) (const Hint *a, const Hint *b);
157 typedef const char *(*HintParseFunction) (Hint *hint, HintState *hstate,
158                                                                                   Query *parse, const char *str);
159
160 /* hint types */
161 #define NUM_HINT_TYPE   4
162 typedef enum HintType
163 {
164         HINT_TYPE_SCAN_METHOD,
165         HINT_TYPE_JOIN_METHOD,
166         HINT_TYPE_LEADING,
167         HINT_TYPE_SET
168 } HintType;
169
170 static const char *HintTypeName[] = {
171         "scan method",
172         "join method",
173         "leading",
174         "set"
175 };
176
177 /* hint status */
178 typedef enum HintStatus
179 {
180         HINT_STATE_NOTUSED = 0,         /* specified relation not used in query */
181         HINT_STATE_USED,                        /* hint is used */
182         HINT_STATE_DUPLICATION,         /* specified hint duplication */
183         HINT_STATE_ERROR                        /* execute error (parse error does not include
184                                                                  * it) */
185 } HintStatus;
186
187 #define hint_state_enabled(hint) ((hint)->base.state == HINT_STATE_NOTUSED || \
188                                                                   (hint)->base.state == HINT_STATE_USED)
189
190 /* common data for all hints. */
191 struct Hint
192 {
193         const char                 *hint_str;           /* must not do pfree */
194         const char                 *keyword;            /* must not do pfree */
195         HintKeyword                     hint_keyword;
196         HintType                        type;
197         HintStatus                      state;
198         HintDeleteFunction      delete_func;
199         HintDescFunction        desc_func;
200         HintCmpFunction         cmp_func;
201         HintParseFunction       parse_func;
202 };
203
204 /* scan method hints */
205 typedef struct ScanMethodHint
206 {
207         Hint                    base;
208         char               *relname;
209         List               *indexnames;
210         bool                    regexp;
211         unsigned char   enforce_mask;
212 } ScanMethodHint;
213
214 typedef struct ParentIndexInfo
215 {
216         bool            indisunique;
217         Oid                     method;
218         List       *column_names;
219         char       *expression_str;
220         Oid                *indcollation;
221         Oid                *opclass;
222         int16      *indoption;
223         char       *indpred_str;
224 } ParentIndexInfo;
225
226 /* join method hints */
227 typedef struct JoinMethodHint
228 {
229         Hint                    base;
230         int                             nrels;
231         int                             inner_nrels;
232         char              **relnames;
233         unsigned char   enforce_mask;
234         Relids                  joinrelids;
235         Relids                  inner_joinrelids;
236 } JoinMethodHint;
237
238 /* join order hints */
239 typedef struct OuterInnerRels
240 {
241         char   *relation;
242         List   *outer_inner_pair;
243 } OuterInnerRels;
244
245 typedef struct LeadingHint
246 {
247         Hint                    base;
248         List               *relations;  /* relation names specified in Leading hint */
249         OuterInnerRels *outer_inner;
250 } LeadingHint;
251
252 /* change a run-time parameter hints */
253 typedef struct SetHint
254 {
255         Hint    base;
256         char   *name;                           /* name of variable */
257         char   *value;
258         List   *words;
259 } SetHint;
260
261 /*
262  * Describes a context of hint processing.
263  */
264 struct HintState
265 {
266         char               *hint_str;                   /* original hint string */
267
268         /* all hint */
269         int                             nall_hints;                     /* # of valid all hints */
270         int                             max_all_hints;          /* # of slots for all hints */
271         Hint              **all_hints;                  /* parsed all hints */
272
273         /* # of each hints */
274         int                             num_hints[NUM_HINT_TYPE];
275
276         /* for scan method hints */
277         ScanMethodHint **scan_hints;            /* parsed scan hints */
278         int                             init_scan_mask;         /* initial value scan parameter */
279         Index                   parent_relid;           /* inherit parent table relid */
280         Oid                             parent_rel_oid;     /* inherit parent table relid */
281         ScanMethodHint *parent_hint;            /* inherit parent table scan hint */
282         List               *parent_index_infos; /* infomation of inherit parent table's
283                                                                                  * index */
284
285         /* for join method hints */
286         JoinMethodHint **join_hints;            /* parsed join hints */
287         int                             init_join_mask;         /* initial value join parameter */
288         List              **join_hint_level;
289
290         /* for Leading hint */
291         LeadingHint       **leading_hint;               /* parsed Leading hints */
292
293         /* for Set hints */
294         SetHint           **set_hints;                  /* parsed Set hints */
295         GucContext              context;                        /* which GUC parameters can we set? */
296 };
297
298 /*
299  * Describes a hint parser module which is bound with particular hint keyword.
300  */
301 typedef struct HintParser
302 {
303         char                       *keyword;
304         HintCreateFunction      create_func;
305         HintKeyword                     hint_keyword;
306 } HintParser;
307
308 /* Module callbacks */
309 void            _PG_init(void);
310 void            _PG_fini(void);
311
312 static void push_hint(HintState *hstate);
313 static void pop_hint(void);
314
315 static void pg_hint_plan_ProcessUtility(Node *parsetree,
316                                                                                 const char *queryString,
317                                                                                 ParamListInfo params, bool isTopLevel,
318                                                                                 DestReceiver *dest,
319                                                                                 char *completionTag);
320 static PlannedStmt *pg_hint_plan_planner(Query *parse, int cursorOptions,
321                                                                                  ParamListInfo boundParams);
322 static void pg_hint_plan_get_relation_info(PlannerInfo *root,
323                                                                                    Oid relationObjectId,
324                                                                                    bool inhparent, RelOptInfo *rel);
325 static RelOptInfo *pg_hint_plan_join_search(PlannerInfo *root,
326                                                                                         int levels_needed,
327                                                                                         List *initial_rels);
328
329 static Hint *ScanMethodHintCreate(const char *hint_str, const char *keyword,
330                                                                   HintKeyword hint_keyword);
331 static void ScanMethodHintDelete(ScanMethodHint *hint);
332 static void ScanMethodHintDesc(ScanMethodHint *hint, StringInfo buf);
333 static int ScanMethodHintCmp(const ScanMethodHint *a, const ScanMethodHint *b);
334 static const char *ScanMethodHintParse(ScanMethodHint *hint, HintState *hstate,
335                                                                            Query *parse, const char *str);
336 static Hint *JoinMethodHintCreate(const char *hint_str, const char *keyword,
337                                                                   HintKeyword hint_keyword);
338 static void JoinMethodHintDelete(JoinMethodHint *hint);
339 static void JoinMethodHintDesc(JoinMethodHint *hint, StringInfo buf);
340 static int JoinMethodHintCmp(const JoinMethodHint *a, const JoinMethodHint *b);
341 static const char *JoinMethodHintParse(JoinMethodHint *hint, HintState *hstate,
342                                                                            Query *parse, const char *str);
343 static Hint *LeadingHintCreate(const char *hint_str, const char *keyword,
344                                                            HintKeyword hint_keyword);
345 static void LeadingHintDelete(LeadingHint *hint);
346 static void LeadingHintDesc(LeadingHint *hint, StringInfo buf);
347 static int LeadingHintCmp(const LeadingHint *a, const LeadingHint *b);
348 static const char *LeadingHintParse(LeadingHint *hint, HintState *hstate,
349                                                                         Query *parse, const char *str);
350 static Hint *SetHintCreate(const char *hint_str, const char *keyword,
351                                                    HintKeyword hint_keyword);
352 static void SetHintDelete(SetHint *hint);
353 static void SetHintDesc(SetHint *hint, StringInfo buf);
354 static int SetHintCmp(const SetHint *a, const SetHint *b);
355 static const char *SetHintParse(SetHint *hint, HintState *hstate, Query *parse,
356                                                                 const char *str);
357
358 static void quote_value(StringInfo buf, const char *value);
359
360 static const char *parse_quoted_value(const char *str, char **word,
361                                                                           bool truncate);
362
363 RelOptInfo *pg_hint_plan_standard_join_search(PlannerInfo *root,
364                                                                                           int levels_needed,
365                                                                                           List *initial_rels);
366 void pg_hint_plan_join_search_one_level(PlannerInfo *root, int level);
367 static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel,
368                                                                           ListCell *other_rels);
369 static void make_rels_by_clauseless_joins(PlannerInfo *root,
370                                                                                   RelOptInfo *old_rel,
371                                                                                   ListCell *other_rels);
372 static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
373 static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
374                                                                         Index rti, RangeTblEntry *rte);
375 #if PG_VERSION_NUM >= 90200
376 static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
377                                                    List *live_childrels,
378                                                    List *all_child_pathkeys);
379 #endif
380 static List *accumulate_append_subpath(List *subpaths, Path *path);
381 #if PG_VERSION_NUM < 90200
382 static void set_dummy_rel_pathlist(RelOptInfo *rel);
383 #endif
384 RelOptInfo *pg_hint_plan_make_join_rel(PlannerInfo *root, RelOptInfo *rel1,
385                                                                            RelOptInfo *rel2);
386
387 /* GUC variables */
388 static bool     pg_hint_plan_enable_hint = true;
389 static bool     pg_hint_plan_debug_print = false;
390 static int      pg_hint_plan_parse_messages = INFO;
391
392 static const struct config_enum_entry parse_messages_level_options[] = {
393         {"debug", DEBUG2, true},
394         {"debug5", DEBUG5, false},
395         {"debug4", DEBUG4, false},
396         {"debug3", DEBUG3, false},
397         {"debug2", DEBUG2, false},
398         {"debug1", DEBUG1, false},
399         {"log", LOG, false},
400         {"info", INFO, false},
401         {"notice", NOTICE, false},
402         {"warning", WARNING, false},
403         {"error", ERROR, false},
404         /*
405          * {"fatal", FATAL, true},
406          * {"panic", PANIC, true},
407          */
408         {NULL, 0, false}
409 };
410
411 /* Saved hook values in case of unload */
412 static ProcessUtility_hook_type prev_ProcessUtility = NULL;
413 static planner_hook_type prev_planner = NULL;
414 static get_relation_info_hook_type prev_get_relation_info = NULL;
415 static join_search_hook_type prev_join_search = NULL;
416
417 /* Hold reference to currently active hint */
418 static HintState *current_hint = NULL;
419
420 /*
421  * List of hint contexts.  We treat the head of the list as the Top of the
422  * context stack, so current_hint always points the first element of this list.
423  */
424 static List *HintStateStack = NIL;
425
426 /*
427  * Holds statement name during executing EXECUTE command.  NULL for other
428  * statements.
429  */
430 static char        *stmt_name = NULL;
431
432 static const HintParser parsers[] = {
433         {HINT_SEQSCAN, ScanMethodHintCreate, HINT_KEYWORD_SEQSCAN},
434         {HINT_INDEXSCAN, ScanMethodHintCreate, HINT_KEYWORD_INDEXSCAN},
435         {HINT_INDEXSCANREGEXP, ScanMethodHintCreate, HINT_KEYWORD_INDEXSCANREGEXP},
436         {HINT_BITMAPSCAN, ScanMethodHintCreate, HINT_KEYWORD_BITMAPSCAN},
437         {HINT_BITMAPSCANREGEXP, ScanMethodHintCreate,
438          HINT_KEYWORD_BITMAPSCANREGEXP},
439         {HINT_TIDSCAN, ScanMethodHintCreate, HINT_KEYWORD_TIDSCAN},
440         {HINT_NOSEQSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOSEQSCAN},
441         {HINT_NOINDEXSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOINDEXSCAN},
442         {HINT_NOBITMAPSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOBITMAPSCAN},
443         {HINT_NOTIDSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOTIDSCAN},
444 #if PG_VERSION_NUM >= 90200
445         {HINT_INDEXONLYSCAN, ScanMethodHintCreate, HINT_KEYWORD_INDEXONLYSCAN},
446         {HINT_INDEXONLYSCANREGEXP, ScanMethodHintCreate,
447          HINT_KEYWORD_INDEXONLYSCANREGEXP},
448         {HINT_NOINDEXONLYSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOINDEXONLYSCAN},
449 #endif
450         {HINT_NESTLOOP, JoinMethodHintCreate, HINT_KEYWORD_NESTLOOP},
451         {HINT_MERGEJOIN, JoinMethodHintCreate, HINT_KEYWORD_MERGEJOIN},
452         {HINT_HASHJOIN, JoinMethodHintCreate, HINT_KEYWORD_HASHJOIN},
453         {HINT_NONESTLOOP, JoinMethodHintCreate, HINT_KEYWORD_NONESTLOOP},
454         {HINT_NOMERGEJOIN, JoinMethodHintCreate, HINT_KEYWORD_NOMERGEJOIN},
455         {HINT_NOHASHJOIN, JoinMethodHintCreate, HINT_KEYWORD_NOHASHJOIN},
456         {HINT_LEADING, LeadingHintCreate, HINT_KEYWORD_LEADING},
457         {HINT_SET, SetHintCreate, HINT_KEYWORD_SET},
458         {NULL, NULL, HINT_KEYWORD_UNRECOGNIZED}
459 };
460
461 /*
462  * Module load callbacks
463  */
464 void
465 _PG_init(void)
466 {
467         /* Define custom GUC variables. */
468         DefineCustomBoolVariable("pg_hint_plan.enable_hint",
469                          "Force planner to use plans specified in the hint comment preceding to the query.",
470                                                          NULL,
471                                                          &pg_hint_plan_enable_hint,
472                                                          true,
473                                                          PGC_USERSET,
474                                                          0,
475                                                          NULL,
476                                                          NULL,
477                                                          NULL);
478
479         DefineCustomBoolVariable("pg_hint_plan.debug_print",
480                                                          "Logs results of hint parsing.",
481                                                          NULL,
482                                                          &pg_hint_plan_debug_print,
483                                                          false,
484                                                          PGC_USERSET,
485                                                          0,
486                                                          NULL,
487                                                          NULL,
488                                                          NULL);
489
490         DefineCustomEnumVariable("pg_hint_plan.parse_messages",
491                                                          "Message level of parse errors.",
492                                                          NULL,
493                                                          &pg_hint_plan_parse_messages,
494                                                          INFO,
495                                                          parse_messages_level_options,
496                                                          PGC_USERSET,
497                                                          0,
498                                                          NULL,
499                                                          NULL,
500                                                          NULL);
501
502         /* Install hooks. */
503         prev_ProcessUtility = ProcessUtility_hook;
504         ProcessUtility_hook = pg_hint_plan_ProcessUtility;
505         prev_planner = planner_hook;
506         planner_hook = pg_hint_plan_planner;
507         prev_get_relation_info = get_relation_info_hook;
508         get_relation_info_hook = pg_hint_plan_get_relation_info;
509         prev_join_search = join_search_hook;
510         join_search_hook = pg_hint_plan_join_search;
511 }
512
513 /*
514  * Module unload callback
515  * XXX never called
516  */
517 void
518 _PG_fini(void)
519 {
520         /* Uninstall hooks. */
521         ProcessUtility_hook = prev_ProcessUtility;
522         planner_hook = prev_planner;
523         get_relation_info_hook = prev_get_relation_info;
524         join_search_hook = prev_join_search;
525 }
526
527 /*
528  * create and delete functions the hint object
529  */
530
531 static Hint *
532 ScanMethodHintCreate(const char *hint_str, const char *keyword,
533                                          HintKeyword hint_keyword)
534 {
535         ScanMethodHint *hint;
536
537         hint = palloc(sizeof(ScanMethodHint));
538         hint->base.hint_str = hint_str;
539         hint->base.keyword = keyword;
540         hint->base.hint_keyword = hint_keyword;
541         hint->base.type = HINT_TYPE_SCAN_METHOD;
542         hint->base.state = HINT_STATE_NOTUSED;
543         hint->base.delete_func = (HintDeleteFunction) ScanMethodHintDelete;
544         hint->base.desc_func = (HintDescFunction) ScanMethodHintDesc;
545         hint->base.cmp_func = (HintCmpFunction) ScanMethodHintCmp;
546         hint->base.parse_func = (HintParseFunction) ScanMethodHintParse;
547         hint->relname = NULL;
548         hint->indexnames = NIL;
549         hint->regexp = false;
550         hint->enforce_mask = 0;
551
552         return (Hint *) hint;
553 }
554
555 static void
556 ScanMethodHintDelete(ScanMethodHint *hint)
557 {
558         if (!hint)
559                 return;
560
561         if (hint->relname)
562                 pfree(hint->relname);
563         list_free_deep(hint->indexnames);
564         pfree(hint);
565 }
566
567 static Hint *
568 JoinMethodHintCreate(const char *hint_str, const char *keyword,
569                                          HintKeyword hint_keyword)
570 {
571         JoinMethodHint *hint;
572
573         hint = palloc(sizeof(JoinMethodHint));
574         hint->base.hint_str = hint_str;
575         hint->base.keyword = keyword;
576         hint->base.hint_keyword = hint_keyword;
577         hint->base.type = HINT_TYPE_JOIN_METHOD;
578         hint->base.state = HINT_STATE_NOTUSED;
579         hint->base.delete_func = (HintDeleteFunction) JoinMethodHintDelete;
580         hint->base.desc_func = (HintDescFunction) JoinMethodHintDesc;
581         hint->base.cmp_func = (HintCmpFunction) JoinMethodHintCmp;
582         hint->base.parse_func = (HintParseFunction) JoinMethodHintParse;
583         hint->nrels = 0;
584         hint->inner_nrels = 0;
585         hint->relnames = NULL;
586         hint->enforce_mask = 0;
587         hint->joinrelids = NULL;
588         hint->inner_joinrelids = NULL;
589
590         return (Hint *) hint;
591 }
592
593 static void
594 JoinMethodHintDelete(JoinMethodHint *hint)
595 {
596         if (!hint)
597                 return;
598
599         if (hint->relnames)
600         {
601                 int     i;
602
603                 for (i = 0; i < hint->nrels; i++)
604                         pfree(hint->relnames[i]);
605                 pfree(hint->relnames);
606         }
607
608         bms_free(hint->joinrelids);
609         bms_free(hint->inner_joinrelids);
610         pfree(hint);
611 }
612
613 static Hint *
614 LeadingHintCreate(const char *hint_str, const char *keyword,
615                                   HintKeyword hint_keyword)
616 {
617         LeadingHint        *hint;
618
619         hint = palloc(sizeof(LeadingHint));
620         hint->base.hint_str = hint_str;
621         hint->base.keyword = keyword;
622         hint->base.hint_keyword = hint_keyword;
623         hint->base.type = HINT_TYPE_LEADING;
624         hint->base.state = HINT_STATE_NOTUSED;
625         hint->base.delete_func = (HintDeleteFunction)LeadingHintDelete;
626         hint->base.desc_func = (HintDescFunction) LeadingHintDesc;
627         hint->base.cmp_func = (HintCmpFunction) LeadingHintCmp;
628         hint->base.parse_func = (HintParseFunction) LeadingHintParse;
629         hint->relations = NIL;
630         hint->outer_inner = NULL;
631
632         return (Hint *) hint;
633 }
634
635 static void
636 LeadingHintDelete(LeadingHint *hint)
637 {
638         if (!hint)
639                 return;
640
641         list_free_deep(hint->relations);
642         if (hint->outer_inner)
643                 pfree(hint->outer_inner);
644         pfree(hint);
645 }
646
647 static Hint *
648 SetHintCreate(const char *hint_str, const char *keyword,
649                           HintKeyword hint_keyword)
650 {
651         SetHint    *hint;
652
653         hint = palloc(sizeof(SetHint));
654         hint->base.hint_str = hint_str;
655         hint->base.keyword = keyword;
656         hint->base.hint_keyword = hint_keyword;
657         hint->base.type = HINT_TYPE_SET;
658         hint->base.state = HINT_STATE_NOTUSED;
659         hint->base.delete_func = (HintDeleteFunction) SetHintDelete;
660         hint->base.desc_func = (HintDescFunction) SetHintDesc;
661         hint->base.cmp_func = (HintCmpFunction) SetHintCmp;
662         hint->base.parse_func = (HintParseFunction) SetHintParse;
663         hint->name = NULL;
664         hint->value = NULL;
665         hint->words = NIL;
666
667         return (Hint *) hint;
668 }
669
670 static void
671 SetHintDelete(SetHint *hint)
672 {
673         if (!hint)
674                 return;
675
676         if (hint->name)
677                 pfree(hint->name);
678         if (hint->value)
679                 pfree(hint->value);
680         if (hint->words)
681                 list_free(hint->words);
682         pfree(hint);
683 }
684
685 static HintState *
686 HintStateCreate(void)
687 {
688         HintState   *hstate;
689
690         hstate = palloc(sizeof(HintState));
691         hstate->hint_str = NULL;
692         hstate->nall_hints = 0;
693         hstate->max_all_hints = 0;
694         hstate->all_hints = NULL;
695         memset(hstate->num_hints, 0, sizeof(hstate->num_hints));
696         hstate->scan_hints = NULL;
697         hstate->init_scan_mask = 0;
698         hstate->parent_relid = 0;
699         hstate->parent_rel_oid = InvalidOid;
700         hstate->parent_hint = NULL;
701         hstate->parent_index_infos = NIL;
702         hstate->join_hints = NULL;
703         hstate->init_join_mask = 0;
704         hstate->join_hint_level = NULL;
705         hstate->leading_hint = NULL;
706         hstate->context = superuser() ? PGC_SUSET : PGC_USERSET;
707         hstate->set_hints = NULL;
708
709         return hstate;
710 }
711
712 static void
713 HintStateDelete(HintState *hstate)
714 {
715         int                     i;
716
717         if (!hstate)
718                 return;
719
720         if (hstate->hint_str)
721                 pfree(hstate->hint_str);
722
723         for (i = 0; i < hstate->num_hints[HINT_TYPE_SCAN_METHOD]; i++)
724                 hstate->all_hints[i]->delete_func(hstate->all_hints[i]);
725         if (hstate->all_hints)
726                 pfree(hstate->all_hints);
727         if (hstate->parent_index_infos)
728                 list_free(hstate->parent_index_infos);
729 }
730
731 /*
732  * Copy given value into buf, with quoting with '"' if necessary.
733  */
734 static void
735 quote_value(StringInfo buf, const char *value)
736 {
737         bool            need_quote = false;
738         const char *str;
739
740         for (str = value; *str != '\0'; str++)
741         {
742                 if (isspace(*str) || *str == '(' || *str == ')' || *str == '"')
743                 {
744                         need_quote = true;
745                         appendStringInfoCharMacro(buf, '"');
746                         break;
747                 }
748         }
749
750         for (str = value; *str != '\0'; str++)
751         {
752                 if (*str == '"')
753                         appendStringInfoCharMacro(buf, '"');
754
755                 appendStringInfoCharMacro(buf, *str);
756         }
757
758         if (need_quote)
759                 appendStringInfoCharMacro(buf, '"');
760 }
761
762 static void
763 ScanMethodHintDesc(ScanMethodHint *hint, StringInfo buf)
764 {
765         ListCell   *l;
766
767         appendStringInfo(buf, "%s(", hint->base.keyword);
768         if (hint->relname != NULL)
769         {
770                 quote_value(buf, hint->relname);
771                 foreach(l, hint->indexnames)
772                 {
773                         appendStringInfoCharMacro(buf, ' ');
774                         quote_value(buf, (char *) lfirst(l));
775                 }
776         }
777         appendStringInfoString(buf, ")\n");
778 }
779
780 static void
781 JoinMethodHintDesc(JoinMethodHint *hint, StringInfo buf)
782 {
783         int     i;
784
785         appendStringInfo(buf, "%s(", hint->base.keyword);
786         if (hint->relnames != NULL)
787         {
788                 quote_value(buf, hint->relnames[0]);
789                 for (i = 1; i < hint->nrels; i++)
790                 {
791                         appendStringInfoCharMacro(buf, ' ');
792                         quote_value(buf, hint->relnames[i]);
793                 }
794         }
795         appendStringInfoString(buf, ")\n");
796
797 }
798
799 static void
800 OuterInnerDesc(OuterInnerRels *outer_inner, StringInfo buf)
801 {
802         if (outer_inner->relation == NULL)
803         {
804                 bool            is_first;
805                 ListCell   *l;
806
807                 is_first = true;
808
809                 appendStringInfoCharMacro(buf, '(');
810                 foreach(l, outer_inner->outer_inner_pair)
811                 {
812                         if (is_first)
813                                 is_first = false;
814                         else
815                                 appendStringInfoCharMacro(buf, ' ');
816
817                         OuterInnerDesc(lfirst(l), buf);
818                 }
819
820                 appendStringInfoCharMacro(buf, ')');
821         }
822         else
823                 quote_value(buf, outer_inner->relation);
824 }
825
826 static void
827 LeadingHintDesc(LeadingHint *hint, StringInfo buf)
828 {
829         appendStringInfo(buf, "%s(", HINT_LEADING);
830         if (hint->outer_inner == NULL)
831         {
832                 ListCell   *l;
833                 bool            is_first;
834
835                 is_first = true;
836
837                 foreach(l, hint->relations)
838                 {
839                         if (is_first)
840                                 is_first = false;
841                         else
842                                 appendStringInfoCharMacro(buf, ' ');
843
844                         quote_value(buf, (char *) lfirst(l));
845                 }
846         }
847         else
848                 OuterInnerDesc(hint->outer_inner, buf);
849
850         appendStringInfoString(buf, ")\n");
851 }
852
853 static void
854 SetHintDesc(SetHint *hint, StringInfo buf)
855 {
856         bool            is_first = true;
857         ListCell   *l;
858
859         appendStringInfo(buf, "%s(", HINT_SET);
860         foreach(l, hint->words)
861         {
862                 if (is_first)
863                         is_first = false;
864                 else
865                         appendStringInfoCharMacro(buf, ' ');
866
867                 quote_value(buf, (char *) lfirst(l));
868         }
869         appendStringInfo(buf, ")\n");
870 }
871
872 /*
873  * Append string which repserents all hints in a given state to buf, with
874  * preceding title with them.
875  */
876 static void
877 desc_hint_in_state(HintState *hstate, StringInfo buf, const char *title,
878                                         HintStatus state)
879 {
880         int     i;
881
882         appendStringInfo(buf, "%s:\n", title);
883         for (i = 0; i < hstate->nall_hints; i++)
884         {
885                 if (hstate->all_hints[i]->state != state)
886                         continue;
887
888                 hstate->all_hints[i]->desc_func(hstate->all_hints[i], buf);
889         }
890 }
891
892 /*
893  * Dump contents of given hstate to server log with log level LOG.
894  */
895 static void
896 HintStateDump(HintState *hstate)
897 {
898         StringInfoData  buf;
899
900         if (!hstate)
901         {
902                 elog(LOG, "pg_hint_plan:\nno hint");
903                 return;
904         }
905
906         initStringInfo(&buf);
907
908         appendStringInfoString(&buf, "pg_hint_plan:\n");
909         desc_hint_in_state(hstate, &buf, "used hint", HINT_STATE_USED);
910         desc_hint_in_state(hstate, &buf, "not used hint", HINT_STATE_NOTUSED);
911         desc_hint_in_state(hstate, &buf, "duplication hint", HINT_STATE_DUPLICATION);
912         desc_hint_in_state(hstate, &buf, "error hint", HINT_STATE_ERROR);
913
914         elog(LOG, "%s", buf.data);
915
916         pfree(buf.data);
917 }
918
919 /*
920  * compare functions
921  */
922
923 static int
924 RelnameCmp(const void *a, const void *b)
925 {
926         const char *relnamea = *((const char **) a);
927         const char *relnameb = *((const char **) b);
928
929         return strcmp(relnamea, relnameb);
930 }
931
932 static int
933 ScanMethodHintCmp(const ScanMethodHint *a, const ScanMethodHint *b)
934 {
935         return RelnameCmp(&a->relname, &b->relname);
936 }
937
938 static int
939 JoinMethodHintCmp(const JoinMethodHint *a, const JoinMethodHint *b)
940 {
941         int     i;
942
943         if (a->nrels != b->nrels)
944                 return a->nrels - b->nrels;
945
946         for (i = 0; i < a->nrels; i++)
947         {
948                 int     result;
949                 if ((result = RelnameCmp(&a->relnames[i], &b->relnames[i])) != 0)
950                         return result;
951         }
952
953         return 0;
954 }
955
956 static int
957 LeadingHintCmp(const LeadingHint *a, const LeadingHint *b)
958 {
959         return 0;
960 }
961
962 static int
963 SetHintCmp(const SetHint *a, const SetHint *b)
964 {
965         return strcmp(a->name, b->name);
966 }
967
968 static int
969 HintCmp(const void *a, const void *b)
970 {
971         const Hint *hinta = *((const Hint **) a);
972         const Hint *hintb = *((const Hint **) b);
973
974         if (hinta->type != hintb->type)
975                 return hinta->type - hintb->type;
976         if (hinta->state == HINT_STATE_ERROR)
977                 return -1;
978         if (hintb->state == HINT_STATE_ERROR)
979                 return 1;
980         return hinta->cmp_func(hinta, hintb);
981 }
982
983 /*
984  * Returns byte offset of hint b from hint a.  If hint a was specified before
985  * b, positive value is returned.
986  */
987 static int
988 HintCmpWithPos(const void *a, const void *b)
989 {
990         const Hint *hinta = *((const Hint **) a);
991         const Hint *hintb = *((const Hint **) b);
992         int             result;
993
994         result = HintCmp(a, b);
995         if (result == 0)
996                 result = hinta->hint_str - hintb->hint_str;
997
998         return result;
999 }
1000
1001 /*
1002  * parse functions
1003  */
1004 static const char *
1005 parse_keyword(const char *str, StringInfo buf)
1006 {
1007         skip_space(str);
1008
1009         while (!isspace(*str) && *str != '(' && *str != '\0')
1010                 appendStringInfoCharMacro(buf, *str++);
1011
1012         return str;
1013 }
1014
1015 static const char *
1016 skip_parenthesis(const char *str, char parenthesis)
1017 {
1018         skip_space(str);
1019
1020         if (*str != parenthesis)
1021         {
1022                 if (parenthesis == '(')
1023                         hint_ereport(str, ("Opening parenthesis is necessary."));
1024                 else if (parenthesis == ')')
1025                         hint_ereport(str, ("Closing parenthesis is necessary."));
1026
1027                 return NULL;
1028         }
1029
1030         str++;
1031
1032         return str;
1033 }
1034
1035 /*
1036  * Parse a token from str, and store malloc'd copy into word.  A token can be
1037  * quoted with '"'.  Return value is pointer to unparsed portion of original
1038  * string, or NULL if an error occurred.
1039  *
1040  * Parsed token is truncated within NAMEDATALEN-1 bytes, when truncate is true.
1041  */
1042 static const char *
1043 parse_quoted_value(const char *str, char **word, bool truncate)
1044 {
1045         StringInfoData  buf;
1046         bool                    in_quote;
1047
1048         /* Skip leading spaces. */
1049         skip_space(str);
1050
1051         initStringInfo(&buf);
1052         if (*str == '"')
1053         {
1054                 str++;
1055                 in_quote = true;
1056         }
1057         else
1058                 in_quote = false;
1059
1060         while (true)
1061         {
1062                 if (in_quote)
1063                 {
1064                         /* Double quotation must be closed. */
1065                         if (*str == '\0')
1066                         {
1067                                 pfree(buf.data);
1068                                 hint_ereport(str, ("Unterminated quoted string."));
1069                                 return NULL;
1070                         }
1071
1072                         /*
1073                          * Skip escaped double quotation.
1074                          *
1075                          * We don't allow slash-asterisk and asterisk-slash (delimiters of
1076                          * block comments) to be an object name, so users must specify
1077                          * alias for such object names.
1078                          *
1079                          * Those special names can be allowed if we care escaped slashes
1080                          * and asterisks, but we don't.
1081                          */
1082                         if (*str == '"')
1083                         {
1084                                 str++;
1085                                 if (*str != '"')
1086                                         break;
1087                         }
1088                 }
1089                 else if (isspace(*str) || *str == '(' || *str == ')' || *str == '"' ||
1090                                  *str == '\0')
1091                         break;
1092
1093                 appendStringInfoCharMacro(&buf, *str++);
1094         }
1095
1096         if (buf.len == 0)
1097         {
1098                 hint_ereport(str, ("Zero-length delimited string."));
1099
1100                 pfree(buf.data);
1101
1102                 return NULL;
1103         }
1104
1105         /* Truncate name if it's too long */
1106         if (truncate)
1107                 truncate_identifier(buf.data, strlen(buf.data), true);
1108
1109         *word = buf.data;
1110
1111         return str;
1112 }
1113
1114 static OuterInnerRels *
1115 OuterInnerRelsCreate(char *name, List *outer_inner_list)
1116 {
1117         OuterInnerRels *outer_inner;
1118
1119         outer_inner = palloc(sizeof(OuterInnerRels));
1120         outer_inner->relation = name;
1121         outer_inner->outer_inner_pair = outer_inner_list;
1122
1123         return outer_inner;
1124 }
1125
1126 static const char *
1127 parse_parentheses_Leading_in(const char *str, OuterInnerRels **outer_inner)
1128 {
1129         List   *outer_inner_pair = NIL;
1130
1131         if ((str = skip_parenthesis(str, '(')) == NULL)
1132                 return NULL;
1133
1134         skip_space(str);
1135
1136         /* Store words in parentheses into outer_inner_list. */
1137         while(*str != ')' && *str != '\0')
1138         {
1139                 OuterInnerRels *outer_inner_rels;
1140
1141                 if (*str == '(')
1142                 {
1143                         str = parse_parentheses_Leading_in(str, &outer_inner_rels);
1144                         if (str == NULL)
1145                                 break;
1146                 }
1147                 else
1148                 {
1149                         char   *name;
1150
1151                         if ((str = parse_quoted_value(str, &name, true)) == NULL)
1152                                 break;
1153                         else
1154                                 outer_inner_rels = OuterInnerRelsCreate(name, NIL);
1155                 }
1156
1157                 outer_inner_pair = lappend(outer_inner_pair, outer_inner_rels);
1158                 skip_space(str);
1159         }
1160
1161         if (str == NULL ||
1162                 (str = skip_parenthesis(str, ')')) == NULL)
1163         {
1164                 list_free(outer_inner_pair);
1165                 return NULL;
1166         }
1167
1168         *outer_inner = OuterInnerRelsCreate(NULL, outer_inner_pair);
1169
1170         return str;
1171 }
1172
1173 static const char *
1174 parse_parentheses_Leading(const char *str, List **name_list,
1175         OuterInnerRels **outer_inner)
1176 {
1177         char   *name;
1178         bool    truncate = true;
1179
1180         if ((str = skip_parenthesis(str, '(')) == NULL)
1181                 return NULL;
1182
1183         skip_space(str);
1184         if (*str =='(')
1185         {
1186                 if ((str = parse_parentheses_Leading_in(str, outer_inner)) == NULL)
1187                         return NULL;
1188         }
1189         else
1190         {
1191                 /* Store words in parentheses into name_list. */
1192                 while(*str != ')' && *str != '\0')
1193                 {
1194                         if ((str = parse_quoted_value(str, &name, truncate)) == NULL)
1195                         {
1196                                 list_free(*name_list);
1197                                 return NULL;
1198                         }
1199
1200                         *name_list = lappend(*name_list, name);
1201                         skip_space(str);
1202                 }
1203         }
1204
1205         if ((str = skip_parenthesis(str, ')')) == NULL)
1206                 return NULL;
1207         return str;
1208 }
1209
1210 static const char *
1211 parse_parentheses(const char *str, List **name_list, HintKeyword keyword)
1212 {
1213         char   *name;
1214         bool    truncate = true;
1215
1216         if ((str = skip_parenthesis(str, '(')) == NULL)
1217                 return NULL;
1218
1219         skip_space(str);
1220
1221         /* Store words in parentheses into name_list. */
1222         while(*str != ')' && *str != '\0')
1223         {
1224                 if ((str = parse_quoted_value(str, &name, truncate)) == NULL)
1225                 {
1226                         list_free(*name_list);
1227                         return NULL;
1228                 }
1229
1230                 *name_list = lappend(*name_list, name);
1231                 skip_space(str);
1232
1233                 if (keyword == HINT_KEYWORD_INDEXSCANREGEXP ||
1234 #if PG_VERSION_NUM >= 90200
1235                         keyword == HINT_KEYWORD_INDEXONLYSCANREGEXP ||
1236 #endif
1237                         keyword == HINT_KEYWORD_BITMAPSCANREGEXP ||
1238                         keyword == HINT_KEYWORD_SET)
1239                 {
1240                         truncate = false;
1241                 }
1242         }
1243
1244         if ((str = skip_parenthesis(str, ')')) == NULL)
1245                 return NULL;
1246         return str;
1247 }
1248
1249 static void
1250 parse_hints(HintState *hstate, Query *parse, const char *str)
1251 {
1252         StringInfoData  buf;
1253         char               *head;
1254
1255         initStringInfo(&buf);
1256         while (*str != '\0')
1257         {
1258                 const HintParser *parser;
1259
1260                 /* in error message, we output the comment including the keyword. */
1261                 head = (char *) str;
1262
1263                 /* parse only the keyword of the hint. */
1264                 resetStringInfo(&buf);
1265                 str = parse_keyword(str, &buf);
1266
1267                 for (parser = parsers; parser->keyword != NULL; parser++)
1268                 {
1269                         char   *keyword = parser->keyword;
1270                         Hint   *hint;
1271
1272                         if (strcasecmp(buf.data, keyword) != 0)
1273                                 continue;
1274
1275                         hint = parser->create_func(head, keyword, parser->hint_keyword);
1276
1277                         /* parser of each hint does parse in a parenthesis. */
1278                         if ((str = hint->parse_func(hint, hstate, parse, str)) == NULL)
1279                         {
1280                                 hint->delete_func(hint);
1281                                 pfree(buf.data);
1282                                 return;
1283                         }
1284
1285                         /*
1286                          * Add hint information into all_hints array.  If we don't have
1287                          * enough space, double the array.
1288                          */
1289                         if (hstate->nall_hints == 0)
1290                         {
1291                                 hstate->max_all_hints = HINT_ARRAY_DEFAULT_INITSIZE;
1292                                 hstate->all_hints = (Hint **)
1293                                         palloc(sizeof(Hint *) * hstate->max_all_hints);
1294                         }
1295                         else if (hstate->nall_hints == hstate->max_all_hints)
1296                         {
1297                                 hstate->max_all_hints *= 2;
1298                                 hstate->all_hints = (Hint **)
1299                                         repalloc(hstate->all_hints,
1300                                                          sizeof(Hint *) * hstate->max_all_hints);
1301                         }
1302
1303                         hstate->all_hints[hstate->nall_hints] = hint;
1304                         hstate->nall_hints++;
1305
1306                         skip_space(str);
1307
1308                         break;
1309                 }
1310
1311                 if (parser->keyword == NULL)
1312                 {
1313                         hint_ereport(head,
1314                                                  ("Unrecognized hint keyword \"%s\".", buf.data));
1315                         pfree(buf.data);
1316                         return;
1317                 }
1318         }
1319
1320         pfree(buf.data);
1321 }
1322
1323 /*
1324  * クエリ文字列を取得する。
1325  */
1326 static const char *
1327 get_query_string(void)
1328 {
1329         const char *p;
1330
1331         /* get client-supplied query string. */
1332         if (stmt_name)
1333         {
1334                 PreparedStatement  *entry;
1335
1336                 entry = FetchPreparedStatement(stmt_name, true);
1337                 p = entry->plansource->query_string;
1338         }
1339         else
1340                 p = debug_query_string;
1341
1342         return p;
1343 }
1344
1345 /*
1346  * クエリに記述されたヒント用ブロックコメントからヒントを取得する。
1347  */
1348 static const char *
1349 get_hints_from_comment(const char *p)
1350 {
1351         const char *hint_head;
1352         char       *head;
1353         char       *tail;
1354         int                     len;
1355
1356         if (p == NULL)
1357                 return NULL;
1358
1359         /* extract query head comment. */
1360         hint_head = strstr(p, HINT_START);
1361         if (hint_head == NULL)
1362                 return NULL;
1363         for (;p < hint_head; p++)
1364         {
1365                 /*
1366                  * Allow these characters precedes hint comment:
1367                  *   - digits
1368                  *   - alphabets which are in ASCII range
1369                  *   - space, tabs and new-lines
1370                  *   - underscores, for identifier
1371                  *   - commas, for SELECT clause, EXPLAIN and PREPARE
1372                  *   - parentheses, for EXPLAIN and PREPARE
1373                  *
1374                  * Note that we don't use isalpha() nor isalnum() in ctype.h here to
1375                  * avoid behavior which depends on locale setting.
1376                  */
1377                 if (!(*p >= '0' && *p <= '9') &&
1378                         !(*p >= 'A' && *p <= 'Z') &&
1379                         !(*p >= 'a' && *p <= 'z') &&
1380                         !isspace(*p) &&
1381                         *p != '_' &&
1382                         *p != ',' &&
1383                         *p != '(' && *p != ')')
1384                         return NULL;
1385         }
1386
1387         len = strlen(HINT_START);
1388         head = (char *) p;
1389         p += len;
1390         skip_space(p);
1391
1392         /* find hint end keyword. */
1393         if ((tail = strstr(p, HINT_END)) == NULL)
1394         {
1395                 hint_ereport(head, ("Unterminated block comment."));
1396                 return NULL;
1397         }
1398
1399         /* We don't support nested block comments. */
1400         if ((head = strstr(p, BLOCK_COMMENT_START)) != NULL && head < tail)
1401         {
1402                 hint_ereport(head, ("Nested block comments are not supported."));
1403                 return NULL;
1404         }
1405
1406         /* Make a copy of hint. */
1407         len = tail - p;
1408         head = palloc(len + 1);
1409         memcpy(head, p, len);
1410         head[len] = '\0';
1411         p = head;
1412
1413         return p;
1414 }
1415
1416 /*
1417  * 取得したヒントをパースする。
1418  */
1419 static HintState *
1420 convert_hints(Query *parse, const char *hints)
1421 {
1422         const char *p;
1423         int                     i;
1424         HintState   *hstate;
1425
1426         if (hints == NULL)
1427                 return NULL;
1428
1429         p = hints;
1430         hstate = HintStateCreate();
1431         hstate->hint_str = (char *) hints;
1432
1433         /* parse each hint. */
1434         parse_hints(hstate, parse, p);
1435
1436         /* When nothing specified a hint, we free HintState and returns NULL. */
1437         if (hstate->nall_hints == 0)
1438         {
1439                 HintStateDelete(hstate);
1440                 return NULL;
1441         }
1442
1443         /* Sort hints in order of original position. */
1444         qsort(hstate->all_hints, hstate->nall_hints, sizeof(Hint *),
1445                   HintCmpWithPos);
1446
1447         /* Count number of hints per hint-type. */
1448         for (i = 0; i < hstate->nall_hints; i++)
1449         {
1450                 Hint   *cur_hint = hstate->all_hints[i];
1451                 hstate->num_hints[cur_hint->type]++;
1452         }
1453
1454         /*
1455          * If an object (or a set of objects) has multiple hints of same hint-type,
1456          * only the last hint is valid and others are igonred in planning.
1457          * Hints except the last are marked as 'duplicated' to remember the order.
1458          */
1459         for (i = 0; i < hstate->nall_hints - 1; i++)
1460         {
1461                 Hint   *cur_hint = hstate->all_hints[i];
1462                 Hint   *next_hint = hstate->all_hints[i + 1];
1463
1464                 /*
1465                  * Leading hint is marked as 'duplicated' in transform_join_hints.
1466                  */
1467                 if (cur_hint->type == HINT_TYPE_LEADING &&
1468                         next_hint->type == HINT_TYPE_LEADING)
1469                         continue;
1470
1471                 /*
1472                  * Note that we need to pass addresses of hint pointers, because
1473                  * HintCmp is designed to sort array of Hint* by qsort.
1474                  */
1475                 if (HintCmp(&cur_hint, &next_hint) == 0)
1476                 {
1477                         hint_ereport(cur_hint->hint_str,
1478                                                  ("Conflict %s hint.", HintTypeName[cur_hint->type]));
1479                         cur_hint->state = HINT_STATE_DUPLICATION;
1480                 }
1481         }
1482
1483         /*
1484          * Make sure that per-type array pointers point proper position in the
1485          * array which consists of all hints.
1486          */
1487         hstate->scan_hints = (ScanMethodHint **) hstate->all_hints;
1488         hstate->join_hints = (JoinMethodHint **) (hstate->scan_hints +
1489                 hstate->num_hints[HINT_TYPE_SCAN_METHOD]);
1490         hstate->leading_hint = (LeadingHint **) (hstate->join_hints +
1491                 hstate->num_hints[HINT_TYPE_JOIN_METHOD]);
1492         hstate->set_hints = (SetHint **) (hstate->leading_hint +
1493                 hstate->num_hints[HINT_TYPE_LEADING]);
1494
1495         return hstate;
1496 }
1497
1498 /*
1499  * Parse inside of parentheses of scan-method hints.
1500  */
1501 static const char *
1502 ScanMethodHintParse(ScanMethodHint *hint, HintState *hstate, Query *parse,
1503                                         const char *str)
1504 {
1505         const char         *keyword = hint->base.keyword;
1506         HintKeyword             hint_keyword = hint->base.hint_keyword;
1507         List               *name_list = NIL;
1508         int                             length;
1509
1510         if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL)
1511                 return NULL;
1512
1513         /* Parse relation name and index name(s) if given hint accepts. */
1514         length = list_length(name_list);
1515         if (length > 0)
1516         {
1517                 hint->relname = linitial(name_list);
1518                 hint->indexnames = list_delete_first(name_list);
1519
1520                 /* check whether the hint accepts index name(s). */
1521                 if (length != 1 &&
1522                         hint_keyword != HINT_KEYWORD_INDEXSCAN &&
1523                         hint_keyword != HINT_KEYWORD_INDEXSCANREGEXP &&
1524 #if PG_VERSION_NUM >= 90200
1525                         hint_keyword != HINT_KEYWORD_INDEXONLYSCAN &&
1526                         hint_keyword != HINT_KEYWORD_INDEXONLYSCANREGEXP &&
1527 #endif
1528                         hint_keyword != HINT_KEYWORD_BITMAPSCAN &&
1529                         hint_keyword != HINT_KEYWORD_BITMAPSCANREGEXP)
1530                 {
1531                         hint_ereport(str,
1532                                                  ("%s hint accepts only one relation.",
1533                                                   hint->base.keyword));
1534                         hint->base.state = HINT_STATE_ERROR;
1535                         return str;
1536                 }
1537         }
1538         else
1539         {
1540                 hint_ereport(str,
1541                                          ("%s hint requires a relation.",
1542                                           hint->base.keyword));
1543                 hint->base.state = HINT_STATE_ERROR;
1544                 return str;
1545         }
1546
1547         /* Set a bit for specified hint. */
1548         switch (hint_keyword)
1549         {
1550                 case HINT_KEYWORD_SEQSCAN:
1551                         hint->enforce_mask = ENABLE_SEQSCAN;
1552                         break;
1553                 case HINT_KEYWORD_INDEXSCAN:
1554                         hint->enforce_mask = ENABLE_INDEXSCAN;
1555                         break;
1556                 case HINT_KEYWORD_INDEXSCANREGEXP:
1557                         hint->enforce_mask = ENABLE_INDEXSCAN;
1558                         hint->regexp = true;
1559                         break;
1560                 case HINT_KEYWORD_BITMAPSCAN:
1561                         hint->enforce_mask = ENABLE_BITMAPSCAN;
1562                         break;
1563                 case HINT_KEYWORD_BITMAPSCANREGEXP:
1564                         hint->enforce_mask = ENABLE_BITMAPSCAN;
1565                         hint->regexp = true;
1566                         break;
1567                 case HINT_KEYWORD_TIDSCAN:
1568                         hint->enforce_mask = ENABLE_TIDSCAN;
1569                         break;
1570                 case HINT_KEYWORD_NOSEQSCAN:
1571                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_SEQSCAN;
1572                         break;
1573                 case HINT_KEYWORD_NOINDEXSCAN:
1574                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXSCAN;
1575                         break;
1576                 case HINT_KEYWORD_NOBITMAPSCAN:
1577                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_BITMAPSCAN;
1578                         break;
1579                 case HINT_KEYWORD_NOTIDSCAN:
1580                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_TIDSCAN;
1581                         break;
1582 #if PG_VERSION_NUM >= 90200
1583                 case HINT_KEYWORD_INDEXONLYSCAN:
1584                         hint->enforce_mask = ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN;
1585                         break;
1586                 case HINT_KEYWORD_INDEXONLYSCANREGEXP:
1587                         hint->enforce_mask = ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN;
1588                         hint->regexp = true;
1589                         break;
1590                 case HINT_KEYWORD_NOINDEXONLYSCAN:
1591                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXONLYSCAN;
1592                         break;
1593 #endif
1594                 default:
1595                         hint_ereport(str, ("Unrecognized hint keyword \"%s\".", keyword));
1596                         return NULL;
1597                         break;
1598         }
1599
1600         return str;
1601 }
1602
1603 static const char *
1604 JoinMethodHintParse(JoinMethodHint *hint, HintState *hstate, Query *parse,
1605                                         const char *str)
1606 {
1607         const char         *keyword = hint->base.keyword;
1608         HintKeyword             hint_keyword = hint->base.hint_keyword;
1609         List               *name_list = NIL;
1610
1611         if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL)
1612                 return NULL;
1613
1614         hint->nrels = list_length(name_list);
1615
1616         if (hint->nrels > 0)
1617         {
1618                 ListCell   *l;
1619                 int                     i = 0;
1620
1621                 /*
1622                  * Transform relation names from list to array to sort them with qsort
1623                  * after.
1624                  */
1625                 hint->relnames = palloc(sizeof(char *) * hint->nrels);
1626                 foreach (l, name_list)
1627                 {
1628                         hint->relnames[i] = lfirst(l);
1629                         i++;
1630                 }
1631         }
1632
1633         list_free(name_list);
1634
1635         /* A join hint requires at least two relations */
1636         if (hint->nrels < 2)
1637         {
1638                 hint_ereport(str,
1639                                          ("%s hint requires at least two relations.",
1640                                           hint->base.keyword));
1641                 hint->base.state = HINT_STATE_ERROR;
1642                 return str;
1643         }
1644
1645         /* Sort hints in alphabetical order of relation names. */
1646         qsort(hint->relnames, hint->nrels, sizeof(char *), RelnameCmp);
1647
1648         switch (hint_keyword)
1649         {
1650                 case HINT_KEYWORD_NESTLOOP:
1651                         hint->enforce_mask = ENABLE_NESTLOOP;
1652                         break;
1653                 case HINT_KEYWORD_MERGEJOIN:
1654                         hint->enforce_mask = ENABLE_MERGEJOIN;
1655                         break;
1656                 case HINT_KEYWORD_HASHJOIN:
1657                         hint->enforce_mask = ENABLE_HASHJOIN;
1658                         break;
1659                 case HINT_KEYWORD_NONESTLOOP:
1660                         hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_NESTLOOP;
1661                         break;
1662                 case HINT_KEYWORD_NOMERGEJOIN:
1663                         hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_MERGEJOIN;
1664                         break;
1665                 case HINT_KEYWORD_NOHASHJOIN:
1666                         hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_HASHJOIN;
1667                         break;
1668                 default:
1669                         hint_ereport(str, ("Unrecognized hint keyword \"%s\".", keyword));
1670                         return NULL;
1671                         break;
1672         }
1673
1674         return str;
1675 }
1676
1677 static bool
1678 OuterInnerPairCheck(OuterInnerRels *outer_inner)
1679 {
1680         ListCell *l;
1681         if (outer_inner->outer_inner_pair == NIL)
1682         {
1683                 if (outer_inner->relation)
1684                         return true;
1685                 else
1686                         return false;
1687         }
1688
1689         if (list_length(outer_inner->outer_inner_pair) == 2)
1690         {
1691                 foreach(l, outer_inner->outer_inner_pair)
1692                 {
1693                         if (!OuterInnerPairCheck(lfirst(l)))
1694                                 return false;
1695                 }
1696         }
1697         else
1698                 return false;
1699
1700         return true;
1701 }
1702
1703 static List *
1704 OuterInnerList(OuterInnerRels *outer_inner)
1705 {
1706         List               *outer_inner_list = NIL;
1707         ListCell           *l;
1708         OuterInnerRels *outer_inner_rels;
1709
1710         foreach(l, outer_inner->outer_inner_pair)
1711         {
1712                 outer_inner_rels = (OuterInnerRels *)(lfirst(l));
1713
1714                 if (outer_inner_rels->relation != NULL)
1715                         outer_inner_list = lappend(outer_inner_list,
1716                                                                            outer_inner_rels->relation);
1717                 else
1718                         outer_inner_list = list_concat(outer_inner_list,
1719                                                                                    OuterInnerList(outer_inner_rels));
1720         }
1721         return outer_inner_list;
1722 }
1723
1724 static const char *
1725 LeadingHintParse(LeadingHint *hint, HintState *hstate, Query *parse,
1726                                  const char *str)
1727 {
1728         List               *name_list = NIL;
1729         OuterInnerRels *outer_inner = NULL;
1730
1731         if ((str = parse_parentheses_Leading(str, &name_list, &outer_inner)) ==
1732                 NULL)
1733                 return NULL;
1734
1735         if (outer_inner != NULL)
1736                 name_list = OuterInnerList(outer_inner);
1737
1738         hint->relations = name_list;
1739         hint->outer_inner = outer_inner;
1740
1741         /* A Leading hint requires at least two relations */
1742         if ( hint->outer_inner == NULL && list_length(hint->relations) < 2)
1743         {
1744                 hint_ereport(hint->base.hint_str,
1745                                          ("%s hint requires at least two relations.",
1746                                           HINT_LEADING));
1747                 hint->base.state = HINT_STATE_ERROR;
1748         }
1749         else if (hint->outer_inner != NULL &&
1750                          !OuterInnerPairCheck(hint->outer_inner))
1751         {
1752                 hint_ereport(hint->base.hint_str,
1753                                          ("%s hint requires two sets of relations when parentheses nests.",
1754                                           HINT_LEADING));
1755                 hint->base.state = HINT_STATE_ERROR;
1756         }
1757
1758         return str;
1759 }
1760
1761 static const char *
1762 SetHintParse(SetHint *hint, HintState *hstate, Query *parse, const char *str)
1763 {
1764         List   *name_list = NIL;
1765
1766         if ((str = parse_parentheses(str, &name_list, hint->base.hint_keyword))
1767                 == NULL)
1768                 return NULL;
1769
1770         hint->words = name_list;
1771
1772         /* We need both name and value to set GUC parameter. */
1773         if (list_length(name_list) == 2)
1774         {
1775                 hint->name = linitial(name_list);
1776                 hint->value = lsecond(name_list);
1777         }
1778         else
1779         {
1780                 hint_ereport(hint->base.hint_str,
1781                                          ("%s hint requires name and value of GUC parameter.",
1782                                           HINT_SET));
1783                 hint->base.state = HINT_STATE_ERROR;
1784         }
1785
1786         return str;
1787 }
1788
1789 /*
1790  * set GUC parameter functions
1791  */
1792
1793 static int
1794 set_config_option_wrapper(const char *name, const char *value,
1795                                                   GucContext context, GucSource source,
1796                                                   GucAction action, bool changeVal, int elevel)
1797 {
1798         int                             result = 0;
1799         MemoryContext   ccxt = CurrentMemoryContext;
1800
1801         PG_TRY();
1802         {
1803 #if PG_VERSION_NUM >= 90200
1804                 result = set_config_option(name, value, context, source,
1805                                                                    action, changeVal, 0);
1806 #else
1807                 result = set_config_option(name, value, context, source,
1808                                                                    action, changeVal);
1809 #endif
1810         }
1811         PG_CATCH();
1812         {
1813                 ErrorData          *errdata;
1814
1815                 /* Save error info */
1816                 MemoryContextSwitchTo(ccxt);
1817                 errdata = CopyErrorData();
1818                 FlushErrorState();
1819
1820                 ereport(elevel, (errcode(errdata->sqlerrcode),
1821                                 errmsg("%s", errdata->message),
1822                                 errdata->detail ? errdetail("%s", errdata->detail) : 0,
1823                                 errdata->hint ? errhint("%s", errdata->hint) : 0));
1824                 FreeErrorData(errdata);
1825         }
1826         PG_END_TRY();
1827
1828         return result;
1829 }
1830
1831 static int
1832 set_config_options(SetHint **options, int noptions, GucContext context)
1833 {
1834         int     i;
1835         int     save_nestlevel;
1836
1837         save_nestlevel = NewGUCNestLevel();
1838
1839         for (i = 0; i < noptions; i++)
1840         {
1841                 SetHint    *hint = options[i];
1842                 int                     result;
1843
1844                 if (!hint_state_enabled(hint))
1845                         continue;
1846
1847                 result = set_config_option_wrapper(hint->name, hint->value, context,
1848                                                                                    PGC_S_SESSION, GUC_ACTION_SAVE, true,
1849                                                                                    pg_hint_plan_parse_messages);
1850                 if (result != 0)
1851                         hint->base.state = HINT_STATE_USED;
1852                 else
1853                         hint->base.state = HINT_STATE_ERROR;
1854         }
1855
1856         return save_nestlevel;
1857 }
1858
1859 #define SET_CONFIG_OPTION(name, type_bits) \
1860         set_config_option_wrapper((name), \
1861                 (mask & (type_bits)) ? "true" : "false", \
1862                 context, PGC_S_SESSION, GUC_ACTION_SAVE, true, ERROR)
1863
1864 static void
1865 set_scan_config_options(unsigned char enforce_mask, GucContext context)
1866 {
1867         unsigned char   mask;
1868
1869         if (enforce_mask == ENABLE_SEQSCAN || enforce_mask == ENABLE_INDEXSCAN ||
1870                 enforce_mask == ENABLE_BITMAPSCAN || enforce_mask == ENABLE_TIDSCAN
1871 #if PG_VERSION_NUM >= 90200
1872                 || enforce_mask == (ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN)
1873 #endif
1874                 )
1875                 mask = enforce_mask;
1876         else
1877                 mask = enforce_mask & current_hint->init_scan_mask;
1878
1879         SET_CONFIG_OPTION("enable_seqscan", ENABLE_SEQSCAN);
1880         SET_CONFIG_OPTION("enable_indexscan", ENABLE_INDEXSCAN);
1881         SET_CONFIG_OPTION("enable_bitmapscan", ENABLE_BITMAPSCAN);
1882         SET_CONFIG_OPTION("enable_tidscan", ENABLE_TIDSCAN);
1883 #if PG_VERSION_NUM >= 90200
1884         SET_CONFIG_OPTION("enable_indexonlyscan", ENABLE_INDEXONLYSCAN);
1885 #endif
1886 }
1887
1888 static void
1889 set_join_config_options(unsigned char enforce_mask, GucContext context)
1890 {
1891         unsigned char   mask;
1892
1893         if (enforce_mask == ENABLE_NESTLOOP || enforce_mask == ENABLE_MERGEJOIN ||
1894                 enforce_mask == ENABLE_HASHJOIN)
1895                 mask = enforce_mask;
1896         else
1897                 mask = enforce_mask & current_hint->init_join_mask;
1898
1899         SET_CONFIG_OPTION("enable_nestloop", ENABLE_NESTLOOP);
1900         SET_CONFIG_OPTION("enable_mergejoin", ENABLE_MERGEJOIN);
1901         SET_CONFIG_OPTION("enable_hashjoin", ENABLE_HASHJOIN);
1902 }
1903
1904 /*
1905  * pg_hint_plan hook functions
1906  */
1907
1908 static void
1909 pg_hint_plan_ProcessUtility(Node *parsetree, const char *queryString,
1910                                                         ParamListInfo params, bool isTopLevel,
1911                                                         DestReceiver *dest, char *completionTag)
1912 {
1913         Node                               *node;
1914
1915         if (!pg_hint_plan_enable_hint)
1916         {
1917                 if (prev_ProcessUtility)
1918                         (*prev_ProcessUtility) (parsetree, queryString, params,
1919                                                                         isTopLevel, dest, completionTag);
1920                 else
1921                         standard_ProcessUtility(parsetree, queryString, params,
1922                                                                         isTopLevel, dest, completionTag);
1923
1924                 return;
1925         }
1926
1927         node = parsetree;
1928         if (IsA(node, ExplainStmt))
1929         {
1930                 /*
1931                  * Draw out parse tree of actual query from Query struct of EXPLAIN
1932                  * statement.
1933                  */
1934                 ExplainStmt        *stmt;
1935                 Query              *query;
1936
1937                 stmt = (ExplainStmt *) node;
1938
1939                 Assert(IsA(stmt->query, Query));
1940                 query = (Query *) stmt->query;
1941
1942                 if (query->commandType == CMD_UTILITY && query->utilityStmt != NULL)
1943                         node = query->utilityStmt;
1944         }
1945
1946         /*
1947          * If the query was a EXECUTE or CREATE TABLE AS EXECUTE, get query string
1948          * specified to preceding PREPARE command to use it as source of hints.
1949          */
1950         if (IsA(node, ExecuteStmt))
1951         {
1952                 ExecuteStmt        *stmt;
1953
1954                 stmt = (ExecuteStmt *) node;
1955                 stmt_name = stmt->name;
1956         }
1957 #if PG_VERSION_NUM >= 90200
1958         /*
1959          * CREATE AS EXECUTE behavior has changed since 9.2, so we must handle it
1960          * specially here.
1961          */
1962         if (IsA(node, CreateTableAsStmt))
1963         {
1964                 CreateTableAsStmt          *stmt;
1965                 Query              *query;
1966
1967                 stmt = (CreateTableAsStmt *) node;
1968                 Assert(IsA(stmt->query, Query));
1969                 query = (Query *) stmt->query;
1970
1971                 if (query->commandType == CMD_UTILITY &&
1972                         IsA(query->utilityStmt, ExecuteStmt))
1973                 {
1974                         ExecuteStmt *estmt = (ExecuteStmt *) query->utilityStmt;
1975                         stmt_name = estmt->name;
1976                 }
1977         }
1978 #endif
1979         if (stmt_name)
1980         {
1981                 PG_TRY();
1982                 {
1983                         if (prev_ProcessUtility)
1984                                 (*prev_ProcessUtility) (parsetree, queryString, params,
1985                                                                                 isTopLevel, dest, completionTag);
1986                         else
1987                                 standard_ProcessUtility(parsetree, queryString, params,
1988                                                                                 isTopLevel, dest, completionTag);
1989                 }
1990                 PG_CATCH();
1991                 {
1992                         stmt_name = NULL;
1993                         PG_RE_THROW();
1994                 }
1995                 PG_END_TRY();
1996
1997                 stmt_name = NULL;
1998
1999                 return;
2000         }
2001
2002         if (prev_ProcessUtility)
2003                 (*prev_ProcessUtility) (parsetree, queryString, params,
2004                                                                 isTopLevel, dest, completionTag);
2005         else
2006                 standard_ProcessUtility(parsetree, queryString, params,
2007                                                                 isTopLevel, dest, completionTag);
2008 }
2009
2010 /*
2011  * Push a hint into hint stack which is implemented with List struct.  Head of
2012  * list is top of stack.
2013  */
2014 static void
2015 push_hint(HintState *hstate)
2016 {
2017         /* Prepend new hint to the list means pushing to stack. */
2018         HintStateStack = lcons(hstate, HintStateStack);
2019
2020         /* Pushed hint is the one which should be used hereafter. */
2021         current_hint = hstate;
2022 }
2023
2024 /* Pop a hint from hint stack.  Popped hint is automatically discarded. */
2025 static void
2026 pop_hint(void)
2027 {
2028         /* Hint stack must not be empty. */
2029         if(HintStateStack == NIL)
2030                 elog(ERROR, "hint stack is empty");
2031
2032         /*
2033          * Take a hint at the head from the list, and free it.  Switch current_hint
2034          * to point new head (NULL if the list is empty).
2035          */
2036         HintStateStack = list_delete_first(HintStateStack);
2037         HintStateDelete(current_hint);
2038         if(HintStateStack == NIL)
2039                 current_hint = NULL;
2040         else
2041                 current_hint = (HintState *) lfirst(list_head(HintStateStack));
2042 }
2043
2044 static PlannedStmt *
2045 pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
2046 {
2047         const char         *hints;
2048         int                             save_nestlevel;
2049         PlannedStmt        *result;
2050         HintState          *hstate;
2051
2052         /*
2053          * Use standard planner if pg_hint_plan is disabled.  Other hook functions
2054          * try to change plan with current_hint if any, so set it to NULL.
2055          */
2056         if (!pg_hint_plan_enable_hint)
2057         {
2058                 current_hint = NULL;
2059
2060                 if (prev_planner)
2061                         return (*prev_planner) (parse, cursorOptions, boundParams);
2062                 else
2063                         return standard_planner(parse, cursorOptions, boundParams);
2064         }
2065
2066         /* Create hint struct from parse tree. */
2067         /*
2068          *      ヒント用テーブル方式を実装する前段階として、
2069          *      parse_head_comment()をクエリに記述されたヒントを見つける処理と
2070          *      ヒントをパースする処理に分割した。
2071          */
2072         hints = get_hints_from_comment(get_query_string());
2073         elog(LOG, "pg_hint_plan: [%s] => [%s]",
2074                  debug_query_string, hints ? hints : "(none)");
2075         hstate = convert_hints(parse, hints);
2076
2077         /*
2078          * Use standard planner if the statement has not valid hint.  Other hook
2079          * functions try to change plan with current_hint if any, so set it to
2080          * NULL.
2081          */
2082         if (!hstate)
2083         {
2084                 current_hint = NULL;
2085
2086                 if (prev_planner)
2087                         return (*prev_planner) (parse, cursorOptions, boundParams);
2088                 else
2089                         return standard_planner(parse, cursorOptions, boundParams);
2090         }
2091
2092         /*
2093          * Push new hint struct to the hint stack to disable previous hint context.
2094          */
2095         push_hint(hstate);
2096
2097         /* Set GUC parameters which are specified with Set hint. */
2098         save_nestlevel = set_config_options(current_hint->set_hints,
2099                                                                                 current_hint->num_hints[HINT_TYPE_SET],
2100                                                                                 current_hint->context);
2101
2102         if (enable_seqscan)
2103                 current_hint->init_scan_mask |= ENABLE_SEQSCAN;
2104         if (enable_indexscan)
2105                 current_hint->init_scan_mask |= ENABLE_INDEXSCAN;
2106         if (enable_bitmapscan)
2107                 current_hint->init_scan_mask |= ENABLE_BITMAPSCAN;
2108         if (enable_tidscan)
2109                 current_hint->init_scan_mask |= ENABLE_TIDSCAN;
2110 #if PG_VERSION_NUM >= 90200
2111         if (enable_indexonlyscan)
2112                 current_hint->init_scan_mask |= ENABLE_INDEXONLYSCAN;
2113 #endif
2114         if (enable_nestloop)
2115                 current_hint->init_join_mask |= ENABLE_NESTLOOP;
2116         if (enable_mergejoin)
2117                 current_hint->init_join_mask |= ENABLE_MERGEJOIN;
2118         if (enable_hashjoin)
2119                 current_hint->init_join_mask |= ENABLE_HASHJOIN;
2120
2121         /*
2122          * Use PG_TRY mechanism to recover GUC parameters and current_hint to the
2123          * state when this planner started when error occurred in planner.
2124          */
2125         PG_TRY();
2126         {
2127                 if (prev_planner)
2128                         result = (*prev_planner) (parse, cursorOptions, boundParams);
2129                 else
2130                         result = standard_planner(parse, cursorOptions, boundParams);
2131         }
2132         PG_CATCH();
2133         {
2134                 /*
2135                  * Rollback changes of GUC parameters, and pop current hint context
2136                  * from hint stack to rewind the state.
2137                  */
2138                 AtEOXact_GUC(true, save_nestlevel);
2139                 pop_hint();
2140                 PG_RE_THROW();
2141         }
2142         PG_END_TRY();
2143
2144         /* Print hint in debug mode. */
2145         if (pg_hint_plan_debug_print)
2146                 HintStateDump(current_hint);
2147
2148         /*
2149          * Rollback changes of GUC parameters, and pop current hint context from
2150          * hint stack to rewind the state.
2151          */
2152         AtEOXact_GUC(true, save_nestlevel);
2153         pop_hint();
2154
2155         return result;
2156 }
2157
2158 /*
2159  * Return scan method hint which matches given aliasname.
2160  */
2161 static ScanMethodHint *
2162 find_scan_hint(PlannerInfo *root, RelOptInfo *rel)
2163 {
2164         RangeTblEntry  *rte;
2165         int                             i;
2166
2167         /*
2168          * We can't apply scan method hint if the relation is:
2169          *   - not a base relation
2170          *   - not an ordinary relation (such as join and subquery)
2171          */
2172         if (rel->reloptkind != RELOPT_BASEREL || rel->rtekind != RTE_RELATION)
2173                 return NULL;
2174
2175         rte = root->simple_rte_array[rel->relid];
2176
2177         /* We can't force scan method of foreign tables */
2178         if (rte->relkind == RELKIND_FOREIGN_TABLE)
2179                 return NULL;
2180
2181         /* Find scan method hint, which matches given names, from the list. */
2182         for (i = 0; i < current_hint->num_hints[HINT_TYPE_SCAN_METHOD]; i++)
2183         {
2184                 ScanMethodHint *hint = current_hint->scan_hints[i];
2185
2186                 /* We ignore disabled hints. */
2187                 if (!hint_state_enabled(hint))
2188                         continue;
2189
2190                 if (RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
2191                         return hint;
2192         }
2193
2194         return NULL;
2195 }
2196
2197 /*
2198  * regexeq
2199  *
2200  * Returns TRUE on match, FALSE on no match.
2201  *
2202  *   s1 --- the data to match against
2203  *   s2 --- the pattern
2204  *
2205  * Because we copy s1 to NameData, make the size of s1 less than NAMEDATALEN.
2206  */
2207 static bool
2208 regexpeq(const char *s1, const char *s2)
2209 {
2210         NameData        name;
2211         text       *regexp;
2212         Datum           result;
2213
2214         strcpy(name.data, s1);
2215         regexp = cstring_to_text(s2);
2216
2217         result = DirectFunctionCall2Coll(nameregexeq,
2218                                                                          DEFAULT_COLLATION_OID,
2219                                                                          NameGetDatum(&name),
2220                                                                          PointerGetDatum(regexp));
2221         return DatumGetBool(result);
2222 }
2223
2224 static void
2225 delete_indexes(ScanMethodHint *hint, RelOptInfo *rel, Oid relationObjectId)
2226 {
2227         ListCell           *cell;
2228         ListCell           *prev;
2229         ListCell           *next;
2230         StringInfoData  buf;
2231
2232         /*
2233          * We delete all the IndexOptInfo list and prevent you from being usable by
2234          * a scan.
2235          */
2236         if (hint->enforce_mask == ENABLE_SEQSCAN ||
2237                 hint->enforce_mask == ENABLE_TIDSCAN)
2238         {
2239                 list_free_deep(rel->indexlist);
2240                 rel->indexlist = NIL;
2241                 hint->base.state = HINT_STATE_USED;
2242
2243                 return;
2244         }
2245
2246         /*
2247          * When a list of indexes is not specified, we just use all indexes.
2248          */
2249         if (hint->indexnames == NIL)
2250                 return;
2251
2252         /*
2253          * Leaving only an specified index, we delete it from a IndexOptInfo list
2254          * other than it.
2255          */
2256         prev = NULL;
2257         if (pg_hint_plan_debug_print)
2258                 initStringInfo(&buf);
2259
2260         for (cell = list_head(rel->indexlist); cell; cell = next)
2261         {
2262                 IndexOptInfo   *info = (IndexOptInfo *) lfirst(cell);
2263                 char               *indexname = get_rel_name(info->indexoid);
2264                 ListCell           *l;
2265                 bool                    use_index = false;
2266
2267                 next = lnext(cell);
2268
2269                 foreach(l, hint->indexnames)
2270                 {
2271                         char   *hintname = (char *) lfirst(l);
2272                         bool    result;
2273
2274                         if (hint->regexp)
2275                                 result = regexpeq(indexname, hintname);
2276                         else
2277                                 result = RelnameCmp(&indexname, &hintname) == 0;
2278
2279                         if (result)
2280                         {
2281                                 use_index = true;
2282                                 if (pg_hint_plan_debug_print)
2283                                 {
2284                                         appendStringInfoCharMacro(&buf, ' ');
2285                                         quote_value(&buf, indexname);
2286                                 }
2287
2288                                 break;
2289                         }
2290                 }
2291
2292                 /*
2293                  * to make the index a candidate when definition of this index is
2294                  * matched with the index's definition of current_hint.
2295                  */
2296                 if (OidIsValid(relationObjectId) && !use_index)
2297                 {
2298                         foreach(l, current_hint->parent_index_infos)
2299                         {
2300                                 int                                     i;
2301                                 HeapTuple                       ht_idx;
2302                                 ParentIndexInfo    *p_info = (ParentIndexInfo *)lfirst(l);
2303
2304                                 /* check to match the parameter of unique */
2305                                 if (p_info->indisunique != info->unique)
2306                                         continue;
2307
2308                                 /* check to match the parameter of index's method */
2309                                 if (p_info->method != info->relam)
2310                                         continue;
2311
2312                                 /* to check to match the indexkey's configuration */
2313                                 if ((list_length(p_info->column_names)) !=
2314                                          info->ncolumns)
2315                                         continue;
2316
2317                                 /* check to match the indexkey's configuration */
2318                                 for (i = 0; i < info->ncolumns; i++)
2319                                 {
2320                                         char       *c_attname = NULL;
2321                                         char       *p_attname = NULL;
2322
2323                                         p_attname =
2324                                                 list_nth(p_info->column_names, i);
2325
2326                                         /* both are expressions */
2327                                         if (info->indexkeys[i] == 0 && !p_attname)
2328                                                 continue;
2329
2330                                         /* one's column is expression, the other is not */
2331                                         if (info->indexkeys[i] == 0 || !p_attname)
2332                                                 break;
2333
2334                                         c_attname = get_attname(relationObjectId,
2335                                                                                                 info->indexkeys[i]);
2336
2337                                         if (strcmp(p_attname, c_attname) != 0)
2338                                                 break;
2339
2340                                         if (p_info->indcollation[i] != info->indexcollations[i])
2341                                                 break;
2342
2343                                         if (p_info->opclass[i] != info->opcintype[i])
2344                                                 break;
2345
2346                                         if (((p_info->indoption[i] & INDOPTION_DESC) != 0) !=
2347                                                 info->reverse_sort[i])
2348                                                 break;
2349
2350                                         if (((p_info->indoption[i] & INDOPTION_NULLS_FIRST) != 0) !=
2351                                                 info->nulls_first[i])
2352                                                 break;
2353
2354                                 }
2355
2356                                 if (i != info->ncolumns)
2357                                         continue;
2358
2359                                 if ((p_info->expression_str && (info->indexprs != NIL)) ||
2360                                         (p_info->indpred_str && (info->indpred != NIL)))
2361                                 {
2362                                         /*
2363                                          * Fetch the pg_index tuple by the Oid of the index
2364                                          */
2365                                         ht_idx = SearchSysCache1(INDEXRELID,
2366                                                                                          ObjectIdGetDatum(info->indexoid));
2367
2368                                         /* check to match the expression's parameter of index */
2369                                         if (p_info->expression_str &&
2370                                                 !heap_attisnull(ht_idx, Anum_pg_index_indexprs))
2371                                         {
2372                                                 Datum       exprsDatum;
2373                                                 bool        isnull;
2374                                                 Datum       result;
2375
2376                                                 /*
2377                                                  * to change the expression's parameter of child's
2378                                                  * index to strings
2379                                                  */
2380                                                 exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
2381                                                                                                          Anum_pg_index_indexprs,
2382                                                                                                          &isnull);
2383
2384                                                 result = DirectFunctionCall2(pg_get_expr,
2385                                                                                                          exprsDatum,
2386                                                                                                          ObjectIdGetDatum(
2387                                                                                                                  relationObjectId));
2388
2389                                                 if (strcmp(p_info->expression_str,
2390                                                                    text_to_cstring(DatumGetTextP(result))) != 0)
2391                                                 {
2392                                                         /* Clean up */
2393                                                         ReleaseSysCache(ht_idx);
2394
2395                                                         continue;
2396                                                 }
2397                                         }
2398
2399                                         /* Check to match the predicate's paraameter of index */
2400                                         if (p_info->indpred_str &&
2401                                                 !heap_attisnull(ht_idx, Anum_pg_index_indpred))
2402                                         {
2403                                                 Datum       predDatum;
2404                                                 bool        isnull;
2405                                                 Datum       result;
2406
2407                                                 /*
2408                                                  * to change the predicate's parabeter of child's
2409                                                  * index to strings
2410                                                  */
2411                                                 predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
2412                                                                                                          Anum_pg_index_indpred,
2413                                                                                                          &isnull);
2414
2415                                                 result = DirectFunctionCall2(pg_get_expr,
2416                                                                                                          predDatum,
2417                                                                                                          ObjectIdGetDatum(
2418                                                                                                                  relationObjectId));
2419
2420                                                 if (strcmp(p_info->indpred_str,
2421                                                                    text_to_cstring(DatumGetTextP(result))) != 0)
2422                                                 {
2423                                                         /* Clean up */
2424                                                         ReleaseSysCache(ht_idx);
2425
2426                                                         continue;
2427                                                 }
2428                                         }
2429
2430                                         /* Clean up */
2431                                         ReleaseSysCache(ht_idx);
2432                                 }
2433                                 else if (p_info->expression_str || (info->indexprs != NIL))
2434                                         continue;
2435                                 else if (p_info->indpred_str || (info->indpred != NIL))
2436                                         continue;
2437
2438                                 use_index = true;
2439
2440                                 /* to log the candidate of index */
2441                                 if (pg_hint_plan_debug_print)
2442                                 {
2443                                         appendStringInfoCharMacro(&buf, ' ');
2444                                         quote_value(&buf, indexname);
2445                                 }
2446
2447                                 break;
2448                         }
2449                 }
2450
2451                 if (!use_index)
2452                         rel->indexlist = list_delete_cell(rel->indexlist, cell, prev);
2453                 else
2454                         prev = cell;
2455
2456                 pfree(indexname);
2457         }
2458
2459         if (pg_hint_plan_debug_print)
2460         {
2461                 char   *relname;
2462                 StringInfoData  rel_buf;
2463
2464                 if (OidIsValid(relationObjectId))
2465                         relname = get_rel_name(relationObjectId);
2466                 else
2467                         relname = hint->relname;
2468
2469                 initStringInfo(&rel_buf);
2470                 quote_value(&rel_buf, relname);
2471
2472                 ereport(LOG,
2473                                 (errmsg("available indexes for %s(%s):%s",
2474                                          hint->base.keyword,
2475                                          rel_buf.data,
2476                                          buf.data)));
2477                 pfree(buf.data);
2478                 pfree(rel_buf.data);
2479         }
2480 }
2481
2482 /* 
2483  * Return information of index definition.
2484  */
2485 static ParentIndexInfo *
2486 get_parent_index_info(Oid indexoid, Oid relid)
2487 {
2488         ParentIndexInfo *p_info = palloc(sizeof(ParentIndexInfo));
2489         Relation            indexRelation;
2490         Form_pg_index   index;
2491         char               *attname;
2492         int                             i;
2493
2494         indexRelation = index_open(indexoid, RowExclusiveLock);
2495
2496         index = indexRelation->rd_index;
2497
2498         p_info->indisunique = index->indisunique;
2499         p_info->method = indexRelation->rd_rel->relam;
2500
2501         p_info->column_names = NIL;
2502         p_info->indcollation = (Oid *) palloc(sizeof(Oid) * index->indnatts);
2503         p_info->opclass = (Oid *) palloc(sizeof(Oid) * index->indnatts);
2504         p_info->indoption = (int16 *) palloc(sizeof(Oid) * index->indnatts);
2505
2506         for (i = 0; i < index->indnatts; i++)
2507         {
2508                 attname = get_attname(relid, index->indkey.values[i]);
2509                 p_info->column_names = lappend(p_info->column_names, attname);
2510
2511                 p_info->indcollation[i] = indexRelation->rd_indcollation[i];
2512                 p_info->opclass[i] = indexRelation->rd_opcintype[i];
2513                 p_info->indoption[i] = indexRelation->rd_indoption[i];
2514         }
2515
2516         /*
2517          * to check to match the expression's paraameter of index with child indexes
2518          */
2519         p_info->expression_str = NULL;
2520         if(!heap_attisnull(indexRelation->rd_indextuple, Anum_pg_index_indexprs))
2521         {
2522                 Datum       exprsDatum;
2523                 bool            isnull;
2524                 Datum           result;
2525
2526                 exprsDatum = SysCacheGetAttr(INDEXRELID, indexRelation->rd_indextuple,
2527                                                                          Anum_pg_index_indexprs, &isnull);
2528
2529                 result = DirectFunctionCall2(pg_get_expr,
2530                                                                          exprsDatum,
2531                                                                          ObjectIdGetDatum(relid));
2532
2533                 p_info->expression_str = text_to_cstring(DatumGetTextP(result));
2534         }
2535
2536         /*
2537          * to check to match the predicate's paraameter of index with child indexes
2538          */
2539         p_info->indpred_str = NULL;
2540         if(!heap_attisnull(indexRelation->rd_indextuple, Anum_pg_index_indpred))
2541         {
2542                 Datum       predDatum;
2543                 bool            isnull;
2544                 Datum           result;
2545
2546                 predDatum = SysCacheGetAttr(INDEXRELID, indexRelation->rd_indextuple,
2547                                                                          Anum_pg_index_indpred, &isnull);
2548
2549                 result = DirectFunctionCall2(pg_get_expr,
2550                                                                          predDatum,
2551                                                                          ObjectIdGetDatum(relid));
2552
2553                 p_info->indpred_str = text_to_cstring(DatumGetTextP(result));
2554         }
2555
2556         index_close(indexRelation, NoLock);
2557
2558         return p_info;
2559 }
2560
2561 static void
2562 pg_hint_plan_get_relation_info(PlannerInfo *root, Oid relationObjectId,
2563                                                            bool inhparent, RelOptInfo *rel)
2564 {
2565         ScanMethodHint *hint;
2566
2567         if (prev_get_relation_info)
2568                 (*prev_get_relation_info) (root, relationObjectId, inhparent, rel);
2569
2570         /* Do nothing if we don't have valid hint in this context. */
2571         if (!current_hint)
2572                 return;
2573
2574         if (inhparent)
2575         {
2576                 /* store does relids of parent table. */
2577                 current_hint->parent_relid = rel->relid;
2578                 current_hint->parent_rel_oid = relationObjectId;
2579         }
2580         else if (current_hint->parent_relid != 0)
2581         {
2582                 /*
2583                  * We use the same GUC parameter if this table is the child table of a
2584                  * table called pg_hint_plan_get_relation_info just before that.
2585                  */
2586                 ListCell   *l;
2587
2588                 /* append_rel_list contains all append rels; ignore others */
2589                 foreach(l, root->append_rel_list)
2590                 {
2591                         AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
2592
2593                         /* This rel is child table. */
2594                         if (appinfo->parent_relid == current_hint->parent_relid &&
2595                                 appinfo->child_relid == rel->relid)
2596                         {
2597                                 if (current_hint->parent_hint)
2598                                         delete_indexes(current_hint->parent_hint, rel,
2599                                                                    relationObjectId);
2600
2601                                 return;
2602                         }
2603                 }
2604
2605                 /* This rel is not inherit table. */
2606                 current_hint->parent_relid = 0;
2607                 current_hint->parent_rel_oid = InvalidOid;
2608                 current_hint->parent_hint = NULL;
2609         }
2610
2611         /*
2612          * If scan method hint was given, reset GUC parameters which control
2613          * planner behavior about choosing scan methods.
2614          */
2615         if ((hint = find_scan_hint(root, rel)) == NULL)
2616         {
2617                 set_scan_config_options(current_hint->init_scan_mask,
2618                                                                 current_hint->context);
2619                 return;
2620         }
2621         set_scan_config_options(hint->enforce_mask, current_hint->context);
2622         hint->base.state = HINT_STATE_USED;
2623
2624         if (inhparent)
2625         {
2626                 Relation    relation;
2627                 List       *indexoidlist;
2628                 ListCell   *l;
2629
2630                 current_hint->parent_hint = hint;
2631
2632                 relation = heap_open(relationObjectId, NoLock);
2633                 indexoidlist = RelationGetIndexList(relation);
2634
2635                 foreach(l, indexoidlist)
2636                 {
2637                         Oid         indexoid = lfirst_oid(l);
2638                         char       *indexname = get_rel_name(indexoid);
2639                         bool        use_index = false;
2640                         ListCell   *lc;
2641                         ParentIndexInfo *parent_index_info;
2642
2643                         foreach(lc, hint->indexnames)
2644                         {
2645                                 if (RelnameCmp(&indexname, &lfirst(lc)) == 0)
2646                                 {
2647                                         use_index = true;
2648                                         break;
2649                                 }
2650                         }
2651                         if (!use_index)
2652                                 continue;
2653
2654                         parent_index_info = get_parent_index_info(indexoid,
2655                                                                                                           relationObjectId);
2656                         current_hint->parent_index_infos =
2657                                 lappend(current_hint->parent_index_infos, parent_index_info);
2658                 }
2659                 heap_close(relation, NoLock);
2660         }
2661         else
2662                 delete_indexes(hint, rel, InvalidOid);
2663 }
2664
2665 /*
2666  * Return index of relation which matches given aliasname, or 0 if not found.
2667  * If same aliasname was used multiple times in a query, return -1.
2668  */
2669 static int
2670 find_relid_aliasname(PlannerInfo *root, char *aliasname, List *initial_rels,
2671                                          const char *str)
2672 {
2673         int             i;
2674         Index   found = 0;
2675
2676         for (i = 1; i < root->simple_rel_array_size; i++)
2677         {
2678                 ListCell   *l;
2679
2680                 if (root->simple_rel_array[i] == NULL)
2681                         continue;
2682
2683                 Assert(i == root->simple_rel_array[i]->relid);
2684
2685                 if (RelnameCmp(&aliasname,
2686                                            &root->simple_rte_array[i]->eref->aliasname) != 0)
2687                         continue;
2688
2689                 foreach(l, initial_rels)
2690                 {
2691                         RelOptInfo *rel = (RelOptInfo *) lfirst(l);
2692
2693                         if (rel->reloptkind == RELOPT_BASEREL)
2694                         {
2695                                 if (rel->relid != i)
2696                                         continue;
2697                         }
2698                         else
2699                         {
2700                                 Assert(rel->reloptkind == RELOPT_JOINREL);
2701
2702                                 if (!bms_is_member(i, rel->relids))
2703                                         continue;
2704                         }
2705
2706                         if (found != 0)
2707                         {
2708                                 hint_ereport(str,
2709                                                          ("Relation name \"%s\" is ambiguous.",
2710                                                           aliasname));
2711                                 return -1;
2712                         }
2713
2714                         found = i;
2715                         break;
2716                 }
2717
2718         }
2719
2720         return found;
2721 }
2722
2723 /*
2724  * Return join hint which matches given joinrelids.
2725  */
2726 static JoinMethodHint *
2727 find_join_hint(Relids joinrelids)
2728 {
2729         List       *join_hint;
2730         ListCell   *l;
2731
2732         join_hint = current_hint->join_hint_level[bms_num_members(joinrelids)];
2733
2734         foreach(l, join_hint)
2735         {
2736                 JoinMethodHint *hint = (JoinMethodHint *) lfirst(l);
2737
2738                 if (bms_equal(joinrelids, hint->joinrelids))
2739                         return hint;
2740         }
2741
2742         return NULL;
2743 }
2744
2745 static Relids
2746 OuterInnerJoinCreate(OuterInnerRels *outer_inner, LeadingHint *leading_hint,
2747         PlannerInfo *root, List *initial_rels, HintState *hstate, int nbaserel)
2748 {
2749         OuterInnerRels *outer_rels;
2750         OuterInnerRels *inner_rels;
2751         Relids                  outer_relids;
2752         Relids                  inner_relids;
2753         Relids                  join_relids;
2754         JoinMethodHint *hint;
2755
2756         if (outer_inner->relation != NULL)
2757         {
2758                 return bms_make_singleton(
2759                                         find_relid_aliasname(root, outer_inner->relation,
2760                                                                                  initial_rels,
2761                                                                                  leading_hint->base.hint_str));
2762         }
2763
2764         outer_rels = lfirst(outer_inner->outer_inner_pair->head);
2765         inner_rels = lfirst(outer_inner->outer_inner_pair->tail);
2766
2767         outer_relids = OuterInnerJoinCreate(outer_rels,
2768                                                                                 leading_hint,
2769                                                                                 root,
2770                                                                                 initial_rels,
2771                                                                                 hstate,
2772                                                                                 nbaserel);
2773         inner_relids = OuterInnerJoinCreate(inner_rels,
2774                                                                                 leading_hint,
2775                                                                                 root,
2776                                                                                 initial_rels,
2777                                                                                 hstate,
2778                                                                                 nbaserel);
2779
2780         join_relids = bms_add_members(outer_relids, inner_relids);
2781
2782         if (bms_num_members(join_relids) > nbaserel)
2783                 return join_relids;
2784
2785         /*
2786          * If we don't have join method hint, create new one for the
2787          * join combination with all join methods are enabled.
2788          */
2789         hint = find_join_hint(join_relids);
2790         if (hint == NULL)
2791         {
2792                 /*
2793                  * Here relnames is not set, since Relids bitmap is sufficient to
2794                  * control paths of this query afterward.
2795                  */
2796                 hint = (JoinMethodHint *) JoinMethodHintCreate(
2797                                         leading_hint->base.hint_str,
2798                                         HINT_LEADING,
2799                                         HINT_KEYWORD_LEADING);
2800                 hint->base.state = HINT_STATE_USED;
2801                 hint->nrels = bms_num_members(join_relids);
2802                 hint->enforce_mask = ENABLE_ALL_JOIN;
2803                 hint->joinrelids = bms_copy(join_relids);
2804                 hint->inner_nrels = bms_num_members(inner_relids);
2805                 hint->inner_joinrelids = bms_copy(inner_relids);
2806
2807                 hstate->join_hint_level[hint->nrels] =
2808                         lappend(hstate->join_hint_level[hint->nrels], hint);
2809         }
2810         else
2811         {
2812                 hint->inner_nrels = bms_num_members(inner_relids);
2813                 hint->inner_joinrelids = bms_copy(inner_relids);
2814         }
2815
2816         return join_relids;
2817 }
2818
2819 /*
2820  * Transform join method hint into handy form.
2821  *
2822  *   - create bitmap of relids from alias names, to make it easier to check
2823  *     whether a join path matches a join method hint.
2824  *   - add join method hints which are necessary to enforce join order
2825  *     specified by Leading hint
2826  */
2827 static bool
2828 transform_join_hints(HintState *hstate, PlannerInfo *root, int nbaserel,
2829                 List *initial_rels, JoinMethodHint **join_method_hints)
2830 {
2831         int                             i;
2832         int                             relid;
2833         Relids                  joinrelids;
2834         int                             njoinrels;
2835         ListCell           *l;
2836         char               *relname;
2837         LeadingHint        *lhint = NULL;
2838
2839         /*
2840          * Create bitmap of relids from alias names for each join method hint.
2841          * Bitmaps are more handy than strings in join searching.
2842          */
2843         for (i = 0; i < hstate->num_hints[HINT_TYPE_JOIN_METHOD]; i++)
2844         {
2845                 JoinMethodHint *hint = hstate->join_hints[i];
2846                 int     j;
2847
2848                 if (!hint_state_enabled(hint) || hint->nrels > nbaserel)
2849                         continue;
2850
2851                 bms_free(hint->joinrelids);
2852                 hint->joinrelids = NULL;
2853                 relid = 0;
2854                 for (j = 0; j < hint->nrels; j++)
2855                 {
2856                         relname = hint->relnames[j];
2857
2858                         relid = find_relid_aliasname(root, relname, initial_rels,
2859                                                                                  hint->base.hint_str);
2860
2861                         if (relid == -1)
2862                                 hint->base.state = HINT_STATE_ERROR;
2863
2864                         if (relid <= 0)
2865                                 break;
2866
2867                         if (bms_is_member(relid, hint->joinrelids))
2868                         {
2869                                 hint_ereport(hint->base.hint_str,
2870                                                          ("Relation name \"%s\" is duplicated.", relname));
2871                                 hint->base.state = HINT_STATE_ERROR;
2872                                 break;
2873                         }
2874
2875                         hint->joinrelids = bms_add_member(hint->joinrelids, relid);
2876                 }
2877
2878                 if (relid <= 0 || hint->base.state == HINT_STATE_ERROR)
2879                         continue;
2880
2881                 hstate->join_hint_level[hint->nrels] =
2882                         lappend(hstate->join_hint_level[hint->nrels], hint);
2883         }
2884
2885         /* Do nothing if no Leading hint was supplied. */
2886         if (hstate->num_hints[HINT_TYPE_LEADING] == 0)
2887                 return false;
2888
2889         /*
2890          * Decide to use Leading hint。
2891          */
2892         for (i = 0; i < hstate->num_hints[HINT_TYPE_LEADING]; i++)
2893         {
2894                 LeadingHint        *leading_hint = (LeadingHint *)hstate->leading_hint[i];
2895                 Relids                  relids;
2896
2897                 if (leading_hint->base.state == HINT_STATE_ERROR)
2898                         continue;
2899
2900                 relid = 0;
2901                 relids = NULL;
2902
2903                 foreach(l, leading_hint->relations)
2904                 {
2905                         relname = (char *)lfirst(l);;
2906
2907                         relid = find_relid_aliasname(root, relname, initial_rels,
2908                                                                                  leading_hint->base.hint_str);
2909                         if (relid == -1)
2910                                 leading_hint->base.state = HINT_STATE_ERROR;
2911
2912                         if (relid <= 0)
2913                                 break;
2914
2915                         if (bms_is_member(relid, relids))
2916                         {
2917                                 hint_ereport(leading_hint->base.hint_str,
2918                                                          ("Relation name \"%s\" is duplicated.", relname));
2919                                 leading_hint->base.state = HINT_STATE_ERROR;
2920                                 break;
2921                         }
2922
2923                         relids = bms_add_member(relids, relid);
2924                 }
2925
2926                 if (relid <= 0 || leading_hint->base.state == HINT_STATE_ERROR)
2927                         continue;
2928
2929                 if (lhint != NULL)
2930                 {
2931                         hint_ereport(lhint->base.hint_str,
2932                                  ("Conflict %s hint.", HintTypeName[lhint->base.type]));
2933                         lhint->base.state = HINT_STATE_DUPLICATION;
2934                 }
2935                 leading_hint->base.state = HINT_STATE_USED;
2936                 lhint = leading_hint;
2937         }
2938
2939         /* check to exist Leading hint marked with 'used'. */
2940         if (lhint == NULL)
2941                 return false;
2942
2943         /*
2944          * We need join method hints which fit specified join order in every join
2945          * level.  For example, Leading(A B C) virtually requires following join
2946          * method hints, if no join method hint supplied:
2947          *   - level 1: none
2948          *   - level 2: NestLoop(A B), MergeJoin(A B), HashJoin(A B)
2949          *   - level 3: NestLoop(A B C), MergeJoin(A B C), HashJoin(A B C)
2950          *
2951          * If we already have join method hint which fits specified join order in
2952          * that join level, we leave it as-is and don't add new hints.
2953          */
2954         joinrelids = NULL;
2955         njoinrels = 0;
2956         if (lhint->outer_inner == NULL)
2957         {
2958                 foreach(l, lhint->relations)
2959                 {
2960                         JoinMethodHint *hint;
2961
2962                         relname = (char *)lfirst(l);
2963
2964                         /*
2965                          * Find relid of the relation which has given name.  If we have the
2966                          * name given in Leading hint multiple times in the join, nothing to
2967                          * do.
2968                          */
2969                         relid = find_relid_aliasname(root, relname, initial_rels,
2970                                                                                  hstate->hint_str);
2971
2972                         /* Create bitmap of relids for current join level. */
2973                         joinrelids = bms_add_member(joinrelids, relid);
2974                         njoinrels++;
2975
2976                         /* We never have join method hint for single relation. */
2977                         if (njoinrels < 2)
2978                                 continue;
2979
2980                         /*
2981                          * If we don't have join method hint, create new one for the
2982                          * join combination with all join methods are enabled.
2983                          */
2984                         hint = find_join_hint(joinrelids);
2985                         if (hint == NULL)
2986                         {
2987                                 /*
2988                                  * Here relnames is not set, since Relids bitmap is sufficient
2989                                  * to control paths of this query afterward.
2990                                  */
2991                                 hint = (JoinMethodHint *) JoinMethodHintCreate(
2992                                                                                         lhint->base.hint_str,
2993                                                                                         HINT_LEADING,
2994                                                                                         HINT_KEYWORD_LEADING);
2995                                 hint->base.state = HINT_STATE_USED;
2996                                 hint->nrels = njoinrels;
2997                                 hint->enforce_mask = ENABLE_ALL_JOIN;
2998                                 hint->joinrelids = bms_copy(joinrelids);
2999                         }
3000
3001                         join_method_hints[njoinrels] = hint;
3002
3003                         if (njoinrels >= nbaserel)
3004                                 break;
3005                 }
3006                 bms_free(joinrelids);
3007
3008                 if (njoinrels < 2)
3009                         return false;
3010
3011                 /*
3012                  * Delete all join hints which have different combination from Leading
3013                  * hint.
3014                  */
3015                 for (i = 2; i <= njoinrels; i++)
3016                 {
3017                         list_free(hstate->join_hint_level[i]);
3018
3019                         hstate->join_hint_level[i] = lappend(NIL, join_method_hints[i]);
3020                 }
3021         }
3022         else
3023         {
3024                 joinrelids = OuterInnerJoinCreate(lhint->outer_inner,
3025                                                                                   lhint,
3026                                           root,
3027                                           initial_rels,
3028                                                                                   hstate,
3029                                                                                   nbaserel);
3030
3031                 njoinrels = bms_num_members(joinrelids);
3032                 Assert(njoinrels >= 2);
3033
3034                 /*
3035                  * Delete all join hints which have different combination from Leading
3036                  * hint.
3037                  */
3038                 for (i = 2;i <= njoinrels; i++)
3039                 {
3040                         if (hstate->join_hint_level[i] != NIL)
3041                         {
3042                                 ListCell *prev = NULL;
3043                                 ListCell *next = NULL;
3044                                 for(l = list_head(hstate->join_hint_level[i]); l; l = next)
3045                                 {
3046
3047                                         JoinMethodHint *hint = (JoinMethodHint *)lfirst(l);
3048
3049                                         next = lnext(l);
3050
3051                                         if (hint->inner_nrels == 0 &&
3052                                                 !(bms_intersect(hint->joinrelids, joinrelids) == NULL ||
3053                                                   bms_equal(bms_union(hint->joinrelids, joinrelids),
3054                                                   hint->joinrelids)))
3055                                         {
3056                                                 hstate->join_hint_level[i] =
3057                                                         list_delete_cell(hstate->join_hint_level[i], l,
3058                                                                                          prev);
3059                                         }
3060                                         else
3061                                                 prev = l;
3062                                 }
3063                         }
3064                 }
3065
3066                 bms_free(joinrelids);
3067         }
3068
3069         if (hint_state_enabled(lhint))
3070         {
3071                 set_join_config_options(DISABLE_ALL_JOIN, current_hint->context);
3072                 return true;
3073         }
3074         return false;
3075 }
3076
3077 /*
3078  * set_plain_rel_pathlist
3079  *        Build access paths for a plain relation (no subquery, no inheritance)
3080  *
3081  * This function was copied and edited from set_plain_rel_pathlist() in
3082  * src/backend/optimizer/path/allpaths.c
3083  */
3084 static void
3085 set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
3086 {
3087         /* Consider sequential scan */
3088 #if PG_VERSION_NUM >= 90200
3089         add_path(rel, create_seqscan_path(root, rel, NULL));
3090 #else
3091         add_path(rel, create_seqscan_path(root, rel));
3092 #endif
3093
3094         /* Consider index scans */
3095         create_index_paths(root, rel);
3096
3097         /* Consider TID scans */
3098         create_tidscan_paths(root, rel);
3099
3100         /* Now find the cheapest of the paths for this rel */
3101         set_cheapest(rel);
3102 }
3103
3104 static void
3105 rebuild_scan_path(HintState *hstate, PlannerInfo *root, int level,
3106                                   List *initial_rels)
3107 {
3108         ListCell   *l;
3109
3110         foreach(l, initial_rels)
3111         {
3112                 RelOptInfo         *rel = (RelOptInfo *) lfirst(l);
3113                 RangeTblEntry  *rte;
3114                 ScanMethodHint *hint;
3115
3116                 /* Skip relations which we can't choose scan method. */
3117                 if (rel->reloptkind != RELOPT_BASEREL || rel->rtekind != RTE_RELATION)
3118                         continue;
3119
3120                 rte = root->simple_rte_array[rel->relid];
3121
3122                 /* We can't force scan method of foreign tables */
3123                 if (rte->relkind == RELKIND_FOREIGN_TABLE)
3124                         continue;
3125
3126                 /*
3127                  * Create scan paths with GUC parameters which are at the beginning of
3128                  * planner if scan method hint is not specified, otherwise use
3129                  * specified hints and mark the hint as used.
3130                  */
3131                 if ((hint = find_scan_hint(root, rel)) == NULL)
3132                         set_scan_config_options(hstate->init_scan_mask,
3133                                                                         hstate->context);
3134                 else
3135                 {
3136                         set_scan_config_options(hint->enforce_mask, hstate->context);
3137                         hint->base.state = HINT_STATE_USED;
3138                 }
3139
3140                 list_free_deep(rel->pathlist);
3141                 rel->pathlist = NIL;
3142                 if (rte->inh)
3143                 {
3144                         /* It's an "append relation", process accordingly */
3145                         set_append_rel_pathlist(root, rel, rel->relid, rte);
3146                 }
3147                 else
3148                 {
3149                         set_plain_rel_pathlist(root, rel, rte);
3150                 }
3151         }
3152
3153         /*
3154          * Restore the GUC variables we set above.
3155          */
3156         set_scan_config_options(hstate->init_scan_mask, hstate->context);
3157 }
3158
3159 /*
3160  * wrapper of make_join_rel()
3161  *
3162  * call make_join_rel() after changing enable_* parameters according to given
3163  * hints.
3164  */
3165 static RelOptInfo *
3166 make_join_rel_wrapper(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
3167 {
3168         Relids                  joinrelids;
3169         JoinMethodHint *hint;
3170         RelOptInfo         *rel;
3171         int                             save_nestlevel;
3172
3173         joinrelids = bms_union(rel1->relids, rel2->relids);
3174         hint = find_join_hint(joinrelids);
3175         bms_free(joinrelids);
3176
3177         if (!hint)
3178                 return pg_hint_plan_make_join_rel(root, rel1, rel2);
3179
3180         if (hint->inner_nrels == 0)
3181         {
3182                 save_nestlevel = NewGUCNestLevel();
3183
3184                 set_join_config_options(hint->enforce_mask, current_hint->context);
3185
3186                 rel = pg_hint_plan_make_join_rel(root, rel1, rel2);
3187                 hint->base.state = HINT_STATE_USED;
3188
3189                 /*
3190                  * Restore the GUC variables we set above.
3191                  */
3192                 AtEOXact_GUC(true, save_nestlevel);
3193         }
3194         else
3195                 rel = pg_hint_plan_make_join_rel(root, rel1, rel2);
3196
3197         return rel;
3198 }
3199
3200 /*
3201  * TODO : comment
3202  */
3203 static void
3204 add_paths_to_joinrel_wrapper(PlannerInfo *root,
3205                                                          RelOptInfo *joinrel,
3206                                                          RelOptInfo *outerrel,
3207                                                          RelOptInfo *innerrel,
3208                                                          JoinType jointype,
3209                                                          SpecialJoinInfo *sjinfo,
3210                                                          List *restrictlist)
3211 {
3212         ScanMethodHint *scan_hint = NULL;
3213         Relids                  joinrelids;
3214         JoinMethodHint *join_hint;
3215         int                             save_nestlevel;
3216
3217         if ((scan_hint = find_scan_hint(root, innerrel)) != NULL)
3218         {
3219                 set_scan_config_options(scan_hint->enforce_mask, current_hint->context);
3220                 scan_hint->base.state = HINT_STATE_USED;
3221         }
3222
3223         joinrelids = bms_union(outerrel->relids, innerrel->relids);
3224         join_hint = find_join_hint(joinrelids);
3225         bms_free(joinrelids);
3226
3227         if (join_hint && join_hint->inner_nrels != 0)
3228         {
3229                 save_nestlevel = NewGUCNestLevel();
3230
3231                 if (bms_equal(join_hint->inner_joinrelids, innerrel->relids))
3232                 {
3233
3234                         set_join_config_options(join_hint->enforce_mask,
3235                                                                         current_hint->context);
3236
3237                         add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
3238                                                                  sjinfo, restrictlist);
3239                         join_hint->base.state = HINT_STATE_USED;
3240                 }
3241                 else
3242                 {
3243                         set_join_config_options(DISABLE_ALL_JOIN, current_hint->context);
3244                         add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
3245                                                                  sjinfo, restrictlist);
3246                 }
3247
3248                 /*
3249                  * Restore the GUC variables we set above.
3250                  */
3251                 AtEOXact_GUC(true, save_nestlevel);
3252         }
3253         else
3254                 add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
3255                                                          sjinfo, restrictlist);
3256
3257         if (scan_hint != NULL)
3258                 set_scan_config_options(current_hint->init_scan_mask,
3259                                                                 current_hint->context);
3260 }
3261
3262 static int
3263 get_num_baserels(List *initial_rels)
3264 {
3265         int                     nbaserel = 0;
3266         ListCell   *l;
3267
3268         foreach(l, initial_rels)
3269         {
3270                 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
3271
3272                 if (rel->reloptkind == RELOPT_BASEREL)
3273                         nbaserel++;
3274                 else if (rel->reloptkind ==RELOPT_JOINREL)
3275                         nbaserel+= bms_num_members(rel->relids);
3276                 else
3277                 {
3278                         /* other values not expected here */
3279                         elog(ERROR, "unrecognized reloptkind type: %d", rel->reloptkind);
3280                 }
3281         }
3282
3283         return nbaserel;
3284 }
3285
3286 static RelOptInfo *
3287 pg_hint_plan_join_search(PlannerInfo *root, int levels_needed,
3288                                                  List *initial_rels)
3289 {
3290         JoinMethodHint    **join_method_hints;
3291         int                                     nbaserel;
3292         RelOptInfo                 *rel;
3293         int                                     i;
3294         bool                            leading_hint_enable;
3295
3296         /*
3297          * Use standard planner (or geqo planner) if pg_hint_plan is disabled or no
3298          * valid hint is supplied.
3299          */
3300         if (!current_hint)
3301         {
3302                 if (prev_join_search)
3303                         return (*prev_join_search) (root, levels_needed, initial_rels);
3304                 else if (enable_geqo && levels_needed >= geqo_threshold)
3305                         return geqo(root, levels_needed, initial_rels);
3306                 else
3307                         return standard_join_search(root, levels_needed, initial_rels);
3308         }
3309
3310         /* We apply scan method hint rebuild scan path. */
3311         rebuild_scan_path(current_hint, root, levels_needed, initial_rels);
3312
3313         /*
3314          * In the case using GEQO, only scan method hints and Set hints have
3315          * effect.  Join method and join order is not controllable by hints.
3316          */
3317         if (enable_geqo && levels_needed >= geqo_threshold)
3318                 return geqo(root, levels_needed, initial_rels);
3319
3320         nbaserel = get_num_baserels(initial_rels);
3321         current_hint->join_hint_level = palloc0(sizeof(List *) * (nbaserel + 1));
3322         join_method_hints = palloc0(sizeof(JoinMethodHint *) * (nbaserel + 1));
3323
3324         leading_hint_enable = transform_join_hints(current_hint, root, nbaserel,
3325                                                                                            initial_rels, join_method_hints);
3326
3327         rel = pg_hint_plan_standard_join_search(root, levels_needed, initial_rels);
3328
3329         for (i = 2; i <= nbaserel; i++)
3330         {
3331                 list_free(current_hint->join_hint_level[i]);
3332
3333                 /* free Leading hint only */
3334                 if (join_method_hints[i] != NULL &&
3335                         join_method_hints[i]->enforce_mask == ENABLE_ALL_JOIN)
3336                         JoinMethodHintDelete(join_method_hints[i]);
3337         }
3338         pfree(current_hint->join_hint_level);
3339         pfree(join_method_hints);
3340
3341         if (leading_hint_enable)
3342                 set_join_config_options(current_hint->init_join_mask,
3343                                                                 current_hint->context);
3344
3345         return rel;
3346 }
3347
3348 /*
3349  * set_rel_pathlist
3350  *        Build access paths for a base relation
3351  *
3352  * This function was copied and edited from set_rel_pathlist() in
3353  * src/backend/optimizer/path/allpaths.c
3354  */
3355 static void
3356 set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
3357                                  Index rti, RangeTblEntry *rte)
3358 {
3359 #if PG_VERSION_NUM >= 90200
3360         if (IS_DUMMY_REL(rel))
3361         {
3362                 /* We already proved the relation empty, so nothing more to do */
3363         }
3364         else if (rte->inh)
3365 #else
3366         if (rte->inh)
3367 #endif
3368         {
3369                 /* It's an "append relation", process accordingly */
3370                 set_append_rel_pathlist(root, rel, rti, rte);
3371         }
3372         else
3373         {
3374                 if (rel->rtekind == RTE_RELATION)
3375                 {
3376                         if (rte->relkind == RELKIND_RELATION)
3377                         {
3378                                 /* Plain relation */
3379                                 set_plain_rel_pathlist(root, rel, rte);
3380                         }
3381                         else
3382                                 elog(ERROR, "unexpected relkind: %c", rte->relkind);
3383                 }
3384                 else
3385                         elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
3386         }
3387 }
3388
3389 #define standard_join_search pg_hint_plan_standard_join_search
3390 #define join_search_one_level pg_hint_plan_join_search_one_level
3391 #define make_join_rel make_join_rel_wrapper
3392 #include "core.c"
3393
3394 #undef make_join_rel
3395 #define make_join_rel pg_hint_plan_make_join_rel
3396 #define add_paths_to_joinrel add_paths_to_joinrel_wrapper
3397 #include "make_join_rel.c"