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