OSDN Git Service

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