OSDN Git Service

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