OSDN Git Service

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