OSDN Git Service

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