OSDN Git Service

0fa0303aae067113de7a441847a1ddee8d80ed20
[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(str,
2349                                          ("Wrong number of arguments for %s hint.",
2350                                           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)
2361         {
2362                 hint_ereport(hint->nworkers_str,
2363                                          ("number of workers must be a positive integer: %s",
2364                                           hint->base.keyword));
2365                 hint->base.state = HINT_STATE_ERROR;
2366                 return str;
2367         }
2368
2369         hint->nworkers = nworkers;
2370
2371         if (nworkers > max_hint_nworkers)
2372                 max_hint_nworkers = nworkers;
2373
2374         /* optional third parameter is specified */
2375         if (length == 3)
2376         {
2377                 const char *modeparam = (const char *)list_nth(name_list, 2);
2378                 if (strcasecmp(modeparam, "hard") == 0)
2379                         force_parallel = true;
2380                 else if (strcasecmp(modeparam, "soft") != 0)
2381                 {
2382                         hint_ereport(str,
2383                                                  ("The mode of Worker hint must be soft or hard."));
2384                         hint->base.state = HINT_STATE_ERROR;
2385                         return str;
2386                 }
2387         }
2388         
2389         hint->force_parallel = force_parallel;
2390
2391         return str;
2392 }
2393
2394 /*
2395  * set GUC parameter functions
2396  */
2397
2398 static int
2399 get_current_scan_mask()
2400 {
2401         int mask = 0;
2402
2403         if (enable_seqscan)
2404                 mask |= ENABLE_SEQSCAN;
2405         if (enable_indexscan)
2406                 mask |= ENABLE_INDEXSCAN;
2407         if (enable_bitmapscan)
2408                 mask |= ENABLE_BITMAPSCAN;
2409         if (enable_tidscan)
2410                 mask |= ENABLE_TIDSCAN;
2411         if (enable_indexonlyscan)
2412                 mask |= ENABLE_INDEXONLYSCAN;
2413
2414         return mask;
2415 }
2416
2417 static int
2418 get_current_join_mask()
2419 {
2420         int mask = 0;
2421
2422         if (enable_nestloop)
2423                 mask |= ENABLE_NESTLOOP;
2424         if (enable_mergejoin)
2425                 mask |= ENABLE_MERGEJOIN;
2426         if (enable_hashjoin)
2427                 mask |= ENABLE_HASHJOIN;
2428
2429         return mask;
2430 }
2431
2432 /*
2433  * Sets GUC prameters without throwing exception. Reutrns false if something
2434  * wrong.
2435  */
2436 static int
2437 set_config_option_noerror(const char *name, const char *value,
2438                                                   GucContext context, GucSource source,
2439                                                   GucAction action, bool changeVal, int elevel)
2440 {
2441         int                             result = 0;
2442         MemoryContext   ccxt = CurrentMemoryContext;
2443
2444         PG_TRY();
2445         {
2446                 result = set_config_option(name, value, context, source,
2447                                                                    action, changeVal, 0, false);
2448         }
2449         PG_CATCH();
2450         {
2451                 ErrorData          *errdata;
2452
2453                 /* Save error info */
2454                 MemoryContextSwitchTo(ccxt);
2455                 errdata = CopyErrorData();
2456                 FlushErrorState();
2457
2458                 ereport(elevel,
2459                                 (errcode(errdata->sqlerrcode),
2460                                  errhidestmt(hidestmt),
2461                                  errmsg("%s", errdata->message),
2462                                  errdata->detail ? errdetail("%s", errdata->detail) : 0,
2463                                  errdata->hint ? errhint("%s", errdata->hint) : 0));
2464                 FreeErrorData(errdata);
2465         }
2466         PG_END_TRY();
2467
2468         return result;
2469 }
2470
2471 /*
2472  * Sets GUC parameter of int32 type without throwing exceptions. Returns false
2473  * if something wrong.
2474  */
2475 static int
2476 set_config_int32_option(const char *name, int32 value, GucContext context)
2477 {
2478         char buf[16];   /* enough for int32 */
2479
2480         if (snprintf(buf, 16, "%d", value) < 0)
2481         {
2482                 ereport(pg_hint_plan_message_level,
2483                                 (errmsg ("Cannot set integer value: %d: %s",
2484                                                  max_hint_nworkers, strerror(errno))));
2485                 return false;
2486         }
2487
2488         return
2489                 set_config_option_noerror(name, buf, context,
2490                                                                   PGC_S_SESSION, GUC_ACTION_SAVE, true,
2491                                                                   pg_hint_plan_message_level);
2492 }
2493
2494 /* setup scan method enforcement according to given options */
2495 static void
2496 setup_guc_enforcement(SetHint **options, int noptions, GucContext context)
2497 {
2498         int     i;
2499
2500         for (i = 0; i < noptions; i++)
2501         {
2502                 SetHint    *hint = options[i];
2503                 int                     result;
2504
2505                 if (!hint_state_enabled(hint))
2506                         continue;
2507
2508                 result = set_config_option_noerror(hint->name, hint->value, context,
2509                                                                                    PGC_S_SESSION, GUC_ACTION_SAVE, true,
2510                                                                                    pg_hint_plan_message_level);
2511                 if (result != 0)
2512                         hint->base.state = HINT_STATE_USED;
2513                 else
2514                         hint->base.state = HINT_STATE_ERROR;
2515         }
2516
2517         return;
2518 }
2519
2520 /*
2521  * Setup parallel execution environment.
2522  *
2523  * If hint is not NULL, set up using it, elsewise reset to initial environment.
2524  */
2525 static void
2526 setup_parallel_plan_enforcement(ParallelHint *hint, HintState *state)
2527 {
2528         if (hint)
2529         {
2530                 hint->base.state = HINT_STATE_USED;
2531                 set_config_int32_option("max_parallel_workers_per_gather",
2532                                                                 hint->nworkers, state->context);
2533         }
2534         else
2535                 set_config_int32_option("max_parallel_workers_per_gather",
2536                                                                 state->init_nworkers, state->context);
2537
2538         /* force means that enforce parallel as far as possible */
2539         if (hint && hint->force_parallel)
2540         {
2541                 set_config_int32_option("parallel_tuple_cost", 0, state->context);
2542                 set_config_int32_option("parallel_setup_cost", 0, state->context);
2543                 set_config_int32_option("min_parallel_relation_size", 0,
2544                                                                 state->context);
2545         }
2546         else
2547         {
2548                 set_config_int32_option("parallel_tuple_cost",
2549                                                                 state->init_paratup_cost, state->context);
2550                 set_config_int32_option("parallel_setup_cost",
2551                                                                 state->init_parasetup_cost, state->context);
2552                 set_config_int32_option("min_parallel_relation_size",
2553                                                                 state->init_min_para_size, state->context);
2554         }
2555 }
2556
2557 #define SET_CONFIG_OPTION(name, type_bits) \
2558         set_config_option_noerror((name), \
2559                 (mask & (type_bits)) ? "true" : "false", \
2560                 context, PGC_S_SESSION, GUC_ACTION_SAVE, true, ERROR)
2561
2562
2563 /*
2564  * Setup GUC environment to enforce scan methods. If scanhint is NULL, reset
2565  * GUCs to the saved state in state.
2566  */
2567 static void
2568 setup_scan_method_enforcement(ScanMethodHint *scanhint, HintState *state)
2569 {
2570         unsigned char   enforce_mask = state->init_scan_mask;
2571         GucContext              context = state->context;
2572         unsigned char   mask;
2573
2574         if (scanhint)
2575         {
2576                 enforce_mask = scanhint->enforce_mask;
2577                 scanhint->base.state = HINT_STATE_USED;
2578         }
2579
2580         if (enforce_mask == ENABLE_SEQSCAN || enforce_mask == ENABLE_INDEXSCAN ||
2581                 enforce_mask == ENABLE_BITMAPSCAN || enforce_mask == ENABLE_TIDSCAN
2582                 || enforce_mask == (ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN)
2583                 )
2584                 mask = enforce_mask;
2585         else
2586                 mask = enforce_mask & current_hint_state->init_scan_mask;
2587
2588         SET_CONFIG_OPTION("enable_seqscan", ENABLE_SEQSCAN);
2589         SET_CONFIG_OPTION("enable_indexscan", ENABLE_INDEXSCAN);
2590         SET_CONFIG_OPTION("enable_bitmapscan", ENABLE_BITMAPSCAN);
2591         SET_CONFIG_OPTION("enable_tidscan", ENABLE_TIDSCAN);
2592         SET_CONFIG_OPTION("enable_indexonlyscan", ENABLE_INDEXONLYSCAN);
2593 }
2594
2595 static void
2596 set_join_config_options(unsigned char enforce_mask, GucContext context)
2597 {
2598         unsigned char   mask;
2599
2600         if (enforce_mask == ENABLE_NESTLOOP || enforce_mask == ENABLE_MERGEJOIN ||
2601                 enforce_mask == ENABLE_HASHJOIN)
2602                 mask = enforce_mask;
2603         else
2604                 mask = enforce_mask & current_hint_state->init_join_mask;
2605
2606         SET_CONFIG_OPTION("enable_nestloop", ENABLE_NESTLOOP);
2607         SET_CONFIG_OPTION("enable_mergejoin", ENABLE_MERGEJOIN);
2608         SET_CONFIG_OPTION("enable_hashjoin", ENABLE_HASHJOIN);
2609 }
2610
2611 /*
2612  * pg_hint_plan hook functions
2613  */
2614
2615 static void
2616 pg_hint_plan_ProcessUtility(Node *parsetree, const char *queryString,
2617                                                         ProcessUtilityContext context,
2618                                                         ParamListInfo params,
2619                                                         DestReceiver *dest, char *completionTag)
2620 {
2621         Node                               *node;
2622
2623         /* 
2624          * Use standard planner if pg_hint_plan is disabled or current nesting 
2625          * depth is nesting depth of SPI calls. 
2626          */
2627         if (!pg_hint_plan_enable_hint || hint_inhibit_level > 0)
2628         {
2629                 if (debug_level > 1)
2630                         ereport(pg_hint_plan_message_level,
2631                                         (errmsg ("pg_hint_plan: ProcessUtility:"
2632                                                          " pg_hint_plan.enable_hint = off")));
2633                 if (prev_ProcessUtility)
2634                         (*prev_ProcessUtility) (parsetree, queryString,
2635                                                                         context, params,
2636                                                                         dest, completionTag);
2637                 else
2638                         standard_ProcessUtility(parsetree, queryString,
2639                                                                         context, params,
2640                                                                         dest, completionTag);
2641                 return;
2642         }
2643
2644         node = parsetree;
2645         if (IsA(node, ExplainStmt))
2646         {
2647                 /*
2648                  * Draw out parse tree of actual query from Query struct of EXPLAIN
2649                  * statement.
2650                  */
2651                 ExplainStmt        *stmt;
2652                 Query              *query;
2653
2654                 stmt = (ExplainStmt *) node;
2655
2656                 Assert(IsA(stmt->query, Query));
2657                 query = (Query *) stmt->query;
2658
2659                 if (query->commandType == CMD_UTILITY && query->utilityStmt != NULL)
2660                         node = query->utilityStmt;
2661         }
2662
2663         /*
2664          * If the query was a EXECUTE or CREATE TABLE AS EXECUTE, get query string
2665          * specified to preceding PREPARE command to use it as source of hints.
2666          */
2667         if (IsA(node, ExecuteStmt))
2668         {
2669                 ExecuteStmt        *stmt;
2670
2671                 stmt = (ExecuteStmt *) node;
2672                 stmt_name = stmt->name;
2673         }
2674
2675         /*
2676          * CREATE AS EXECUTE behavior has changed since 9.2, so we must handle it
2677          * specially here.
2678          */
2679         if (IsA(node, CreateTableAsStmt))
2680         {
2681                 CreateTableAsStmt          *stmt;
2682                 Query              *query;
2683
2684                 stmt = (CreateTableAsStmt *) node;
2685                 Assert(IsA(stmt->query, Query));
2686                 query = (Query *) stmt->query;
2687
2688                 if (query->commandType == CMD_UTILITY &&
2689                         IsA(query->utilityStmt, ExecuteStmt))
2690                 {
2691                         ExecuteStmt *estmt = (ExecuteStmt *) query->utilityStmt;
2692                         stmt_name = estmt->name;
2693                 }
2694         }
2695
2696         if (stmt_name)
2697         {
2698                 if (debug_level > 1)
2699                         ereport(pg_hint_plan_message_level,
2700                                         (errmsg ("pg_hint_plan: ProcessUtility:"
2701                                                          " stmt_name = \"%s\", statement=\"%s\"",
2702                                                          stmt_name, queryString)));
2703
2704                 PG_TRY();
2705                 {
2706                         if (prev_ProcessUtility)
2707                                 (*prev_ProcessUtility) (parsetree, queryString,
2708                                                                                 context, params,
2709                                                                                 dest, completionTag);
2710                         else
2711                                 standard_ProcessUtility(parsetree, queryString,
2712                                                                                 context, params,
2713                                                                                 dest, completionTag);
2714                 }
2715                 PG_CATCH();
2716                 {
2717                         stmt_name = NULL;
2718                         PG_RE_THROW();
2719                 }
2720                 PG_END_TRY();
2721
2722                 stmt_name = NULL;
2723
2724                 return;
2725         }
2726
2727         if (prev_ProcessUtility)
2728                         (*prev_ProcessUtility) (parsetree, queryString,
2729                                                                         context, params,
2730                                                                         dest, completionTag);
2731                 else
2732                         standard_ProcessUtility(parsetree, queryString,
2733                                                                         context, params,
2734                                                                         dest, completionTag);
2735 }
2736
2737 /*
2738  * Push a hint into hint stack which is implemented with List struct.  Head of
2739  * list is top of stack.
2740  */
2741 static void
2742 push_hint(HintState *hstate)
2743 {
2744         /* Prepend new hint to the list means pushing to stack. */
2745         HintStateStack = lcons(hstate, HintStateStack);
2746
2747         /* Pushed hint is the one which should be used hereafter. */
2748         current_hint_state = hstate;
2749 }
2750
2751 /* Pop a hint from hint stack.  Popped hint is automatically discarded. */
2752 static void
2753 pop_hint(void)
2754 {
2755         /* Hint stack must not be empty. */
2756         if(HintStateStack == NIL)
2757                 elog(ERROR, "hint stack is empty");
2758
2759         /*
2760          * Take a hint at the head from the list, and free it.  Switch
2761          * current_hint_state to point new head (NULL if the list is empty).
2762          */
2763         HintStateStack = list_delete_first(HintStateStack);
2764         HintStateDelete(current_hint_state);
2765         if(HintStateStack == NIL)
2766                 current_hint_state = NULL;
2767         else
2768                 current_hint_state = (HintState *) lfirst(list_head(HintStateStack));
2769 }
2770
2771 static PlannedStmt *
2772 pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
2773 {
2774         const char         *hints = NULL;
2775         const char         *query;
2776         char               *norm_query;
2777         pgssJumbleState jstate;
2778         int                             query_len;
2779         int                             save_nestlevel;
2780         PlannedStmt        *result;
2781         HintState          *hstate;
2782         char                    msgstr[1024];
2783
2784         qnostr[0] = 0;
2785         strcpy(msgstr, "");
2786         if (debug_level > 1)
2787                 snprintf(qnostr, sizeof(qnostr), "[qno=0x%x]", qno++);
2788         hidestmt = false;
2789
2790         /*
2791          * Use standard planner if pg_hint_plan is disabled or current nesting 
2792          * depth is nesting depth of SPI calls. Other hook functions try to change
2793          * plan with current_hint_state if any, so set it to NULL.
2794          */
2795         if (!pg_hint_plan_enable_hint || hint_inhibit_level > 0)
2796         {
2797                 if (debug_level > 1)
2798                         elog(pg_hint_plan_message_level,
2799                                  "pg_hint_plan%s: planner: enable_hint=%d,"
2800                                  " hint_inhibit_level=%d",
2801                                  qnostr, pg_hint_plan_enable_hint, hint_inhibit_level);
2802                 hidestmt = true;
2803
2804                 goto standard_planner_proc;
2805         }
2806
2807         /* Create hint struct from client-supplied query string. */
2808         query = get_query_string();
2809
2810         /*
2811          * Create hintstate from hint specified for the query, if any.
2812          *
2813          * First we lookup hint in pg_hint.hints table by normalized query string,
2814          * unless pg_hint_plan.enable_hint_table is OFF.
2815          * This parameter provides option to avoid overhead of table lookup during
2816          * planning.
2817          *
2818          * If no hint was found, then we try to get hint from special query comment.
2819          */
2820         if (pg_hint_plan_enable_hint_table)
2821         {
2822                 /*
2823                  * Search hint information which is stored for the query and the
2824                  * application.  Query string is normalized before using in condition
2825                  * in order to allow fuzzy matching.
2826                  *
2827                  * XXX: normalizing code is copied from pg_stat_statements.c, so be
2828                  * careful when supporting PostgreSQL's version up.
2829                  */
2830                 jstate.jumble = (unsigned char *) palloc(JUMBLE_SIZE);
2831                 jstate.jumble_len = 0;
2832                 jstate.clocations_buf_size = 32;
2833                 jstate.clocations = (pgssLocationLen *)
2834                         palloc(jstate.clocations_buf_size * sizeof(pgssLocationLen));
2835                 jstate.clocations_count = 0;
2836                 JumbleQuery(&jstate, parse);
2837                 /*
2838                  * generate_normalized_query() copies exact given query_len bytes, so we
2839                  * add 1 byte for null-termination here.  As comments on
2840                  * generate_normalized_query says, generate_normalized_query doesn't
2841                  * take care of null-terminate, but additional 1 byte ensures that '\0'
2842                  * byte in the source buffer to be copied into norm_query.
2843                  */
2844                 query_len = strlen(query) + 1;
2845                 norm_query = generate_normalized_query(&jstate,
2846                                                                                            query,
2847                                                                                            &query_len,
2848                                                                                            GetDatabaseEncoding());
2849                 hints = get_hints_from_table(norm_query, application_name);
2850                 if (debug_level > 1)
2851                 {
2852                         if (hints)
2853                                 snprintf(msgstr, 1024, "hints from table: \"%s\":"
2854                                                  " normalzed_query=\"%s\", application name =\"%s\"",
2855                                                  hints, norm_query, application_name);
2856                         else
2857                         {
2858                                 ereport(pg_hint_plan_message_level,
2859                                                 (errhidestmt(hidestmt),
2860                                                  errmsg("pg_hint_plan%s:"
2861                                                                 " no match found in table:"
2862                                                                 "  application name = \"%s\","
2863                                                                 " normalzed_query=\"%s\"",
2864                                                                 qnostr, application_name, norm_query)));
2865                                 hidestmt = true;
2866                         }
2867                 }
2868         }
2869         if (hints == NULL)
2870         {
2871                 hints = get_hints_from_comment(query);
2872
2873                 if (debug_level > 1)
2874                 {
2875                         snprintf(msgstr, 1024, "hints in comment=\"%s\"",
2876                                          hints ? hints : "(none)");
2877                         if (debug_level > 2 || 
2878                                 stmt_name || strcmp(query, debug_query_string))
2879                                 snprintf(msgstr + strlen(msgstr), 1024- strlen(msgstr), 
2880                                          ", stmt=\"%s\", query=\"%s\", debug_query_string=\"%s\"",
2881                                                  stmt_name, query, debug_query_string);
2882                 }
2883         }
2884
2885         hstate = create_hintstate(parse, hints);
2886
2887         /*
2888          * Use standard planner if the statement has not valid hint.  Other hook
2889          * functions try to change plan with current_hint_state if any, so set it
2890          * to NULL.
2891          */
2892         if (!hstate)
2893                 goto standard_planner_proc;
2894
2895         /*
2896          * Push new hint struct to the hint stack to disable previous hint context.
2897          */
2898         push_hint(hstate);
2899
2900         /*  Set scan enforcement here. */
2901         save_nestlevel = NewGUCNestLevel();
2902
2903         /* Apply Set hints, then save it as the initial state  */
2904         setup_guc_enforcement(current_hint_state->set_hints,
2905                                                    current_hint_state->num_hints[HINT_TYPE_SET],
2906                                                    current_hint_state->context);
2907         
2908         current_hint_state->init_scan_mask = get_current_scan_mask();
2909         current_hint_state->init_join_mask = get_current_join_mask();
2910         current_hint_state->init_min_para_size = min_parallel_relation_size;
2911         current_hint_state->init_paratup_cost = parallel_tuple_cost;
2912         current_hint_state->init_parasetup_cost = parallel_setup_cost;
2913
2914         /*
2915          * max_parallel_workers_per_gather should be non-zero here if Workers hint
2916          * is specified.
2917          */
2918         if (max_hint_nworkers >= 0)
2919         {
2920                 current_hint_state->init_nworkers = 0;
2921                 set_config_int32_option("max_parallel_workers_per_gather",
2922                                                                 1, current_hint_state->context);
2923         }
2924
2925         if (debug_level > 1)
2926         {
2927                 ereport(pg_hint_plan_message_level,
2928                                 (errhidestmt(hidestmt),
2929                                  errmsg("pg_hint_plan%s: planner: %s",
2930                                                 qnostr, msgstr))); 
2931                 hidestmt = true;
2932         }
2933
2934         /*
2935          * Use PG_TRY mechanism to recover GUC parameters and current_hint_state to
2936          * the state when this planner started when error occurred in planner.
2937          */
2938         PG_TRY();
2939         {
2940                 if (prev_planner)
2941                         result = (*prev_planner) (parse, cursorOptions, boundParams);
2942                 else
2943                         result = standard_planner(parse, cursorOptions, boundParams);
2944         }
2945         PG_CATCH();
2946         {
2947                 /*
2948                  * Rollback changes of GUC parameters, and pop current hint context
2949                  * from hint stack to rewind the state.
2950                  */
2951                 AtEOXact_GUC(true, save_nestlevel);
2952                 pop_hint();
2953                 PG_RE_THROW();
2954         }
2955         PG_END_TRY();
2956
2957         /* Print hint in debug mode. */
2958         if (debug_level == 1)
2959                 HintStateDump(current_hint_state);
2960         else if (debug_level > 1)
2961                 HintStateDump2(current_hint_state);
2962
2963         /*
2964          * Rollback changes of GUC parameters, and pop current hint context from
2965          * hint stack to rewind the state.
2966          */
2967         AtEOXact_GUC(true, save_nestlevel);
2968         pop_hint();
2969
2970         return result;
2971
2972 standard_planner_proc:
2973         if (debug_level > 1)
2974         {
2975                 ereport(pg_hint_plan_message_level,
2976                                 (errhidestmt(hidestmt),
2977                                  errmsg("pg_hint_plan%s: planner: no valid hint (%s)",
2978                                                 qnostr, msgstr)));
2979                 hidestmt = true;
2980         }
2981         current_hint_state = NULL;
2982         if (prev_planner)
2983                 return (*prev_planner) (parse, cursorOptions, boundParams);
2984         else
2985                 return standard_planner(parse, cursorOptions, boundParams);
2986 }
2987
2988 /*
2989  * Find scan method hint to be applied to the given relation
2990  */
2991 static ScanMethodHint *
2992 find_scan_hint(PlannerInfo *root, Index relid, RelOptInfo *rel)
2993 {
2994         RangeTblEntry  *rte;
2995         int                             i;
2996
2997         /*
2998          * We don't apply scan method hint if the relation is:
2999          *   - not a base relation
3000          *   - not an ordinary relation (such as join and subquery)
3001          */
3002         if (rel && (rel->reloptkind != RELOPT_BASEREL ||
3003                                 rel->rtekind != RTE_RELATION))
3004                 return NULL;
3005
3006         rte = root->simple_rte_array[relid];
3007
3008         /* We don't force scan method of foreign tables */
3009         if (rte->relkind == RELKIND_FOREIGN_TABLE)
3010                 return NULL;
3011
3012         /* Find scan method hint, which matches given names, from the list. */
3013         for (i = 0; i < current_hint_state->num_hints[HINT_TYPE_SCAN_METHOD]; i++)
3014         {
3015                 ScanMethodHint *hint = current_hint_state->scan_hints[i];
3016
3017                 /* We ignore disabled hints. */
3018                 if (!hint_state_enabled(hint))
3019                         continue;
3020
3021                 if (RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
3022                         return hint;
3023         }
3024
3025         return NULL;
3026 }
3027
3028 static ParallelHint *
3029 find_parallel_hint(PlannerInfo *root, Index relid, RelOptInfo *rel)
3030 {
3031         RangeTblEntry  *rte;
3032         int                             i;
3033
3034         /*
3035          * We don't apply scan method hint if the relation is:
3036          *   - not a base relation and inheritance children
3037          *   - not an ordinary relation (such as join and subquery)
3038          */
3039         if (!rel || rel->rtekind != RTE_RELATION ||
3040                 (rel->reloptkind != RELOPT_BASEREL &&
3041                  rel->reloptkind != RELOPT_OTHER_MEMBER_REL))
3042                 return NULL;
3043
3044         rte = root->simple_rte_array[relid];
3045
3046         /* We can't force scan method of foreign tables */
3047         if (rte->relkind == RELKIND_FOREIGN_TABLE)
3048                 return NULL;
3049
3050         /* Find scan method hint, which matches given names, from the list. */
3051         for (i = 0; i < current_hint_state->num_hints[HINT_TYPE_PARALLEL]; i++)
3052         {
3053                 ParallelHint *hint = current_hint_state->parallel_hints[i];
3054
3055                 /* We ignore disabled hints. */
3056                 if (!hint_state_enabled(hint))
3057                         continue;
3058
3059                 if (RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
3060                         return hint;
3061         }
3062
3063         return NULL;
3064 }
3065
3066 /*
3067  * regexeq
3068  *
3069  * Returns TRUE on match, FALSE on no match.
3070  *
3071  *   s1 --- the data to match against
3072  *   s2 --- the pattern
3073  *
3074  * Because we copy s1 to NameData, make the size of s1 less than NAMEDATALEN.
3075  */
3076 static bool
3077 regexpeq(const char *s1, const char *s2)
3078 {
3079         NameData        name;
3080         text       *regexp;
3081         Datum           result;
3082
3083         strcpy(name.data, s1);
3084         regexp = cstring_to_text(s2);
3085
3086         result = DirectFunctionCall2Coll(nameregexeq,
3087                                                                          DEFAULT_COLLATION_OID,
3088                                                                          NameGetDatum(&name),
3089                                                                          PointerGetDatum(regexp));
3090         return DatumGetBool(result);
3091 }
3092
3093
3094 /* Remove indexes instructed not to use by hint. */
3095 static void
3096 restrict_indexes(PlannerInfo *root, ScanMethodHint *hint, RelOptInfo *rel,
3097                            bool using_parent_hint)
3098 {
3099         ListCell           *cell;
3100         ListCell           *prev;
3101         ListCell           *next;
3102         StringInfoData  buf;
3103         RangeTblEntry  *rte = root->simple_rte_array[rel->relid];
3104         Oid                             relationObjectId = rte->relid;
3105
3106         /*
3107          * We delete all the IndexOptInfo list and prevent you from being usable by
3108          * a scan.
3109          */
3110         if (hint->enforce_mask == ENABLE_SEQSCAN ||
3111                 hint->enforce_mask == ENABLE_TIDSCAN)
3112         {
3113                 list_free_deep(rel->indexlist);
3114                 rel->indexlist = NIL;
3115                 hint->base.state = HINT_STATE_USED;
3116
3117                 return;
3118         }
3119
3120         /*
3121          * When a list of indexes is not specified, we just use all indexes.
3122          */
3123         if (hint->indexnames == NIL)
3124                 return;
3125
3126         /*
3127          * Leaving only an specified index, we delete it from a IndexOptInfo list
3128          * other than it.
3129          */
3130         prev = NULL;
3131         if (debug_level > 0)
3132                 initStringInfo(&buf);
3133
3134         for (cell = list_head(rel->indexlist); cell; cell = next)
3135         {
3136                 IndexOptInfo   *info = (IndexOptInfo *) lfirst(cell);
3137                 char               *indexname = get_rel_name(info->indexoid);
3138                 ListCell           *l;
3139                 bool                    use_index = false;
3140
3141                 next = lnext(cell);
3142
3143                 foreach(l, hint->indexnames)
3144                 {
3145                         char   *hintname = (char *) lfirst(l);
3146                         bool    result;
3147
3148                         if (hint->regexp)
3149                                 result = regexpeq(indexname, hintname);
3150                         else
3151                                 result = RelnameCmp(&indexname, &hintname) == 0;
3152
3153                         if (result)
3154                         {
3155                                 use_index = true;
3156                                 if (debug_level > 0)
3157                                 {
3158                                         appendStringInfoCharMacro(&buf, ' ');
3159                                         quote_value(&buf, indexname);
3160                                 }
3161
3162                                 break;
3163                         }
3164                 }
3165
3166                 /*
3167                  * Apply index restriction of parent hint to children. Since index
3168                  * inheritance is not explicitly described we should search for an
3169                  * children's index with the same definition to that of the parent.
3170                  */
3171                 if (using_parent_hint && !use_index)
3172                 {
3173                         foreach(l, current_hint_state->parent_index_infos)
3174                         {
3175                                 int                                     i;
3176                                 HeapTuple                       ht_idx;
3177                                 ParentIndexInfo    *p_info = (ParentIndexInfo *)lfirst(l);
3178
3179                                 /*
3180                                  * we check the 'same' index by comparing uniqueness, access
3181                                  * method and index key columns.
3182                                  */
3183                                 if (p_info->indisunique != info->unique ||
3184                                         p_info->method != info->relam ||
3185                                         list_length(p_info->column_names) != info->ncolumns)
3186                                         continue;
3187
3188                                 /* Check if index key columns match */
3189                                 for (i = 0; i < info->ncolumns; i++)
3190                                 {
3191                                         char       *c_attname = NULL;
3192                                         char       *p_attname = NULL;
3193
3194                                         p_attname = list_nth(p_info->column_names, i);
3195
3196                                         /*
3197                                          * if both of the key of the same position are expressions,
3198                                          * ignore them for now and check later.
3199                                          */
3200                                         if (info->indexkeys[i] == 0 && !p_attname)
3201                                                 continue;
3202
3203                                         /* deny if one is expression while another is not */
3204                                         if (info->indexkeys[i] == 0 || !p_attname)
3205                                                 break;
3206
3207                                         c_attname = get_attname(relationObjectId,
3208                                                                                                 info->indexkeys[i]);
3209
3210                                         /* deny if any of column attributes don't match */
3211                                         if (strcmp(p_attname, c_attname) != 0 ||
3212                                                 p_info->indcollation[i] != info->indexcollations[i] ||
3213                                                 p_info->opclass[i] != info->opcintype[i]||
3214                                                 ((p_info->indoption[i] & INDOPTION_DESC) != 0)
3215                                                 != info->reverse_sort[i] ||
3216                                                 ((p_info->indoption[i] & INDOPTION_NULLS_FIRST) != 0)
3217                                                 != info->nulls_first[i])
3218                                                 break;
3219                                 }
3220
3221                                 /* deny this if any difference found */
3222                                 if (i != info->ncolumns)
3223                                         continue;
3224
3225                                 /* check on key expressions  */
3226                                 if ((p_info->expression_str && (info->indexprs != NIL)) ||
3227                                         (p_info->indpred_str && (info->indpred != NIL)))
3228                                 {
3229                                         /* fetch the index of this child */
3230                                         ht_idx = SearchSysCache1(INDEXRELID,
3231                                                                                          ObjectIdGetDatum(info->indexoid));
3232
3233                                         /* check expressions if both expressions are available */
3234                                         if (p_info->expression_str &&
3235                                                 !heap_attisnull(ht_idx, Anum_pg_index_indexprs))
3236                                         {
3237                                                 Datum       exprsDatum;
3238                                                 bool        isnull;
3239                                                 Datum       result;
3240
3241                                                 /*
3242                                                  * to change the expression's parameter of child's
3243                                                  * index to strings
3244                                                  */
3245                                                 exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
3246                                                                                                          Anum_pg_index_indexprs,
3247                                                                                                          &isnull);
3248
3249                                                 result = DirectFunctionCall2(pg_get_expr,
3250                                                                                                          exprsDatum,
3251                                                                                                          ObjectIdGetDatum(
3252                                                                                                                  relationObjectId));
3253
3254                                                 /* deny if expressions don't match */
3255                                                 if (strcmp(p_info->expression_str,
3256                                                                    text_to_cstring(DatumGetTextP(result))) != 0)
3257                                                 {
3258                                                         /* Clean up */
3259                                                         ReleaseSysCache(ht_idx);
3260                                                         continue;
3261                                                 }
3262                                         }
3263
3264                                         /* compare index predicates  */
3265                                         if (p_info->indpred_str &&
3266                                                 !heap_attisnull(ht_idx, Anum_pg_index_indpred))
3267                                         {
3268                                                 Datum       predDatum;
3269                                                 bool        isnull;
3270                                                 Datum       result;
3271
3272                                                 predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
3273                                                                                                          Anum_pg_index_indpred,
3274                                                                                                          &isnull);
3275
3276                                                 result = DirectFunctionCall2(pg_get_expr,
3277                                                                                                          predDatum,
3278                                                                                                          ObjectIdGetDatum(
3279                                                                                                                  relationObjectId));
3280
3281                                                 if (strcmp(p_info->indpred_str,
3282                                                                    text_to_cstring(DatumGetTextP(result))) != 0)
3283                                                 {
3284                                                         /* Clean up */
3285                                                         ReleaseSysCache(ht_idx);
3286                                                         continue;
3287                                                 }
3288                                         }
3289
3290                                         /* Clean up */
3291                                         ReleaseSysCache(ht_idx);
3292                                 }
3293                                 else if (p_info->expression_str || (info->indexprs != NIL))
3294                                         continue;
3295                                 else if (p_info->indpred_str || (info->indpred != NIL))
3296                                         continue;
3297
3298                                 use_index = true;
3299
3300                                 /* to log the candidate of index */
3301                                 if (debug_level > 0)
3302                                 {
3303                                         appendStringInfoCharMacro(&buf, ' ');
3304                                         quote_value(&buf, indexname);
3305                                 }
3306
3307                                 break;
3308                         }
3309                 }
3310
3311                 if (!use_index)
3312                         rel->indexlist = list_delete_cell(rel->indexlist, cell, prev);
3313                 else
3314                         prev = cell;
3315
3316                 pfree(indexname);
3317         }
3318
3319         if (debug_level == 1)
3320         {
3321                 StringInfoData  rel_buf;
3322                 char *disprelname = "";
3323
3324                 /*
3325                  * If this hint targetted the parent, use the real name of this
3326                  * child. Otherwise use hint specification.
3327                  */
3328                 if (using_parent_hint)
3329                         disprelname = get_rel_name(rte->relid);
3330                 else
3331                         disprelname = hint->relname;
3332                         
3333
3334                 initStringInfo(&rel_buf);
3335                 quote_value(&rel_buf, disprelname);
3336
3337                 ereport(LOG,
3338                                 (errmsg("available indexes for %s(%s):%s",
3339                                          hint->base.keyword,
3340                                          rel_buf.data,
3341                                          buf.data)));
3342                 pfree(buf.data);
3343                 pfree(rel_buf.data);
3344         }
3345 }
3346
3347 /* 
3348  * Return information of index definition.
3349  */
3350 static ParentIndexInfo *
3351 get_parent_index_info(Oid indexoid, Oid relid)
3352 {
3353         ParentIndexInfo *p_info = palloc(sizeof(ParentIndexInfo));
3354         Relation            indexRelation;
3355         Form_pg_index   index;
3356         char               *attname;
3357         int                             i;
3358
3359         indexRelation = index_open(indexoid, RowExclusiveLock);
3360
3361         index = indexRelation->rd_index;
3362
3363         p_info->indisunique = index->indisunique;
3364         p_info->method = indexRelation->rd_rel->relam;
3365
3366         p_info->column_names = NIL;
3367         p_info->indcollation = (Oid *) palloc(sizeof(Oid) * index->indnatts);
3368         p_info->opclass = (Oid *) palloc(sizeof(Oid) * index->indnatts);
3369         p_info->indoption = (int16 *) palloc(sizeof(Oid) * index->indnatts);
3370
3371         for (i = 0; i < index->indnatts; i++)
3372         {
3373                 attname = get_attname(relid, index->indkey.values[i]);
3374                 p_info->column_names = lappend(p_info->column_names, attname);
3375
3376                 p_info->indcollation[i] = indexRelation->rd_indcollation[i];
3377                 p_info->opclass[i] = indexRelation->rd_opcintype[i];
3378                 p_info->indoption[i] = indexRelation->rd_indoption[i];
3379         }
3380
3381         /*
3382          * to check to match the expression's parameter of index with child indexes
3383          */
3384         p_info->expression_str = NULL;
3385         if(!heap_attisnull(indexRelation->rd_indextuple, Anum_pg_index_indexprs))
3386         {
3387                 Datum       exprsDatum;
3388                 bool            isnull;
3389                 Datum           result;
3390
3391                 exprsDatum = SysCacheGetAttr(INDEXRELID, indexRelation->rd_indextuple,
3392                                                                          Anum_pg_index_indexprs, &isnull);
3393
3394                 result = DirectFunctionCall2(pg_get_expr,
3395                                                                          exprsDatum,
3396                                                                          ObjectIdGetDatum(relid));
3397
3398                 p_info->expression_str = text_to_cstring(DatumGetTextP(result));
3399         }
3400
3401         /*
3402          * to check to match the predicate's parameter of index with child indexes
3403          */
3404         p_info->indpred_str = NULL;
3405         if(!heap_attisnull(indexRelation->rd_indextuple, Anum_pg_index_indpred))
3406         {
3407                 Datum       predDatum;
3408                 bool            isnull;
3409                 Datum           result;
3410
3411                 predDatum = SysCacheGetAttr(INDEXRELID, indexRelation->rd_indextuple,
3412                                                                          Anum_pg_index_indpred, &isnull);
3413
3414                 result = DirectFunctionCall2(pg_get_expr,
3415                                                                          predDatum,
3416                                                                          ObjectIdGetDatum(relid));
3417
3418                 p_info->indpred_str = text_to_cstring(DatumGetTextP(result));
3419         }
3420
3421         index_close(indexRelation, NoLock);
3422
3423         return p_info;
3424 }
3425
3426 /*
3427  * cancel hint enforcement
3428  */
3429 static void
3430 reset_hint_enforcement()
3431 {
3432         setup_scan_method_enforcement(NULL, current_hint_state);
3433         setup_parallel_plan_enforcement(NULL, current_hint_state);
3434 }
3435
3436 /*
3437  * Set planner guc parameters according to corresponding scan hints.
3438  */
3439 static bool
3440 setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel)
3441 {
3442         Index   new_parent_relid = 0;
3443         ListCell *l;
3444         ScanMethodHint *shint = NULL;
3445         ParallelHint   *phint = NULL;
3446         bool                    inhparent = root->simple_rte_array[rel->relid]->inh;
3447         Oid             relationObjectId = root->simple_rte_array[rel->relid]->relid;
3448
3449         /*
3450          * We could register the parent relation of the following children here
3451          * when inhparent == true but inheritnce planner doesn't call this function
3452          * for parents. Since we cannot distinguish who called this function we
3453          * cannot do other than always seeking the parent regardless of who called
3454          * this function.
3455          */
3456         if (inhparent)
3457         {
3458                 if (debug_level > 1)
3459                         ereport(pg_hint_plan_message_level,
3460                                         (errhidestmt(true),
3461                                          errmsg ("pg_hint_plan%s: setup_hint_enforcement"
3462                                                          " skipping inh parent: relation=%u(%s), inhparent=%d,"
3463                                                          " current_hint_state=%p, hint_inhibit_level=%d",
3464                                                          qnostr, relationObjectId,
3465                                                          get_rel_name(relationObjectId),
3466                                                          inhparent, current_hint_state, hint_inhibit_level)));
3467                 return false;
3468         }
3469
3470         /* Find the parent for this relation other than the registered parent */
3471         foreach (l, root->append_rel_list)
3472         {
3473                 AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
3474
3475                 if (appinfo->child_relid == rel->relid)
3476                 {
3477                         if (current_hint_state->parent_relid != appinfo->parent_relid)
3478                                 new_parent_relid = appinfo->parent_relid;
3479                         break;
3480                 }
3481         }
3482
3483         if (!l)
3484         {
3485                 /* This relation doesn't have a parent. Cancel current_hint_state. */
3486                 current_hint_state->parent_relid = 0;
3487                 current_hint_state->parent_scan_hint = NULL;
3488                 current_hint_state->parent_parallel_hint = NULL;
3489         }
3490
3491         if (new_parent_relid > 0)
3492         {
3493                 /*
3494                  * Here we found a new parent for the current relation. Scan continues
3495                  * hint to other childrens of this parent so remember it * to avoid
3496                  * hinthintredundant setup cost.
3497                  */
3498                 current_hint_state->parent_relid = new_parent_relid;
3499                                 
3500                 /* Find hints for the parent */
3501                 current_hint_state->parent_scan_hint =
3502                         find_scan_hint(root, current_hint_state->parent_relid, NULL);
3503
3504                 current_hint_state->parent_parallel_hint =
3505                         find_parallel_hint(root, current_hint_state->parent_relid, NULL);
3506
3507                 /*
3508                  * If hint is found for the parent, apply it for this child instead
3509                  * of its own.
3510                  */
3511                 if (current_hint_state->parent_scan_hint)
3512                 {
3513                         ScanMethodHint * pshint = current_hint_state->parent_scan_hint;
3514
3515                         pshint->base.state = HINT_STATE_USED;
3516
3517                         /* Apply index mask in the same manner to the parent. */
3518                         if (pshint->indexnames)
3519                         {
3520                                 Oid                     parentrel_oid;
3521                                 Relation        parent_rel;
3522
3523                                 parentrel_oid =
3524                                         root->simple_rte_array[current_hint_state->parent_relid]->relid;
3525                                 parent_rel = heap_open(parentrel_oid, NoLock);
3526
3527                                 /* Search the parent relation for indexes match the hint spec */
3528                                 foreach(l, RelationGetIndexList(parent_rel))
3529                                 {
3530                                         Oid         indexoid = lfirst_oid(l);
3531                                         char       *indexname = get_rel_name(indexoid);
3532                                         ListCell   *lc;
3533                                         ParentIndexInfo *parent_index_info;
3534
3535                                         foreach(lc, pshint->indexnames)
3536                                         {
3537                                                 if (RelnameCmp(&indexname, &lfirst(lc)) == 0)
3538                                                         break;
3539                                         }
3540                                         if (!lc)
3541                                                 continue;
3542
3543                                         parent_index_info =
3544                                                 get_parent_index_info(indexoid, parentrel_oid);
3545                                         current_hint_state->parent_index_infos =
3546                                                 lappend(current_hint_state->parent_index_infos,
3547                                                                 parent_index_info);
3548                                 }
3549                                 heap_close(parent_rel, NoLock);
3550                         }
3551                 }
3552         }
3553
3554         if (current_hint_state->parent_scan_hint)
3555                 shint = current_hint_state->parent_scan_hint;
3556         else
3557                 shint = find_scan_hint(root, rel->relid, rel);
3558
3559         if (shint)
3560         {
3561                 bool using_parent_hint =
3562                         (shint == current_hint_state->parent_scan_hint);
3563
3564                 /* Setup scan enforcement environment */
3565                 setup_scan_method_enforcement(shint, current_hint_state);
3566
3567                 /* restrict unwanted inexes */
3568                 restrict_indexes(root, shint, rel, using_parent_hint);
3569
3570                 if (debug_level > 1)
3571                 {
3572                         char *additional_message = "";
3573
3574                         if (shint == current_hint_state->parent_scan_hint)
3575                                 additional_message = " by parent hint";
3576
3577                         ereport(pg_hint_plan_message_level,
3578                                         (errhidestmt(true),
3579                                          errmsg ("pg_hint_plan%s: setup_hint_enforcement"
3580                                                          " index deletion%s:"
3581                                                          " relation=%u(%s), inhparent=%d, "
3582                                                          "current_hint_state=%p,"
3583                                                          " hint_inhibit_level=%d, scanmask=0x%x",
3584                                                          qnostr, additional_message,
3585                                                          relationObjectId,
3586                                                          get_rel_name(relationObjectId),
3587                                                          inhparent, current_hint_state,
3588                                                          hint_inhibit_level,
3589                                                          shint->enforce_mask)));
3590                 }
3591         }
3592
3593         /* Do the same for parallel plan enforcement */
3594         if (current_hint_state->parent_parallel_hint)
3595                 phint = current_hint_state->parent_parallel_hint;
3596         else
3597                 phint = find_parallel_hint(root, rel->relid, rel);
3598
3599         setup_parallel_plan_enforcement(phint, current_hint_state);
3600
3601         /* Nothing to apply. Reset the scan mask to intial state */
3602         if (!shint && ! phint)
3603         {
3604                 if (debug_level > 1)
3605                         ereport(pg_hint_plan_message_level,
3606                                         (errhidestmt (true),
3607                                          errmsg ("pg_hint_plan%s: get_relation_info"
3608                                                          " no hint applied:"
3609                                                          " relation=%u(%s), inhparent=%d, current_hint=%p,"
3610                                                          " hint_inhibit_level=%d, scanmask=0x%x",
3611                                                          qnostr, relationObjectId,
3612                                                          get_rel_name(relationObjectId),
3613                                                          inhparent, current_hint_state, hint_inhibit_level,
3614                                                          current_hint_state->init_scan_mask)));
3615
3616                 setup_scan_method_enforcement(NULL,     current_hint_state);
3617
3618                 return false;
3619         }
3620
3621         return true;
3622 }
3623
3624 /*
3625  * Return index of relation which matches given aliasname, or 0 if not found.
3626  * If same aliasname was used multiple times in a query, return -1.
3627  */
3628 static int
3629 find_relid_aliasname(PlannerInfo *root, char *aliasname, List *initial_rels,
3630                                          const char *str)
3631 {
3632         int             i;
3633         Index   found = 0;
3634
3635         for (i = 1; i < root->simple_rel_array_size; i++)
3636         {
3637                 ListCell   *l;
3638
3639                 if (root->simple_rel_array[i] == NULL)
3640                         continue;
3641
3642                 Assert(i == root->simple_rel_array[i]->relid);
3643
3644                 if (RelnameCmp(&aliasname,
3645                                            &root->simple_rte_array[i]->eref->aliasname) != 0)
3646                         continue;
3647
3648                 foreach(l, initial_rels)
3649                 {
3650                         RelOptInfo *rel = (RelOptInfo *) lfirst(l);
3651
3652                         if (rel->reloptkind == RELOPT_BASEREL)
3653                         {
3654                                 if (rel->relid != i)
3655                                         continue;
3656                         }
3657                         else
3658                         {
3659                                 Assert(rel->reloptkind == RELOPT_JOINREL);
3660
3661                                 if (!bms_is_member(i, rel->relids))
3662                                         continue;
3663                         }
3664
3665                         if (found != 0)
3666                         {
3667                                 hint_ereport(str,
3668                                                          ("Relation name \"%s\" is ambiguous.",
3669                                                           aliasname));
3670                                 return -1;
3671                         }
3672
3673                         found = i;
3674                         break;
3675                 }
3676
3677         }
3678
3679         return found;
3680 }
3681
3682 /*
3683  * Return join hint which matches given joinrelids.
3684  */
3685 static JoinMethodHint *
3686 find_join_hint(Relids joinrelids)
3687 {
3688         List       *join_hint;
3689         ListCell   *l;
3690
3691         join_hint = current_hint_state->join_hint_level[bms_num_members(joinrelids)];
3692
3693         foreach(l, join_hint)
3694         {
3695                 JoinMethodHint *hint = (JoinMethodHint *) lfirst(l);
3696
3697                 if (bms_equal(joinrelids, hint->joinrelids))
3698                         return hint;
3699         }
3700
3701         return NULL;
3702 }
3703
3704 static Relids
3705 OuterInnerJoinCreate(OuterInnerRels *outer_inner, LeadingHint *leading_hint,
3706         PlannerInfo *root, List *initial_rels, HintState *hstate, int nbaserel)
3707 {
3708         OuterInnerRels *outer_rels;
3709         OuterInnerRels *inner_rels;
3710         Relids                  outer_relids;
3711         Relids                  inner_relids;
3712         Relids                  join_relids;
3713         JoinMethodHint *hint;
3714
3715         if (outer_inner->relation != NULL)
3716         {
3717                 return bms_make_singleton(
3718                                         find_relid_aliasname(root, outer_inner->relation,
3719                                                                                  initial_rels,
3720                                                                                  leading_hint->base.hint_str));
3721         }
3722
3723         outer_rels = lfirst(outer_inner->outer_inner_pair->head);
3724         inner_rels = lfirst(outer_inner->outer_inner_pair->tail);
3725
3726         outer_relids = OuterInnerJoinCreate(outer_rels,
3727                                                                                 leading_hint,
3728                                                                                 root,
3729                                                                                 initial_rels,
3730                                                                                 hstate,
3731                                                                                 nbaserel);
3732         inner_relids = OuterInnerJoinCreate(inner_rels,
3733                                                                                 leading_hint,
3734                                                                                 root,
3735                                                                                 initial_rels,
3736                                                                                 hstate,
3737                                                                                 nbaserel);
3738
3739         join_relids = bms_add_members(outer_relids, inner_relids);
3740
3741         if (bms_num_members(join_relids) > nbaserel)
3742                 return join_relids;
3743
3744         /*
3745          * If we don't have join method hint, create new one for the
3746          * join combination with all join methods are enabled.
3747          */
3748         hint = find_join_hint(join_relids);
3749         if (hint == NULL)
3750         {
3751                 /*
3752                  * Here relnames is not set, since Relids bitmap is sufficient to
3753                  * control paths of this query afterward.
3754                  */
3755                 hint = (JoinMethodHint *) JoinMethodHintCreate(
3756                                         leading_hint->base.hint_str,
3757                                         HINT_LEADING,
3758                                         HINT_KEYWORD_LEADING);
3759                 hint->base.state = HINT_STATE_USED;
3760                 hint->nrels = bms_num_members(join_relids);
3761                 hint->enforce_mask = ENABLE_ALL_JOIN;
3762                 hint->joinrelids = bms_copy(join_relids);
3763                 hint->inner_nrels = bms_num_members(inner_relids);
3764                 hint->inner_joinrelids = bms_copy(inner_relids);
3765
3766                 hstate->join_hint_level[hint->nrels] =
3767                         lappend(hstate->join_hint_level[hint->nrels], hint);
3768         }
3769         else
3770         {
3771                 hint->inner_nrels = bms_num_members(inner_relids);
3772                 hint->inner_joinrelids = bms_copy(inner_relids);
3773         }
3774
3775         return join_relids;
3776 }
3777
3778 static Relids
3779 create_bms_of_relids(Hint *base, PlannerInfo *root, List *initial_rels,
3780                 int nrels, char **relnames)
3781 {
3782         int             relid;
3783         Relids  relids = NULL;
3784         int             j;
3785         char   *relname;
3786
3787         for (j = 0; j < nrels; j++)
3788         {
3789                 relname = relnames[j];
3790
3791                 relid = find_relid_aliasname(root, relname, initial_rels,
3792                                                                          base->hint_str);
3793
3794                 if (relid == -1)
3795                         base->state = HINT_STATE_ERROR;
3796
3797                 /*
3798                  * the aliasname is not found(relid == 0) or same aliasname was used
3799                  * multiple times in a query(relid == -1)
3800                  */
3801                 if (relid <= 0)
3802                 {
3803                         relids = NULL;
3804                         break;
3805                 }
3806                 if (bms_is_member(relid, relids))
3807                 {
3808                         hint_ereport(base->hint_str,
3809                                                  ("Relation name \"%s\" is duplicated.", relname));
3810                         base->state = HINT_STATE_ERROR;
3811                         break;
3812                 }
3813
3814                 relids = bms_add_member(relids, relid);
3815         }
3816         return relids;
3817 }
3818 /*
3819  * Transform join method hint into handy form.
3820  *
3821  *   - create bitmap of relids from alias names, to make it easier to check
3822  *     whether a join path matches a join method hint.
3823  *   - add join method hints which are necessary to enforce join order
3824  *     specified by Leading hint
3825  */
3826 static bool
3827 transform_join_hints(HintState *hstate, PlannerInfo *root, int nbaserel,
3828                 List *initial_rels, JoinMethodHint **join_method_hints)
3829 {
3830         int                             i;
3831         int                             relid;
3832         Relids                  joinrelids;
3833         int                             njoinrels;
3834         ListCell           *l;
3835         char               *relname;
3836         LeadingHint        *lhint = NULL;
3837
3838         /*
3839          * Create bitmap of relids from alias names for each join method hint.
3840          * Bitmaps are more handy than strings in join searching.
3841          */
3842         for (i = 0; i < hstate->num_hints[HINT_TYPE_JOIN_METHOD]; i++)
3843         {
3844                 JoinMethodHint *hint = hstate->join_hints[i];
3845
3846                 if (!hint_state_enabled(hint) || hint->nrels > nbaserel)
3847                         continue;
3848
3849                 hint->joinrelids = create_bms_of_relids(&(hint->base), root,
3850                                                                          initial_rels, hint->nrels, hint->relnames);
3851
3852                 if (hint->joinrelids == NULL || hint->base.state == HINT_STATE_ERROR)
3853                         continue;
3854
3855                 hstate->join_hint_level[hint->nrels] =
3856                         lappend(hstate->join_hint_level[hint->nrels], hint);
3857         }
3858
3859         /*
3860          * Create bitmap of relids from alias names for each rows hint.
3861          * Bitmaps are more handy than strings in join searching.
3862          */
3863         for (i = 0; i < hstate->num_hints[HINT_TYPE_ROWS]; i++)
3864         {
3865                 RowsHint *hint = hstate->rows_hints[i];
3866
3867                 if (!hint_state_enabled(hint) || hint->nrels > nbaserel)
3868                         continue;
3869
3870                 hint->joinrelids = create_bms_of_relids(&(hint->base), root,
3871                                                                          initial_rels, hint->nrels, hint->relnames);
3872         }
3873
3874         /* Do nothing if no Leading hint was supplied. */
3875         if (hstate->num_hints[HINT_TYPE_LEADING] == 0)
3876                 return false;
3877
3878         /*
3879          * Decide whether to use Leading hint
3880          */
3881         for (i = 0; i < hstate->num_hints[HINT_TYPE_LEADING]; i++)
3882         {
3883                 LeadingHint        *leading_hint = (LeadingHint *)hstate->leading_hint[i];
3884                 Relids                  relids;
3885
3886                 if (leading_hint->base.state == HINT_STATE_ERROR)
3887                         continue;
3888
3889                 relid = 0;
3890                 relids = NULL;
3891
3892                 foreach(l, leading_hint->relations)
3893                 {
3894                         relname = (char *)lfirst(l);;
3895
3896                         relid = find_relid_aliasname(root, relname, initial_rels,
3897                                                                                  leading_hint->base.hint_str);
3898                         if (relid == -1)
3899                                 leading_hint->base.state = HINT_STATE_ERROR;
3900
3901                         if (relid <= 0)
3902                                 break;
3903
3904                         if (bms_is_member(relid, relids))
3905                         {
3906                                 hint_ereport(leading_hint->base.hint_str,
3907                                                          ("Relation name \"%s\" is duplicated.", relname));
3908                                 leading_hint->base.state = HINT_STATE_ERROR;
3909                                 break;
3910                         }
3911
3912                         relids = bms_add_member(relids, relid);
3913                 }
3914
3915                 if (relid <= 0 || leading_hint->base.state == HINT_STATE_ERROR)
3916                         continue;
3917
3918                 if (lhint != NULL)
3919                 {
3920                         hint_ereport(lhint->base.hint_str,
3921                                  ("Conflict %s hint.", HintTypeName[lhint->base.type]));
3922                         lhint->base.state = HINT_STATE_DUPLICATION;
3923                 }
3924                 leading_hint->base.state = HINT_STATE_USED;
3925                 lhint = leading_hint;
3926         }
3927
3928         /* check to exist Leading hint marked with 'used'. */
3929         if (lhint == NULL)
3930                 return false;
3931
3932         /*
3933          * We need join method hints which fit specified join order in every join
3934          * level.  For example, Leading(A B C) virtually requires following join
3935          * method hints, if no join method hint supplied:
3936          *   - level 1: none
3937          *   - level 2: NestLoop(A B), MergeJoin(A B), HashJoin(A B)
3938          *   - level 3: NestLoop(A B C), MergeJoin(A B C), HashJoin(A B C)
3939          *
3940          * If we already have join method hint which fits specified join order in
3941          * that join level, we leave it as-is and don't add new hints.
3942          */
3943         joinrelids = NULL;
3944         njoinrels = 0;
3945         if (lhint->outer_inner == NULL)
3946         {
3947                 foreach(l, lhint->relations)
3948                 {
3949                         JoinMethodHint *hint;
3950
3951                         relname = (char *)lfirst(l);
3952
3953                         /*
3954                          * Find relid of the relation which has given name.  If we have the
3955                          * name given in Leading hint multiple times in the join, nothing to
3956                          * do.
3957                          */
3958                         relid = find_relid_aliasname(root, relname, initial_rels,
3959                                                                                  hstate->hint_str);
3960
3961                         /* Create bitmap of relids for current join level. */
3962                         joinrelids = bms_add_member(joinrelids, relid);
3963                         njoinrels++;
3964
3965                         /* We never have join method hint for single relation. */
3966                         if (njoinrels < 2)
3967                                 continue;
3968
3969                         /*
3970                          * If we don't have join method hint, create new one for the
3971                          * join combination with all join methods are enabled.
3972                          */
3973                         hint = find_join_hint(joinrelids);
3974                         if (hint == NULL)
3975                         {
3976                                 /*
3977                                  * Here relnames is not set, since Relids bitmap is sufficient
3978                                  * to control paths of this query afterward.
3979                                  */
3980                                 hint = (JoinMethodHint *) JoinMethodHintCreate(
3981                                                                                         lhint->base.hint_str,
3982                                                                                         HINT_LEADING,
3983                                                                                         HINT_KEYWORD_LEADING);
3984                                 hint->base.state = HINT_STATE_USED;
3985                                 hint->nrels = njoinrels;
3986                                 hint->enforce_mask = ENABLE_ALL_JOIN;
3987                                 hint->joinrelids = bms_copy(joinrelids);
3988                         }
3989
3990                         join_method_hints[njoinrels] = hint;
3991
3992                         if (njoinrels >= nbaserel)
3993                                 break;
3994                 }
3995                 bms_free(joinrelids);
3996
3997                 if (njoinrels < 2)
3998                         return false;
3999
4000                 /*
4001                  * Delete all join hints which have different combination from Leading
4002                  * hint.
4003                  */
4004                 for (i = 2; i <= njoinrels; i++)
4005                 {
4006                         list_free(hstate->join_hint_level[i]);
4007
4008                         hstate->join_hint_level[i] = lappend(NIL, join_method_hints[i]);
4009                 }
4010         }
4011         else
4012         {
4013                 joinrelids = OuterInnerJoinCreate(lhint->outer_inner,
4014                                                                                   lhint,
4015                                           root,
4016                                           initial_rels,
4017                                                                                   hstate,
4018                                                                                   nbaserel);
4019
4020                 njoinrels = bms_num_members(joinrelids);
4021                 Assert(njoinrels >= 2);
4022
4023                 /*
4024                  * Delete all join hints which have different combination from Leading
4025                  * hint.
4026                  */
4027                 for (i = 2;i <= njoinrels; i++)
4028                 {
4029                         if (hstate->join_hint_level[i] != NIL)
4030                         {
4031                                 ListCell *prev = NULL;
4032                                 ListCell *next = NULL;
4033                                 for(l = list_head(hstate->join_hint_level[i]); l; l = next)
4034                                 {
4035
4036                                         JoinMethodHint *hint = (JoinMethodHint *)lfirst(l);
4037
4038                                         next = lnext(l);
4039
4040                                         if (hint->inner_nrels == 0 &&
4041                                                 !(bms_intersect(hint->joinrelids, joinrelids) == NULL ||
4042                                                   bms_equal(bms_union(hint->joinrelids, joinrelids),
4043                                                   hint->joinrelids)))
4044                                         {
4045                                                 hstate->join_hint_level[i] =
4046                                                         list_delete_cell(hstate->join_hint_level[i], l,
4047                                                                                          prev);
4048                                         }
4049                                         else
4050                                                 prev = l;
4051                                 }
4052                         }
4053                 }
4054
4055                 bms_free(joinrelids);
4056         }
4057
4058         if (hint_state_enabled(lhint))
4059         {
4060                 set_join_config_options(DISABLE_ALL_JOIN, current_hint_state->context);
4061                 return true;
4062         }
4063         return false;
4064 }
4065
4066 /*
4067  * wrapper of make_join_rel()
4068  *
4069  * call make_join_rel() after changing enable_* parameters according to given
4070  * hints.
4071  */
4072 static RelOptInfo *
4073 make_join_rel_wrapper(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
4074 {
4075         Relids                  joinrelids;
4076         JoinMethodHint *hint;
4077         RelOptInfo         *rel;
4078         int                             save_nestlevel;
4079
4080         joinrelids = bms_union(rel1->relids, rel2->relids);
4081         hint = find_join_hint(joinrelids);
4082         bms_free(joinrelids);
4083
4084         if (!hint)
4085                 return pg_hint_plan_make_join_rel(root, rel1, rel2);
4086
4087         if (hint->inner_nrels == 0)
4088         {
4089                 save_nestlevel = NewGUCNestLevel();
4090
4091                 set_join_config_options(hint->enforce_mask,
4092                                                                 current_hint_state->context);
4093
4094                 rel = pg_hint_plan_make_join_rel(root, rel1, rel2);
4095                 hint->base.state = HINT_STATE_USED;
4096
4097                 /*
4098                  * Restore the GUC variables we set above.
4099                  */
4100                 AtEOXact_GUC(true, save_nestlevel);
4101         }
4102         else
4103                 rel = pg_hint_plan_make_join_rel(root, rel1, rel2);
4104
4105         return rel;
4106 }
4107
4108 /*
4109  * TODO : comment
4110  */
4111 static void
4112 add_paths_to_joinrel_wrapper(PlannerInfo *root,
4113                                                          RelOptInfo *joinrel,
4114                                                          RelOptInfo *outerrel,
4115                                                          RelOptInfo *innerrel,
4116                                                          JoinType jointype,
4117                                                          SpecialJoinInfo *sjinfo,
4118                                                          List *restrictlist)
4119 {
4120         ScanMethodHint *scan_hint = NULL;
4121         Relids                  joinrelids;
4122         JoinMethodHint *join_hint;
4123         int                             save_nestlevel;
4124
4125         if ((scan_hint = find_scan_hint(root, innerrel->relid, innerrel)) != NULL)
4126                 setup_scan_method_enforcement(scan_hint, current_hint_state);
4127
4128         joinrelids = bms_union(outerrel->relids, innerrel->relids);
4129         join_hint = find_join_hint(joinrelids);
4130         bms_free(joinrelids);
4131
4132         if (join_hint && join_hint->inner_nrels != 0)
4133         {
4134                 save_nestlevel = NewGUCNestLevel();
4135
4136                 if (bms_equal(join_hint->inner_joinrelids, innerrel->relids))
4137                 {
4138
4139                         set_join_config_options(join_hint->enforce_mask,
4140                                                                         current_hint_state->context);
4141
4142                         add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
4143                                                                  sjinfo, restrictlist);
4144                         join_hint->base.state = HINT_STATE_USED;
4145                 }
4146                 else
4147                 {
4148                         set_join_config_options(DISABLE_ALL_JOIN,
4149                                                                         current_hint_state->context);
4150                         add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
4151                                                                  sjinfo, restrictlist);
4152                 }
4153
4154                 /*
4155                  * Restore the GUC variables we set above.
4156                  */
4157                 AtEOXact_GUC(true, save_nestlevel);
4158         }
4159         else
4160                 add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
4161                                                          sjinfo, restrictlist);
4162
4163         /* Reset the environment if changed */
4164         if (scan_hint != NULL)
4165                 setup_scan_method_enforcement(NULL, current_hint_state);
4166 }
4167
4168 static int
4169 get_num_baserels(List *initial_rels)
4170 {
4171         int                     nbaserel = 0;
4172         ListCell   *l;
4173
4174         foreach(l, initial_rels)
4175         {
4176                 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
4177
4178                 if (rel->reloptkind == RELOPT_BASEREL)
4179                         nbaserel++;
4180                 else if (rel->reloptkind ==RELOPT_JOINREL)
4181                         nbaserel+= bms_num_members(rel->relids);
4182                 else
4183                 {
4184                         /* other values not expected here */
4185                         elog(ERROR, "unrecognized reloptkind type: %d", rel->reloptkind);
4186                 }
4187         }
4188
4189         return nbaserel;
4190 }
4191
4192 static RelOptInfo *
4193 pg_hint_plan_join_search(PlannerInfo *root, int levels_needed,
4194                                                  List *initial_rels)
4195 {
4196         JoinMethodHint    **join_method_hints;
4197         int                                     nbaserel;
4198         RelOptInfo                 *rel;
4199         int                                     i;
4200         bool                            leading_hint_enable;
4201
4202         /*
4203          * Use standard planner (or geqo planner) if pg_hint_plan is disabled or no
4204          * valid hint is supplied or current nesting depth is nesting depth of SPI
4205          * calls.
4206          */
4207         if (!current_hint_state || hint_inhibit_level > 0)
4208         {
4209                 if (prev_join_search)
4210                         return (*prev_join_search) (root, levels_needed, initial_rels);
4211                 else if (enable_geqo && levels_needed >= geqo_threshold)
4212                         return geqo(root, levels_needed, initial_rels);
4213                 else
4214                         return standard_join_search(root, levels_needed, initial_rels);
4215         }
4216
4217         /*
4218          * In the case using GEQO, only scan method hints and Set hints have
4219          * effect.  Join method and join order is not controllable by hints.
4220          */
4221         if (enable_geqo && levels_needed >= geqo_threshold)
4222                 return geqo(root, levels_needed, initial_rels);
4223
4224         nbaserel = get_num_baserels(initial_rels);
4225         current_hint_state->join_hint_level =
4226                 palloc0(sizeof(List *) * (nbaserel + 1));
4227         join_method_hints = palloc0(sizeof(JoinMethodHint *) * (nbaserel + 1));
4228
4229         leading_hint_enable = transform_join_hints(current_hint_state,
4230                                                                                            root, nbaserel,
4231                                                                                            initial_rels, join_method_hints);
4232
4233         rel = pg_hint_plan_standard_join_search(root, levels_needed, initial_rels);
4234
4235         for (i = 2; i <= nbaserel; i++)
4236         {
4237                 list_free(current_hint_state->join_hint_level[i]);
4238
4239                 /* free Leading hint only */
4240                 if (join_method_hints[i] != NULL &&
4241                         join_method_hints[i]->enforce_mask == ENABLE_ALL_JOIN)
4242                         JoinMethodHintDelete(join_method_hints[i]);
4243         }
4244         pfree(current_hint_state->join_hint_level);
4245         pfree(join_method_hints);
4246
4247         if (leading_hint_enable)
4248                 set_join_config_options(current_hint_state->init_join_mask,
4249                                                                 current_hint_state->context);
4250
4251         return rel;
4252 }
4253
4254 /*
4255  * Force number of wokers if instructed by hint
4256  */
4257 void
4258 pg_hint_plan_set_rel_pathlist(PlannerInfo * root, RelOptInfo *rel,
4259                                                           Index rti, RangeTblEntry *rte)
4260 {
4261         ParallelHint   *phint;
4262         ListCell           *l;
4263
4264         /* call the previous hook */
4265         if (prev_set_rel_pathlist)
4266                 prev_set_rel_pathlist(root, rel, rti, rte);
4267
4268         /* Nothing to do when hint has not been parsed yet */
4269         if (current_hint_state == NULL)
4270                 return;
4271
4272         /* Don't touch dummy rel */
4273         if (IS_DUMMY_REL(rel))
4274                 return;
4275
4276         /* We cannot handle if this requires an outer */
4277         if (rel->lateral_relids)
4278                 return;
4279
4280         if (!setup_hint_enforcement(root, rel))
4281         {
4282                 /*
4283                  * No enforcement requested, but we might have to generate gather
4284                  * path on this relation
4285                  */
4286
4287                 /* If no need of a gather path, just return */
4288                 if (rel->reloptkind != RELOPT_BASEREL || max_hint_nworkers < 1 ||
4289                         rel->partial_pathlist == NIL)
4290                         return;
4291
4292                 /* Lower the priorities of existing paths, then add a new path */
4293                 foreach (l, rel->pathlist)
4294                 {
4295                         Path *path = (Path *) lfirst(l);
4296
4297                         if (path->startup_cost < disable_cost)
4298                         {
4299                                 path->startup_cost += disable_cost;
4300                                 path->total_cost += disable_cost;
4301                         }
4302                 }
4303
4304                 generate_gather_paths(root, rel);
4305                 return;
4306         }
4307
4308         /* Here, we regenerate paths with the current hint restriction */
4309
4310         /* Remove prviously paths except dummy rels */
4311         list_free_deep(rel->pathlist);
4312         rel->pathlist = NIL;
4313
4314         /* Rebuild access paths */
4315         set_plain_rel_pathlist(root, rel, rte);
4316
4317         /*
4318          * create_plain_partial_paths creates partial paths with reasonably
4319          * estimated number of workers. Force the requested number of workers if
4320          * hard mode.
4321          */
4322         phint = find_parallel_hint(root, rel->relid, rel);
4323
4324         if (phint)
4325         {
4326                 /* if inhibiting parallel, remove existing partial paths  */
4327                 if (phint->nworkers == 0 && rel->partial_pathlist)
4328                 {
4329                         list_free_deep(rel->partial_pathlist);
4330                         rel->partial_pathlist = NIL;
4331                 }
4332
4333                 /* enforce number of workers if requested */
4334                 if (rel->partial_pathlist && phint->force_parallel)
4335                 {
4336                         foreach (l, rel->partial_pathlist)
4337                         {
4338                                 Path *ppath = (Path *) lfirst(l);
4339
4340                                 ppath->parallel_workers = phint->nworkers;
4341                         }
4342                 }
4343
4344                 /* Generate gather paths for base rels */
4345                 if (rel->reloptkind == RELOPT_BASEREL)
4346                         generate_gather_paths(root, rel);
4347         }
4348
4349         reset_hint_enforcement();
4350 }
4351
4352 /*
4353  * set_rel_pathlist
4354  *        Build access paths for a base relation
4355  *
4356  * This function was copied and edited from set_rel_pathlist() in
4357  * src/backend/optimizer/path/allpaths.c in order not to copy other static
4358  * functions not required here.
4359  */
4360 static void
4361 set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
4362                                  Index rti, RangeTblEntry *rte)
4363 {
4364         if (IS_DUMMY_REL(rel))
4365         {
4366                 /* We already proved the relation empty, so nothing more to do */
4367         }
4368         else if (rte->inh)
4369         {
4370                 /* It's an "append relation", process accordingly */
4371                 set_append_rel_pathlist(root, rel, rti, rte);
4372         }
4373         else
4374         {
4375                 if (rel->rtekind == RTE_RELATION)
4376                 {
4377                         if (rte->relkind == RELKIND_RELATION)
4378                         {
4379                                 if(rte->tablesample != NULL)
4380                                         elog(ERROR, "sampled relation is not supported");
4381
4382                                 /* Plain relation */
4383                                 set_plain_rel_pathlist(root, rel, rte);
4384                         }
4385                         else
4386                                 elog(ERROR, "unexpected relkind: %c", rte->relkind);
4387                 }
4388                 else
4389                         elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
4390         }
4391
4392         /*
4393          * Allow a plugin to editorialize on the set of Paths for this base
4394          * relation.  It could add new paths (such as CustomPaths) by calling
4395          * add_path(), or delete or modify paths added by the core code.
4396          */
4397         if (set_rel_pathlist_hook)
4398                 (*set_rel_pathlist_hook) (root, rel, rti, rte);
4399
4400         /* Now find the cheapest of the paths for this rel */
4401         set_cheapest(rel);
4402 }
4403
4404 /*
4405  * stmt_beg callback is called when each query in PL/pgSQL function is about
4406  * to be executed.  At that timing, we save query string in the global variable
4407  * plpgsql_query_string to use it in planner hook.  It's safe to use one global
4408  * variable for the purpose, because its content is only necessary until
4409  * planner hook is called for the query, so recursive PL/pgSQL function calls
4410  * don't harm this mechanism.
4411  */
4412 static void
4413 pg_hint_plan_plpgsql_stmt_beg(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
4414 {
4415         plpgsql_recurse_level++;
4416 }
4417
4418 /*
4419  * stmt_end callback is called then each query in PL/pgSQL function has
4420  * finished.  At that timing, we clear plpgsql_query_string to tell planner
4421  * hook that next call is not for a query written in PL/pgSQL block.
4422  */
4423 static void
4424 pg_hint_plan_plpgsql_stmt_end(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
4425 {
4426         plpgsql_recurse_level--;
4427 }
4428
4429 void plpgsql_query_erase_callback(ResourceReleasePhase phase,
4430                                                                   bool isCommit,
4431                                                                   bool isTopLevel,
4432                                                                   void *arg)
4433 {
4434         if (phase != RESOURCE_RELEASE_AFTER_LOCKS)
4435                 return;
4436         /* Cancel plpgsql nest level*/
4437         plpgsql_recurse_level = 0;
4438 }
4439
4440 #define standard_join_search pg_hint_plan_standard_join_search
4441 #define join_search_one_level pg_hint_plan_join_search_one_level
4442 #define make_join_rel make_join_rel_wrapper
4443 #include "core.c"
4444
4445 #undef make_join_rel
4446 #define make_join_rel pg_hint_plan_make_join_rel
4447 #define add_paths_to_joinrel add_paths_to_joinrel_wrapper
4448 #include "make_join_rel.c"
4449
4450 #include "pg_stat_statements.c"