OSDN Git Service

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