OSDN Git Service

Enhance comments.
[pghintplan/pg_hint_plan.git] / pg_hint_plan.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_hint_plan.c
4  *                do instructions or hints to the planner using C-style block comments
5  *                of the SQL.
6  *
7  * Copyright (c) 2012-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
8  *
9  *-------------------------------------------------------------------------
10  */
11 #include "postgres.h"
12 #include "catalog/pg_collation.h"
13 #include "catalog/pg_index.h"
14 #include "commands/prepare.h"
15 #include "mb/pg_wchar.h"
16 #include "miscadmin.h"
17 #include "nodes/nodeFuncs.h"
18 #include "optimizer/clauses.h"
19 #include "optimizer/cost.h"
20 #include "optimizer/geqo.h"
21 #include "optimizer/joininfo.h"
22 #include "optimizer/pathnode.h"
23 #include "optimizer/paths.h"
24 #include "optimizer/plancat.h"
25 #include "optimizer/planner.h"
26 #include "optimizer/prep.h"
27 #include "optimizer/restrictinfo.h"
28 #include "parser/scansup.h"
29 #include "tcop/utility.h"
30 #include "utils/builtins.h"
31 #include "utils/lsyscache.h"
32 #include "utils/memutils.h"
33 #include "utils/rel.h"
34 #include "utils/syscache.h"
35 #if PG_VERSION_NUM >= 90200
36 #include "catalog/pg_class.h"
37 #endif
38
39 #include "executor/spi.h"
40 #include "catalog/pg_type.h"
41 #include "plpgsql.h"
42
43 /* partially copied from pg_stat_statements */
44 #include "normalize_query.h"
45
46 #ifdef PG_MODULE_MAGIC
47 PG_MODULE_MAGIC;
48 #endif
49
50 #if PG_VERSION_NUM < 90100
51 #error unsupported PostgreSQL version
52 #endif
53
54 #define BLOCK_COMMENT_START             "/*"
55 #define BLOCK_COMMENT_END               "*/"
56 #define HINT_COMMENT_KEYWORD    "+"
57 #define HINT_START                              BLOCK_COMMENT_START HINT_COMMENT_KEYWORD
58 #define HINT_END                                BLOCK_COMMENT_END
59
60 /* hint keywords */
61 #define HINT_SEQSCAN                    "SeqScan"
62 #define HINT_INDEXSCAN                  "IndexScan"
63 #define HINT_INDEXSCANREGEXP    "IndexScanRegexp"
64 #define HINT_BITMAPSCAN                 "BitmapScan"
65 #define HINT_BITMAPSCANREGEXP   "BitmapScanRegexp"
66 #define HINT_TIDSCAN                    "TidScan"
67 #define HINT_NOSEQSCAN                  "NoSeqScan"
68 #define HINT_NOINDEXSCAN                "NoIndexScan"
69 #define HINT_NOBITMAPSCAN               "NoBitmapScan"
70 #define HINT_NOTIDSCAN                  "NoTidScan"
71 #if PG_VERSION_NUM >= 90200
72 #define HINT_INDEXONLYSCAN              "IndexOnlyScan"
73 #define HINT_INDEXONLYSCANREGEXP        "IndexOnlyScanRegexp"
74 #define HINT_NOINDEXONLYSCAN    "NoIndexOnlyScan"
75 #endif
76 #define HINT_NESTLOOP                   "NestLoop"
77 #define HINT_MERGEJOIN                  "MergeJoin"
78 #define HINT_HASHJOIN                   "HashJoin"
79 #define HINT_NONESTLOOP                 "NoNestLoop"
80 #define HINT_NOMERGEJOIN                "NoMergeJoin"
81 #define HINT_NOHASHJOIN                 "NoHashJoin"
82 #define HINT_LEADING                    "Leading"
83 #define HINT_SET                                "Set"
84
85 #define HINT_ARRAY_DEFAULT_INITSIZE 8
86
87 #define hint_ereport(str, detail) \
88         ereport(pg_hint_plan_parse_messages, \
89                         (errmsg("hint syntax error at or near \"%s\"", (str)), \
90                          errdetail detail))
91
92 #define skip_space(str) \
93         while (isspace(*str)) \
94                 str++;
95
96 enum
97 {
98         ENABLE_SEQSCAN = 0x01,
99         ENABLE_INDEXSCAN = 0x02,
100         ENABLE_BITMAPSCAN = 0x04,
101         ENABLE_TIDSCAN = 0x08,
102 #if PG_VERSION_NUM >= 90200
103         ENABLE_INDEXONLYSCAN = 0x10
104 #endif
105 } SCAN_TYPE_BITS;
106
107 enum
108 {
109         ENABLE_NESTLOOP = 0x01,
110         ENABLE_MERGEJOIN = 0x02,
111         ENABLE_HASHJOIN = 0x04
112 } JOIN_TYPE_BITS;
113
114 #if PG_VERSION_NUM >= 90200
115 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | \
116                                                  ENABLE_BITMAPSCAN | ENABLE_TIDSCAN | \
117                                                  ENABLE_INDEXONLYSCAN)
118 #else
119 #define ENABLE_ALL_SCAN (ENABLE_SEQSCAN | ENABLE_INDEXSCAN | \
120                                                  ENABLE_BITMAPSCAN | ENABLE_TIDSCAN)
121 #endif
122 #define ENABLE_ALL_JOIN (ENABLE_NESTLOOP | ENABLE_MERGEJOIN | ENABLE_HASHJOIN)
123 #define DISABLE_ALL_SCAN 0
124 #define DISABLE_ALL_JOIN 0
125
126 /* hint keyword of enum type*/
127 typedef enum HintKeyword
128 {
129         HINT_KEYWORD_SEQSCAN,
130         HINT_KEYWORD_INDEXSCAN,
131         HINT_KEYWORD_INDEXSCANREGEXP,
132         HINT_KEYWORD_BITMAPSCAN,
133         HINT_KEYWORD_BITMAPSCANREGEXP,
134         HINT_KEYWORD_TIDSCAN,
135         HINT_KEYWORD_NOSEQSCAN,
136         HINT_KEYWORD_NOINDEXSCAN,
137         HINT_KEYWORD_NOBITMAPSCAN,
138         HINT_KEYWORD_NOTIDSCAN,
139 #if PG_VERSION_NUM >= 90200
140         HINT_KEYWORD_INDEXONLYSCAN,
141         HINT_KEYWORD_INDEXONLYSCANREGEXP,
142         HINT_KEYWORD_NOINDEXONLYSCAN,
143 #endif
144         HINT_KEYWORD_NESTLOOP,
145         HINT_KEYWORD_MERGEJOIN,
146         HINT_KEYWORD_HASHJOIN,
147         HINT_KEYWORD_NONESTLOOP,
148         HINT_KEYWORD_NOMERGEJOIN,
149         HINT_KEYWORD_NOHASHJOIN,
150         HINT_KEYWORD_LEADING,
151         HINT_KEYWORD_SET,
152         HINT_KEYWORD_UNRECOGNIZED
153 } HintKeyword;
154
155 typedef struct Hint Hint;
156 typedef struct HintState HintState;
157
158 typedef Hint *(*HintCreateFunction) (const char *hint_str,
159                                                                          const char *keyword,
160                                                                          HintKeyword hint_keyword);
161 typedef void (*HintDeleteFunction) (Hint *hint);
162 typedef void (*HintDescFunction) (Hint *hint, StringInfo buf);
163 typedef int (*HintCmpFunction) (const Hint *a, const Hint *b);
164 typedef const char *(*HintParseFunction) (Hint *hint, HintState *hstate,
165                                                                                   Query *parse, const char *str);
166
167 /* hint types */
168 #define NUM_HINT_TYPE   4
169 typedef enum HintType
170 {
171         HINT_TYPE_SCAN_METHOD,
172         HINT_TYPE_JOIN_METHOD,
173         HINT_TYPE_LEADING,
174         HINT_TYPE_SET
175 } HintType;
176
177 static const char *HintTypeName[] = {
178         "scan method",
179         "join method",
180         "leading",
181         "set"
182 };
183
184 /* hint status */
185 typedef enum HintStatus
186 {
187         HINT_STATE_NOTUSED = 0,         /* specified relation not used in query */
188         HINT_STATE_USED,                        /* hint is used */
189         HINT_STATE_DUPLICATION,         /* specified hint duplication */
190         HINT_STATE_ERROR                        /* execute error (parse error does not include
191                                                                  * it) */
192 } HintStatus;
193
194 #define hint_state_enabled(hint) ((hint)->base.state == HINT_STATE_NOTUSED || \
195                                                                   (hint)->base.state == HINT_STATE_USED)
196
197 /* common data for all hints. */
198 struct Hint
199 {
200         const char                 *hint_str;           /* must not do pfree */
201         const char                 *keyword;            /* must not do pfree */
202         HintKeyword                     hint_keyword;
203         HintType                        type;
204         HintStatus                      state;
205         HintDeleteFunction      delete_func;
206         HintDescFunction        desc_func;
207         HintCmpFunction         cmp_func;
208         HintParseFunction       parse_func;
209 };
210
211 /* scan method hints */
212 typedef struct ScanMethodHint
213 {
214         Hint                    base;
215         char               *relname;
216         List               *indexnames;
217         bool                    regexp;
218         unsigned char   enforce_mask;
219 } ScanMethodHint;
220
221 typedef struct ParentIndexInfo
222 {
223         bool            indisunique;
224         Oid                     method;
225         List       *column_names;
226         char       *expression_str;
227         Oid                *indcollation;
228         Oid                *opclass;
229         int16      *indoption;
230         char       *indpred_str;
231 } ParentIndexInfo;
232
233 /* join method hints */
234 typedef struct JoinMethodHint
235 {
236         Hint                    base;
237         int                             nrels;
238         int                             inner_nrels;
239         char              **relnames;
240         unsigned char   enforce_mask;
241         Relids                  joinrelids;
242         Relids                  inner_joinrelids;
243 } JoinMethodHint;
244
245 /* join order hints */
246 typedef struct OuterInnerRels
247 {
248         char   *relation;
249         List   *outer_inner_pair;
250 } OuterInnerRels;
251
252 typedef struct LeadingHint
253 {
254         Hint                    base;
255         List               *relations;  /* relation names specified in Leading hint */
256         OuterInnerRels *outer_inner;
257 } LeadingHint;
258
259 /* change a run-time parameter hints */
260 typedef struct SetHint
261 {
262         Hint    base;
263         char   *name;                           /* name of variable */
264         char   *value;
265         List   *words;
266 } SetHint;
267
268 /*
269  * Describes a context of hint processing.
270  */
271 struct HintState
272 {
273         char               *hint_str;                   /* original hint string */
274
275         /* all hint */
276         int                             nall_hints;                     /* # of valid all hints */
277         int                             max_all_hints;          /* # of slots for all hints */
278         Hint              **all_hints;                  /* parsed all hints */
279
280         /* # of each hints */
281         int                             num_hints[NUM_HINT_TYPE];
282
283         /* for scan method hints */
284         ScanMethodHint **scan_hints;            /* parsed scan hints */
285         int                             init_scan_mask;         /* initial value scan parameter */
286         Index                   parent_relid;           /* inherit parent table relid */
287         Oid                             parent_rel_oid;     /* inherit parent table relid */
288         ScanMethodHint *parent_hint;            /* inherit parent table scan hint */
289         List               *parent_index_infos; /* infomation of inherit parent table's
290                                                                                  * index */
291
292         /* for join method hints */
293         JoinMethodHint **join_hints;            /* parsed join hints */
294         int                             init_join_mask;         /* initial value join parameter */
295         List              **join_hint_level;
296
297         /* for Leading hint */
298         LeadingHint       **leading_hint;               /* parsed Leading hints */
299
300         /* for Set hints */
301         SetHint           **set_hints;                  /* parsed Set hints */
302         GucContext              context;                        /* which GUC parameters can we set? */
303 };
304
305 /*
306  * Describes a hint parser module which is bound with particular hint keyword.
307  */
308 typedef struct HintParser
309 {
310         char                       *keyword;
311         HintCreateFunction      create_func;
312         HintKeyword                     hint_keyword;
313 } HintParser;
314
315 /* Module callbacks */
316 void            _PG_init(void);
317 void            _PG_fini(void);
318
319 static void push_hint(HintState *hstate);
320 static void pop_hint(void);
321
322 static void pg_hint_plan_ProcessUtility(Node *parsetree,
323                                                                                 const char *queryString,
324                                                                                 ParamListInfo params, bool isTopLevel,
325                                                                                 DestReceiver *dest,
326                                                                                 char *completionTag);
327 static PlannedStmt *pg_hint_plan_planner(Query *parse, int cursorOptions,
328                                                                                  ParamListInfo boundParams);
329 static void pg_hint_plan_get_relation_info(PlannerInfo *root,
330                                                                                    Oid relationObjectId,
331                                                                                    bool inhparent, RelOptInfo *rel);
332 static RelOptInfo *pg_hint_plan_join_search(PlannerInfo *root,
333                                                                                         int levels_needed,
334                                                                                         List *initial_rels);
335
336 static Hint *ScanMethodHintCreate(const char *hint_str, const char *keyword,
337                                                                   HintKeyword hint_keyword);
338 static void ScanMethodHintDelete(ScanMethodHint *hint);
339 static void ScanMethodHintDesc(ScanMethodHint *hint, StringInfo buf);
340 static int ScanMethodHintCmp(const ScanMethodHint *a, const ScanMethodHint *b);
341 static const char *ScanMethodHintParse(ScanMethodHint *hint, HintState *hstate,
342                                                                            Query *parse, const char *str);
343 static Hint *JoinMethodHintCreate(const char *hint_str, const char *keyword,
344                                                                   HintKeyword hint_keyword);
345 static void JoinMethodHintDelete(JoinMethodHint *hint);
346 static void JoinMethodHintDesc(JoinMethodHint *hint, StringInfo buf);
347 static int JoinMethodHintCmp(const JoinMethodHint *a, const JoinMethodHint *b);
348 static const char *JoinMethodHintParse(JoinMethodHint *hint, HintState *hstate,
349                                                                            Query *parse, const char *str);
350 static Hint *LeadingHintCreate(const char *hint_str, const char *keyword,
351                                                            HintKeyword hint_keyword);
352 static void LeadingHintDelete(LeadingHint *hint);
353 static void LeadingHintDesc(LeadingHint *hint, StringInfo buf);
354 static int LeadingHintCmp(const LeadingHint *a, const LeadingHint *b);
355 static const char *LeadingHintParse(LeadingHint *hint, HintState *hstate,
356                                                                         Query *parse, const char *str);
357 static Hint *SetHintCreate(const char *hint_str, const char *keyword,
358                                                    HintKeyword hint_keyword);
359 static void SetHintDelete(SetHint *hint);
360 static void SetHintDesc(SetHint *hint, StringInfo buf);
361 static int SetHintCmp(const SetHint *a, const SetHint *b);
362 static const char *SetHintParse(SetHint *hint, HintState *hstate, Query *parse,
363                                                                 const char *str);
364
365 static void quote_value(StringInfo buf, const char *value);
366
367 static const char *parse_quoted_value(const char *str, char **word,
368                                                                           bool truncate);
369
370 RelOptInfo *pg_hint_plan_standard_join_search(PlannerInfo *root,
371                                                                                           int levels_needed,
372                                                                                           List *initial_rels);
373 void pg_hint_plan_join_search_one_level(PlannerInfo *root, int level);
374 static void make_rels_by_clause_joins(PlannerInfo *root, RelOptInfo *old_rel,
375                                                                           ListCell *other_rels);
376 static void make_rels_by_clauseless_joins(PlannerInfo *root,
377                                                                                   RelOptInfo *old_rel,
378                                                                                   ListCell *other_rels);
379 static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
380 static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
381                                                                         Index rti, RangeTblEntry *rte);
382 #if PG_VERSION_NUM >= 90200
383 static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
384                                                    List *live_childrels,
385                                                    List *all_child_pathkeys);
386 #endif
387 static List *accumulate_append_subpath(List *subpaths, Path *path);
388 #if PG_VERSION_NUM < 90200
389 static void set_dummy_rel_pathlist(RelOptInfo *rel);
390 #endif
391 RelOptInfo *pg_hint_plan_make_join_rel(PlannerInfo *root, RelOptInfo *rel1,
392                                                                            RelOptInfo *rel2);
393
394 static void pg_hint_plan_plpgsql_stmt_beg(PLpgSQL_execstate *estate,
395                                                                                   PLpgSQL_stmt *stmt);
396 static void pg_hint_plan_plpgsql_stmt_end(PLpgSQL_execstate *estate,
397                                                                                   PLpgSQL_stmt *stmt);
398
399 /* GUC variables */
400 static bool     pg_hint_plan_enable_hint = true;
401 static bool     pg_hint_plan_debug_print = false;
402 static int      pg_hint_plan_parse_messages = INFO;
403
404 static const struct config_enum_entry parse_messages_level_options[] = {
405         {"debug", DEBUG2, true},
406         {"debug5", DEBUG5, false},
407         {"debug4", DEBUG4, false},
408         {"debug3", DEBUG3, false},
409         {"debug2", DEBUG2, false},
410         {"debug1", DEBUG1, false},
411         {"log", LOG, false},
412         {"info", INFO, false},
413         {"notice", NOTICE, false},
414         {"warning", WARNING, false},
415         {"error", ERROR, false},
416         /*
417          * {"fatal", FATAL, true},
418          * {"panic", PANIC, true},
419          */
420         {NULL, 0, false}
421 };
422
423 /* Saved hook values in case of unload */
424 static ProcessUtility_hook_type prev_ProcessUtility = NULL;
425 static planner_hook_type prev_planner = NULL;
426 static get_relation_info_hook_type prev_get_relation_info = NULL;
427 static join_search_hook_type prev_join_search = NULL;
428
429 /* Hold reference to currently active hint */
430 static HintState *current_hint = NULL;
431
432 /*
433  * List of hint contexts.  We treat the head of the list as the Top of the
434  * context stack, so current_hint always points the first element of this list.
435  */
436 static List *HintStateStack = NIL;
437
438 /*
439  * Holds statement name during executing EXECUTE command.  NULL for other
440  * statements.
441  */
442 static char        *stmt_name = NULL;
443
444 static const HintParser parsers[] = {
445         {HINT_SEQSCAN, ScanMethodHintCreate, HINT_KEYWORD_SEQSCAN},
446         {HINT_INDEXSCAN, ScanMethodHintCreate, HINT_KEYWORD_INDEXSCAN},
447         {HINT_INDEXSCANREGEXP, ScanMethodHintCreate, HINT_KEYWORD_INDEXSCANREGEXP},
448         {HINT_BITMAPSCAN, ScanMethodHintCreate, HINT_KEYWORD_BITMAPSCAN},
449         {HINT_BITMAPSCANREGEXP, ScanMethodHintCreate,
450          HINT_KEYWORD_BITMAPSCANREGEXP},
451         {HINT_TIDSCAN, ScanMethodHintCreate, HINT_KEYWORD_TIDSCAN},
452         {HINT_NOSEQSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOSEQSCAN},
453         {HINT_NOINDEXSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOINDEXSCAN},
454         {HINT_NOBITMAPSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOBITMAPSCAN},
455         {HINT_NOTIDSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOTIDSCAN},
456 #if PG_VERSION_NUM >= 90200
457         {HINT_INDEXONLYSCAN, ScanMethodHintCreate, HINT_KEYWORD_INDEXONLYSCAN},
458         {HINT_INDEXONLYSCANREGEXP, ScanMethodHintCreate,
459          HINT_KEYWORD_INDEXONLYSCANREGEXP},
460         {HINT_NOINDEXONLYSCAN, ScanMethodHintCreate, HINT_KEYWORD_NOINDEXONLYSCAN},
461 #endif
462         {HINT_NESTLOOP, JoinMethodHintCreate, HINT_KEYWORD_NESTLOOP},
463         {HINT_MERGEJOIN, JoinMethodHintCreate, HINT_KEYWORD_MERGEJOIN},
464         {HINT_HASHJOIN, JoinMethodHintCreate, HINT_KEYWORD_HASHJOIN},
465         {HINT_NONESTLOOP, JoinMethodHintCreate, HINT_KEYWORD_NONESTLOOP},
466         {HINT_NOMERGEJOIN, JoinMethodHintCreate, HINT_KEYWORD_NOMERGEJOIN},
467         {HINT_NOHASHJOIN, JoinMethodHintCreate, HINT_KEYWORD_NOHASHJOIN},
468         {HINT_LEADING, LeadingHintCreate, HINT_KEYWORD_LEADING},
469         {HINT_SET, SetHintCreate, HINT_KEYWORD_SET},
470         {NULL, NULL, HINT_KEYWORD_UNRECOGNIZED}
471 };
472
473 /*
474  * PL/pgSQL plugin for retrieving string representation of each query during
475  * function execution.
476  */
477 const char *plpgsql_query_string = NULL;
478 PLpgSQL_plugin  plugin_funcs = {
479         NULL,
480         NULL,
481         NULL,
482         pg_hint_plan_plpgsql_stmt_beg,
483         pg_hint_plan_plpgsql_stmt_end,
484         NULL,
485         NULL,
486 };
487
488 /*
489  * Module load callbacks
490  */
491 void
492 _PG_init(void)
493 {
494         PLpgSQL_plugin  **var_ptr;
495
496         /* Define custom GUC variables. */
497         DefineCustomBoolVariable("pg_hint_plan.enable_hint",
498                          "Force planner to use plans specified in the hint comment preceding to the query.",
499                                                          NULL,
500                                                          &pg_hint_plan_enable_hint,
501                                                          true,
502                                                          PGC_USERSET,
503                                                          0,
504                                                          NULL,
505                                                          NULL,
506                                                          NULL);
507
508         DefineCustomBoolVariable("pg_hint_plan.debug_print",
509                                                          "Logs results of hint parsing.",
510                                                          NULL,
511                                                          &pg_hint_plan_debug_print,
512                                                          false,
513                                                          PGC_USERSET,
514                                                          0,
515                                                          NULL,
516                                                          NULL,
517                                                          NULL);
518
519         DefineCustomEnumVariable("pg_hint_plan.parse_messages",
520                                                          "Message level of parse errors.",
521                                                          NULL,
522                                                          &pg_hint_plan_parse_messages,
523                                                          INFO,
524                                                          parse_messages_level_options,
525                                                          PGC_USERSET,
526                                                          0,
527                                                          NULL,
528                                                          NULL,
529                                                          NULL);
530
531         /* Install hooks. */
532         prev_ProcessUtility = ProcessUtility_hook;
533         ProcessUtility_hook = pg_hint_plan_ProcessUtility;
534         prev_planner = planner_hook;
535         planner_hook = pg_hint_plan_planner;
536         prev_get_relation_info = get_relation_info_hook;
537         get_relation_info_hook = pg_hint_plan_get_relation_info;
538         prev_join_search = join_search_hook;
539         join_search_hook = pg_hint_plan_join_search;
540
541         /* setup PL/pgSQL plugin hook */
542         var_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
543         *var_ptr = &plugin_funcs;
544 }
545
546 /*
547  * Module unload callback
548  * XXX never called
549  */
550 void
551 _PG_fini(void)
552 {
553         PLpgSQL_plugin  **var_ptr;
554
555         /* Uninstall hooks. */
556         ProcessUtility_hook = prev_ProcessUtility;
557         planner_hook = prev_planner;
558         get_relation_info_hook = prev_get_relation_info;
559         join_search_hook = prev_join_search;
560
561         /* uninstall PL/pgSQL plugin hook */
562         var_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
563         *var_ptr = NULL;
564 }
565
566 /*
567  * create and delete functions the hint object
568  */
569
570 static Hint *
571 ScanMethodHintCreate(const char *hint_str, const char *keyword,
572                                          HintKeyword hint_keyword)
573 {
574         ScanMethodHint *hint;
575
576         hint = palloc(sizeof(ScanMethodHint));
577         hint->base.hint_str = hint_str;
578         hint->base.keyword = keyword;
579         hint->base.hint_keyword = hint_keyword;
580         hint->base.type = HINT_TYPE_SCAN_METHOD;
581         hint->base.state = HINT_STATE_NOTUSED;
582         hint->base.delete_func = (HintDeleteFunction) ScanMethodHintDelete;
583         hint->base.desc_func = (HintDescFunction) ScanMethodHintDesc;
584         hint->base.cmp_func = (HintCmpFunction) ScanMethodHintCmp;
585         hint->base.parse_func = (HintParseFunction) ScanMethodHintParse;
586         hint->relname = NULL;
587         hint->indexnames = NIL;
588         hint->regexp = false;
589         hint->enforce_mask = 0;
590
591         return (Hint *) hint;
592 }
593
594 static void
595 ScanMethodHintDelete(ScanMethodHint *hint)
596 {
597         if (!hint)
598                 return;
599
600         if (hint->relname)
601                 pfree(hint->relname);
602         list_free_deep(hint->indexnames);
603         pfree(hint);
604 }
605
606 static Hint *
607 JoinMethodHintCreate(const char *hint_str, const char *keyword,
608                                          HintKeyword hint_keyword)
609 {
610         JoinMethodHint *hint;
611
612         hint = palloc(sizeof(JoinMethodHint));
613         hint->base.hint_str = hint_str;
614         hint->base.keyword = keyword;
615         hint->base.hint_keyword = hint_keyword;
616         hint->base.type = HINT_TYPE_JOIN_METHOD;
617         hint->base.state = HINT_STATE_NOTUSED;
618         hint->base.delete_func = (HintDeleteFunction) JoinMethodHintDelete;
619         hint->base.desc_func = (HintDescFunction) JoinMethodHintDesc;
620         hint->base.cmp_func = (HintCmpFunction) JoinMethodHintCmp;
621         hint->base.parse_func = (HintParseFunction) JoinMethodHintParse;
622         hint->nrels = 0;
623         hint->inner_nrels = 0;
624         hint->relnames = NULL;
625         hint->enforce_mask = 0;
626         hint->joinrelids = NULL;
627         hint->inner_joinrelids = NULL;
628
629         return (Hint *) hint;
630 }
631
632 static void
633 JoinMethodHintDelete(JoinMethodHint *hint)
634 {
635         if (!hint)
636                 return;
637
638         if (hint->relnames)
639         {
640                 int     i;
641
642                 for (i = 0; i < hint->nrels; i++)
643                         pfree(hint->relnames[i]);
644                 pfree(hint->relnames);
645         }
646
647         bms_free(hint->joinrelids);
648         bms_free(hint->inner_joinrelids);
649         pfree(hint);
650 }
651
652 static Hint *
653 LeadingHintCreate(const char *hint_str, const char *keyword,
654                                   HintKeyword hint_keyword)
655 {
656         LeadingHint        *hint;
657
658         hint = palloc(sizeof(LeadingHint));
659         hint->base.hint_str = hint_str;
660         hint->base.keyword = keyword;
661         hint->base.hint_keyword = hint_keyword;
662         hint->base.type = HINT_TYPE_LEADING;
663         hint->base.state = HINT_STATE_NOTUSED;
664         hint->base.delete_func = (HintDeleteFunction)LeadingHintDelete;
665         hint->base.desc_func = (HintDescFunction) LeadingHintDesc;
666         hint->base.cmp_func = (HintCmpFunction) LeadingHintCmp;
667         hint->base.parse_func = (HintParseFunction) LeadingHintParse;
668         hint->relations = NIL;
669         hint->outer_inner = NULL;
670
671         return (Hint *) hint;
672 }
673
674 static void
675 LeadingHintDelete(LeadingHint *hint)
676 {
677         if (!hint)
678                 return;
679
680         list_free_deep(hint->relations);
681         if (hint->outer_inner)
682                 pfree(hint->outer_inner);
683         pfree(hint);
684 }
685
686 static Hint *
687 SetHintCreate(const char *hint_str, const char *keyword,
688                           HintKeyword hint_keyword)
689 {
690         SetHint    *hint;
691
692         hint = palloc(sizeof(SetHint));
693         hint->base.hint_str = hint_str;
694         hint->base.keyword = keyword;
695         hint->base.hint_keyword = hint_keyword;
696         hint->base.type = HINT_TYPE_SET;
697         hint->base.state = HINT_STATE_NOTUSED;
698         hint->base.delete_func = (HintDeleteFunction) SetHintDelete;
699         hint->base.desc_func = (HintDescFunction) SetHintDesc;
700         hint->base.cmp_func = (HintCmpFunction) SetHintCmp;
701         hint->base.parse_func = (HintParseFunction) SetHintParse;
702         hint->name = NULL;
703         hint->value = NULL;
704         hint->words = NIL;
705
706         return (Hint *) hint;
707 }
708
709 static void
710 SetHintDelete(SetHint *hint)
711 {
712         if (!hint)
713                 return;
714
715         if (hint->name)
716                 pfree(hint->name);
717         if (hint->value)
718                 pfree(hint->value);
719         if (hint->words)
720                 list_free(hint->words);
721         pfree(hint);
722 }
723
724 static HintState *
725 HintStateCreate(void)
726 {
727         HintState   *hstate;
728
729         hstate = palloc(sizeof(HintState));
730         hstate->hint_str = NULL;
731         hstate->nall_hints = 0;
732         hstate->max_all_hints = 0;
733         hstate->all_hints = NULL;
734         memset(hstate->num_hints, 0, sizeof(hstate->num_hints));
735         hstate->scan_hints = NULL;
736         hstate->init_scan_mask = 0;
737         hstate->parent_relid = 0;
738         hstate->parent_rel_oid = InvalidOid;
739         hstate->parent_hint = NULL;
740         hstate->parent_index_infos = NIL;
741         hstate->join_hints = NULL;
742         hstate->init_join_mask = 0;
743         hstate->join_hint_level = NULL;
744         hstate->leading_hint = NULL;
745         hstate->context = superuser() ? PGC_SUSET : PGC_USERSET;
746         hstate->set_hints = NULL;
747
748         return hstate;
749 }
750
751 static void
752 HintStateDelete(HintState *hstate)
753 {
754         int                     i;
755
756         if (!hstate)
757                 return;
758
759         if (hstate->hint_str)
760                 pfree(hstate->hint_str);
761
762         for (i = 0; i < hstate->num_hints[HINT_TYPE_SCAN_METHOD]; i++)
763                 hstate->all_hints[i]->delete_func(hstate->all_hints[i]);
764         if (hstate->all_hints)
765                 pfree(hstate->all_hints);
766         if (hstate->parent_index_infos)
767                 list_free(hstate->parent_index_infos);
768 }
769
770 /*
771  * Copy given value into buf, with quoting with '"' if necessary.
772  */
773 static void
774 quote_value(StringInfo buf, const char *value)
775 {
776         bool            need_quote = false;
777         const char *str;
778
779         for (str = value; *str != '\0'; str++)
780         {
781                 if (isspace(*str) || *str == '(' || *str == ')' || *str == '"')
782                 {
783                         need_quote = true;
784                         appendStringInfoCharMacro(buf, '"');
785                         break;
786                 }
787         }
788
789         for (str = value; *str != '\0'; str++)
790         {
791                 if (*str == '"')
792                         appendStringInfoCharMacro(buf, '"');
793
794                 appendStringInfoCharMacro(buf, *str);
795         }
796
797         if (need_quote)
798                 appendStringInfoCharMacro(buf, '"');
799 }
800
801 static void
802 ScanMethodHintDesc(ScanMethodHint *hint, StringInfo buf)
803 {
804         ListCell   *l;
805
806         appendStringInfo(buf, "%s(", hint->base.keyword);
807         if (hint->relname != NULL)
808         {
809                 quote_value(buf, hint->relname);
810                 foreach(l, hint->indexnames)
811                 {
812                         appendStringInfoCharMacro(buf, ' ');
813                         quote_value(buf, (char *) lfirst(l));
814                 }
815         }
816         appendStringInfoString(buf, ")\n");
817 }
818
819 static void
820 JoinMethodHintDesc(JoinMethodHint *hint, StringInfo buf)
821 {
822         int     i;
823
824         appendStringInfo(buf, "%s(", hint->base.keyword);
825         if (hint->relnames != NULL)
826         {
827                 quote_value(buf, hint->relnames[0]);
828                 for (i = 1; i < hint->nrels; i++)
829                 {
830                         appendStringInfoCharMacro(buf, ' ');
831                         quote_value(buf, hint->relnames[i]);
832                 }
833         }
834         appendStringInfoString(buf, ")\n");
835
836 }
837
838 static void
839 OuterInnerDesc(OuterInnerRels *outer_inner, StringInfo buf)
840 {
841         if (outer_inner->relation == NULL)
842         {
843                 bool            is_first;
844                 ListCell   *l;
845
846                 is_first = true;
847
848                 appendStringInfoCharMacro(buf, '(');
849                 foreach(l, outer_inner->outer_inner_pair)
850                 {
851                         if (is_first)
852                                 is_first = false;
853                         else
854                                 appendStringInfoCharMacro(buf, ' ');
855
856                         OuterInnerDesc(lfirst(l), buf);
857                 }
858
859                 appendStringInfoCharMacro(buf, ')');
860         }
861         else
862                 quote_value(buf, outer_inner->relation);
863 }
864
865 static void
866 LeadingHintDesc(LeadingHint *hint, StringInfo buf)
867 {
868         appendStringInfo(buf, "%s(", HINT_LEADING);
869         if (hint->outer_inner == NULL)
870         {
871                 ListCell   *l;
872                 bool            is_first;
873
874                 is_first = true;
875
876                 foreach(l, hint->relations)
877                 {
878                         if (is_first)
879                                 is_first = false;
880                         else
881                                 appendStringInfoCharMacro(buf, ' ');
882
883                         quote_value(buf, (char *) lfirst(l));
884                 }
885         }
886         else
887                 OuterInnerDesc(hint->outer_inner, buf);
888
889         appendStringInfoString(buf, ")\n");
890 }
891
892 static void
893 SetHintDesc(SetHint *hint, StringInfo buf)
894 {
895         bool            is_first = true;
896         ListCell   *l;
897
898         appendStringInfo(buf, "%s(", HINT_SET);
899         foreach(l, hint->words)
900         {
901                 if (is_first)
902                         is_first = false;
903                 else
904                         appendStringInfoCharMacro(buf, ' ');
905
906                 quote_value(buf, (char *) lfirst(l));
907         }
908         appendStringInfo(buf, ")\n");
909 }
910
911 /*
912  * Append string which repserents all hints in a given state to buf, with
913  * preceding title with them.
914  */
915 static void
916 desc_hint_in_state(HintState *hstate, StringInfo buf, const char *title,
917                                         HintStatus state)
918 {
919         int     i;
920
921         appendStringInfo(buf, "%s:\n", title);
922         for (i = 0; i < hstate->nall_hints; i++)
923         {
924                 if (hstate->all_hints[i]->state != state)
925                         continue;
926
927                 hstate->all_hints[i]->desc_func(hstate->all_hints[i], buf);
928         }
929 }
930
931 /*
932  * Dump contents of given hstate to server log with log level LOG.
933  */
934 static void
935 HintStateDump(HintState *hstate)
936 {
937         StringInfoData  buf;
938
939         if (!hstate)
940         {
941                 elog(LOG, "pg_hint_plan:\nno hint");
942                 return;
943         }
944
945         initStringInfo(&buf);
946
947         appendStringInfoString(&buf, "pg_hint_plan:\n");
948         desc_hint_in_state(hstate, &buf, "used hint", HINT_STATE_USED);
949         desc_hint_in_state(hstate, &buf, "not used hint", HINT_STATE_NOTUSED);
950         desc_hint_in_state(hstate, &buf, "duplication hint", HINT_STATE_DUPLICATION);
951         desc_hint_in_state(hstate, &buf, "error hint", HINT_STATE_ERROR);
952
953         elog(LOG, "%s", buf.data);
954
955         pfree(buf.data);
956 }
957
958 /*
959  * compare functions
960  */
961
962 static int
963 RelnameCmp(const void *a, const void *b)
964 {
965         const char *relnamea = *((const char **) a);
966         const char *relnameb = *((const char **) b);
967
968         return strcmp(relnamea, relnameb);
969 }
970
971 static int
972 ScanMethodHintCmp(const ScanMethodHint *a, const ScanMethodHint *b)
973 {
974         return RelnameCmp(&a->relname, &b->relname);
975 }
976
977 static int
978 JoinMethodHintCmp(const JoinMethodHint *a, const JoinMethodHint *b)
979 {
980         int     i;
981
982         if (a->nrels != b->nrels)
983                 return a->nrels - b->nrels;
984
985         for (i = 0; i < a->nrels; i++)
986         {
987                 int     result;
988                 if ((result = RelnameCmp(&a->relnames[i], &b->relnames[i])) != 0)
989                         return result;
990         }
991
992         return 0;
993 }
994
995 static int
996 LeadingHintCmp(const LeadingHint *a, const LeadingHint *b)
997 {
998         return 0;
999 }
1000
1001 static int
1002 SetHintCmp(const SetHint *a, const SetHint *b)
1003 {
1004         return strcmp(a->name, b->name);
1005 }
1006
1007 static int
1008 HintCmp(const void *a, const void *b)
1009 {
1010         const Hint *hinta = *((const Hint **) a);
1011         const Hint *hintb = *((const Hint **) b);
1012
1013         if (hinta->type != hintb->type)
1014                 return hinta->type - hintb->type;
1015         if (hinta->state == HINT_STATE_ERROR)
1016                 return -1;
1017         if (hintb->state == HINT_STATE_ERROR)
1018                 return 1;
1019         return hinta->cmp_func(hinta, hintb);
1020 }
1021
1022 /*
1023  * Returns byte offset of hint b from hint a.  If hint a was specified before
1024  * b, positive value is returned.
1025  */
1026 static int
1027 HintCmpWithPos(const void *a, const void *b)
1028 {
1029         const Hint *hinta = *((const Hint **) a);
1030         const Hint *hintb = *((const Hint **) b);
1031         int             result;
1032
1033         result = HintCmp(a, b);
1034         if (result == 0)
1035                 result = hinta->hint_str - hintb->hint_str;
1036
1037         return result;
1038 }
1039
1040 /*
1041  * parse functions
1042  */
1043 static const char *
1044 parse_keyword(const char *str, StringInfo buf)
1045 {
1046         skip_space(str);
1047
1048         while (!isspace(*str) && *str != '(' && *str != '\0')
1049                 appendStringInfoCharMacro(buf, *str++);
1050
1051         return str;
1052 }
1053
1054 static const char *
1055 skip_parenthesis(const char *str, char parenthesis)
1056 {
1057         skip_space(str);
1058
1059         if (*str != parenthesis)
1060         {
1061                 if (parenthesis == '(')
1062                         hint_ereport(str, ("Opening parenthesis is necessary."));
1063                 else if (parenthesis == ')')
1064                         hint_ereport(str, ("Closing parenthesis is necessary."));
1065
1066                 return NULL;
1067         }
1068
1069         str++;
1070
1071         return str;
1072 }
1073
1074 /*
1075  * Parse a token from str, and store malloc'd copy into word.  A token can be
1076  * quoted with '"'.  Return value is pointer to unparsed portion of original
1077  * string, or NULL if an error occurred.
1078  *
1079  * Parsed token is truncated within NAMEDATALEN-1 bytes, when truncate is true.
1080  */
1081 static const char *
1082 parse_quoted_value(const char *str, char **word, bool truncate)
1083 {
1084         StringInfoData  buf;
1085         bool                    in_quote;
1086
1087         /* Skip leading spaces. */
1088         skip_space(str);
1089
1090         initStringInfo(&buf);
1091         if (*str == '"')
1092         {
1093                 str++;
1094                 in_quote = true;
1095         }
1096         else
1097                 in_quote = false;
1098
1099         while (true)
1100         {
1101                 if (in_quote)
1102                 {
1103                         /* Double quotation must be closed. */
1104                         if (*str == '\0')
1105                         {
1106                                 pfree(buf.data);
1107                                 hint_ereport(str, ("Unterminated quoted string."));
1108                                 return NULL;
1109                         }
1110
1111                         /*
1112                          * Skip escaped double quotation.
1113                          *
1114                          * We don't allow slash-asterisk and asterisk-slash (delimiters of
1115                          * block comments) to be an object name, so users must specify
1116                          * alias for such object names.
1117                          *
1118                          * Those special names can be allowed if we care escaped slashes
1119                          * and asterisks, but we don't.
1120                          */
1121                         if (*str == '"')
1122                         {
1123                                 str++;
1124                                 if (*str != '"')
1125                                         break;
1126                         }
1127                 }
1128                 else if (isspace(*str) || *str == '(' || *str == ')' || *str == '"' ||
1129                                  *str == '\0')
1130                         break;
1131
1132                 appendStringInfoCharMacro(&buf, *str++);
1133         }
1134
1135         if (buf.len == 0)
1136         {
1137                 hint_ereport(str, ("Zero-length delimited string."));
1138
1139                 pfree(buf.data);
1140
1141                 return NULL;
1142         }
1143
1144         /* Truncate name if it's too long */
1145         if (truncate)
1146                 truncate_identifier(buf.data, strlen(buf.data), true);
1147
1148         *word = buf.data;
1149
1150         return str;
1151 }
1152
1153 static OuterInnerRels *
1154 OuterInnerRelsCreate(char *name, List *outer_inner_list)
1155 {
1156         OuterInnerRels *outer_inner;
1157
1158         outer_inner = palloc(sizeof(OuterInnerRels));
1159         outer_inner->relation = name;
1160         outer_inner->outer_inner_pair = outer_inner_list;
1161
1162         return outer_inner;
1163 }
1164
1165 static const char *
1166 parse_parentheses_Leading_in(const char *str, OuterInnerRels **outer_inner)
1167 {
1168         List   *outer_inner_pair = NIL;
1169
1170         if ((str = skip_parenthesis(str, '(')) == NULL)
1171                 return NULL;
1172
1173         skip_space(str);
1174
1175         /* Store words in parentheses into outer_inner_list. */
1176         while(*str != ')' && *str != '\0')
1177         {
1178                 OuterInnerRels *outer_inner_rels;
1179
1180                 if (*str == '(')
1181                 {
1182                         str = parse_parentheses_Leading_in(str, &outer_inner_rels);
1183                         if (str == NULL)
1184                                 break;
1185                 }
1186                 else
1187                 {
1188                         char   *name;
1189
1190                         if ((str = parse_quoted_value(str, &name, true)) == NULL)
1191                                 break;
1192                         else
1193                                 outer_inner_rels = OuterInnerRelsCreate(name, NIL);
1194                 }
1195
1196                 outer_inner_pair = lappend(outer_inner_pair, outer_inner_rels);
1197                 skip_space(str);
1198         }
1199
1200         if (str == NULL ||
1201                 (str = skip_parenthesis(str, ')')) == NULL)
1202         {
1203                 list_free(outer_inner_pair);
1204                 return NULL;
1205         }
1206
1207         *outer_inner = OuterInnerRelsCreate(NULL, outer_inner_pair);
1208
1209         return str;
1210 }
1211
1212 static const char *
1213 parse_parentheses_Leading(const char *str, List **name_list,
1214         OuterInnerRels **outer_inner)
1215 {
1216         char   *name;
1217         bool    truncate = true;
1218
1219         if ((str = skip_parenthesis(str, '(')) == NULL)
1220                 return NULL;
1221
1222         skip_space(str);
1223         if (*str =='(')
1224         {
1225                 if ((str = parse_parentheses_Leading_in(str, outer_inner)) == NULL)
1226                         return NULL;
1227         }
1228         else
1229         {
1230                 /* Store words in parentheses into name_list. */
1231                 while(*str != ')' && *str != '\0')
1232                 {
1233                         if ((str = parse_quoted_value(str, &name, truncate)) == NULL)
1234                         {
1235                                 list_free(*name_list);
1236                                 return NULL;
1237                         }
1238
1239                         *name_list = lappend(*name_list, name);
1240                         skip_space(str);
1241                 }
1242         }
1243
1244         if ((str = skip_parenthesis(str, ')')) == NULL)
1245                 return NULL;
1246         return str;
1247 }
1248
1249 static const char *
1250 parse_parentheses(const char *str, List **name_list, HintKeyword keyword)
1251 {
1252         char   *name;
1253         bool    truncate = true;
1254
1255         if ((str = skip_parenthesis(str, '(')) == NULL)
1256                 return NULL;
1257
1258         skip_space(str);
1259
1260         /* Store words in parentheses into name_list. */
1261         while(*str != ')' && *str != '\0')
1262         {
1263                 if ((str = parse_quoted_value(str, &name, truncate)) == NULL)
1264                 {
1265                         list_free(*name_list);
1266                         return NULL;
1267                 }
1268
1269                 *name_list = lappend(*name_list, name);
1270                 skip_space(str);
1271
1272                 if (keyword == HINT_KEYWORD_INDEXSCANREGEXP ||
1273 #if PG_VERSION_NUM >= 90200
1274                         keyword == HINT_KEYWORD_INDEXONLYSCANREGEXP ||
1275 #endif
1276                         keyword == HINT_KEYWORD_BITMAPSCANREGEXP ||
1277                         keyword == HINT_KEYWORD_SET)
1278                 {
1279                         truncate = false;
1280                 }
1281         }
1282
1283         if ((str = skip_parenthesis(str, ')')) == NULL)
1284                 return NULL;
1285         return str;
1286 }
1287
1288 static void
1289 parse_hints(HintState *hstate, Query *parse, const char *str)
1290 {
1291         StringInfoData  buf;
1292         char               *head;
1293
1294         initStringInfo(&buf);
1295         while (*str != '\0')
1296         {
1297                 const HintParser *parser;
1298
1299                 /* in error message, we output the comment including the keyword. */
1300                 head = (char *) str;
1301
1302                 /* parse only the keyword of the hint. */
1303                 resetStringInfo(&buf);
1304                 str = parse_keyword(str, &buf);
1305
1306                 for (parser = parsers; parser->keyword != NULL; parser++)
1307                 {
1308                         char   *keyword = parser->keyword;
1309                         Hint   *hint;
1310
1311                         if (strcasecmp(buf.data, keyword) != 0)
1312                                 continue;
1313
1314                         hint = parser->create_func(head, keyword, parser->hint_keyword);
1315
1316                         /* parser of each hint does parse in a parenthesis. */
1317                         if ((str = hint->parse_func(hint, hstate, parse, str)) == NULL)
1318                         {
1319                                 hint->delete_func(hint);
1320                                 pfree(buf.data);
1321                                 return;
1322                         }
1323
1324                         /*
1325                          * Add hint information into all_hints array.  If we don't have
1326                          * enough space, double the array.
1327                          */
1328                         if (hstate->nall_hints == 0)
1329                         {
1330                                 hstate->max_all_hints = HINT_ARRAY_DEFAULT_INITSIZE;
1331                                 hstate->all_hints = (Hint **)
1332                                         palloc(sizeof(Hint *) * hstate->max_all_hints);
1333                         }
1334                         else if (hstate->nall_hints == hstate->max_all_hints)
1335                         {
1336                                 hstate->max_all_hints *= 2;
1337                                 hstate->all_hints = (Hint **)
1338                                         repalloc(hstate->all_hints,
1339                                                          sizeof(Hint *) * hstate->max_all_hints);
1340                         }
1341
1342                         hstate->all_hints[hstate->nall_hints] = hint;
1343                         hstate->nall_hints++;
1344
1345                         skip_space(str);
1346
1347                         break;
1348                 }
1349
1350                 if (parser->keyword == NULL)
1351                 {
1352                         hint_ereport(head,
1353                                                  ("Unrecognized hint keyword \"%s\".", buf.data));
1354                         pfree(buf.data);
1355                         return;
1356                 }
1357         }
1358
1359         pfree(buf.data);
1360 }
1361
1362
1363 /* 
1364  * Get hints from table by client-supplied query string and application name.
1365  */
1366 static const char *
1367 get_hints_from_table(const char *client_query, const char *client_application)
1368 {
1369         const char *search_query =
1370                 "SELECT hints "
1371                 "  FROM hint_plan.hints "
1372                 " WHERE norm_query_string = $1 "
1373                 "   AND ( application_name = $2 "
1374                 "    OR application_name = '' ) "
1375                 " ORDER BY application_name DESC";
1376         static SPIPlanPtr plan = NULL;
1377         int             ret;
1378         char   *hints = NULL;
1379         Oid             argtypes[2] = { TEXTOID, TEXTOID };
1380         Datum   values[2];
1381         bool    nulls[2] = { false, false };
1382         text   *qry;
1383         text   *app;
1384
1385         ret = SPI_connect();
1386         if (ret != SPI_OK_CONNECT)
1387                 elog(ERROR, "pg_hint_plan: SPI_connect => %d", ret);
1388
1389         if (plan == NULL)
1390         {
1391                 SPIPlanPtr      p;
1392                 p = SPI_prepare(search_query, 2, argtypes);
1393                 if (p == NULL)
1394                         elog(ERROR, "pg_hint_plan: SPI_prepare => %d", SPI_result);
1395                 plan = SPI_saveplan(p);
1396                 SPI_freeplan(p);
1397         }
1398
1399         qry = cstring_to_text(client_query);
1400         app = cstring_to_text(client_application);
1401         values[0] = PointerGetDatum(qry);
1402         values[1] = PointerGetDatum(app);
1403
1404         pg_hint_plan_enable_hint = false;
1405         ret = SPI_execute_plan(plan, values, nulls, true, 1);
1406         pg_hint_plan_enable_hint = true;
1407         if (ret != SPI_OK_SELECT)
1408                 elog(ERROR, "pg_hint_plan: SPI_execute_plan => %d", ret);
1409
1410         if (SPI_processed > 0)
1411         {
1412                 char    *buf;
1413
1414                 hints = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
1415                 /*
1416                  * Here we use SPI_palloc to ensure that hints string is valid even
1417                  * after SPI_finish call.  We can't use simple palloc because it
1418                  * allocates memory in SPI's context and that context is deleted in
1419                  * SPI_finish.
1420                  */
1421                 buf = SPI_palloc(strlen(hints) + 1);
1422                 strcpy(buf, hints);
1423                 hints = buf;
1424         }
1425
1426         SPI_finish();
1427
1428         return hints;
1429 }
1430
1431 /*
1432  * Get client-supplied query string.
1433  */
1434 static const char *
1435 get_query_string(void)
1436 {
1437         const char *p;
1438
1439         if (stmt_name)
1440         {
1441                 PreparedStatement  *entry;
1442
1443                 entry = FetchPreparedStatement(stmt_name, true);
1444                 p = entry->plansource->query_string;
1445         }
1446         else if (plpgsql_query_string)
1447                 p = plpgsql_query_string;
1448         else
1449                 p = debug_query_string;
1450
1451         return p;
1452 }
1453
1454 /*
1455  * Get hints from the head block comment in client-supplied query string.
1456  */
1457 static const char *
1458 get_hints_from_comment(const char *p)
1459 {
1460         const char *hint_head;
1461         char       *head;
1462         char       *tail;
1463         int                     len;
1464
1465         if (p == NULL)
1466                 return NULL;
1467
1468         /* extract query head comment. */
1469         hint_head = strstr(p, HINT_START);
1470         if (hint_head == NULL)
1471                 return NULL;
1472         for (;p < hint_head; p++)
1473         {
1474                 /*
1475                  * Allow these characters precedes hint comment:
1476                  *   - digits
1477                  *   - alphabets which are in ASCII range
1478                  *   - space, tabs and new-lines
1479                  *   - underscores, for identifier
1480                  *   - commas, for SELECT clause, EXPLAIN and PREPARE
1481                  *   - parentheses, for EXPLAIN and PREPARE
1482                  *
1483                  * Note that we don't use isalpha() nor isalnum() in ctype.h here to
1484                  * avoid behavior which depends on locale setting.
1485                  */
1486                 if (!(*p >= '0' && *p <= '9') &&
1487                         !(*p >= 'A' && *p <= 'Z') &&
1488                         !(*p >= 'a' && *p <= 'z') &&
1489                         !isspace(*p) &&
1490                         *p != '_' &&
1491                         *p != ',' &&
1492                         *p != '(' && *p != ')')
1493                         return NULL;
1494         }
1495
1496         len = strlen(HINT_START);
1497         head = (char *) p;
1498         p += len;
1499         skip_space(p);
1500
1501         /* find hint end keyword. */
1502         if ((tail = strstr(p, HINT_END)) == NULL)
1503         {
1504                 hint_ereport(head, ("Unterminated block comment."));
1505                 return NULL;
1506         }
1507
1508         /* We don't support nested block comments. */
1509         if ((head = strstr(p, BLOCK_COMMENT_START)) != NULL && head < tail)
1510         {
1511                 hint_ereport(head, ("Nested block comments are not supported."));
1512                 return NULL;
1513         }
1514
1515         /* Make a copy of hint. */
1516         len = tail - p;
1517         head = palloc(len + 1);
1518         memcpy(head, p, len);
1519         head[len] = '\0';
1520         p = head;
1521
1522         return p;
1523 }
1524
1525 /*
1526  * Parse hints that got, create hint struct from parse tree and parse hints.
1527  */
1528 static HintState *
1529 create_hintstate(Query *parse, const char *hints)
1530 {
1531         const char *p;
1532         int                     i;
1533         HintState   *hstate;
1534
1535         if (hints == NULL)
1536                 return NULL;
1537
1538         p = hints;
1539         hstate = HintStateCreate();
1540         hstate->hint_str = (char *) hints;
1541
1542         /* parse each hint. */
1543         parse_hints(hstate, parse, p);
1544
1545         /* When nothing specified a hint, we free HintState and returns NULL. */
1546         if (hstate->nall_hints == 0)
1547         {
1548                 HintStateDelete(hstate);
1549                 return NULL;
1550         }
1551
1552         /* Sort hints in order of original position. */
1553         qsort(hstate->all_hints, hstate->nall_hints, sizeof(Hint *),
1554                   HintCmpWithPos);
1555
1556         /* Count number of hints per hint-type. */
1557         for (i = 0; i < hstate->nall_hints; i++)
1558         {
1559                 Hint   *cur_hint = hstate->all_hints[i];
1560                 hstate->num_hints[cur_hint->type]++;
1561         }
1562
1563         /*
1564          * If an object (or a set of objects) has multiple hints of same hint-type,
1565          * only the last hint is valid and others are igonred in planning.
1566          * Hints except the last are marked as 'duplicated' to remember the order.
1567          */
1568         for (i = 0; i < hstate->nall_hints - 1; i++)
1569         {
1570                 Hint   *cur_hint = hstate->all_hints[i];
1571                 Hint   *next_hint = hstate->all_hints[i + 1];
1572
1573                 /*
1574                  * Leading hint is marked as 'duplicated' in transform_join_hints.
1575                  */
1576                 if (cur_hint->type == HINT_TYPE_LEADING &&
1577                         next_hint->type == HINT_TYPE_LEADING)
1578                         continue;
1579
1580                 /*
1581                  * Note that we need to pass addresses of hint pointers, because
1582                  * HintCmp is designed to sort array of Hint* by qsort.
1583                  */
1584                 if (HintCmp(&cur_hint, &next_hint) == 0)
1585                 {
1586                         hint_ereport(cur_hint->hint_str,
1587                                                  ("Conflict %s hint.", HintTypeName[cur_hint->type]));
1588                         cur_hint->state = HINT_STATE_DUPLICATION;
1589                 }
1590         }
1591
1592         /*
1593          * Make sure that per-type array pointers point proper position in the
1594          * array which consists of all hints.
1595          */
1596         hstate->scan_hints = (ScanMethodHint **) hstate->all_hints;
1597         hstate->join_hints = (JoinMethodHint **) (hstate->scan_hints +
1598                 hstate->num_hints[HINT_TYPE_SCAN_METHOD]);
1599         hstate->leading_hint = (LeadingHint **) (hstate->join_hints +
1600                 hstate->num_hints[HINT_TYPE_JOIN_METHOD]);
1601         hstate->set_hints = (SetHint **) (hstate->leading_hint +
1602                 hstate->num_hints[HINT_TYPE_LEADING]);
1603
1604         return hstate;
1605 }
1606
1607 /*
1608  * Parse inside of parentheses of scan-method hints.
1609  */
1610 static const char *
1611 ScanMethodHintParse(ScanMethodHint *hint, HintState *hstate, Query *parse,
1612                                         const char *str)
1613 {
1614         const char         *keyword = hint->base.keyword;
1615         HintKeyword             hint_keyword = hint->base.hint_keyword;
1616         List               *name_list = NIL;
1617         int                             length;
1618
1619         if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL)
1620                 return NULL;
1621
1622         /* Parse relation name and index name(s) if given hint accepts. */
1623         length = list_length(name_list);
1624         if (length > 0)
1625         {
1626                 hint->relname = linitial(name_list);
1627                 hint->indexnames = list_delete_first(name_list);
1628
1629                 /* check whether the hint accepts index name(s). */
1630                 if (length != 1 &&
1631                         hint_keyword != HINT_KEYWORD_INDEXSCAN &&
1632                         hint_keyword != HINT_KEYWORD_INDEXSCANREGEXP &&
1633 #if PG_VERSION_NUM >= 90200
1634                         hint_keyword != HINT_KEYWORD_INDEXONLYSCAN &&
1635                         hint_keyword != HINT_KEYWORD_INDEXONLYSCANREGEXP &&
1636 #endif
1637                         hint_keyword != HINT_KEYWORD_BITMAPSCAN &&
1638                         hint_keyword != HINT_KEYWORD_BITMAPSCANREGEXP)
1639                 {
1640                         hint_ereport(str,
1641                                                  ("%s hint accepts only one relation.",
1642                                                   hint->base.keyword));
1643                         hint->base.state = HINT_STATE_ERROR;
1644                         return str;
1645                 }
1646         }
1647         else
1648         {
1649                 hint_ereport(str,
1650                                          ("%s hint requires a relation.",
1651                                           hint->base.keyword));
1652                 hint->base.state = HINT_STATE_ERROR;
1653                 return str;
1654         }
1655
1656         /* Set a bit for specified hint. */
1657         switch (hint_keyword)
1658         {
1659                 case HINT_KEYWORD_SEQSCAN:
1660                         hint->enforce_mask = ENABLE_SEQSCAN;
1661                         break;
1662                 case HINT_KEYWORD_INDEXSCAN:
1663                         hint->enforce_mask = ENABLE_INDEXSCAN;
1664                         break;
1665                 case HINT_KEYWORD_INDEXSCANREGEXP:
1666                         hint->enforce_mask = ENABLE_INDEXSCAN;
1667                         hint->regexp = true;
1668                         break;
1669                 case HINT_KEYWORD_BITMAPSCAN:
1670                         hint->enforce_mask = ENABLE_BITMAPSCAN;
1671                         break;
1672                 case HINT_KEYWORD_BITMAPSCANREGEXP:
1673                         hint->enforce_mask = ENABLE_BITMAPSCAN;
1674                         hint->regexp = true;
1675                         break;
1676                 case HINT_KEYWORD_TIDSCAN:
1677                         hint->enforce_mask = ENABLE_TIDSCAN;
1678                         break;
1679                 case HINT_KEYWORD_NOSEQSCAN:
1680                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_SEQSCAN;
1681                         break;
1682                 case HINT_KEYWORD_NOINDEXSCAN:
1683                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXSCAN;
1684                         break;
1685                 case HINT_KEYWORD_NOBITMAPSCAN:
1686                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_BITMAPSCAN;
1687                         break;
1688                 case HINT_KEYWORD_NOTIDSCAN:
1689                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_TIDSCAN;
1690                         break;
1691 #if PG_VERSION_NUM >= 90200
1692                 case HINT_KEYWORD_INDEXONLYSCAN:
1693                         hint->enforce_mask = ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN;
1694                         break;
1695                 case HINT_KEYWORD_INDEXONLYSCANREGEXP:
1696                         hint->enforce_mask = ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN;
1697                         hint->regexp = true;
1698                         break;
1699                 case HINT_KEYWORD_NOINDEXONLYSCAN:
1700                         hint->enforce_mask = ENABLE_ALL_SCAN ^ ENABLE_INDEXONLYSCAN;
1701                         break;
1702 #endif
1703                 default:
1704                         hint_ereport(str, ("Unrecognized hint keyword \"%s\".", keyword));
1705                         return NULL;
1706                         break;
1707         }
1708
1709         return str;
1710 }
1711
1712 static const char *
1713 JoinMethodHintParse(JoinMethodHint *hint, HintState *hstate, Query *parse,
1714                                         const char *str)
1715 {
1716         const char         *keyword = hint->base.keyword;
1717         HintKeyword             hint_keyword = hint->base.hint_keyword;
1718         List               *name_list = NIL;
1719
1720         if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL)
1721                 return NULL;
1722
1723         hint->nrels = list_length(name_list);
1724
1725         if (hint->nrels > 0)
1726         {
1727                 ListCell   *l;
1728                 int                     i = 0;
1729
1730                 /*
1731                  * Transform relation names from list to array to sort them with qsort
1732                  * after.
1733                  */
1734                 hint->relnames = palloc(sizeof(char *) * hint->nrels);
1735                 foreach (l, name_list)
1736                 {
1737                         hint->relnames[i] = lfirst(l);
1738                         i++;
1739                 }
1740         }
1741
1742         list_free(name_list);
1743
1744         /* A join hint requires at least two relations */
1745         if (hint->nrels < 2)
1746         {
1747                 hint_ereport(str,
1748                                          ("%s hint requires at least two relations.",
1749                                           hint->base.keyword));
1750                 hint->base.state = HINT_STATE_ERROR;
1751                 return str;
1752         }
1753
1754         /* Sort hints in alphabetical order of relation names. */
1755         qsort(hint->relnames, hint->nrels, sizeof(char *), RelnameCmp);
1756
1757         switch (hint_keyword)
1758         {
1759                 case HINT_KEYWORD_NESTLOOP:
1760                         hint->enforce_mask = ENABLE_NESTLOOP;
1761                         break;
1762                 case HINT_KEYWORD_MERGEJOIN:
1763                         hint->enforce_mask = ENABLE_MERGEJOIN;
1764                         break;
1765                 case HINT_KEYWORD_HASHJOIN:
1766                         hint->enforce_mask = ENABLE_HASHJOIN;
1767                         break;
1768                 case HINT_KEYWORD_NONESTLOOP:
1769                         hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_NESTLOOP;
1770                         break;
1771                 case HINT_KEYWORD_NOMERGEJOIN:
1772                         hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_MERGEJOIN;
1773                         break;
1774                 case HINT_KEYWORD_NOHASHJOIN:
1775                         hint->enforce_mask = ENABLE_ALL_JOIN ^ ENABLE_HASHJOIN;
1776                         break;
1777                 default:
1778                         hint_ereport(str, ("Unrecognized hint keyword \"%s\".", keyword));
1779                         return NULL;
1780                         break;
1781         }
1782
1783         return str;
1784 }
1785
1786 static bool
1787 OuterInnerPairCheck(OuterInnerRels *outer_inner)
1788 {
1789         ListCell *l;
1790         if (outer_inner->outer_inner_pair == NIL)
1791         {
1792                 if (outer_inner->relation)
1793                         return true;
1794                 else
1795                         return false;
1796         }
1797
1798         if (list_length(outer_inner->outer_inner_pair) == 2)
1799         {
1800                 foreach(l, outer_inner->outer_inner_pair)
1801                 {
1802                         if (!OuterInnerPairCheck(lfirst(l)))
1803                                 return false;
1804                 }
1805         }
1806         else
1807                 return false;
1808
1809         return true;
1810 }
1811
1812 static List *
1813 OuterInnerList(OuterInnerRels *outer_inner)
1814 {
1815         List               *outer_inner_list = NIL;
1816         ListCell           *l;
1817         OuterInnerRels *outer_inner_rels;
1818
1819         foreach(l, outer_inner->outer_inner_pair)
1820         {
1821                 outer_inner_rels = (OuterInnerRels *)(lfirst(l));
1822
1823                 if (outer_inner_rels->relation != NULL)
1824                         outer_inner_list = lappend(outer_inner_list,
1825                                                                            outer_inner_rels->relation);
1826                 else
1827                         outer_inner_list = list_concat(outer_inner_list,
1828                                                                                    OuterInnerList(outer_inner_rels));
1829         }
1830         return outer_inner_list;
1831 }
1832
1833 static const char *
1834 LeadingHintParse(LeadingHint *hint, HintState *hstate, Query *parse,
1835                                  const char *str)
1836 {
1837         List               *name_list = NIL;
1838         OuterInnerRels *outer_inner = NULL;
1839
1840         if ((str = parse_parentheses_Leading(str, &name_list, &outer_inner)) ==
1841                 NULL)
1842                 return NULL;
1843
1844         if (outer_inner != NULL)
1845                 name_list = OuterInnerList(outer_inner);
1846
1847         hint->relations = name_list;
1848         hint->outer_inner = outer_inner;
1849
1850         /* A Leading hint requires at least two relations */
1851         if ( hint->outer_inner == NULL && list_length(hint->relations) < 2)
1852         {
1853                 hint_ereport(hint->base.hint_str,
1854                                          ("%s hint requires at least two relations.",
1855                                           HINT_LEADING));
1856                 hint->base.state = HINT_STATE_ERROR;
1857         }
1858         else if (hint->outer_inner != NULL &&
1859                          !OuterInnerPairCheck(hint->outer_inner))
1860         {
1861                 hint_ereport(hint->base.hint_str,
1862                                          ("%s hint requires two sets of relations when parentheses nests.",
1863                                           HINT_LEADING));
1864                 hint->base.state = HINT_STATE_ERROR;
1865         }
1866
1867         return str;
1868 }
1869
1870 static const char *
1871 SetHintParse(SetHint *hint, HintState *hstate, Query *parse, const char *str)
1872 {
1873         List   *name_list = NIL;
1874
1875         if ((str = parse_parentheses(str, &name_list, hint->base.hint_keyword))
1876                 == NULL)
1877                 return NULL;
1878
1879         hint->words = name_list;
1880
1881         /* We need both name and value to set GUC parameter. */
1882         if (list_length(name_list) == 2)
1883         {
1884                 hint->name = linitial(name_list);
1885                 hint->value = lsecond(name_list);
1886         }
1887         else
1888         {
1889                 hint_ereport(hint->base.hint_str,
1890                                          ("%s hint requires name and value of GUC parameter.",
1891                                           HINT_SET));
1892                 hint->base.state = HINT_STATE_ERROR;
1893         }
1894
1895         return str;
1896 }
1897
1898 /*
1899  * set GUC parameter functions
1900  */
1901
1902 static int
1903 set_config_option_wrapper(const char *name, const char *value,
1904                                                   GucContext context, GucSource source,
1905                                                   GucAction action, bool changeVal, int elevel)
1906 {
1907         int                             result = 0;
1908         MemoryContext   ccxt = CurrentMemoryContext;
1909
1910         PG_TRY();
1911         {
1912 #if PG_VERSION_NUM >= 90200
1913                 result = set_config_option(name, value, context, source,
1914                                                                    action, changeVal, 0);
1915 #else
1916                 result = set_config_option(name, value, context, source,
1917                                                                    action, changeVal);
1918 #endif
1919         }
1920         PG_CATCH();
1921         {
1922                 ErrorData          *errdata;
1923
1924                 /* Save error info */
1925                 MemoryContextSwitchTo(ccxt);
1926                 errdata = CopyErrorData();
1927                 FlushErrorState();
1928
1929                 ereport(elevel, (errcode(errdata->sqlerrcode),
1930                                 errmsg("%s", errdata->message),
1931                                 errdata->detail ? errdetail("%s", errdata->detail) : 0,
1932                                 errdata->hint ? errhint("%s", errdata->hint) : 0));
1933                 FreeErrorData(errdata);
1934         }
1935         PG_END_TRY();
1936
1937         return result;
1938 }
1939
1940 static int
1941 set_config_options(SetHint **options, int noptions, GucContext context)
1942 {
1943         int     i;
1944         int     save_nestlevel;
1945
1946         save_nestlevel = NewGUCNestLevel();
1947
1948         for (i = 0; i < noptions; i++)
1949         {
1950                 SetHint    *hint = options[i];
1951                 int                     result;
1952
1953                 if (!hint_state_enabled(hint))
1954                         continue;
1955
1956                 result = set_config_option_wrapper(hint->name, hint->value, context,
1957                                                                                    PGC_S_SESSION, GUC_ACTION_SAVE, true,
1958                                                                                    pg_hint_plan_parse_messages);
1959                 if (result != 0)
1960                         hint->base.state = HINT_STATE_USED;
1961                 else
1962                         hint->base.state = HINT_STATE_ERROR;
1963         }
1964
1965         return save_nestlevel;
1966 }
1967
1968 #define SET_CONFIG_OPTION(name, type_bits) \
1969         set_config_option_wrapper((name), \
1970                 (mask & (type_bits)) ? "true" : "false", \
1971                 context, PGC_S_SESSION, GUC_ACTION_SAVE, true, ERROR)
1972
1973 static void
1974 set_scan_config_options(unsigned char enforce_mask, GucContext context)
1975 {
1976         unsigned char   mask;
1977
1978         if (enforce_mask == ENABLE_SEQSCAN || enforce_mask == ENABLE_INDEXSCAN ||
1979                 enforce_mask == ENABLE_BITMAPSCAN || enforce_mask == ENABLE_TIDSCAN
1980 #if PG_VERSION_NUM >= 90200
1981                 || enforce_mask == (ENABLE_INDEXSCAN | ENABLE_INDEXONLYSCAN)
1982 #endif
1983                 )
1984                 mask = enforce_mask;
1985         else
1986                 mask = enforce_mask & current_hint->init_scan_mask;
1987
1988         SET_CONFIG_OPTION("enable_seqscan", ENABLE_SEQSCAN);
1989         SET_CONFIG_OPTION("enable_indexscan", ENABLE_INDEXSCAN);
1990         SET_CONFIG_OPTION("enable_bitmapscan", ENABLE_BITMAPSCAN);
1991         SET_CONFIG_OPTION("enable_tidscan", ENABLE_TIDSCAN);
1992 #if PG_VERSION_NUM >= 90200
1993         SET_CONFIG_OPTION("enable_indexonlyscan", ENABLE_INDEXONLYSCAN);
1994 #endif
1995 }
1996
1997 static void
1998 set_join_config_options(unsigned char enforce_mask, GucContext context)
1999 {
2000         unsigned char   mask;
2001
2002         if (enforce_mask == ENABLE_NESTLOOP || enforce_mask == ENABLE_MERGEJOIN ||
2003                 enforce_mask == ENABLE_HASHJOIN)
2004                 mask = enforce_mask;
2005         else
2006                 mask = enforce_mask & current_hint->init_join_mask;
2007
2008         SET_CONFIG_OPTION("enable_nestloop", ENABLE_NESTLOOP);
2009         SET_CONFIG_OPTION("enable_mergejoin", ENABLE_MERGEJOIN);
2010         SET_CONFIG_OPTION("enable_hashjoin", ENABLE_HASHJOIN);
2011 }
2012
2013 /*
2014  * pg_hint_plan hook functions
2015  */
2016
2017 static void
2018 pg_hint_plan_ProcessUtility(Node *parsetree, const char *queryString,
2019                                                         ParamListInfo params, bool isTopLevel,
2020                                                         DestReceiver *dest, char *completionTag)
2021 {
2022         Node                               *node;
2023
2024         if (!pg_hint_plan_enable_hint)
2025         {
2026                 if (prev_ProcessUtility)
2027                         (*prev_ProcessUtility) (parsetree, queryString, params,
2028                                                                         isTopLevel, dest, completionTag);
2029                 else
2030                         standard_ProcessUtility(parsetree, queryString, params,
2031                                                                         isTopLevel, dest, completionTag);
2032
2033                 return;
2034         }
2035
2036         node = parsetree;
2037         if (IsA(node, ExplainStmt))
2038         {
2039                 /*
2040                  * Draw out parse tree of actual query from Query struct of EXPLAIN
2041                  * statement.
2042                  */
2043                 ExplainStmt        *stmt;
2044                 Query              *query;
2045
2046                 stmt = (ExplainStmt *) node;
2047
2048                 Assert(IsA(stmt->query, Query));
2049                 query = (Query *) stmt->query;
2050
2051                 if (query->commandType == CMD_UTILITY && query->utilityStmt != NULL)
2052                         node = query->utilityStmt;
2053         }
2054
2055         /*
2056          * If the query was a EXECUTE or CREATE TABLE AS EXECUTE, get query string
2057          * specified to preceding PREPARE command to use it as source of hints.
2058          */
2059         if (IsA(node, ExecuteStmt))
2060         {
2061                 ExecuteStmt        *stmt;
2062
2063                 stmt = (ExecuteStmt *) node;
2064                 stmt_name = stmt->name;
2065         }
2066 #if PG_VERSION_NUM >= 90200
2067         /*
2068          * CREATE AS EXECUTE behavior has changed since 9.2, so we must handle it
2069          * specially here.
2070          */
2071         if (IsA(node, CreateTableAsStmt))
2072         {
2073                 CreateTableAsStmt          *stmt;
2074                 Query              *query;
2075
2076                 stmt = (CreateTableAsStmt *) node;
2077                 Assert(IsA(stmt->query, Query));
2078                 query = (Query *) stmt->query;
2079
2080                 if (query->commandType == CMD_UTILITY &&
2081                         IsA(query->utilityStmt, ExecuteStmt))
2082                 {
2083                         ExecuteStmt *estmt = (ExecuteStmt *) query->utilityStmt;
2084                         stmt_name = estmt->name;
2085                 }
2086         }
2087 #endif
2088         if (stmt_name)
2089         {
2090                 PG_TRY();
2091                 {
2092                         if (prev_ProcessUtility)
2093                                 (*prev_ProcessUtility) (parsetree, queryString, params,
2094                                                                                 isTopLevel, dest, completionTag);
2095                         else
2096                                 standard_ProcessUtility(parsetree, queryString, params,
2097                                                                                 isTopLevel, dest, completionTag);
2098                 }
2099                 PG_CATCH();
2100                 {
2101                         stmt_name = NULL;
2102                         PG_RE_THROW();
2103                 }
2104                 PG_END_TRY();
2105
2106                 stmt_name = NULL;
2107
2108                 return;
2109         }
2110
2111         if (prev_ProcessUtility)
2112                 (*prev_ProcessUtility) (parsetree, queryString, params,
2113                                                                 isTopLevel, dest, completionTag);
2114         else
2115                 standard_ProcessUtility(parsetree, queryString, params,
2116                                                                 isTopLevel, dest, completionTag);
2117 }
2118
2119 /*
2120  * Push a hint into hint stack which is implemented with List struct.  Head of
2121  * list is top of stack.
2122  */
2123 static void
2124 push_hint(HintState *hstate)
2125 {
2126         /* Prepend new hint to the list means pushing to stack. */
2127         HintStateStack = lcons(hstate, HintStateStack);
2128
2129         /* Pushed hint is the one which should be used hereafter. */
2130         current_hint = hstate;
2131 }
2132
2133 /* Pop a hint from hint stack.  Popped hint is automatically discarded. */
2134 static void
2135 pop_hint(void)
2136 {
2137         /* Hint stack must not be empty. */
2138         if(HintStateStack == NIL)
2139                 elog(ERROR, "hint stack is empty");
2140
2141         /*
2142          * Take a hint at the head from the list, and free it.  Switch current_hint
2143          * to point new head (NULL if the list is empty).
2144          */
2145         HintStateStack = list_delete_first(HintStateStack);
2146         HintStateDelete(current_hint);
2147         if(HintStateStack == NIL)
2148                 current_hint = NULL;
2149         else
2150                 current_hint = (HintState *) lfirst(list_head(HintStateStack));
2151 }
2152
2153 static PlannedStmt *
2154 pg_hint_plan_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
2155 {
2156         const char         *hints;
2157         const char         *query;
2158         char               *norm_query;
2159         pgssJumbleState jstate;
2160         int                             query_len;
2161         int                             save_nestlevel;
2162         PlannedStmt        *result;
2163         HintState          *hstate;
2164
2165         /*
2166          * Use standard planner if pg_hint_plan is disabled.  Other hook functions
2167          * try to change plan with current_hint if any, so set it to NULL.
2168          */
2169         if (!pg_hint_plan_enable_hint)
2170                 goto standard_planner_proc;
2171
2172         /* Create hint struct from client-supplied query string. */
2173         query = get_query_string();
2174
2175         /*
2176          * Search hint information which is stored for the query and the
2177          * application.  Query string is normalized before using in condition
2178          * in order to allow fuzzy matching.
2179          *
2180          * XXX: normalizing code is copied from pg_stat_statements.c, so be careful
2181          * when supporting PostgreSQL's version up.
2182          */
2183         jstate.jumble = (unsigned char *) palloc(JUMBLE_SIZE);
2184         jstate.jumble_len = 0;
2185         jstate.clocations_buf_size = 32;
2186         jstate.clocations = (pgssLocationLen *)
2187                 palloc(jstate.clocations_buf_size * sizeof(pgssLocationLen));
2188         jstate.clocations_count = 0;
2189         JumbleQuery(&jstate, parse);
2190         /*
2191          * generate_normalized_query() copies exact given query_len bytes, so we
2192          * add 1 byte for null-termination here.  As comments on
2193          * generate_normalized_query says, generate_normalized_query doesn't take
2194          * care of null-terminate, but additional 1 byte ensures that '\0' byte in
2195          * the source buffer to be copied into norm_query.
2196          */
2197         query_len = strlen(query) + 1;
2198         norm_query = generate_normalized_query(&jstate,
2199                                                                                    query,
2200                                                                                    &query_len,
2201                                                                                    GetDatabaseEncoding());
2202         hints = get_hints_from_table(norm_query, application_name);
2203         elog(DEBUG1,
2204                  "pg_hint_plan: get_hints_from_table [%s][%s]=>[%s]",
2205                  norm_query, application_name,
2206                  hints ? hints : "(none)");
2207         if (hints == NULL)
2208                 hints = get_hints_from_comment(query);
2209         hstate = create_hintstate(parse, hints);
2210
2211         /*
2212          * Use standard planner if the statement has not valid hint.  Other hook
2213          * functions try to change plan with current_hint if any, so set it to
2214          * NULL.
2215          */
2216         if (!hstate)
2217                 goto standard_planner_proc;
2218
2219         /*
2220          * Push new hint struct to the hint stack to disable previous hint context.
2221          */
2222         push_hint(hstate);
2223
2224         /* Set GUC parameters which are specified with Set hint. */
2225         save_nestlevel = set_config_options(current_hint->set_hints,
2226                                                                                 current_hint->num_hints[HINT_TYPE_SET],
2227                                                                                 current_hint->context);
2228
2229         if (enable_seqscan)
2230                 current_hint->init_scan_mask |= ENABLE_SEQSCAN;
2231         if (enable_indexscan)
2232                 current_hint->init_scan_mask |= ENABLE_INDEXSCAN;
2233         if (enable_bitmapscan)
2234                 current_hint->init_scan_mask |= ENABLE_BITMAPSCAN;
2235         if (enable_tidscan)
2236                 current_hint->init_scan_mask |= ENABLE_TIDSCAN;
2237 #if PG_VERSION_NUM >= 90200
2238         if (enable_indexonlyscan)
2239                 current_hint->init_scan_mask |= ENABLE_INDEXONLYSCAN;
2240 #endif
2241         if (enable_nestloop)
2242                 current_hint->init_join_mask |= ENABLE_NESTLOOP;
2243         if (enable_mergejoin)
2244                 current_hint->init_join_mask |= ENABLE_MERGEJOIN;
2245         if (enable_hashjoin)
2246                 current_hint->init_join_mask |= ENABLE_HASHJOIN;
2247
2248         /*
2249          * Use PG_TRY mechanism to recover GUC parameters and current_hint to the
2250          * state when this planner started when error occurred in planner.
2251          */
2252         PG_TRY();
2253         {
2254                 if (prev_planner)
2255                         result = (*prev_planner) (parse, cursorOptions, boundParams);
2256                 else
2257                         result = standard_planner(parse, cursorOptions, boundParams);
2258         }
2259         PG_CATCH();
2260         {
2261                 /*
2262                  * Rollback changes of GUC parameters, and pop current hint context
2263                  * from hint stack to rewind the state.
2264                  */
2265                 AtEOXact_GUC(true, save_nestlevel);
2266                 pop_hint();
2267                 PG_RE_THROW();
2268         }
2269         PG_END_TRY();
2270
2271         /* Print hint in debug mode. */
2272         if (pg_hint_plan_debug_print)
2273                 HintStateDump(current_hint);
2274
2275         /*
2276          * Rollback changes of GUC parameters, and pop current hint context from
2277          * hint stack to rewind the state.
2278          */
2279         AtEOXact_GUC(true, save_nestlevel);
2280         pop_hint();
2281
2282         return result;
2283
2284 standard_planner_proc:
2285         current_hint = NULL;
2286         if (prev_planner)
2287                 return (*prev_planner) (parse, cursorOptions, boundParams);
2288         else
2289                 return standard_planner(parse, cursorOptions, boundParams);
2290 }
2291
2292 /*
2293  * Return scan method hint which matches given aliasname.
2294  */
2295 static ScanMethodHint *
2296 find_scan_hint(PlannerInfo *root, RelOptInfo *rel)
2297 {
2298         RangeTblEntry  *rte;
2299         int                             i;
2300
2301         /*
2302          * We can't apply scan method hint if the relation is:
2303          *   - not a base relation
2304          *   - not an ordinary relation (such as join and subquery)
2305          */
2306         if (rel->reloptkind != RELOPT_BASEREL || rel->rtekind != RTE_RELATION)
2307                 return NULL;
2308
2309         rte = root->simple_rte_array[rel->relid];
2310
2311         /* We can't force scan method of foreign tables */
2312         if (rte->relkind == RELKIND_FOREIGN_TABLE)
2313                 return NULL;
2314
2315         /* Find scan method hint, which matches given names, from the list. */
2316         for (i = 0; i < current_hint->num_hints[HINT_TYPE_SCAN_METHOD]; i++)
2317         {
2318                 ScanMethodHint *hint = current_hint->scan_hints[i];
2319
2320                 /* We ignore disabled hints. */
2321                 if (!hint_state_enabled(hint))
2322                         continue;
2323
2324                 if (RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
2325                         return hint;
2326         }
2327
2328         return NULL;
2329 }
2330
2331 /*
2332  * regexeq
2333  *
2334  * Returns TRUE on match, FALSE on no match.
2335  *
2336  *   s1 --- the data to match against
2337  *   s2 --- the pattern
2338  *
2339  * Because we copy s1 to NameData, make the size of s1 less than NAMEDATALEN.
2340  */
2341 static bool
2342 regexpeq(const char *s1, const char *s2)
2343 {
2344         NameData        name;
2345         text       *regexp;
2346         Datum           result;
2347
2348         strcpy(name.data, s1);
2349         regexp = cstring_to_text(s2);
2350
2351         result = DirectFunctionCall2Coll(nameregexeq,
2352                                                                          DEFAULT_COLLATION_OID,
2353                                                                          NameGetDatum(&name),
2354                                                                          PointerGetDatum(regexp));
2355         return DatumGetBool(result);
2356 }
2357
2358 static void
2359 delete_indexes(ScanMethodHint *hint, RelOptInfo *rel, Oid relationObjectId)
2360 {
2361         ListCell           *cell;
2362         ListCell           *prev;
2363         ListCell           *next;
2364         StringInfoData  buf;
2365
2366         /*
2367          * We delete all the IndexOptInfo list and prevent you from being usable by
2368          * a scan.
2369          */
2370         if (hint->enforce_mask == ENABLE_SEQSCAN ||
2371                 hint->enforce_mask == ENABLE_TIDSCAN)
2372         {
2373                 list_free_deep(rel->indexlist);
2374                 rel->indexlist = NIL;
2375                 hint->base.state = HINT_STATE_USED;
2376
2377                 return;
2378         }
2379
2380         /*
2381          * When a list of indexes is not specified, we just use all indexes.
2382          */
2383         if (hint->indexnames == NIL)
2384                 return;
2385
2386         /*
2387          * Leaving only an specified index, we delete it from a IndexOptInfo list
2388          * other than it.
2389          */
2390         prev = NULL;
2391         if (pg_hint_plan_debug_print)
2392                 initStringInfo(&buf);
2393
2394         for (cell = list_head(rel->indexlist); cell; cell = next)
2395         {
2396                 IndexOptInfo   *info = (IndexOptInfo *) lfirst(cell);
2397                 char               *indexname = get_rel_name(info->indexoid);
2398                 ListCell           *l;
2399                 bool                    use_index = false;
2400
2401                 next = lnext(cell);
2402
2403                 foreach(l, hint->indexnames)
2404                 {
2405                         char   *hintname = (char *) lfirst(l);
2406                         bool    result;
2407
2408                         if (hint->regexp)
2409                                 result = regexpeq(indexname, hintname);
2410                         else
2411                                 result = RelnameCmp(&indexname, &hintname) == 0;
2412
2413                         if (result)
2414                         {
2415                                 use_index = true;
2416                                 if (pg_hint_plan_debug_print)
2417                                 {
2418                                         appendStringInfoCharMacro(&buf, ' ');
2419                                         quote_value(&buf, indexname);
2420                                 }
2421
2422                                 break;
2423                         }
2424                 }
2425
2426                 /*
2427                  * to make the index a candidate when definition of this index is
2428                  * matched with the index's definition of current_hint.
2429                  */
2430                 if (OidIsValid(relationObjectId) && !use_index)
2431                 {
2432                         foreach(l, current_hint->parent_index_infos)
2433                         {
2434                                 int                                     i;
2435                                 HeapTuple                       ht_idx;
2436                                 ParentIndexInfo    *p_info = (ParentIndexInfo *)lfirst(l);
2437
2438                                 /* check to match the parameter of unique */
2439                                 if (p_info->indisunique != info->unique)
2440                                         continue;
2441
2442                                 /* check to match the parameter of index's method */
2443                                 if (p_info->method != info->relam)
2444                                         continue;
2445
2446                                 /* to check to match the indexkey's configuration */
2447                                 if ((list_length(p_info->column_names)) !=
2448                                          info->ncolumns)
2449                                         continue;
2450
2451                                 /* check to match the indexkey's configuration */
2452                                 for (i = 0; i < info->ncolumns; i++)
2453                                 {
2454                                         char       *c_attname = NULL;
2455                                         char       *p_attname = NULL;
2456
2457                                         p_attname =
2458                                                 list_nth(p_info->column_names, i);
2459
2460                                         /* both are expressions */
2461                                         if (info->indexkeys[i] == 0 && !p_attname)
2462                                                 continue;
2463
2464                                         /* one's column is expression, the other is not */
2465                                         if (info->indexkeys[i] == 0 || !p_attname)
2466                                                 break;
2467
2468                                         c_attname = get_attname(relationObjectId,
2469                                                                                                 info->indexkeys[i]);
2470
2471                                         if (strcmp(p_attname, c_attname) != 0)
2472                                                 break;
2473
2474                                         if (p_info->indcollation[i] != info->indexcollations[i])
2475                                                 break;
2476
2477                                         if (p_info->opclass[i] != info->opcintype[i])
2478                                                 break;
2479
2480                                         if (((p_info->indoption[i] & INDOPTION_DESC) != 0) !=
2481                                                 info->reverse_sort[i])
2482                                                 break;
2483
2484                                         if (((p_info->indoption[i] & INDOPTION_NULLS_FIRST) != 0) !=
2485                                                 info->nulls_first[i])
2486                                                 break;
2487
2488                                 }
2489
2490                                 if (i != info->ncolumns)
2491                                         continue;
2492
2493                                 if ((p_info->expression_str && (info->indexprs != NIL)) ||
2494                                         (p_info->indpred_str && (info->indpred != NIL)))
2495                                 {
2496                                         /*
2497                                          * Fetch the pg_index tuple by the Oid of the index
2498                                          */
2499                                         ht_idx = SearchSysCache1(INDEXRELID,
2500                                                                                          ObjectIdGetDatum(info->indexoid));
2501
2502                                         /* check to match the expression's parameter of index */
2503                                         if (p_info->expression_str &&
2504                                                 !heap_attisnull(ht_idx, Anum_pg_index_indexprs))
2505                                         {
2506                                                 Datum       exprsDatum;
2507                                                 bool        isnull;
2508                                                 Datum       result;
2509
2510                                                 /*
2511                                                  * to change the expression's parameter of child's
2512                                                  * index to strings
2513                                                  */
2514                                                 exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
2515                                                                                                          Anum_pg_index_indexprs,
2516                                                                                                          &isnull);
2517
2518                                                 result = DirectFunctionCall2(pg_get_expr,
2519                                                                                                          exprsDatum,
2520                                                                                                          ObjectIdGetDatum(
2521                                                                                                                  relationObjectId));
2522
2523                                                 if (strcmp(p_info->expression_str,
2524                                                                    text_to_cstring(DatumGetTextP(result))) != 0)
2525                                                 {
2526                                                         /* Clean up */
2527                                                         ReleaseSysCache(ht_idx);
2528
2529                                                         continue;
2530                                                 }
2531                                         }
2532
2533                                         /* Check to match the predicate's paraameter of index */
2534                                         if (p_info->indpred_str &&
2535                                                 !heap_attisnull(ht_idx, Anum_pg_index_indpred))
2536                                         {
2537                                                 Datum       predDatum;
2538                                                 bool        isnull;
2539                                                 Datum       result;
2540
2541                                                 /*
2542                                                  * to change the predicate's parabeter of child's
2543                                                  * index to strings
2544                                                  */
2545                                                 predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
2546                                                                                                          Anum_pg_index_indpred,
2547                                                                                                          &isnull);
2548
2549                                                 result = DirectFunctionCall2(pg_get_expr,
2550                                                                                                          predDatum,
2551                                                                                                          ObjectIdGetDatum(
2552                                                                                                                  relationObjectId));
2553
2554                                                 if (strcmp(p_info->indpred_str,
2555                                                                    text_to_cstring(DatumGetTextP(result))) != 0)
2556                                                 {
2557                                                         /* Clean up */
2558                                                         ReleaseSysCache(ht_idx);
2559
2560                                                         continue;
2561                                                 }
2562                                         }
2563
2564                                         /* Clean up */
2565                                         ReleaseSysCache(ht_idx);
2566                                 }
2567                                 else if (p_info->expression_str || (info->indexprs != NIL))
2568                                         continue;
2569                                 else if (p_info->indpred_str || (info->indpred != NIL))
2570                                         continue;
2571
2572                                 use_index = true;
2573
2574                                 /* to log the candidate of index */
2575                                 if (pg_hint_plan_debug_print)
2576                                 {
2577                                         appendStringInfoCharMacro(&buf, ' ');
2578                                         quote_value(&buf, indexname);
2579                                 }
2580
2581                                 break;
2582                         }
2583                 }
2584
2585                 if (!use_index)
2586                         rel->indexlist = list_delete_cell(rel->indexlist, cell, prev);
2587                 else
2588                         prev = cell;
2589
2590                 pfree(indexname);
2591         }
2592
2593         if (pg_hint_plan_debug_print)
2594         {
2595                 char   *relname;
2596                 StringInfoData  rel_buf;
2597
2598                 if (OidIsValid(relationObjectId))
2599                         relname = get_rel_name(relationObjectId);
2600                 else
2601                         relname = hint->relname;
2602
2603                 initStringInfo(&rel_buf);
2604                 quote_value(&rel_buf, relname);
2605
2606                 ereport(LOG,
2607                                 (errmsg("available indexes for %s(%s):%s",
2608                                          hint->base.keyword,
2609                                          rel_buf.data,
2610                                          buf.data)));
2611                 pfree(buf.data);
2612                 pfree(rel_buf.data);
2613         }
2614 }
2615
2616 /* 
2617  * Return information of index definition.
2618  */
2619 static ParentIndexInfo *
2620 get_parent_index_info(Oid indexoid, Oid relid)
2621 {
2622         ParentIndexInfo *p_info = palloc(sizeof(ParentIndexInfo));
2623         Relation            indexRelation;
2624         Form_pg_index   index;
2625         char               *attname;
2626         int                             i;
2627
2628         indexRelation = index_open(indexoid, RowExclusiveLock);
2629
2630         index = indexRelation->rd_index;
2631
2632         p_info->indisunique = index->indisunique;
2633         p_info->method = indexRelation->rd_rel->relam;
2634
2635         p_info->column_names = NIL;
2636         p_info->indcollation = (Oid *) palloc(sizeof(Oid) * index->indnatts);
2637         p_info->opclass = (Oid *) palloc(sizeof(Oid) * index->indnatts);
2638         p_info->indoption = (int16 *) palloc(sizeof(Oid) * index->indnatts);
2639
2640         for (i = 0; i < index->indnatts; i++)
2641         {
2642                 attname = get_attname(relid, index->indkey.values[i]);
2643                 p_info->column_names = lappend(p_info->column_names, attname);
2644
2645                 p_info->indcollation[i] = indexRelation->rd_indcollation[i];
2646                 p_info->opclass[i] = indexRelation->rd_opcintype[i];
2647                 p_info->indoption[i] = indexRelation->rd_indoption[i];
2648         }
2649
2650         /*
2651          * to check to match the expression's paraameter of index with child indexes
2652          */
2653         p_info->expression_str = NULL;
2654         if(!heap_attisnull(indexRelation->rd_indextuple, Anum_pg_index_indexprs))
2655         {
2656                 Datum       exprsDatum;
2657                 bool            isnull;
2658                 Datum           result;
2659
2660                 exprsDatum = SysCacheGetAttr(INDEXRELID, indexRelation->rd_indextuple,
2661                                                                          Anum_pg_index_indexprs, &isnull);
2662
2663                 result = DirectFunctionCall2(pg_get_expr,
2664                                                                          exprsDatum,
2665                                                                          ObjectIdGetDatum(relid));
2666
2667                 p_info->expression_str = text_to_cstring(DatumGetTextP(result));
2668         }
2669
2670         /*
2671          * to check to match the predicate's paraameter of index with child indexes
2672          */
2673         p_info->indpred_str = NULL;
2674         if(!heap_attisnull(indexRelation->rd_indextuple, Anum_pg_index_indpred))
2675         {
2676                 Datum       predDatum;
2677                 bool            isnull;
2678                 Datum           result;
2679
2680                 predDatum = SysCacheGetAttr(INDEXRELID, indexRelation->rd_indextuple,
2681                                                                          Anum_pg_index_indpred, &isnull);
2682
2683                 result = DirectFunctionCall2(pg_get_expr,
2684                                                                          predDatum,
2685                                                                          ObjectIdGetDatum(relid));
2686
2687                 p_info->indpred_str = text_to_cstring(DatumGetTextP(result));
2688         }
2689
2690         index_close(indexRelation, NoLock);
2691
2692         return p_info;
2693 }
2694
2695 static void
2696 pg_hint_plan_get_relation_info(PlannerInfo *root, Oid relationObjectId,
2697                                                            bool inhparent, RelOptInfo *rel)
2698 {
2699         ScanMethodHint *hint;
2700
2701         if (prev_get_relation_info)
2702                 (*prev_get_relation_info) (root, relationObjectId, inhparent, rel);
2703
2704         /* Do nothing if we don't have valid hint in this context. */
2705         if (!current_hint)
2706                 return;
2707
2708         if (inhparent)
2709         {
2710                 /* store does relids of parent table. */
2711                 current_hint->parent_relid = rel->relid;
2712                 current_hint->parent_rel_oid = relationObjectId;
2713         }
2714         else if (current_hint->parent_relid != 0)
2715         {
2716                 /*
2717                  * We use the same GUC parameter if this table is the child table of a
2718                  * table called pg_hint_plan_get_relation_info just before that.
2719                  */
2720                 ListCell   *l;
2721
2722                 /* append_rel_list contains all append rels; ignore others */
2723                 foreach(l, root->append_rel_list)
2724                 {
2725                         AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
2726
2727                         /* This rel is child table. */
2728                         if (appinfo->parent_relid == current_hint->parent_relid &&
2729                                 appinfo->child_relid == rel->relid)
2730                         {
2731                                 if (current_hint->parent_hint)
2732                                         delete_indexes(current_hint->parent_hint, rel,
2733                                                                    relationObjectId);
2734
2735                                 return;
2736                         }
2737                 }
2738
2739                 /* This rel is not inherit table. */
2740                 current_hint->parent_relid = 0;
2741                 current_hint->parent_rel_oid = InvalidOid;
2742                 current_hint->parent_hint = NULL;
2743         }
2744
2745         /*
2746          * If scan method hint was given, reset GUC parameters which control
2747          * planner behavior about choosing scan methods.
2748          */
2749         if ((hint = find_scan_hint(root, rel)) == NULL)
2750         {
2751                 set_scan_config_options(current_hint->init_scan_mask,
2752                                                                 current_hint->context);
2753                 return;
2754         }
2755         set_scan_config_options(hint->enforce_mask, current_hint->context);
2756         hint->base.state = HINT_STATE_USED;
2757
2758         if (inhparent)
2759         {
2760                 Relation    relation;
2761                 List       *indexoidlist;
2762                 ListCell   *l;
2763
2764                 current_hint->parent_hint = hint;
2765
2766                 relation = heap_open(relationObjectId, NoLock);
2767                 indexoidlist = RelationGetIndexList(relation);
2768
2769                 foreach(l, indexoidlist)
2770                 {
2771                         Oid         indexoid = lfirst_oid(l);
2772                         char       *indexname = get_rel_name(indexoid);
2773                         bool        use_index = false;
2774                         ListCell   *lc;
2775                         ParentIndexInfo *parent_index_info;
2776
2777                         foreach(lc, hint->indexnames)
2778                         {
2779                                 if (RelnameCmp(&indexname, &lfirst(lc)) == 0)
2780                                 {
2781                                         use_index = true;
2782                                         break;
2783                                 }
2784                         }
2785                         if (!use_index)
2786                                 continue;
2787
2788                         parent_index_info = get_parent_index_info(indexoid,
2789                                                                                                           relationObjectId);
2790                         current_hint->parent_index_infos =
2791                                 lappend(current_hint->parent_index_infos, parent_index_info);
2792                 }
2793                 heap_close(relation, NoLock);
2794         }
2795         else
2796                 delete_indexes(hint, rel, InvalidOid);
2797 }
2798
2799 /*
2800  * Return index of relation which matches given aliasname, or 0 if not found.
2801  * If same aliasname was used multiple times in a query, return -1.
2802  */
2803 static int
2804 find_relid_aliasname(PlannerInfo *root, char *aliasname, List *initial_rels,
2805                                          const char *str)
2806 {
2807         int             i;
2808         Index   found = 0;
2809
2810         for (i = 1; i < root->simple_rel_array_size; i++)
2811         {
2812                 ListCell   *l;
2813
2814                 if (root->simple_rel_array[i] == NULL)
2815                         continue;
2816
2817                 Assert(i == root->simple_rel_array[i]->relid);
2818
2819                 if (RelnameCmp(&aliasname,
2820                                            &root->simple_rte_array[i]->eref->aliasname) != 0)
2821                         continue;
2822
2823                 foreach(l, initial_rels)
2824                 {
2825                         RelOptInfo *rel = (RelOptInfo *) lfirst(l);
2826
2827                         if (rel->reloptkind == RELOPT_BASEREL)
2828                         {
2829                                 if (rel->relid != i)
2830                                         continue;
2831                         }
2832                         else
2833                         {
2834                                 Assert(rel->reloptkind == RELOPT_JOINREL);
2835
2836                                 if (!bms_is_member(i, rel->relids))
2837                                         continue;
2838                         }
2839
2840                         if (found != 0)
2841                         {
2842                                 hint_ereport(str,
2843                                                          ("Relation name \"%s\" is ambiguous.",
2844                                                           aliasname));
2845                                 return -1;
2846                         }
2847
2848                         found = i;
2849                         break;
2850                 }
2851
2852         }
2853
2854         return found;
2855 }
2856
2857 /*
2858  * Return join hint which matches given joinrelids.
2859  */
2860 static JoinMethodHint *
2861 find_join_hint(Relids joinrelids)
2862 {
2863         List       *join_hint;
2864         ListCell   *l;
2865
2866         join_hint = current_hint->join_hint_level[bms_num_members(joinrelids)];
2867
2868         foreach(l, join_hint)
2869         {
2870                 JoinMethodHint *hint = (JoinMethodHint *) lfirst(l);
2871
2872                 if (bms_equal(joinrelids, hint->joinrelids))
2873                         return hint;
2874         }
2875
2876         return NULL;
2877 }
2878
2879 static Relids
2880 OuterInnerJoinCreate(OuterInnerRels *outer_inner, LeadingHint *leading_hint,
2881         PlannerInfo *root, List *initial_rels, HintState *hstate, int nbaserel)
2882 {
2883         OuterInnerRels *outer_rels;
2884         OuterInnerRels *inner_rels;
2885         Relids                  outer_relids;
2886         Relids                  inner_relids;
2887         Relids                  join_relids;
2888         JoinMethodHint *hint;
2889
2890         if (outer_inner->relation != NULL)
2891         {
2892                 return bms_make_singleton(
2893                                         find_relid_aliasname(root, outer_inner->relation,
2894                                                                                  initial_rels,
2895                                                                                  leading_hint->base.hint_str));
2896         }
2897
2898         outer_rels = lfirst(outer_inner->outer_inner_pair->head);
2899         inner_rels = lfirst(outer_inner->outer_inner_pair->tail);
2900
2901         outer_relids = OuterInnerJoinCreate(outer_rels,
2902                                                                                 leading_hint,
2903                                                                                 root,
2904                                                                                 initial_rels,
2905                                                                                 hstate,
2906                                                                                 nbaserel);
2907         inner_relids = OuterInnerJoinCreate(inner_rels,
2908                                                                                 leading_hint,
2909                                                                                 root,
2910                                                                                 initial_rels,
2911                                                                                 hstate,
2912                                                                                 nbaserel);
2913
2914         join_relids = bms_add_members(outer_relids, inner_relids);
2915
2916         if (bms_num_members(join_relids) > nbaserel)
2917                 return join_relids;
2918
2919         /*
2920          * If we don't have join method hint, create new one for the
2921          * join combination with all join methods are enabled.
2922          */
2923         hint = find_join_hint(join_relids);
2924         if (hint == NULL)
2925         {
2926                 /*
2927                  * Here relnames is not set, since Relids bitmap is sufficient to
2928                  * control paths of this query afterward.
2929                  */
2930                 hint = (JoinMethodHint *) JoinMethodHintCreate(
2931                                         leading_hint->base.hint_str,
2932                                         HINT_LEADING,
2933                                         HINT_KEYWORD_LEADING);
2934                 hint->base.state = HINT_STATE_USED;
2935                 hint->nrels = bms_num_members(join_relids);
2936                 hint->enforce_mask = ENABLE_ALL_JOIN;
2937                 hint->joinrelids = bms_copy(join_relids);
2938                 hint->inner_nrels = bms_num_members(inner_relids);
2939                 hint->inner_joinrelids = bms_copy(inner_relids);
2940
2941                 hstate->join_hint_level[hint->nrels] =
2942                         lappend(hstate->join_hint_level[hint->nrels], hint);
2943         }
2944         else
2945         {
2946                 hint->inner_nrels = bms_num_members(inner_relids);
2947                 hint->inner_joinrelids = bms_copy(inner_relids);
2948         }
2949
2950         return join_relids;
2951 }
2952
2953 /*
2954  * Transform join method hint into handy form.
2955  *
2956  *   - create bitmap of relids from alias names, to make it easier to check
2957  *     whether a join path matches a join method hint.
2958  *   - add join method hints which are necessary to enforce join order
2959  *     specified by Leading hint
2960  */
2961 static bool
2962 transform_join_hints(HintState *hstate, PlannerInfo *root, int nbaserel,
2963                 List *initial_rels, JoinMethodHint **join_method_hints)
2964 {
2965         int                             i;
2966         int                             relid;
2967         Relids                  joinrelids;
2968         int                             njoinrels;
2969         ListCell           *l;
2970         char               *relname;
2971         LeadingHint        *lhint = NULL;
2972
2973         /*
2974          * Create bitmap of relids from alias names for each join method hint.
2975          * Bitmaps are more handy than strings in join searching.
2976          */
2977         for (i = 0; i < hstate->num_hints[HINT_TYPE_JOIN_METHOD]; i++)
2978         {
2979                 JoinMethodHint *hint = hstate->join_hints[i];
2980                 int     j;
2981
2982                 if (!hint_state_enabled(hint) || hint->nrels > nbaserel)
2983                         continue;
2984
2985                 bms_free(hint->joinrelids);
2986                 hint->joinrelids = NULL;
2987                 relid = 0;
2988                 for (j = 0; j < hint->nrels; j++)
2989                 {
2990                         relname = hint->relnames[j];
2991
2992                         relid = find_relid_aliasname(root, relname, initial_rels,
2993                                                                                  hint->base.hint_str);
2994
2995                         if (relid == -1)
2996                                 hint->base.state = HINT_STATE_ERROR;
2997
2998                         if (relid <= 0)
2999                                 break;
3000
3001                         if (bms_is_member(relid, hint->joinrelids))
3002                         {
3003                                 hint_ereport(hint->base.hint_str,
3004                                                          ("Relation name \"%s\" is duplicated.", relname));
3005                                 hint->base.state = HINT_STATE_ERROR;
3006                                 break;
3007                         }
3008
3009                         hint->joinrelids = bms_add_member(hint->joinrelids, relid);
3010                 }
3011
3012                 if (relid <= 0 || hint->base.state == HINT_STATE_ERROR)
3013                         continue;
3014
3015                 hstate->join_hint_level[hint->nrels] =
3016                         lappend(hstate->join_hint_level[hint->nrels], hint);
3017         }
3018
3019         /* Do nothing if no Leading hint was supplied. */
3020         if (hstate->num_hints[HINT_TYPE_LEADING] == 0)
3021                 return false;
3022
3023         /*
3024          * Decide to use Leading hint。
3025          */
3026         for (i = 0; i < hstate->num_hints[HINT_TYPE_LEADING]; i++)
3027         {
3028                 LeadingHint        *leading_hint = (LeadingHint *)hstate->leading_hint[i];
3029                 Relids                  relids;
3030
3031                 if (leading_hint->base.state == HINT_STATE_ERROR)
3032                         continue;
3033
3034                 relid = 0;
3035                 relids = NULL;
3036
3037                 foreach(l, leading_hint->relations)
3038                 {
3039                         relname = (char *)lfirst(l);;
3040
3041                         relid = find_relid_aliasname(root, relname, initial_rels,
3042                                                                                  leading_hint->base.hint_str);
3043                         if (relid == -1)
3044                                 leading_hint->base.state = HINT_STATE_ERROR;
3045
3046                         if (relid <= 0)
3047                                 break;
3048
3049                         if (bms_is_member(relid, relids))
3050                         {
3051                                 hint_ereport(leading_hint->base.hint_str,
3052                                                          ("Relation name \"%s\" is duplicated.", relname));
3053                                 leading_hint->base.state = HINT_STATE_ERROR;
3054                                 break;
3055                         }
3056
3057                         relids = bms_add_member(relids, relid);
3058                 }
3059
3060                 if (relid <= 0 || leading_hint->base.state == HINT_STATE_ERROR)
3061                         continue;
3062
3063                 if (lhint != NULL)
3064                 {
3065                         hint_ereport(lhint->base.hint_str,
3066                                  ("Conflict %s hint.", HintTypeName[lhint->base.type]));
3067                         lhint->base.state = HINT_STATE_DUPLICATION;
3068                 }
3069                 leading_hint->base.state = HINT_STATE_USED;
3070                 lhint = leading_hint;
3071         }
3072
3073         /* check to exist Leading hint marked with 'used'. */
3074         if (lhint == NULL)
3075                 return false;
3076
3077         /*
3078          * We need join method hints which fit specified join order in every join
3079          * level.  For example, Leading(A B C) virtually requires following join
3080          * method hints, if no join method hint supplied:
3081          *   - level 1: none
3082          *   - level 2: NestLoop(A B), MergeJoin(A B), HashJoin(A B)
3083          *   - level 3: NestLoop(A B C), MergeJoin(A B C), HashJoin(A B C)
3084          *
3085          * If we already have join method hint which fits specified join order in
3086          * that join level, we leave it as-is and don't add new hints.
3087          */
3088         joinrelids = NULL;
3089         njoinrels = 0;
3090         if (lhint->outer_inner == NULL)
3091         {
3092                 foreach(l, lhint->relations)
3093                 {
3094                         JoinMethodHint *hint;
3095
3096                         relname = (char *)lfirst(l);
3097
3098                         /*
3099                          * Find relid of the relation which has given name.  If we have the
3100                          * name given in Leading hint multiple times in the join, nothing to
3101                          * do.
3102                          */
3103                         relid = find_relid_aliasname(root, relname, initial_rels,
3104                                                                                  hstate->hint_str);
3105
3106                         /* Create bitmap of relids for current join level. */
3107                         joinrelids = bms_add_member(joinrelids, relid);
3108                         njoinrels++;
3109
3110                         /* We never have join method hint for single relation. */
3111                         if (njoinrels < 2)
3112                                 continue;
3113
3114                         /*
3115                          * If we don't have join method hint, create new one for the
3116                          * join combination with all join methods are enabled.
3117                          */
3118                         hint = find_join_hint(joinrelids);
3119                         if (hint == NULL)
3120                         {
3121                                 /*
3122                                  * Here relnames is not set, since Relids bitmap is sufficient
3123                                  * to control paths of this query afterward.
3124                                  */
3125                                 hint = (JoinMethodHint *) JoinMethodHintCreate(
3126                                                                                         lhint->base.hint_str,
3127                                                                                         HINT_LEADING,
3128                                                                                         HINT_KEYWORD_LEADING);
3129                                 hint->base.state = HINT_STATE_USED;
3130                                 hint->nrels = njoinrels;
3131                                 hint->enforce_mask = ENABLE_ALL_JOIN;
3132                                 hint->joinrelids = bms_copy(joinrelids);
3133                         }
3134
3135                         join_method_hints[njoinrels] = hint;
3136
3137                         if (njoinrels >= nbaserel)
3138                                 break;
3139                 }
3140                 bms_free(joinrelids);
3141
3142                 if (njoinrels < 2)
3143                         return false;
3144
3145                 /*
3146                  * Delete all join hints which have different combination from Leading
3147                  * hint.
3148                  */
3149                 for (i = 2; i <= njoinrels; i++)
3150                 {
3151                         list_free(hstate->join_hint_level[i]);
3152
3153                         hstate->join_hint_level[i] = lappend(NIL, join_method_hints[i]);
3154                 }
3155         }
3156         else
3157         {
3158                 joinrelids = OuterInnerJoinCreate(lhint->outer_inner,
3159                                                                                   lhint,
3160                                           root,
3161                                           initial_rels,
3162                                                                                   hstate,
3163                                                                                   nbaserel);
3164
3165                 njoinrels = bms_num_members(joinrelids);
3166                 Assert(njoinrels >= 2);
3167
3168                 /*
3169                  * Delete all join hints which have different combination from Leading
3170                  * hint.
3171                  */
3172                 for (i = 2;i <= njoinrels; i++)
3173                 {
3174                         if (hstate->join_hint_level[i] != NIL)
3175                         {
3176                                 ListCell *prev = NULL;
3177                                 ListCell *next = NULL;
3178                                 for(l = list_head(hstate->join_hint_level[i]); l; l = next)
3179                                 {
3180
3181                                         JoinMethodHint *hint = (JoinMethodHint *)lfirst(l);
3182
3183                                         next = lnext(l);
3184
3185                                         if (hint->inner_nrels == 0 &&
3186                                                 !(bms_intersect(hint->joinrelids, joinrelids) == NULL ||
3187                                                   bms_equal(bms_union(hint->joinrelids, joinrelids),
3188                                                   hint->joinrelids)))
3189                                         {
3190                                                 hstate->join_hint_level[i] =
3191                                                         list_delete_cell(hstate->join_hint_level[i], l,
3192                                                                                          prev);
3193                                         }
3194                                         else
3195                                                 prev = l;
3196                                 }
3197                         }
3198                 }
3199
3200                 bms_free(joinrelids);
3201         }
3202
3203         if (hint_state_enabled(lhint))
3204         {
3205                 set_join_config_options(DISABLE_ALL_JOIN, current_hint->context);
3206                 return true;
3207         }
3208         return false;
3209 }
3210
3211 /*
3212  * set_plain_rel_pathlist
3213  *        Build access paths for a plain relation (no subquery, no inheritance)
3214  *
3215  * This function was copied and edited from set_plain_rel_pathlist() in
3216  * src/backend/optimizer/path/allpaths.c
3217  */
3218 static void
3219 set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
3220 {
3221         /* Consider sequential scan */
3222 #if PG_VERSION_NUM >= 90200
3223         add_path(rel, create_seqscan_path(root, rel, NULL));
3224 #else
3225         add_path(rel, create_seqscan_path(root, rel));
3226 #endif
3227
3228         /* Consider index scans */
3229         create_index_paths(root, rel);
3230
3231         /* Consider TID scans */
3232         create_tidscan_paths(root, rel);
3233
3234         /* Now find the cheapest of the paths for this rel */
3235         set_cheapest(rel);
3236 }
3237
3238 static void
3239 rebuild_scan_path(HintState *hstate, PlannerInfo *root, int level,
3240                                   List *initial_rels)
3241 {
3242         ListCell   *l;
3243
3244         foreach(l, initial_rels)
3245         {
3246                 RelOptInfo         *rel = (RelOptInfo *) lfirst(l);
3247                 RangeTblEntry  *rte;
3248                 ScanMethodHint *hint;
3249
3250                 /* Skip relations which we can't choose scan method. */
3251                 if (rel->reloptkind != RELOPT_BASEREL || rel->rtekind != RTE_RELATION)
3252                         continue;
3253
3254                 rte = root->simple_rte_array[rel->relid];
3255
3256                 /* We can't force scan method of foreign tables */
3257                 if (rte->relkind == RELKIND_FOREIGN_TABLE)
3258                         continue;
3259
3260                 /*
3261                  * Create scan paths with GUC parameters which are at the beginning of
3262                  * planner if scan method hint is not specified, otherwise use
3263                  * specified hints and mark the hint as used.
3264                  */
3265                 if ((hint = find_scan_hint(root, rel)) == NULL)
3266                         set_scan_config_options(hstate->init_scan_mask,
3267                                                                         hstate->context);
3268                 else
3269                 {
3270                         set_scan_config_options(hint->enforce_mask, hstate->context);
3271                         hint->base.state = HINT_STATE_USED;
3272                 }
3273
3274                 list_free_deep(rel->pathlist);
3275                 rel->pathlist = NIL;
3276                 if (rte->inh)
3277                 {
3278                         /* It's an "append relation", process accordingly */
3279                         set_append_rel_pathlist(root, rel, rel->relid, rte);
3280                 }
3281                 else
3282                 {
3283                         set_plain_rel_pathlist(root, rel, rte);
3284                 }
3285         }
3286
3287         /*
3288          * Restore the GUC variables we set above.
3289          */
3290         set_scan_config_options(hstate->init_scan_mask, hstate->context);
3291 }
3292
3293 /*
3294  * wrapper of make_join_rel()
3295  *
3296  * call make_join_rel() after changing enable_* parameters according to given
3297  * hints.
3298  */
3299 static RelOptInfo *
3300 make_join_rel_wrapper(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
3301 {
3302         Relids                  joinrelids;
3303         JoinMethodHint *hint;
3304         RelOptInfo         *rel;
3305         int                             save_nestlevel;
3306
3307         joinrelids = bms_union(rel1->relids, rel2->relids);
3308         hint = find_join_hint(joinrelids);
3309         bms_free(joinrelids);
3310
3311         if (!hint)
3312                 return pg_hint_plan_make_join_rel(root, rel1, rel2);
3313
3314         if (hint->inner_nrels == 0)
3315         {
3316                 save_nestlevel = NewGUCNestLevel();
3317
3318                 set_join_config_options(hint->enforce_mask, current_hint->context);
3319
3320                 rel = pg_hint_plan_make_join_rel(root, rel1, rel2);
3321                 hint->base.state = HINT_STATE_USED;
3322
3323                 /*
3324                  * Restore the GUC variables we set above.
3325                  */
3326                 AtEOXact_GUC(true, save_nestlevel);
3327         }
3328         else
3329                 rel = pg_hint_plan_make_join_rel(root, rel1, rel2);
3330
3331         return rel;
3332 }
3333
3334 /*
3335  * TODO : comment
3336  */
3337 static void
3338 add_paths_to_joinrel_wrapper(PlannerInfo *root,
3339                                                          RelOptInfo *joinrel,
3340                                                          RelOptInfo *outerrel,
3341                                                          RelOptInfo *innerrel,
3342                                                          JoinType jointype,
3343                                                          SpecialJoinInfo *sjinfo,
3344                                                          List *restrictlist)
3345 {
3346         ScanMethodHint *scan_hint = NULL;
3347         Relids                  joinrelids;
3348         JoinMethodHint *join_hint;
3349         int                             save_nestlevel;
3350
3351         if ((scan_hint = find_scan_hint(root, innerrel)) != NULL)
3352         {
3353                 set_scan_config_options(scan_hint->enforce_mask, current_hint->context);
3354                 scan_hint->base.state = HINT_STATE_USED;
3355         }
3356
3357         joinrelids = bms_union(outerrel->relids, innerrel->relids);
3358         join_hint = find_join_hint(joinrelids);
3359         bms_free(joinrelids);
3360
3361         if (join_hint && join_hint->inner_nrels != 0)
3362         {
3363                 save_nestlevel = NewGUCNestLevel();
3364
3365                 if (bms_equal(join_hint->inner_joinrelids, innerrel->relids))
3366                 {
3367
3368                         set_join_config_options(join_hint->enforce_mask,
3369                                                                         current_hint->context);
3370
3371                         add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
3372                                                                  sjinfo, restrictlist);
3373                         join_hint->base.state = HINT_STATE_USED;
3374                 }
3375                 else
3376                 {
3377                         set_join_config_options(DISABLE_ALL_JOIN, current_hint->context);
3378                         add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
3379                                                                  sjinfo, restrictlist);
3380                 }
3381
3382                 /*
3383                  * Restore the GUC variables we set above.
3384                  */
3385                 AtEOXact_GUC(true, save_nestlevel);
3386         }
3387         else
3388                 add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
3389                                                          sjinfo, restrictlist);
3390
3391         if (scan_hint != NULL)
3392                 set_scan_config_options(current_hint->init_scan_mask,
3393                                                                 current_hint->context);
3394 }
3395
3396 static int
3397 get_num_baserels(List *initial_rels)
3398 {
3399         int                     nbaserel = 0;
3400         ListCell   *l;
3401
3402         foreach(l, initial_rels)
3403         {
3404                 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
3405
3406                 if (rel->reloptkind == RELOPT_BASEREL)
3407                         nbaserel++;
3408                 else if (rel->reloptkind ==RELOPT_JOINREL)
3409                         nbaserel+= bms_num_members(rel->relids);
3410                 else
3411                 {
3412                         /* other values not expected here */
3413                         elog(ERROR, "unrecognized reloptkind type: %d", rel->reloptkind);
3414                 }
3415         }
3416
3417         return nbaserel;
3418 }
3419
3420 static RelOptInfo *
3421 pg_hint_plan_join_search(PlannerInfo *root, int levels_needed,
3422                                                  List *initial_rels)
3423 {
3424         JoinMethodHint    **join_method_hints;
3425         int                                     nbaserel;
3426         RelOptInfo                 *rel;
3427         int                                     i;
3428         bool                            leading_hint_enable;
3429
3430         /*
3431          * Use standard planner (or geqo planner) if pg_hint_plan is disabled or no
3432          * valid hint is supplied.
3433          */
3434         if (!current_hint)
3435         {
3436                 if (prev_join_search)
3437                         return (*prev_join_search) (root, levels_needed, initial_rels);
3438                 else if (enable_geqo && levels_needed >= geqo_threshold)
3439                         return geqo(root, levels_needed, initial_rels);
3440                 else
3441                         return standard_join_search(root, levels_needed, initial_rels);
3442         }
3443
3444         /* We apply scan method hint rebuild scan path. */
3445         rebuild_scan_path(current_hint, root, levels_needed, initial_rels);
3446
3447         /*
3448          * In the case using GEQO, only scan method hints and Set hints have
3449          * effect.  Join method and join order is not controllable by hints.
3450          */
3451         if (enable_geqo && levels_needed >= geqo_threshold)
3452                 return geqo(root, levels_needed, initial_rels);
3453
3454         nbaserel = get_num_baserels(initial_rels);
3455         current_hint->join_hint_level = palloc0(sizeof(List *) * (nbaserel + 1));
3456         join_method_hints = palloc0(sizeof(JoinMethodHint *) * (nbaserel + 1));
3457
3458         leading_hint_enable = transform_join_hints(current_hint, root, nbaserel,
3459                                                                                            initial_rels, join_method_hints);
3460
3461         rel = pg_hint_plan_standard_join_search(root, levels_needed, initial_rels);
3462
3463         for (i = 2; i <= nbaserel; i++)
3464         {
3465                 list_free(current_hint->join_hint_level[i]);
3466
3467                 /* free Leading hint only */
3468                 if (join_method_hints[i] != NULL &&
3469                         join_method_hints[i]->enforce_mask == ENABLE_ALL_JOIN)
3470                         JoinMethodHintDelete(join_method_hints[i]);
3471         }
3472         pfree(current_hint->join_hint_level);
3473         pfree(join_method_hints);
3474
3475         if (leading_hint_enable)
3476                 set_join_config_options(current_hint->init_join_mask,
3477                                                                 current_hint->context);
3478
3479         return rel;
3480 }
3481
3482 /*
3483  * set_rel_pathlist
3484  *        Build access paths for a base relation
3485  *
3486  * This function was copied and edited from set_rel_pathlist() in
3487  * src/backend/optimizer/path/allpaths.c
3488  */
3489 static void
3490 set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
3491                                  Index rti, RangeTblEntry *rte)
3492 {
3493 #if PG_VERSION_NUM >= 90200
3494         if (IS_DUMMY_REL(rel))
3495         {
3496                 /* We already proved the relation empty, so nothing more to do */
3497         }
3498         else if (rte->inh)
3499 #else
3500         if (rte->inh)
3501 #endif
3502         {
3503                 /* It's an "append relation", process accordingly */
3504                 set_append_rel_pathlist(root, rel, rti, rte);
3505         }
3506         else
3507         {
3508                 if (rel->rtekind == RTE_RELATION)
3509                 {
3510                         if (rte->relkind == RELKIND_RELATION)
3511                         {
3512                                 /* Plain relation */
3513                                 set_plain_rel_pathlist(root, rel, rte);
3514                         }
3515                         else
3516                                 elog(ERROR, "unexpected relkind: %c", rte->relkind);
3517                 }
3518                 else
3519                         elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
3520         }
3521 }
3522
3523 /*
3524  * stmt_beg callback is called when each query in PL/pgSQL function is about
3525  * to be executed.  At that timing, we save query string in the global variable
3526  * plpgsql_query_string to use it in planner hook.  It's safe to use one global
3527  * variable for the purpose, because its content is only necessary until
3528  * planner hook is called for the query, so recursive PL/pgSQL function calls
3529  * don't harm this mechanismk.
3530  */
3531 static void
3532 pg_hint_plan_plpgsql_stmt_beg(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
3533 {
3534         if ((enum PLpgSQL_stmt_types) stmt->cmd_type == PLPGSQL_STMT_EXECSQL)
3535         {
3536                 PLpgSQL_expr *expr = ((PLpgSQL_stmt_execsql *) stmt)->sqlstmt;
3537                 plpgsql_query_string = expr->query;
3538         }
3539 }
3540
3541 /*
3542  * stmt_end callback is called then each query in PL/pgSQL function has
3543  * finished.  At that timing, we clear plpgsql_query_string to tell planner
3544  * hook that next call is not for a query written in PL/pgSQL block.
3545  */
3546 static void
3547 pg_hint_plan_plpgsql_stmt_end(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
3548 {
3549         if ((enum PLpgSQL_stmt_types) stmt->cmd_type == PLPGSQL_STMT_EXECSQL)
3550                 plpgsql_query_string = NULL;
3551 }
3552
3553 #define standard_join_search pg_hint_plan_standard_join_search
3554 #define join_search_one_level pg_hint_plan_join_search_one_level
3555 #define make_join_rel make_join_rel_wrapper
3556 #include "core.c"
3557
3558 #undef make_join_rel
3559 #define make_join_rel pg_hint_plan_make_join_rel
3560 #define add_paths_to_joinrel add_paths_to_joinrel_wrapper
3561 #include "make_join_rel.c"
3562
3563 #include "pg_stat_statements.c"