OSDN Git Service

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