OSDN Git Service

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