OSDN Git Service

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