1 /* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 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 Foundation, 21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ 22 23 24 #ifndef OPT_EXPLAIN_FORMAT_INCLUDED 25 #define OPT_EXPLAIN_FORMAT_INCLUDED 26 27 /** @file "EXPLAIN FORMAT=<format> <command>" 28 */ 29 30 31 #include "sql_class.h" 32 33 struct st_join_table; 34 35 36 /** 37 Names for different query parse tree parts 38 */ 39 40 enum Explain_context_enum 41 { 42 CTX_NONE= 0, ///< Empty value 43 CTX_MESSAGE, ///< "No tables used" messages etc. 44 CTX_TABLE, ///< for single-table UPDATE/DELETE 45 CTX_SELECT_LIST, ///< SELECT (subquery), (subquery)... 46 CTX_UPDATE_VALUE_LIST, ///< UPDATE ... SET field=(subquery)... 47 CTX_JOIN, 48 CTX_JOIN_TAB, 49 CTX_MATERIALIZATION, 50 CTX_DUPLICATES_WEEDOUT, 51 CTX_DERIVED, ///< "Derived" subquery 52 CTX_WHERE, ///< Subquery in WHERE clause item tree 53 CTX_HAVING, ///< Subquery in HAVING clause item tree 54 CTX_ORDER_BY, ///< ORDER BY clause execution context 55 CTX_GROUP_BY, ///< GROUP BY clause execution context 56 CTX_SIMPLE_ORDER_BY, ///< ORDER BY clause execution context 57 CTX_SIMPLE_GROUP_BY, ///< GROUP BY clause execution context 58 CTX_DISTINCT, ///< DISTINCT clause execution context 59 CTX_SIMPLE_DISTINCT, ///< DISTINCT clause execution context 60 CTX_BUFFER_RESULT, ///< see SQL_BUFFER_RESULT in the manual 61 CTX_ORDER_BY_SQ, ///< Subquery in ORDER BY clause item tree 62 CTX_GROUP_BY_SQ, ///< Subquery in GROUP BY clause item tree 63 CTX_OPTIMIZED_AWAY_SUBQUERY, ///< Subquery executed once during optimization 64 CTX_UNION, 65 CTX_UNION_RESULT, ///< Pseudo-table context for UNION result 66 CTX_QUERY_SPEC ///< Inner SELECTs of UNION expression 67 }; 68 69 70 /** 71 Types of traditional "extra" column parts and property names for hierarchical 72 73 The traditional_extra_tags[] and json_extra_tags[] arrays must be in sync 74 with this enum. 75 */ 76 enum Extra_tag 77 { 78 ET_none, 79 ET_USING_TEMPORARY, 80 ET_USING_FILESORT, 81 ET_USING_INDEX_CONDITION, 82 ET_USING, 83 ET_RANGE_CHECKED_FOR_EACH_RECORD, 84 ET_USING_WHERE_WITH_PUSHED_CONDITION, 85 ET_USING_WHERE, 86 ET_NOT_EXISTS, 87 ET_USING_MRR, 88 ET_USING_INDEX, 89 ET_FULL_SCAN_ON_NULL_KEY, 90 ET_SKIP_OPEN_TABLE, 91 ET_OPEN_FRM_ONLY, 92 ET_OPEN_FULL_TABLE, 93 ET_SCANNED_DATABASES, 94 ET_USING_INDEX_FOR_GROUP_BY, 95 ET_DISTINCT, 96 ET_LOOSESCAN, 97 ET_START_TEMPORARY, 98 ET_END_TEMPORARY, 99 ET_FIRST_MATCH, 100 ET_MATERIALIZE, 101 ET_START_MATERIALIZE, 102 ET_END_MATERIALIZE, 103 ET_SCAN, 104 ET_USING_JOIN_BUFFER, 105 ET_CONST_ROW_NOT_FOUND, 106 ET_UNIQUE_ROW_NOT_FOUND, 107 ET_IMPOSSIBLE_ON_CONDITION, 108 ET_PUSHED_JOIN, 109 //------------------------------------ 110 ET_total 111 }; 112 113 114 /** 115 Emulate lazy computation 116 */ 117 class Lazy: public Sql_alloc 118 { 119 public: ~Lazy()120 virtual ~Lazy() {} 121 122 /** 123 Deferred evaluation of encapsulated expression 124 125 @param [out] ret Return string value 126 127 @retval false Success 128 @retval true Failure (OOM) 129 */ 130 virtual bool eval(String *ret)= 0; 131 }; 132 133 /** 134 Base class for all EXPLAIN context descriptor classes 135 136 In structured EXPLAIN implementation Explain_context is a base class for 137 notes of an intermediate tree. 138 */ 139 struct Explain_context : Sql_alloc 140 { 141 Explain_context_enum type; ///< type tag 142 Explain_contextExplain_context143 explicit Explain_context(Explain_context_enum type_arg) : type(type_arg) {} 144 }; 145 146 147 namespace opt_explain_json_namespace // for forward declaration of "context" 148 { 149 class context; 150 } 151 152 /** 153 Helper class for table property buffering 154 155 For traditional EXPLAIN this structure contains cached data for a single 156 output row. 157 158 For hierarchical EXPLAIN this structure contains property values for a single 159 CTX_TABLE/CTX_JOIN_TAB context node of the intermediate tree. 160 */ 161 162 class qep_row : public Sql_alloc 163 { 164 private: 165 /* Don't copy this structure */ 166 explicit qep_row(const qep_row &x); // undefined 167 qep_row &operator=(const qep_row &x); // undefined 168 169 public: 170 /** 171 A wrapper for numeric table properties 172 173 For traditional EXPLAIN this structure contains a value of one cell of the 174 output row (excluding textual column values - see mem_root_str, and 175 "Extra" column - see the col_extra list). 176 177 For hierarchical EXPLAIN this structure contains a numeric property value 178 for a single CTX_TABLE/CTX_JOIN_TAB context node of the intermediate tree. 179 */ 180 template<typename T> 181 struct column 182 { 183 private: 184 bool nil; ///< true if the column contains NULL 185 public: 186 T value; 187 188 public: columncolumn189 column() { cleanup(); } is_emptycolumn190 bool is_empty() const { return nil; } cleanupcolumn191 void cleanup() { nil= true; } setcolumn192 void set(T value_arg) { value= value_arg; nil= false; } getcolumn193 T get() const { DBUG_ASSERT(!nil); return value; } 194 }; 195 196 /** 197 Helper class to keep string data in MEM_ROOT before passing to Item_string 198 199 Since Item_string constructors doesn't copy input string parameter data 200 in the most cases, those input strings must have the same lifetime as 201 Item_string objects, i.e. lifetime of MEM_ROOT. 202 This class allocates input parameters for Item_string objects in MEM_ROOT. 203 204 @note Call to is_empty() is necessary before the access to "str" and 205 "length" fields, since is_empty() may trigger an evaluation of 206 an associated expression that updates these fields. 207 */ 208 struct mem_root_str 209 { 210 const char *str; 211 size_t length; 212 Lazy *deferred; //< encapsulated expression to evaluate it later (on demand) 213 mem_root_strmem_root_str214 mem_root_str() { cleanup(); } cleanupmem_root_str215 void cleanup() 216 { 217 str= NULL; 218 length= 0; 219 deferred= NULL; 220 } is_emptymem_root_str221 bool is_empty() 222 { 223 if (deferred) 224 { 225 StringBuffer<128> buff(system_charset_info); 226 if (deferred->eval(&buff) || set(buff)) 227 { 228 DBUG_ASSERT(!"OOM!"); 229 return true; // ignore OOM 230 } 231 deferred= NULL; // prevent double evaluation, if any 232 } 233 return str == NULL; 234 } setmem_root_str235 bool set(const char *str_arg) 236 { 237 return set(str_arg, strlen(str_arg)); 238 } setmem_root_str239 bool set(const String &s) 240 { 241 return set(s.ptr(), s.length()); 242 } 243 /** 244 Make a copy of the string in MEM_ROOT 245 246 @param str_arg string to copy 247 @param length_arg input string length 248 249 @return false if success, true if error 250 */ setmem_root_str251 bool set(const char *str_arg, size_t length_arg) 252 { 253 deferred= NULL; 254 if (!(str= strndup_root(current_thd->mem_root, str_arg, length_arg))) 255 return true; /* purecov: inspected */ 256 length= length_arg; 257 return false; 258 } 259 /** 260 Save expression for further evaluation 261 262 @param x Expression 263 */ setmem_root_str264 void set(Lazy *x) 265 { 266 deferred= x; 267 str= NULL; 268 length= 0; 269 } 270 /** 271 Make a copy of string constant 272 273 Variant of set() usable when the str_arg argument lives longer 274 than the mem_root_str instance. 275 */ set_constmem_root_str276 void set_const(const char *str_arg) 277 { 278 return set_const(str_arg, strlen(str_arg)); 279 } set_constmem_root_str280 void set_const(const char *str_arg, size_t length_arg) 281 { 282 deferred= NULL; 283 str= str_arg; 284 length= length_arg; 285 } 286 strndup_rootmem_root_str287 static char *strndup_root(MEM_ROOT *root, const char *str, size_t len) 288 { 289 if (len == 0 || str == NULL) 290 return const_cast<char *>(""); 291 if (str[len - 1] == 0) 292 return static_cast<char *>(memdup_root(root, str, len)); 293 294 char *ret= static_cast<char*>(alloc_root(root, len + 1)); 295 if (ret != NULL) 296 { 297 memcpy(ret, str, len); 298 ret[len]= 0; 299 } 300 return ret; 301 } 302 }; 303 304 /** 305 Part of traditional "extra" column or related hierarchical property 306 */ 307 struct extra: public Sql_alloc 308 { 309 /** 310 A property name or a constant text head of the "extra" column part 311 */ 312 const Extra_tag tag; 313 /** 314 Property value or a variable tail of the "extra" column part 315 316 If data == NULL, hierarchical formatter outputs a boolean property 317 value of "true". 318 */ 319 const char *const data; 320 321 explicit extra(Extra_tag tag_arg, const char *data_arg= NULL) tagextra322 : tag(tag_arg), data(data_arg) 323 {} 324 }; 325 326 /* 327 Next "col_*" fields are intended to be filling by "explain_*()" functions. 328 329 NOTE: NULL value or mem_root_str.is_empty()==true means that Item_null object 330 will be pushed into "items" list instead. 331 */ 332 column<uint> col_id; ///< "id" column: seq. number of SELECT withing the query 333 column<SELECT_LEX::type_enum> col_select_type; ///< "select_type" column 334 mem_root_str col_table_name; ///< "table" to which the row of output refers 335 List<const char> col_partitions; ///< "partitions" column 336 mem_root_str col_join_type; ///< "type" column, see join_type_str array 337 List<const char> col_possible_keys; ///< "possible_keys": comma-separated list 338 mem_root_str col_key; ///< "key" column: index that is actually decided to use 339 mem_root_str col_key_len; ///< "key_length" column: length of the "key" above 340 List<const char> col_ref; ///< "ref":columns/constants which are compared to "key" 341 column<longlong> col_rows; ///< "rows": estimated number of examined table rows 342 column<float> col_filtered; ///< "filtered": % of rows filtered by condition 343 List<extra> col_extra; ///< "extra" column (traditional) or property list 344 345 // non-TRADITIONAL stuff: 346 mem_root_str col_message; ///< replaces "Extra" column if not empty 347 mem_root_str col_attached_condition; ///< former "Using where" 348 349 /* For structured EXPLAIN in CTX_JOIN_TAB context: */ 350 uint query_block_id; ///< query block id for materialized subqueries 351 352 /** 353 List of "derived" subquery trees 354 */ 355 List<opt_explain_json_namespace::context> derived_from; 356 357 List<const char> col_key_parts; ///< used parts of the key 358 359 bool is_dependent; 360 bool is_cacheable; 361 bool using_temporary; 362 bool is_materialized_from_subquery; 363 bool is_update; //< UPDATE modified this table 364 bool is_delete; //< DELETE modified this table 365 qep_row()366 qep_row() : 367 query_block_id(0), 368 is_dependent(false), 369 is_cacheable(true), 370 using_temporary(false), 371 is_materialized_from_subquery(false), 372 is_update(false), 373 is_delete(false) 374 {} 375 ~qep_row()376 virtual ~qep_row() {} 377 cleanup()378 void cleanup() 379 { 380 col_id.cleanup(); 381 col_table_name.cleanup(); 382 col_partitions.empty(); 383 col_join_type.cleanup(); 384 col_possible_keys.empty(); 385 col_key.cleanup(); 386 col_key_len.cleanup(); 387 col_ref.empty(); 388 col_rows.cleanup(); 389 col_filtered.cleanup(); 390 col_extra.empty(); 391 col_message.cleanup(); 392 col_attached_condition.cleanup(); 393 col_key_parts.empty(); 394 395 /* 396 Not needed (we call cleanup() for structured EXPLAIN only, 397 just for the consistency). 398 */ 399 query_block_id= 0; 400 derived_from.empty(); 401 is_dependent= false; 402 is_cacheable= true; 403 using_temporary= false; 404 is_materialized_from_subquery= false; 405 is_update= false; 406 is_delete= false; 407 } 408 409 /** 410 Remember a subquery's unit 411 412 JOIN_TAB inside a JOIN, a table in a join-less query (single-table 413 UPDATE/DELETE) or a table that's optimized out may have a WHERE 414 condition. We create the Explain_context of such a JOIN_TAB or 415 table when the Explain_context objects of its in-WHERE subqueries 416 don't exist. 417 This function collects unit pointers of WHERE subqueries that are 418 associated with the current JOIN_TAB or table. Then we can match these 419 units with units of newly-created Explain_context objects of WHERE 420 subqueries. 421 422 @param subquery WHERE clause subquery's unit 423 */ register_where_subquery(SELECT_LEX_UNIT * subquery)424 virtual void register_where_subquery(SELECT_LEX_UNIT *subquery) {} 425 }; 426 427 428 /** 429 Argument for Item::explain_subquery_checker() 430 431 Just a tuple of (destination, type) to pass as a single argument. 432 See a commentary for Item_subselect::explain_subquery_checker 433 */ 434 435 struct Explain_subquery_marker 436 { 437 class qep_row *destination; ///< hosting TABLE/JOIN_TAB 438 Explain_context_enum type; ///< CTX_WHERE/CTX_HAVING/CTX_ORDER_BY/CTX_GROUP_BY 439 Explain_subquery_markerExplain_subquery_marker440 Explain_subquery_marker(qep_row *destination_arg, 441 Explain_context_enum type_arg) 442 : destination(destination_arg), type(type_arg) 443 {} 444 }; 445 446 /** 447 Enumeration of ORDER BY, GROUP BY and DISTINCT clauses for array indexing 448 449 See Explain_format_flags::sorts 450 */ 451 enum Explain_sort_clause 452 { 453 ESC_none = 0, 454 ESC_ORDER_BY = 1, 455 ESC_GROUP_BY = 2, 456 ESC_DISTINCT = 3, 457 ESC_BUFFER_RESULT = 4, 458 //----------------- 459 ESC_MAX 460 }; 461 462 /** 463 Bit flags to explain GROUP BY, ORDER BY and DISTINCT clauses 464 */ 465 enum Explain_sort_property 466 { 467 ESP_none = 0, 468 ESP_EXISTS = 1 << 0, //< Original query has this clause 469 ESP_IS_SIMPLE = 1 << 1, //< Clause is effective for single JOIN_TAB only 470 ESP_USING_FILESORT = 1 << 2, //< Clause causes a filesort 471 ESP_USING_TMPTABLE = 1 << 3, //< Clause creates an intermediate table 472 ESP_DUPS_REMOVAL = 1 << 4, //< Duplicate removal for DISTINCT 473 ESP_CHECKED = 1 << 5 //< Properties were already checked 474 }; 475 476 477 class Explain_format_flags 478 { 479 /** 480 Bitmasks of Explain_sort_property flags for Explain_sort_clause clauses 481 */ 482 uint8 sorts[ESC_MAX]; 483 484 public: Explain_format_flags()485 Explain_format_flags() { memset(sorts, 0, sizeof(sorts)); } 486 487 /** 488 Set property bit flag for the clause 489 */ set(Explain_sort_clause clause,Explain_sort_property property)490 void set(Explain_sort_clause clause, Explain_sort_property property) 491 { 492 sorts[clause]|= property | ESP_EXISTS; 493 } 494 set(Explain_format_flags & flags)495 void set(Explain_format_flags &flags) 496 { 497 memcpy(sorts, flags.sorts, sizeof(sorts)); 498 } 499 500 /** 501 Clear property bit flag for the clause 502 */ reset(Explain_sort_clause clause,Explain_sort_property property)503 void reset(Explain_sort_clause clause, Explain_sort_property property) 504 { 505 sorts[clause]&= ~property; 506 } 507 508 /** 509 Return true if property is set for the clause 510 */ get(Explain_sort_clause clause,Explain_sort_property property)511 bool get(Explain_sort_clause clause, Explain_sort_property property) const 512 { 513 return (sorts[clause] & property) || (sorts[clause] & ESP_CHECKED); 514 } 515 516 /** 517 Return true if any of clauses has this property set 518 */ any(Explain_sort_property property)519 bool any(Explain_sort_property property) const 520 { 521 for (size_t i= ESC_none + 1; i <= ESC_MAX - 1; i++) 522 { 523 if (sorts[i] & property || sorts[i] & ESP_CHECKED) 524 return true; 525 } 526 return false; 527 } 528 }; 529 530 531 /** 532 Base class for structured and hierarchical EXPLAIN output formatters 533 */ 534 535 class Explain_format : public Sql_alloc 536 { 537 private: 538 /* Don't copy Explain_format values */ 539 Explain_format(Explain_format &); // undefined 540 Explain_format &operator=(Explain_format &); // undefined 541 542 public: 543 select_result *output; ///< output resulting data there 544 545 public: Explain_format()546 Explain_format() : output(NULL) {} ~Explain_format()547 virtual ~Explain_format() {} 548 549 550 /** 551 A hierarchical text or a plain table 552 553 @retval true Formatter produces hierarchical text 554 @retval false Traditional explain 555 */ 556 virtual bool is_hierarchical() const= 0; 557 558 /** 559 Send EXPLAIN header item(s) to output stream 560 561 @note: This function caches the output result set pointer for further use. 562 563 @param result output result set 564 565 @retval false OK 566 @retval true Error 567 */ send_headers(select_result * result)568 virtual bool send_headers(select_result *result) 569 { 570 output= result; 571 return false; 572 } 573 574 /** 575 Enter a specified context 576 577 @param context context type 578 @param subquery for CTX_WHERE: unit of the subquery 579 */ 580 virtual bool begin_context(Explain_context_enum context, 581 SELECT_LEX_UNIT *subquery = 0, 582 const Explain_format_flags *flags= NULL)= 0; 583 584 /** 585 Leave the current context 586 587 @param context current context type (for validation/debugging) 588 */ 589 virtual bool end_context(Explain_context_enum context)= 0; 590 591 /** 592 Flush TABLE/JOIN_TAB property set 593 594 For traditional EXPLAIN: output a single EXPLAIN row. 595 */ 596 virtual bool flush_entry()= 0; 597 598 /** 599 Get a pointer to the current TABLE/JOIN_TAB property set 600 */ 601 virtual qep_row *entry()= 0; 602 }; 603 604 #endif//OPT_EXPLAIN_FORMAT_INCLUDED 605