OSDN Git Service

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