OSDN Git Service

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