OSDN Git Service

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