OSDN Git Service

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