OSDN Git Service

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