OSDN Git Service

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