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