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