OSDN Git Service

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