OSDN Git Service

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