OSDN Git Service

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