1 /* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 /*
24   Parse tree node classes for optimizer hint syntax
25 */
26 
27 
28 #ifndef OPT_HINTS_INCLUDED
29 #define OPT_HINTS_INCLUDED
30 
31 #include "my_config.h"
32 #include "parse_tree_node_base.h"
33 #include "sql_alloc.h"
34 #include "sql_list.h"
35 #include "mem_root_array.h"
36 #include "sql_string.h"
37 #include "sql_bitmap.h"
38 #include "sql_show.h"
39 #include "item_subselect.h"
40 
41 struct LEX;
42 struct TABLE;
43 
44 
45 /**
46   Hint types, MAX_HINT_ENUM should be always last.
47   This enum should be synchronized with opt_hint_info
48   array(see opt_hints.cc).
49 */
50 enum opt_hints_enum
51 {
52   BKA_HINT_ENUM= 0,
53   BNL_HINT_ENUM,
54   ICP_HINT_ENUM,
55   MRR_HINT_ENUM,
56   NO_RANGE_HINT_ENUM,
57   MAX_EXEC_TIME_HINT_ENUM,
58   QB_NAME_HINT_ENUM,
59   SEMIJOIN_HINT_ENUM,
60   SUBQUERY_HINT_ENUM,
61   MAX_HINT_ENUM
62 };
63 
64 
65 struct st_opt_hint_info
66 {
67   const char* hint_name;  // Hint name.
68   bool check_upper_lvl;   // true if upper level hint check is needed (for hints
69                           // which can be specified on more than one level).
70   bool switch_hint;       // true if hint is not complex.
71 };
72 
73 
74 /**
75   Opt_hints_map contains information
76   about hint state(specified or not, hint value).
77 */
78 
79 class Opt_hints_map : public Sql_alloc
80 {
81   Bitmap<64> hints;           // hint state
82   Bitmap<64> hints_specified; // true if hint is specified
83 public:
84 
85   /**
86      Check if hint is specified.
87 
88      @param type_arg   hint type
89 
90      @return true if hint is specified
91   */
is_specified(opt_hints_enum type_arg)92   my_bool is_specified(opt_hints_enum type_arg) const
93   {
94     return hints_specified.is_set(type_arg);
95   }
96   /**
97      Set switch value and set hint into specified state.
98 
99      @param type_arg           hint type
100      @param switch_state_arg   switch value
101   */
set_switch(opt_hints_enum type_arg,bool switch_state_arg)102   void set_switch(opt_hints_enum type_arg,
103                   bool switch_state_arg)
104   {
105     if (switch_state_arg)
106       hints.set_bit(type_arg);
107     else
108       hints.clear_bit(type_arg);
109     hints_specified.set_bit(type_arg);
110   }
111   /**
112      Get switch value.
113 
114      @param type_arg    hint type
115 
116      @return switch value.
117   */
switch_on(opt_hints_enum type_arg)118   bool switch_on(opt_hints_enum type_arg) const
119   {
120     return hints.is_set(type_arg);
121   }
122 };
123 
124 
125 class PT_hint;
126 class PT_hint_max_execution_time;
127 class Opt_hints_key;
128 
129 
130 /**
131   Opt_hints class is used as ancestor for Opt_hints_global,
132   Opt_hints_qb, Opt_hints_table, Opt_hints_key classes.
133 
134   Opt_hints_global class is hierarchical structure.
135   It contains information about global hints and also
136   conains array of QUERY BLOCK level objects (Opt_hints_qb class).
137   Each QUERY BLOCK level object contains array of TABLE level hints
138   (class Opt_hints_table). Each TABLE level hint contains array of
139   KEY lelev hints (Opt_hints_key class).
140   Hint information(specified, on|off state) is stored in hints_map object.
141 */
142 
143 class Opt_hints : public Sql_alloc
144 {
145   /*
146     Name of object referred by the hint.
147     This name is empty for global level,
148     query block name for query block level,
149     table name for table level and key name
150     for key level.
151   */
152   const LEX_CSTRING *name;
153   /*
154     Parent object. There is no parent for global level,
155     for query block level parent is Opt_hints_global object,
156     for table level parent is Opt_hints_qb object,
157     for key level parent is Opt_hints_key object.
158   */
159   Opt_hints *parent;
160 
161   Opt_hints_map hints_map;   // Hint map
162 
163   /* Array of child objects. i.e. array of the lower level objects */
164   Mem_root_array<Opt_hints*, true> child_array;
165   /* true if hint is connected to the real object */
166   bool resolved;
167   /* Number of resolved children */
168   uint resolved_children;
169 
170 public:
171 
Opt_hints(const LEX_CSTRING * name_arg,Opt_hints * parent_arg,MEM_ROOT * mem_root_arg)172   Opt_hints(const LEX_CSTRING *name_arg,
173             Opt_hints *parent_arg,
174             MEM_ROOT *mem_root_arg)
175     : name(name_arg), parent(parent_arg), child_array(mem_root_arg),
176       resolved(false), resolved_children(0)
177   { }
178 
is_specified(opt_hints_enum type_arg)179   bool is_specified(opt_hints_enum type_arg) const
180   {
181     return hints_map.is_specified(type_arg);
182   }
183 
184   /**
185     Function sets switch hint state.
186 
187     @param switch_state_arg  switch hint state
188     @param type_arg          hint type
189     @param check_parent      true if hint can be on parent level
190 
191     @return  true if hint is already specified,
192              false otherwise
193   */
set_switch(bool switch_state_arg,opt_hints_enum type_arg,bool check_parent)194   bool set_switch(bool switch_state_arg,
195                   opt_hints_enum type_arg,
196                   bool check_parent)
197   {
198     if (is_specified(type_arg) ||
199         (check_parent && parent->is_specified(type_arg)))
200       return true;
201 
202     hints_map.set_switch(type_arg, switch_state_arg);
203     return false;
204   }
205 
206   /**
207     Function returns switch hint state.
208 
209     @param type_arg          hint type
210 
211     @return  hint value if hint is specified,
212             false otherwise
213   */
214   bool get_switch(opt_hints_enum type_arg) const;
215 
get_name()216   virtual const LEX_CSTRING *get_name() const { return name; }
set_name(const LEX_CSTRING * name_arg)217   void set_name(const LEX_CSTRING *name_arg) { name= name_arg; }
get_parent()218   Opt_hints *get_parent() const { return parent; }
set_resolved()219   void set_resolved() { resolved= true; }
is_resolved()220   bool is_resolved() const { return resolved; }
incr_resolved_children()221   void incr_resolved_children() { resolved_children++; }
child_array_ptr()222   Mem_root_array<Opt_hints*, true> *child_array_ptr() { return &child_array; }
223 
is_all_resolved()224   bool is_all_resolved() const
225   {
226     return child_array.size() == resolved_children;
227   }
228 
register_child(Opt_hints * hint_arg)229   void register_child(Opt_hints* hint_arg)
230   {
231     child_array.push_back(hint_arg);
232   }
233 
234   /**
235     Returns pointer to complex hint for a given type.
236 
237     A complex hint is a hint that has arguments.
238     (It is not just an on/off switch.)
239 
240     @param type  hint type
241 
242     @return  pointer to complex hint for a given type.
243   */
get_complex_hints(opt_hints_enum type)244   virtual PT_hint *get_complex_hints(opt_hints_enum type)
245   {
246     assert(0);
247     return NULL; /* error C4716: must return a value */
248   };
249 
250   /**
251     Find hint among lower-level hint objects.
252 
253     @param name_arg        hint name
254     @param cs              Pointer to character set
255 
256     @return  hint if found,
257              NULL otherwise
258   */
259   Opt_hints *find_by_name(const LEX_CSTRING *name_arg,
260                           const CHARSET_INFO *cs) const;
261   /**
262     Print all hints except of QB_NAME hint.
263 
264     @param thd              Pointer to THD object
265     @param str              Pointer to String object
266     @param query_type       If query type is QT_NORMALIZED_FORMAT,
267                             un-resolved hints will also be printed
268   */
269   void print(THD *thd, String *str, enum_query_type query_type);
270   /**
271     Check if there are any unresolved hint objects and
272     print warnings for them.
273 
274     @param thd             Pointer to THD object
275   */
276   void check_unresolved(THD *thd);
277   virtual void append_name(THD *thd, String *str)= 0;
278 
279 private:
280   /**
281     Append hint type.
282 
283     @param str             Pointer to String object
284     @param type            Hint type
285   */
286   void append_hint_type(String *str, opt_hints_enum type);
287   /**
288     Print warning for unresolved hint name.
289 
290     @param thd             Pointer to THD object
291   */
292   void print_warn_unresolved(THD *thd);
293 };
294 
295 
296 /**
297   Global level hints.
298 */
299 
300 class Opt_hints_global : public Opt_hints
301 {
302 
303 public:
304   PT_hint_max_execution_time *max_exec_time;
305 
Opt_hints_global(MEM_ROOT * mem_root_arg)306   Opt_hints_global(MEM_ROOT *mem_root_arg)
307     : Opt_hints(NULL, NULL, mem_root_arg)
308   {
309     max_exec_time= NULL;
310   }
311 
append_name(THD * thd,String * str)312   virtual void append_name(THD *thd, String *str) {}
313   virtual PT_hint *get_complex_hints(opt_hints_enum type);
314 };
315 
316 
317 class PT_qb_level_hint;
318 
319 /**
320   Query block level hints.
321 */
322 
323 class Opt_hints_qb : public Opt_hints
324 {
325   uint select_number;     // SELECT_LEX number
326   LEX_CSTRING sys_name;   // System QB name
327   char buff[32];          // Buffer to hold sys name
328 
329   PT_qb_level_hint *subquery_hint, *semijoin_hint;
330   // PT_qb_level_hint::contextualize sets subquery/semijoin_hint during parsing.
331   friend class PT_qb_level_hint;
332 
333 public:
334 
335   Opt_hints_qb(Opt_hints *opt_hints_arg,
336                MEM_ROOT *mem_root_arg,
337                uint select_number_arg);
338 
get_print_name()339   const LEX_CSTRING *get_print_name()
340   {
341     const LEX_CSTRING *str= Opt_hints::get_name();
342     return str ? str : &sys_name;
343   }
344 
345   /**
346     Append query block hint.
347 
348     @param thd   pointer to THD object
349     @param str   pointer to String object
350   */
append_qb_hint(THD * thd,String * str)351   void append_qb_hint(THD *thd, String *str)
352   {
353     if (get_name())
354     {
355       str->append(STRING_WITH_LEN("QB_NAME("));
356       append_identifier(thd, str, get_name()->str, get_name()->length);
357       str->append(STRING_WITH_LEN(") "));
358     }
359   }
360   /**
361     Append query block name.
362 
363     @param thd   pointer to THD object
364     @param str   pointer to String object
365   */
append_name(THD * thd,String * str)366   virtual void append_name(THD *thd, String *str)
367   {
368     str->append(STRING_WITH_LEN("@"));
369     append_identifier(thd, str, get_print_name()->str, get_print_name()->length);
370   }
371 
372   virtual PT_hint *get_complex_hints(opt_hints_enum type);
373 
374   /**
375     Function finds Opt_hints_table object corresponding to
376     table alias in the query block and attaches corresponding
377     key hint objects to appropriate KEY structures.
378 
379     @param table      Pointer to TABLE object
380     @param alias      Table alias
381 
382     @return  pointer Opt_hints_table object if this object is found,
383              NULL otherwise.
384   */
385   Opt_hints_table *adjust_table_hints(TABLE *table, const char *alias);
386 
387   /**
388     Returns whether semi-join is enabled for this query block
389 
390     A SEMIJOIN hint will force semi-join regardless of optimizer_switch settings.
391     A NO_SEMIJOIN hint will only turn off semi-join if the variant with no
392     strategies is used.
393     A SUBQUERY hint will turn off semi-join.
394     If there is no SEMIJOIN/SUBQUERY hint, optimizer_switch setting determines
395     whether SEMIJOIN is used.
396 
397     @param thd  Pointer to THD object for session.
398                 Used to access optimizer_switch
399 
400     @return true if semijoin is enabled
401   */
402   bool semijoin_enabled(THD *thd) const;
403 
404   /**
405     Returns bit mask of which semi-join strategies are enabled for this query
406     block.
407 
408     @param opt_switches Bit map of strategies enabled by optimizer_switch
409 
410     @return Bit mask of strategies that are enabled
411   */
412   uint sj_enabled_strategies(uint opt_switches) const;
413 
414   /**
415     Returns which subquery execution strategy has been specified by hints
416     for this query block.
417 
418     @retval EXEC_MATERIALIZATION  Subquery Materialization should be used
419     @retval EXEC_EXISTS In-to-exists execution should be used
420     @retval EXEC_UNSPECIFIED No SUBQUERY hint for this query block
421   */
422   Item_exists_subselect::enum_exec_method subquery_strategy() const;
423 };
424 
425 
426 /**
427   Table level hints.
428 */
429 
430 class Opt_hints_table : public Opt_hints
431 {
432 public:
433   Mem_root_array<Opt_hints_key*, true> keyinfo_array;
434 
Opt_hints_table(const LEX_CSTRING * table_name_arg,Opt_hints_qb * qb_hints_arg,MEM_ROOT * mem_root_arg)435   Opt_hints_table(const LEX_CSTRING *table_name_arg,
436                   Opt_hints_qb *qb_hints_arg,
437                   MEM_ROOT *mem_root_arg)
438     : Opt_hints(table_name_arg, qb_hints_arg, mem_root_arg),
439       keyinfo_array(mem_root_arg)
440   { }
441 
442   /**
443     Append table name.
444 
445     @param thd   pointer to THD object
446     @param str   pointer to String object
447   */
append_name(THD * thd,String * str)448   virtual void append_name(THD *thd, String *str)
449   {
450     append_identifier(thd, str, get_name()->str, get_name()->length);
451     get_parent()->append_name(thd, str);
452   }
453   /**
454     Function sets correlation between key hint objects and
455     appropriate KEY structures.
456 
457     @param table      Pointer to TABLE object
458   */
459   void adjust_key_hints(TABLE *table);
460 };
461 
462 
463 /**
464   Key level hints.
465 */
466 
467 class Opt_hints_key : public Opt_hints
468 {
469 public:
470 
Opt_hints_key(const LEX_CSTRING * key_name_arg,Opt_hints_table * table_hints_arg,MEM_ROOT * mem_root_arg)471   Opt_hints_key(const LEX_CSTRING *key_name_arg,
472                 Opt_hints_table *table_hints_arg,
473                 MEM_ROOT *mem_root_arg)
474     : Opt_hints(key_name_arg, table_hints_arg, mem_root_arg)
475   { }
476 
477   /**
478     Append key name.
479 
480     @param thd   pointer to THD object
481     @param str   pointer to String object
482   */
append_name(THD * thd,String * str)483   virtual void append_name(THD *thd, String *str)
484   {
485     get_parent()->append_name(thd, str);
486     str->append(' ');
487     append_identifier(thd, str, get_name()->str, get_name()->length);
488   }
489 };
490 
491 
492 /**
493   Returns key hint value if hint is specified, returns
494   optimizer switch value if hint is not specified.
495 
496   @param thd               Pointer to THD object
497   @param tab               Pointer to TABLE object
498   @param keyno             Key number
499   @param type_arg          Hint type
500   @param optimizer_switch  Optimizer switch flag
501 
502   @return key hint value if hint is specified,
503           otherwise optimizer switch value.
504 */
505 bool hint_key_state(const THD *thd, const TABLE *table,
506                     uint keyno, opt_hints_enum type_arg,
507                     uint optimizer_switch);
508 
509 /**
510   Returns table hint value if hint is specified, returns
511   optimizer switch value if hint is not specified.
512 
513   @param thd                Pointer to THD object
514   @param tab                Pointer to TABLE object
515   @param type_arg           Hint type
516   @param optimizer_switch   Optimizer switch flag
517 
518   @return table hint value if hint is specified,
519           otherwise optimizer switch value.
520 */
521 bool hint_table_state(const THD *thd, const TABLE *table,
522                       opt_hints_enum type_arg,
523                       uint optimizer_switch);
524 
525 #endif /* OPT_HINTS_INCLUDED */
526