OSDN Git Service

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