1 /* Copyright (c) 2011, 2013, 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 /** @file "EXPLAIN <command>" implementation */
24 
25 #include "opt_explain.h"
26 #include "sql_select.h"
27 #include "sql_optimizer.h" // JOIN
28 #include "sql_partition.h" // for make_used_partitions_str()
29 #include "sql_join_buffer.h" // JOIN_CACHE
30 #include "filesort.h"        // Filesort
31 #include "opt_explain_format.h"
32 #include "sql_base.h"      // lock_tables
33 
34 typedef qep_row::extra extra;
35 
36 static bool mysql_explain_unit(THD *thd, SELECT_LEX_UNIT *unit,
37                                select_result *result);
38 static void propagate_explain_option(THD *thd, SELECT_LEX_UNIT *unit);
39 
40 const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
41 			      "ALL","range","index","fulltext",
42 			      "ref_or_null","unique_subquery","index_subquery",
43                               "index_merge"
44 };
45 
46 static const enum_query_type cond_print_flags=
47   enum_query_type(QT_ORDINARY | QT_SHOW_SELECT_NUMBER);
48 
49 
50 /**
51   A base for all Explain_* classes
52 
53   Explain_* classes collect and output EXPLAIN data.
54 
55   This class hierarchy is a successor of the old select_describe() function of 5.5.
56 */
57 
58 class Explain
59 {
60 protected:
61   THD *const thd; ///< cached THD pointer
62   const CHARSET_INFO *const cs; ///< cached pointer to system_charset_info
63   JOIN *const join; ///< top-level JOIN (if any) provided by caller
64 
65   select_result *const external_result; ///< stream (if any) provided by caller
66 
67   Explain_format *const fmt; ///< shortcut for thd->lex->explain_format
68   Explain_context_enum context_type; ///< associated value for struct. explain
69 
70   JOIN::ORDER_with_src order_list; //< ORDER BY item tree list
71   JOIN::ORDER_with_src group_list; //< GROUP BY item tee list
72 
73 protected:
74   class Lazy_condition: public Lazy
75   {
76     Item *const condition;
77   public:
Lazy_condition(Item * condition_arg)78     Lazy_condition(Item *condition_arg): condition(condition_arg) {}
eval(String * ret)79     virtual bool eval(String *ret)
80     {
81       ret->length(0);
82       if (condition)
83         condition->print(ret, cond_print_flags);
84       return false;
85     }
86   };
87 
Explain(Explain_context_enum context_type_arg,THD * thd_arg,JOIN * join_arg=NULL)88   explicit Explain(Explain_context_enum context_type_arg,
89                    THD *thd_arg, JOIN *join_arg= NULL)
90   : thd(thd_arg),
91     cs(system_charset_info),
92     join(join_arg),
93     external_result(join ? join->result : NULL),
94     fmt(thd->lex->explain_format),
95     context_type(context_type_arg),
96     order_list(NULL),
97     group_list(NULL)
98   {
99     if (join)
100     {
101       order_list= join->order;
102       group_list= join->group_list;
103     }
104     else
105     {
106       if (select_lex()->order_list.elements)
107         order_list= JOIN::ORDER_with_src(select_lex()->order_list.first,
108                                          ESC_ORDER_BY);
109       if (select_lex()->group_list.elements)
110         group_list= JOIN::ORDER_with_src(select_lex()->group_list.first,
111                                          ESC_GROUP_BY);
112     }
113   }
114 
115 public:
~Explain()116   virtual ~Explain() {}
117 
118   bool send();
119 
120 protected:
121   /**
122     Explain everything but subqueries
123   */
124   virtual bool shallow_explain();
125   /**
126     Explain the rest of things after the @c shallow_explain() call
127   */
128   bool explain_subqueries(select_result *result);
129   bool mark_subqueries(Item *item, qep_row *destination,
130                        Explain_context_enum type);
131   bool mark_order_subqueries(const JOIN::ORDER_with_src &order);
132   bool prepare_columns();
describe(uint8 mask) const133   bool describe(uint8 mask) const { return thd->lex->describe & mask; }
134 
select_lex() const135   SELECT_LEX *select_lex() const
136   {
137     return join ? join->select_lex : &thd->lex->select_lex;
138   }
139 
140 
141   /**
142     Prepare the self-allocated result object
143 
144     For queries with top-level JOIN the caller provides pre-allocated
145     select_send object. Then that JOIN object prepares the select_send
146     object calling result->prepare() in JOIN::prepare(),
147     result->initalize_tables() in JOIN::optimize() and result->prepare2()
148     in JOIN::exec().
149     However without the presence of the top-level JOIN we have to
150     prepare/initialize select_send object manually.
151   */
prepare(select_result * result)152   bool prepare(select_result *result)
153   {
154     DBUG_ASSERT(join == NULL);
155     List<Item> dummy;
156     return result->prepare(dummy, select_lex()->master_unit()) ||
157            result->prepare2();
158   }
159 
160   /**
161     Push a part of the "extra" column into formatter
162 
163     Traditional formatter outputs traditional_extra_tags[tag] as is.
164     Hierarchical formatter outputs a property with the json_extra_tags[tag] name
165     and a boolean value of true.
166 
167     @param      tag     type of the "extra" part
168 
169     @retval     false   Ok
170     @retval     true    Error (OOM)
171   */
push_extra(Extra_tag tag)172   bool push_extra(Extra_tag tag)
173   {
174     extra *e= new extra(tag);
175     return e == NULL || fmt->entry()->col_extra.push_back(e);
176   }
177 
178   /**
179     Push a part of the "extra" column into formatter
180 
181     @param      tag     type of the "extra" part
182     @param      arg     for traditional formatter: rest of the part text,
183                         for hierarchical format: string value of the property
184 
185     @retval     false   Ok
186     @retval     true    Error (OOM)
187   */
push_extra(Extra_tag tag,const String & arg)188   bool push_extra(Extra_tag tag, const String &arg)
189   {
190     if (arg.is_empty())
191       return push_extra(tag);
192     extra *e= new extra(tag, arg.dup(thd->mem_root));
193     return !e || !e->data || fmt->entry()->col_extra.push_back(e);
194   }
195 
196   /**
197     Push a part of the "extra" column into formatter
198 
199     @param      tag     type of the "extra" part
200     @param      arg     for traditional formatter: rest of the part text,
201                         for hierarchical format: string value of the property
202 
203     NOTE: arg must be a long-living string constant.
204 
205     @retval     false   Ok
206     @retval     true    Error (OOM)
207   */
push_extra(Extra_tag tag,const char * arg)208   bool push_extra(Extra_tag tag, const char *arg)
209   {
210     extra *e= new extra(tag, arg);
211     return !e || fmt->entry()->col_extra.push_back(e);
212   }
213 
214   /*
215     Rest of the functions are overloadable functions, those calculate and fill
216     "col_*" fields with Items for further sending as EXPLAIN columns.
217 
218     "explain_*" functions return false on success and true on error (usually OOM).
219   */
220   virtual bool explain_id();
221   virtual bool explain_select_type();
explain_table_name()222   virtual bool explain_table_name() { return false; }
explain_partitions()223   virtual bool explain_partitions() { return false; }
explain_join_type()224   virtual bool explain_join_type() { return false; }
explain_possible_keys()225   virtual bool explain_possible_keys() { return false; }
226   /** fill col_key and and col_key_len fields together */
explain_key_and_len()227   virtual bool explain_key_and_len() { return false; }
explain_ref()228   virtual bool explain_ref() { return false; }
229   /** fill col_rows and col_filtered fields together */
explain_rows_and_filtered()230   virtual bool explain_rows_and_filtered() { return false; }
explain_extra()231   virtual bool explain_extra() { return false; }
explain_modify_flags()232   virtual bool explain_modify_flags() { return false; }
233 };
234 
235 
236 /**
237   Explain_no_table class outputs a trivial EXPLAIN row with "extra" column
238 
239   This class is intended for simple cases to produce EXPLAIN output
240   with "No tables used", "No matching records" etc.
241   Optionally it can output number of estimated rows in the "row"
242   column.
243 
244   @note This class also produces EXPLAIN rows for inner units (if any).
245 */
246 
247 class Explain_no_table: public Explain
248 {
249 private:
250   const char *message; ///< cached "message" argument
251   const ha_rows rows; ///< HA_POS_ERROR or cached "rows" argument
252 
253 public:
Explain_no_table(THD * thd_arg,JOIN * join_arg,const char * message_arg)254   Explain_no_table(THD *thd_arg, JOIN *join_arg, const char *message_arg)
255   : Explain(CTX_JOIN, thd_arg, join_arg),
256     message(message_arg), rows(HA_POS_ERROR)
257   {}
258 
Explain_no_table(THD * thd_arg,const char * message_arg,ha_rows rows_arg=HA_POS_ERROR)259   Explain_no_table(THD *thd_arg, const char *message_arg,
260                    ha_rows rows_arg= HA_POS_ERROR)
261   : Explain(CTX_JOIN, thd_arg),
262     message(message_arg), rows(rows_arg)
263   {}
264 
265 protected:
266   virtual bool shallow_explain();
267 
268   virtual bool explain_rows_and_filtered();
269   virtual bool explain_extra();
270 };
271 
272 
273 /**
274   Explain_union_result class outputs EXPLAIN row for UNION
275 */
276 
277 class Explain_union_result : public Explain
278 {
279 public:
Explain_union_result(THD * thd_arg,JOIN * join_arg)280   Explain_union_result(THD *thd_arg, JOIN *join_arg)
281   : Explain(CTX_UNION_RESULT, thd_arg, join_arg)
282   {
283     /* it's a UNION: */
284     DBUG_ASSERT(join_arg->select_lex == join_arg->unit->fake_select_lex);
285   }
286 
287 protected:
288   virtual bool explain_id();
289   virtual bool explain_table_name();
290   virtual bool explain_join_type();
291   virtual bool explain_extra();
292 };
293 
294 
295 
296 /**
297   Common base class for Explain_join and Explain_table
298 */
299 
300 class Explain_table_base : public Explain {
301 protected:
302   const TABLE *table;
303   key_map usable_keys;
304 
Explain_table_base(Explain_context_enum context_type_arg,THD * const thd_arg,JOIN * const join_arg)305   Explain_table_base(Explain_context_enum context_type_arg,
306                      THD *const thd_arg, JOIN *const join_arg)
307   : Explain(context_type_arg, thd_arg, join_arg), table(NULL)
308   {}
309 
Explain_table_base(Explain_context_enum context_type_arg,THD * const thd_arg,TABLE * const table_arg)310   Explain_table_base(Explain_context_enum context_type_arg,
311                      THD *const thd_arg, TABLE *const table_arg)
312   : Explain(context_type_arg, thd_arg), table(table_arg)
313   {}
314 
315   virtual bool explain_partitions();
316   virtual bool explain_possible_keys();
317 
318   bool explain_key_parts(int key, uint key_parts);
319   bool explain_key_and_len_quick(const SQL_SELECT *select);
320   bool explain_key_and_len_index(int key);
321   bool explain_key_and_len_index(int key, uint key_length, uint key_parts);
322   bool explain_extra_common(const SQL_SELECT *select,
323                             const JOIN_TAB *tab,
324                             int quick_type,
325                             uint keyno);
326   bool explain_tmptable_and_filesort(bool need_tmp_table_arg,
327                                      bool need_sort_arg);
328   virtual bool explain_modify_flags();
329 };
330 
331 
332 /**
333   Explain_join class produces EXPLAIN output for JOINs
334 */
335 
336 class Explain_join : public Explain_table_base
337 {
338 private:
339   bool need_tmp_table; ///< add "Using temporary" to "extra" if true
340   bool need_order; ///< add "Using filesort"" to "extra" if true
341   const bool distinct; ///< add "Distinct" string to "extra" column if true
342 
343   uint tabnum; ///< current tab number in join->join_tab[]
344   JOIN_TAB *tab; ///< current JOIN_TAB
345   SQL_SELECT *select; ///< current SQL_SELECT
346   int quick_type; ///< current quick type, see anon. enum at QUICK_SELECT_I
347   table_map used_tables; ///< accumulate used tables bitmap
348 
349 public:
Explain_join(THD * thd_arg,JOIN * join_arg,bool need_tmp_table_arg,bool need_order_arg,bool distinct_arg)350   Explain_join(THD *thd_arg, JOIN *join_arg,
351                bool need_tmp_table_arg, bool need_order_arg,
352                bool distinct_arg)
353   : Explain_table_base(CTX_JOIN, thd_arg, join_arg),
354     need_tmp_table(need_tmp_table_arg),
355     need_order(need_order_arg), distinct(distinct_arg),
356     tabnum(0), select(0), used_tables(0)
357   {
358     /* it is not UNION: */
359     DBUG_ASSERT(join_arg->select_lex != join_arg->unit->fake_select_lex);
360   }
361 
362 private:
363   // Next 4 functions begin and end context for GROUP BY, ORDER BY and DISTINC
364   bool begin_sort_context(Explain_sort_clause clause, Explain_context_enum ctx);
365   bool end_sort_context(Explain_sort_clause clause, Explain_context_enum ctx);
366   bool begin_simple_sort_context(Explain_sort_clause clause,
367                                  Explain_context_enum ctx);
368   bool end_simple_sort_context(Explain_sort_clause clause,
369                                Explain_context_enum ctx);
370   bool explain_join_tab(size_t tab_num);
371 
372 protected:
373   virtual bool shallow_explain();
374 
375   virtual bool explain_table_name();
376   virtual bool explain_join_type();
377   virtual bool explain_key_and_len();
378   virtual bool explain_ref();
379   virtual bool explain_rows_and_filtered();
380   virtual bool explain_extra();
381   virtual bool explain_select_type();
382   virtual bool explain_id();
383 };
384 
385 
386 /**
387   Explain_table class produce EXPLAIN output for queries without top-level JOIN
388 
389   This class is a simplified version of the Explain_join class. It works in the
390   context of queries which implementation lacks top-level JOIN object (EXPLAIN
391   single-table UPDATE and DELETE).
392 */
393 
394 class Explain_table: public Explain_table_base
395 {
396 private:
397   const SQL_SELECT *const select; ///< cached "select" argument
398   const uint       key;        ///< cached "key" number argument
399   const ha_rows    limit;      ///< HA_POS_ERROR or cached "limit" argument
400   const bool       need_tmp_table; ///< cached need_tmp_table argument
401   const bool       need_sort;  ///< cached need_sort argument
402   const bool       is_update; // is_update ? UPDATE command : DELETE command
403   const bool       used_key_is_modified; ///< UPDATE command updates used key
404 
405 public:
Explain_table(THD * const thd_arg,TABLE * const table_arg,const SQL_SELECT * select_arg,uint key_arg,ha_rows limit_arg,bool need_tmp_table_arg,bool need_sort_arg,bool is_update_arg,bool used_key_is_modified_arg)406   Explain_table(THD *const thd_arg, TABLE *const table_arg,
407                 const SQL_SELECT *select_arg,
408                 uint key_arg, ha_rows limit_arg,
409                 bool need_tmp_table_arg, bool need_sort_arg,
410                 bool is_update_arg, bool used_key_is_modified_arg)
411   : Explain_table_base(CTX_JOIN, thd_arg, table_arg),
412     select(select_arg), key(key_arg),
413     limit(limit_arg),
414     need_tmp_table(need_tmp_table_arg), need_sort(need_sort_arg),
415     is_update(is_update_arg), used_key_is_modified(used_key_is_modified_arg)
416   {
417     usable_keys= table->possible_quick_keys;
418   }
419 
420   virtual bool explain_modify_flags();
421 
422 private:
423   virtual bool explain_tmptable_and_filesort(bool need_tmp_table_arg,
424                                              bool need_sort_arg);
425   virtual bool shallow_explain();
426 
427   virtual bool explain_ref();
428   virtual bool explain_table_name();
429   virtual bool explain_join_type();
430   virtual bool explain_key_and_len();
431   virtual bool explain_rows_and_filtered();
432   virtual bool explain_extra();
433 };
434 
435 
calc_join_type(int quick_type)436 static join_type calc_join_type(int quick_type)
437 {
438   if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) ||
439       (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) ||
440       (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION))
441     return JT_INDEX_MERGE;
442   else
443     return JT_RANGE;
444 }
445 
446 
447 /* Explain class functions ****************************************************/
448 
449 
shallow_explain()450 bool Explain::shallow_explain()
451 {
452   return prepare_columns() || fmt->flush_entry();
453 }
454 
455 
456 /**
457   Qualify subqueries with WHERE/HAVING/ORDER BY/GROUP BY clause type marker
458 
459   @param item           Item tree to find subqueries
460   @param destination    For WHERE clauses
461   @param type           Clause type
462 
463   @note WHERE clause belongs to TABLE or JOIN_TAB. The @c destination parameter
464         provides a pointer to QEP data for such a table to associate a future
465         subquery EXPLAIN output with table QEP provided.
466 
467   @retval false         OK
468   @retval true          Error
469 */
470 
mark_subqueries(Item * item,qep_row * destination,Explain_context_enum type)471 bool Explain::mark_subqueries(Item *item, qep_row *destination,
472                               Explain_context_enum type)
473 {
474   if (item == NULL || !fmt->is_hierarchical())
475     return false;
476 
477   Explain_subquery_marker marker(destination, type);
478   Explain_subquery_marker *marker_ptr= &marker;
479 
480   item->compile(&Item::explain_subquery_checker,
481                 reinterpret_cast<uchar **>(&marker_ptr),
482                 &Item::explain_subquery_propagator,
483                 NULL);
484   return false;
485 }
486 
487 
mark_order_subqueries(const JOIN::ORDER_with_src & order)488 bool Explain::mark_order_subqueries(const JOIN::ORDER_with_src &order)
489 {
490   if (!order)
491     return false;
492 
493   Explain_context_enum sq_context;
494   switch (order.src) {
495   case ESC_ORDER_BY:
496     sq_context= CTX_ORDER_BY_SQ;
497     break;
498   case ESC_GROUP_BY:
499     sq_context= CTX_GROUP_BY_SQ;
500     break;
501   case ESC_DISTINCT:
502     // DISTINCT can't have subqueries, but we can get here when
503     // DISTINCT is converted to GROUP BY
504     return false;
505   default:
506     DBUG_ASSERT(0);
507     return true;
508   }
509   for (const ORDER *o= order; o; o= o->next)
510   {
511     if (mark_subqueries(*o->item, NULL, sq_context))
512       return true;
513   }
514   return false;
515 }
516 
explain_ref_key(Explain_format * fmt,uint key_parts,store_key * key_copy[])517 static bool explain_ref_key(Explain_format *fmt,
518                             uint key_parts, store_key *key_copy[])
519 {
520   if (key_parts == 0)
521     return false;
522 
523   for (uint part_no= 0; part_no < key_parts; part_no++)
524   {
525     const store_key *const s_key= key_copy[part_no];
526     if (s_key == NULL)
527       continue;
528     if (fmt->entry()->col_ref.push_back(s_key->name()))
529       return true;
530   }
531   return false;
532 }
533 
534 
535 /**
536   Traverses SQL clauses of this query specification to identify children
537   subqueries, marks each of them with the clause they belong to.
538   Then goes though all children subqueries and produces their EXPLAIN
539   output, attached to the proper clause's context.
540 
541   @param        result  result stream
542 
543   @retval       false   Ok
544   @retval       true    Error (OOM)
545 */
explain_subqueries(select_result * result)546 bool Explain::explain_subqueries(select_result *result)
547 {
548   if (join)
549   {
550     if (mark_subqueries(join->having, NULL, CTX_HAVING))
551       return true;
552 
553     if (mark_order_subqueries(group_list))
554       return true;
555 
556     if (!join->fields_list.is_empty())
557     {
558       List_iterator<Item> it(join->fields_list);
559       Item *item;
560       while ((item= it++))
561       {
562         if (mark_subqueries(item, NULL, CTX_SELECT_LIST))
563           return true;
564       }
565     }
566   }
567   if (&thd->lex->select_lex == select_lex() &&
568       !thd->lex->value_list.is_empty())
569   {
570     /*
571       Collect subqueries from UPDATE ... SET foo=subquery and
572       INSERT ... SELECT ... ON DUPLICATE KEY UPDATE x=(SELECT...)
573     */
574     DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE ||
575                 thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
576                 thd->lex->sql_command == SQLCOM_INSERT ||
577                 thd->lex->sql_command == SQLCOM_INSERT_SELECT);
578     List_iterator<Item> it(thd->lex->value_list);
579     Item *item;
580     while ((item= it++))
581     {
582       if (mark_subqueries(item, NULL, CTX_UPDATE_VALUE_LIST))
583         return true;
584     }
585   }
586 
587   if (mark_order_subqueries(order_list))
588     return true;
589 
590   for (SELECT_LEX_UNIT *unit= select_lex()->first_inner_unit();
591        unit;
592        unit= unit->next_unit())
593   {
594     SELECT_LEX *sl= unit->first_select();
595     Explain_context_enum context;
596     if (sl->type(thd) == SELECT_LEX::SLT_DERIVED)
597     {
598       DBUG_ASSERT(unit->explain_marker == CTX_NONE);
599       context= CTX_DERIVED;
600     }
601     else if (unit->explain_marker == CTX_NONE)
602       context= CTX_OPTIMIZED_AWAY_SUBQUERY;
603     else
604       context= static_cast<Explain_context_enum>(unit->explain_marker);
605 
606     if (fmt->begin_context(context, unit))
607       return true;
608 
609     if (mysql_explain_unit(thd, unit, result))
610       return true;
611 
612     /*
613       This must be after mysql_explain_unit() so that JOIN::optimize() has run
614       and had a chance to choose materialization.
615     */
616     if (fmt->is_hierarchical() &&
617         (context == CTX_WHERE || context == CTX_HAVING ||
618          context == CTX_SELECT_LIST ||
619          context == CTX_GROUP_BY_SQ || context == CTX_ORDER_BY_SQ) &&
620         unit->item &&
621         (unit->item->get_engine_for_explain()->engine_type() ==
622          subselect_engine::HASH_SJ_ENGINE))
623     {
624       fmt->entry()->is_materialized_from_subquery= true;
625       fmt->entry()->col_table_name.set_const("<materialized_subquery>");
626       fmt->entry()->using_temporary= true;
627       fmt->entry()->col_join_type.set_const(join_type_str[JT_EQ_REF]);
628       fmt->entry()->col_key.set_const("<auto_key>");
629 
630       const subselect_hash_sj_engine * const engine=
631         static_cast<const subselect_hash_sj_engine *>
632         (unit->item->get_engine_for_explain());
633       const JOIN_TAB * const tmp_tab= engine->get_join_tab();
634 
635       char buff_key_len[24];
636       fmt->entry()->col_key_len.set(buff_key_len,
637                                     longlong2str(tmp_tab->table->key_info[0].key_length,
638                                                  buff_key_len, 10) - buff_key_len);
639 
640       if (explain_ref_key(fmt, tmp_tab->ref.key_parts,
641                           tmp_tab->ref.key_copy))
642         return true;
643 
644       fmt->entry()->col_rows.set(1);
645       /*
646        The value to look up depends on the outer value, so the materialized
647        subquery is dependent and not cacheable:
648       */
649       fmt->entry()->is_dependent= true;
650       fmt->entry()->is_cacheable= false;
651     }
652 
653     if (fmt->end_context(context))
654       return true;
655   }
656   return false;
657 }
658 
659 
660 /**
661   Pre-calculate table property values for further EXPLAIN output
662 */
prepare_columns()663 bool Explain::prepare_columns()
664 {
665   return explain_id() ||
666     explain_select_type() ||
667     explain_table_name() ||
668     explain_partitions() ||
669     explain_join_type() ||
670     explain_possible_keys() ||
671     explain_key_and_len() ||
672     explain_ref() ||
673     explain_rows_and_filtered() ||
674     explain_extra() ||
675     explain_modify_flags();
676 }
677 
678 
679 /**
680   Explain class main function
681 
682   This function:
683     a) allocates a select_send object (if no one pre-allocated available),
684     b) calculates and sends whole EXPLAIN data.
685 
686   @return false if success, true if error
687 */
688 
send()689 bool Explain::send()
690 {
691   DBUG_ENTER("Explain::send");
692 
693   if (fmt->begin_context(context_type, NULL))
694     DBUG_RETURN(true);
695 
696   /* Don't log this into the slow query log */
697   thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED |
698                          SERVER_QUERY_NO_GOOD_INDEX_USED);
699 
700   select_result *result;
701   if (external_result == NULL)
702   {
703     /* Create select_result object if the caller doesn't provide one: */
704     if (!(result= new select_send))
705       DBUG_RETURN(true); /* purecov: inspected */
706     if (fmt->send_headers(result) || prepare(result))
707       DBUG_RETURN(true);
708   }
709   else
710   {
711     result= external_result;
712     external_result->reset_offset_limit_cnt();
713   }
714 
715   for (SELECT_LEX_UNIT *unit= select_lex()->first_inner_unit();
716        unit;
717        unit= unit->next_unit())
718     propagate_explain_option(thd, unit);
719 
720   bool ret= shallow_explain() || explain_subqueries(result);
721 
722   if (!ret)
723     ret= fmt->end_context(context_type);
724 
725   if (ret && join)
726     join->error= 1; /* purecov: inspected */
727 
728   if (external_result == NULL)
729   {
730     if (ret)
731       result->abort_result_set();
732     else
733       result->send_eof();
734     delete result;
735   }
736 
737   DBUG_RETURN(ret);
738 }
739 
740 
explain_id()741 bool Explain::explain_id()
742 {
743   fmt->entry()->col_id.set(select_lex()->select_number);
744   return false;
745 }
746 
747 
explain_select_type()748 bool Explain::explain_select_type()
749 {
750   if (&thd->lex->select_lex != select_lex()) // ignore top-level SELECT_LEXes
751   {
752     fmt->entry()->is_dependent= select_lex()->is_dependent();
753     if (select_lex()->type(thd) != SELECT_LEX::SLT_DERIVED)
754       fmt->entry()->is_cacheable= select_lex()->is_cacheable();
755   }
756   fmt->entry()->col_select_type.set(select_lex()->type(thd));
757   return false;
758 }
759 
760 
761 /* Explain_no_table class functions *******************************************/
762 
763 
shallow_explain()764 bool Explain_no_table::shallow_explain()
765 {
766   return (fmt->begin_context(CTX_MESSAGE) ||
767           Explain::shallow_explain() ||
768           mark_subqueries(select_lex()->where, fmt->entry(), CTX_WHERE) ||
769           fmt->end_context(CTX_MESSAGE));
770 }
771 
772 
explain_rows_and_filtered()773 bool Explain_no_table::explain_rows_and_filtered()
774 {
775   if (rows == HA_POS_ERROR)
776     return false;
777   fmt->entry()->col_rows.set(rows);
778   return false;
779 }
780 
781 
explain_extra()782 bool Explain_no_table::explain_extra()
783 {
784   return fmt->entry()->col_message.set(message);
785 }
786 
787 
788 /* Explain_union_result class functions ****************************************/
789 
790 
explain_id()791 bool Explain_union_result::explain_id()
792 {
793   return false;
794 }
795 
796 
explain_table_name()797 bool Explain_union_result::explain_table_name()
798 {
799   SELECT_LEX *last_select= join->unit->first_select()->last_select();
800   // # characters needed to print select_number of last select
801   int last_length= (int)log10((double)last_select->select_number)+1;
802 
803   SELECT_LEX *sl= join->unit->first_select();
804   uint len= 6, lastop= 0;
805   char table_name_buffer[NAME_LEN];
806   memcpy(table_name_buffer, STRING_WITH_LEN("<union"));
807   /*
808     - len + lastop: current position in table_name_buffer
809     - 6 + last_length: the number of characters needed to print
810       '...,'<last_select->select_number>'>\0'
811   */
812   for (;
813        sl && len + lastop + 6 + last_length < NAME_CHAR_LEN;
814        sl= sl->next_select())
815   {
816     len+= lastop;
817     lastop= my_snprintf(table_name_buffer + len, NAME_CHAR_LEN - len,
818                         "%u,", sl->select_number);
819   }
820   if (sl || len + lastop >= NAME_CHAR_LEN)
821   {
822     memcpy(table_name_buffer + len, STRING_WITH_LEN("...,"));
823     len+= 4;
824     lastop= my_snprintf(table_name_buffer + len, NAME_CHAR_LEN - len,
825                         "%u,", last_select->select_number);
826   }
827   len+= lastop;
828   table_name_buffer[len - 1]= '>';  // change ',' to '>'
829 
830   return fmt->entry()->col_table_name.set(table_name_buffer, len);
831 }
832 
833 
explain_join_type()834 bool Explain_union_result::explain_join_type()
835 {
836   fmt->entry()->col_join_type.set_const(join_type_str[JT_ALL]);
837   return false;
838 }
839 
840 
explain_extra()841 bool Explain_union_result::explain_extra()
842 {
843   if (!fmt->is_hierarchical())
844   {
845     /*
846      Currently we always use temporary table for UNION result
847     */
848     if (push_extra(ET_USING_TEMPORARY))
849       return true;
850     /*
851       here we assume that the query will return at least two rows, so we
852       show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong
853       and no filesort will be actually done, but executing all selects in
854       the UNION to provide precise EXPLAIN information will hardly be
855       appreciated :)
856     */
857     if (join->unit->global_parameters->order_list.first)
858     {
859       return push_extra(ET_USING_FILESORT);
860     }
861   }
862   return Explain::explain_extra();
863 }
864 
865 
866 /* Explain_table_base class functions *****************************************/
867 
868 
explain_partitions()869 bool Explain_table_base::explain_partitions()
870 {
871 #ifdef WITH_PARTITION_STORAGE_ENGINE
872   if (!table->pos_in_table_list->derived && table->part_info)
873     return make_used_partitions_str(table->part_info,
874                                     &fmt->entry()->col_partitions);
875 #endif
876   return false;
877 }
878 
879 
explain_possible_keys()880 bool Explain_table_base::explain_possible_keys()
881 {
882   if (usable_keys.is_clear_all())
883     return false;
884 
885   for (uint j= 0 ; j < table->s->keys ; j++)
886   {
887     if (usable_keys.is_set(j) &&
888         fmt->entry()->col_possible_keys.push_back(table->key_info[j].name))
889       return true;
890   }
891   return false;
892 }
893 
894 
explain_key_parts(int key,uint key_parts)895 bool Explain_table_base::explain_key_parts(int key, uint key_parts)
896 {
897   KEY_PART_INFO *kp= table->key_info[key].key_part;
898   for (uint i= 0; i < key_parts; i++, kp++)
899     if (fmt->entry()->col_key_parts.push_back(kp->field->field_name))
900       return true;
901   return false;
902 }
903 
904 
explain_key_and_len_quick(const SQL_SELECT * select)905 bool Explain_table_base::explain_key_and_len_quick(const SQL_SELECT *select)
906 {
907   DBUG_ASSERT(select && select->quick);
908 
909   bool ret= false;
910   StringBuffer<512> str_key(cs);
911   StringBuffer<512> str_key_len(cs);
912 
913   if (select->quick->index != MAX_KEY)
914     ret= explain_key_parts(select->quick->index,
915                            select->quick->used_key_parts);
916   select->quick->add_keys_and_lengths(&str_key, &str_key_len);
917   return (ret || fmt->entry()->col_key.set(str_key) ||
918           fmt->entry()->col_key_len.set(str_key_len));
919 }
920 
921 
explain_key_and_len_index(int key)922 bool Explain_table_base::explain_key_and_len_index(int key)
923 {
924   DBUG_ASSERT(key != MAX_KEY);
925   return explain_key_and_len_index(key, table->key_info[key].key_length,
926                                    table->key_info[key].user_defined_key_parts);
927 }
928 
929 
explain_key_and_len_index(int key,uint key_length,uint key_parts)930 bool Explain_table_base::explain_key_and_len_index(int key, uint key_length,
931                                                    uint key_parts)
932 {
933   DBUG_ASSERT(key != MAX_KEY);
934 
935   char buff_key_len[24];
936   const KEY *key_info= table->key_info + key;
937   const int length= longlong2str(key_length, buff_key_len, 10) - buff_key_len;
938   const bool ret= explain_key_parts(key, key_parts);
939   return (ret || fmt->entry()->col_key.set(key_info->name) ||
940           fmt->entry()->col_key_len.set(buff_key_len, length));
941 }
942 
943 
explain_extra_common(const SQL_SELECT * select,const JOIN_TAB * tab,int quick_type,uint keyno)944 bool Explain_table_base::explain_extra_common(const SQL_SELECT *select,
945                                               const JOIN_TAB *tab,
946                                               int quick_type,
947                                               uint keyno)
948 {
949   if (((keyno != MAX_KEY &&
950         keyno == table->file->pushed_idx_cond_keyno &&
951         table->file->pushed_idx_cond) ||
952        (tab && tab->cache_idx_cond)))
953   {
954     StringBuffer<160> buff(cs);
955     if (fmt->is_hierarchical())
956     {
957       if (table->file->pushed_idx_cond)
958         table->file->pushed_idx_cond->print(&buff, cond_print_flags);
959       else
960         tab->cache_idx_cond->print(&buff, cond_print_flags);
961     }
962     if (push_extra(ET_USING_INDEX_CONDITION, buff))
963     return true;
964   }
965 
966   const TABLE* pushed_root= table->file->root_of_pushed_join();
967   if (pushed_root)
968   {
969     char buf[128];
970     int len;
971     int pushed_id= 0;
972 
973     for (JOIN_TAB* prev= join->join_tab; prev <= tab; prev++)
974     {
975       const TABLE* prev_root= prev->table->file->root_of_pushed_join();
976       if (prev_root == prev->table)
977       {
978         pushed_id++;
979         if (prev_root == pushed_root)
980           break;
981       }
982     }
983     if (pushed_root == table)
984     {
985       uint pushed_count= tab->table->file->number_of_pushed_joins();
986       len= my_snprintf(buf, sizeof(buf)-1,
987                        "Parent of %d pushed join@%d",
988                        pushed_count, pushed_id);
989     }
990     else
991     {
992       len= my_snprintf(buf, sizeof(buf)-1,
993                        "Child of '%s' in pushed join@%d",
994                        tab->table->file->parent_of_pushed_join()->alias,
995                        pushed_id);
996     }
997 
998     {
999       StringBuffer<128> buff(cs);
1000       buff.append(buf,len);
1001       if (push_extra(ET_PUSHED_JOIN, buff))
1002         return true;
1003     }
1004   }
1005 
1006   switch (quick_type) {
1007   case QUICK_SELECT_I::QS_TYPE_ROR_UNION:
1008   case QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT:
1009   case QUICK_SELECT_I::QS_TYPE_INDEX_MERGE:
1010     {
1011       StringBuffer<32> buff(cs);
1012       select->quick->add_info_string(&buff);
1013       if (fmt->is_hierarchical())
1014       {
1015         /*
1016           We are replacing existing col_key value with a quickselect info,
1017           but not the reverse:
1018         */
1019         DBUG_ASSERT(fmt->entry()->col_key.length);
1020         if (fmt->entry()->col_key.set(buff)) // keep col_key_len intact
1021           return true;
1022       }
1023       else
1024       {
1025         if (push_extra(ET_USING, buff))
1026           return true;
1027       }
1028     }
1029     break;
1030   default: ;
1031   }
1032 
1033   if (select)
1034   {
1035     if (tab && tab->use_quick == QS_DYNAMIC_RANGE)
1036     {
1037       StringBuffer<64> str(STRING_WITH_LEN("index map: 0x"), cs);
1038       /* 4 bits per 1 hex digit + terminating '\0' */
1039       char buf[MAX_KEY / 4 + 1];
1040       str.append(tab->keys.print(buf));
1041       if (push_extra(ET_RANGE_CHECKED_FOR_EACH_RECORD, str))
1042         return true;
1043     }
1044     else if (select->cond)
1045     {
1046       const Item *pushed_cond= table->file->pushed_cond;
1047 
1048       if (thd->optimizer_switch_flag(OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN) &&
1049           pushed_cond)
1050       {
1051         StringBuffer<64> buff(cs);
1052         if (describe(DESCRIBE_EXTENDED))
1053           ((Item *)pushed_cond)->print(&buff, cond_print_flags);
1054         if (push_extra(ET_USING_WHERE_WITH_PUSHED_CONDITION, buff))
1055           return true;
1056       }
1057       else
1058       {
1059         if (fmt->is_hierarchical())
1060         {
1061           Lazy_condition *c= new Lazy_condition(tab && !tab->filesort ?
1062                                                 tab->condition() :
1063                                                 select->cond);
1064           if (c == NULL)
1065             return true;
1066           fmt->entry()->col_attached_condition.set(c);
1067         }
1068         else if (push_extra(ET_USING_WHERE))
1069           return true;
1070       }
1071     }
1072     else
1073       DBUG_ASSERT(!tab || !tab->condition());
1074   }
1075   if (table->reginfo.not_exists_optimize && push_extra(ET_NOT_EXISTS))
1076     return true;
1077 
1078   if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE)
1079   {
1080     uint mrr_flags=
1081       ((QUICK_RANGE_SELECT*)(select->quick))->mrr_flags;
1082 
1083     /*
1084       During normal execution of a query, multi_range_read_init() is
1085       called to initialize MRR. If HA_MRR_SORTED is set at this point,
1086       multi_range_read_init() for any native MRR implementation will
1087       revert to default MRR if not HA_MRR_SUPPORT_SORTED.
1088       Calling multi_range_read_init() can potentially be costly, so it
1089       is not done when executing an EXPLAIN. We therefore simulate
1090       its effect here:
1091     */
1092     if (mrr_flags & HA_MRR_SORTED && !(mrr_flags & HA_MRR_SUPPORT_SORTED))
1093       mrr_flags|= HA_MRR_USE_DEFAULT_IMPL;
1094 
1095     if (!(mrr_flags & HA_MRR_USE_DEFAULT_IMPL) && push_extra(ET_USING_MRR))
1096       return true;
1097   }
1098   return false;
1099 }
1100 
explain_tmptable_and_filesort(bool need_tmp_table_arg,bool need_sort_arg)1101 bool Explain_table_base::explain_tmptable_and_filesort(bool need_tmp_table_arg,
1102                                                        bool need_sort_arg)
1103 {
1104   /*
1105     For hierarchical EXPLAIN we output "Using temporary" and
1106     "Using filesort" with related ORDER BY, GROUP BY or DISTINCT
1107   */
1108   if (fmt->is_hierarchical())
1109     return false;
1110 
1111   if (need_tmp_table_arg && push_extra(ET_USING_TEMPORARY))
1112     return true;
1113   if (need_sort_arg && push_extra(ET_USING_FILESORT))
1114     return true;
1115   return false;
1116 }
1117 
1118 
explain_modify_flags()1119 bool Explain_table_base::explain_modify_flags()
1120 {
1121   if (!fmt->is_hierarchical())
1122       return false;
1123   switch (thd->lex->sql_command) {
1124   case SQLCOM_UPDATE_MULTI:
1125     if (!bitmap_is_clear_all(table->write_set) &&
1126         table->s->table_category != TABLE_CATEGORY_TEMPORARY)
1127       fmt->entry()->is_update= true;
1128     break;
1129   case SQLCOM_DELETE_MULTI:
1130     {
1131       TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
1132       for (TABLE_LIST *at= aux_tables; at; at= at->next_local)
1133       {
1134         if (at->table == table)
1135         {
1136           fmt->entry()->is_delete= true;
1137           break;
1138         }
1139       }
1140       break;
1141     }
1142   default: ;
1143   };
1144   return false;
1145 }
1146 
1147 
1148 /* Explain_join class functions ***********************************************/
1149 
begin_sort_context(Explain_sort_clause clause,Explain_context_enum ctx)1150 bool Explain_join::begin_sort_context(Explain_sort_clause clause,
1151                                       Explain_context_enum ctx)
1152 {
1153   const Explain_format_flags *flags= &join->explain_flags;
1154   return (flags->get(clause, ESP_EXISTS) &&
1155           !flags->get(clause, ESP_IS_SIMPLE) &&
1156           fmt->begin_context(ctx, NULL, flags));
1157 }
1158 
1159 
end_sort_context(Explain_sort_clause clause,Explain_context_enum ctx)1160 bool Explain_join::end_sort_context(Explain_sort_clause clause,
1161                                     Explain_context_enum ctx)
1162 {
1163   const Explain_format_flags *flags= &join->explain_flags;
1164   return (flags->get(clause, ESP_EXISTS) &&
1165           !flags->get(clause, ESP_IS_SIMPLE) &&
1166           fmt->end_context(ctx));
1167 }
1168 
1169 
begin_simple_sort_context(Explain_sort_clause clause,Explain_context_enum ctx)1170 bool Explain_join::begin_simple_sort_context(Explain_sort_clause clause,
1171                                              Explain_context_enum ctx)
1172 {
1173   const Explain_format_flags *flags= &join->explain_flags;
1174   return (flags->get(clause, ESP_IS_SIMPLE) &&
1175           fmt->begin_context(ctx, NULL, flags));
1176 }
1177 
1178 
end_simple_sort_context(Explain_sort_clause clause,Explain_context_enum ctx)1179 bool Explain_join::end_simple_sort_context(Explain_sort_clause clause,
1180                                            Explain_context_enum ctx)
1181 {
1182   const Explain_format_flags *flags= &join->explain_flags;
1183   return (flags->get(clause, ESP_IS_SIMPLE) &&
1184           fmt->end_context(ctx));
1185 }
1186 
1187 
shallow_explain()1188 bool Explain_join::shallow_explain()
1189 {
1190   if (begin_sort_context(ESC_ORDER_BY, CTX_ORDER_BY))
1191     return true;
1192   if (begin_sort_context(ESC_DISTINCT, CTX_DISTINCT))
1193     return true;
1194   if (begin_sort_context(ESC_GROUP_BY, CTX_GROUP_BY))
1195     return true;
1196   if (begin_sort_context(ESC_BUFFER_RESULT, CTX_BUFFER_RESULT))
1197     return true;
1198 
1199   for (size_t t= 0,
1200        cnt= fmt->is_hierarchical() ? join->primary_tables : join->tables;
1201        t < cnt; t++)
1202   {
1203     if (explain_join_tab(t))
1204       return true;
1205   }
1206 
1207   if (end_sort_context(ESC_BUFFER_RESULT, CTX_BUFFER_RESULT))
1208     return true;
1209   if (end_sort_context(ESC_GROUP_BY, CTX_GROUP_BY))
1210     return true;
1211   if (end_sort_context(ESC_DISTINCT, CTX_DISTINCT))
1212     return true;
1213   if (end_sort_context(ESC_ORDER_BY, CTX_ORDER_BY))
1214     return true;
1215 
1216   return false;
1217 }
1218 
1219 
explain_join_tab(size_t tab_num)1220 bool Explain_join::explain_join_tab(size_t tab_num)
1221 {
1222   tabnum= tab_num;
1223   tab= join->join_tab + tabnum;
1224   table= tab->table;
1225   if (!tab->position)
1226     return false;
1227   usable_keys= tab->keys;
1228   quick_type= -1;
1229   select= (tab->filesort && tab->filesort->select) ?
1230            tab->filesort->select : tab->select;
1231 
1232   if (tab->type == JT_ALL && select && select->quick)
1233   {
1234     quick_type= select->quick->get_type();
1235     tab->type= calc_join_type(quick_type);
1236   }
1237 
1238   if (tab->starts_weedout())
1239     fmt->begin_context(CTX_DUPLICATES_WEEDOUT);
1240 
1241   const bool first_non_const= tabnum == join->const_tables;
1242 
1243   if (first_non_const)
1244   {
1245     if (begin_simple_sort_context(ESC_ORDER_BY, CTX_SIMPLE_ORDER_BY))
1246       return true;
1247     if (begin_simple_sort_context(ESC_DISTINCT, CTX_SIMPLE_DISTINCT))
1248       return true;
1249     if (begin_simple_sort_context(ESC_GROUP_BY, CTX_SIMPLE_GROUP_BY))
1250       return true;
1251   }
1252 
1253   Semijoin_mat_exec *sjm= tab->sj_mat_exec;
1254   Explain_context_enum c= sjm ? CTX_MATERIALIZATION : CTX_JOIN_TAB;
1255 
1256   if (fmt->begin_context(c) || prepare_columns())
1257     return true;
1258 
1259   fmt->entry()->query_block_id= table->pos_in_table_list->query_block_id();
1260 
1261   if (sjm)
1262   {
1263     if (sjm->is_scan)
1264     {
1265       fmt->entry()->col_rows.cleanup(); // TODO: set(something reasonable)
1266     }
1267     else
1268     {
1269       fmt->entry()->col_rows.set(1);
1270     }
1271   }
1272 
1273   if (fmt->flush_entry() ||
1274       mark_subqueries(tab->condition(), fmt->entry(), CTX_WHERE))
1275     return true;
1276 
1277   if (sjm && fmt->is_hierarchical())
1278   {
1279     for (size_t sjt= sjm->inner_table_index, end= sjt + sjm->table_count;
1280          sjt < end; sjt++)
1281     {
1282       if (explain_join_tab(sjt))
1283         return true;
1284     }
1285   }
1286 
1287   if (fmt->end_context(c))
1288     return true;
1289 
1290   if (first_non_const)
1291   {
1292     if (end_simple_sort_context(ESC_GROUP_BY, CTX_SIMPLE_GROUP_BY))
1293       return true;
1294     if (end_simple_sort_context(ESC_DISTINCT, CTX_SIMPLE_DISTINCT))
1295       return true;
1296     if (end_simple_sort_context(ESC_ORDER_BY, CTX_SIMPLE_ORDER_BY))
1297       return true;
1298   }
1299 
1300   if (tab->check_weed_out_table &&
1301       fmt->end_context(CTX_DUPLICATES_WEEDOUT))
1302     return true;
1303 
1304   used_tables|= table->map;
1305 
1306   return false;
1307 }
1308 
1309 
explain_table_name()1310 bool Explain_join::explain_table_name()
1311 {
1312   if (table->pos_in_table_list->derived && !fmt->is_hierarchical())
1313   {
1314     /* Derived table name generation */
1315     char table_name_buffer[NAME_LEN];
1316     const size_t len= my_snprintf(table_name_buffer,
1317                                   sizeof(table_name_buffer) - 1,
1318                                   "<derived%u>",
1319                                   table->pos_in_table_list->query_block_id());
1320     return fmt->entry()->col_table_name.set(table_name_buffer, len);
1321   }
1322   else
1323     return fmt->entry()->col_table_name.set(table->pos_in_table_list->alias);
1324 }
1325 
1326 
explain_select_type()1327 bool Explain_join::explain_select_type()
1328 {
1329   if (sj_is_materialize_strategy(tab->get_sj_strategy()))
1330     fmt->entry()->col_select_type.set(st_select_lex::SLT_MATERIALIZED);
1331   else
1332     return Explain::explain_select_type();
1333   return false;
1334 }
1335 
1336 
explain_id()1337 bool Explain_join::explain_id()
1338 {
1339   if (sj_is_materialize_strategy(tab->get_sj_strategy()))
1340     fmt->entry()->col_id.set(tab->sjm_query_block_id());
1341   else
1342     return Explain::explain_id();
1343   return false;
1344 }
1345 
1346 
explain_join_type()1347 bool Explain_join::explain_join_type()
1348 {
1349   fmt->entry()->col_join_type.set_const(join_type_str[tab->type]);
1350   return false;
1351 }
1352 
1353 
explain_key_and_len()1354 bool Explain_join::explain_key_and_len()
1355 {
1356   if (tab->ref.key_parts)
1357     return explain_key_and_len_index(tab->ref.key, tab->ref.key_length,
1358                                      tab->ref.key_parts);
1359   else if (tab->type == JT_INDEX_SCAN)
1360     return explain_key_and_len_index(tab->index);
1361   else if (select && select->quick)
1362     return explain_key_and_len_quick(select);
1363   else
1364   {
1365     const TABLE_LIST *table_list= table->pos_in_table_list;
1366     if (table_list->schema_table &&
1367         table_list->schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
1368     {
1369       StringBuffer<512> str_key(cs);
1370       const char *f_name;
1371       int f_idx;
1372       if (table_list->has_db_lookup_value)
1373       {
1374         f_idx= table_list->schema_table->idx_field1;
1375         f_name= table_list->schema_table->fields_info[f_idx].field_name;
1376         str_key.append(f_name, strlen(f_name), cs);
1377       }
1378       if (table_list->has_table_lookup_value)
1379       {
1380         if (table_list->has_db_lookup_value)
1381           str_key.append(',');
1382         f_idx= table_list->schema_table->idx_field2;
1383         f_name= table_list->schema_table->fields_info[f_idx].field_name;
1384         str_key.append(f_name, strlen(f_name), cs);
1385       }
1386       if (str_key.length())
1387         return fmt->entry()->col_key.set(str_key);
1388     }
1389   }
1390   return false;
1391 }
1392 
1393 
explain_ref()1394 bool Explain_join::explain_ref()
1395 {
1396   return explain_ref_key(fmt, tab->ref.key_parts, tab->ref.key_copy);
1397 }
1398 
1399 
explain_rows_and_filtered()1400 bool Explain_join::explain_rows_and_filtered()
1401 {
1402   if (table->pos_in_table_list->schema_table)
1403     return false;
1404 
1405   double examined_rows;
1406   if (select && select->quick)
1407     examined_rows= rows2double(select->quick->records);
1408   else if (tab->type == JT_INDEX_SCAN || tab->type == JT_ALL)
1409   {
1410     if (tab->limit)
1411       examined_rows= rows2double(tab->limit);
1412     else
1413     {
1414       table->pos_in_table_list->fetch_number_of_rows();
1415       examined_rows= rows2double(table->file->stats.records);
1416     }
1417   }
1418   else
1419     examined_rows= tab->position->records_read;
1420 
1421   fmt->entry()->col_rows.set(static_cast<longlong>(examined_rows));
1422 
1423   /* Add "filtered" field */
1424   if (describe(DESCRIBE_EXTENDED))
1425   {
1426     float f= 0.0;
1427     if (examined_rows)
1428       f= 100.0 * tab->position->records_read / examined_rows;
1429     fmt->entry()->col_filtered.set(f);
1430   }
1431   return false;
1432 }
1433 
1434 
explain_extra()1435 bool Explain_join::explain_extra()
1436 {
1437   if (tab->info)
1438   {
1439     if (push_extra(tab->info))
1440       return true;
1441   }
1442   else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
1443   {
1444     if (tab->packed_info & TAB_INFO_USING_INDEX)
1445     {
1446       if (push_extra(ET_USING_INDEX))
1447         return true;
1448     }
1449     if (tab->packed_info & TAB_INFO_USING_WHERE)
1450     {
1451       if (fmt->is_hierarchical())
1452       {
1453         Lazy_condition *c= new Lazy_condition(tab->condition());
1454         if (c == NULL)
1455           return true;
1456         fmt->entry()->col_attached_condition.set(c);
1457       }
1458       else if (push_extra(ET_USING_WHERE))
1459         return true;
1460     }
1461     if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
1462     {
1463       if (fmt->entry()->col_extra.push_back(new
1464                                             extra(ET_FULL_SCAN_ON_NULL_KEY)))
1465         return true;
1466     }
1467   }
1468   else
1469   {
1470     uint keyno= MAX_KEY;
1471     if (tab->ref.key_parts)
1472       keyno= tab->ref.key;
1473     else if (select && select->quick)
1474       keyno = select->quick->index;
1475 
1476     if (explain_extra_common(select, tab, quick_type, keyno))
1477       return true;
1478 
1479     const TABLE_LIST *table_list= table->pos_in_table_list;
1480     if (table_list->schema_table &&
1481         table_list->schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
1482     {
1483       if (!table_list->table_open_method)
1484       {
1485         if (push_extra(ET_SKIP_OPEN_TABLE))
1486           return true;
1487       }
1488       else if (table_list->table_open_method == OPEN_FRM_ONLY)
1489       {
1490         if (push_extra(ET_OPEN_FRM_ONLY))
1491           return true;
1492       }
1493       else
1494       {
1495         if (push_extra(ET_OPEN_FULL_TABLE))
1496           return true;
1497       }
1498 
1499       StringBuffer<32> buff(cs);
1500       if (table_list->has_db_lookup_value &&
1501           table_list->has_table_lookup_value)
1502       {
1503         if (push_extra(ET_SCANNED_DATABASES, "0"))
1504           return true;
1505       }
1506       else if (table_list->has_db_lookup_value ||
1507                table_list->has_table_lookup_value)
1508       {
1509         if (push_extra(ET_SCANNED_DATABASES, "1"))
1510           return true;
1511       }
1512       else
1513       {
1514         if (push_extra(ET_SCANNED_DATABASES, "all"))
1515           return true;
1516       }
1517     }
1518     if (((tab->type == JT_INDEX_SCAN || tab->type == JT_CONST) &&
1519          table->covering_keys.is_set(tab->index)) ||
1520         (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&
1521          !((QUICK_ROR_INTERSECT_SELECT*) select->quick)->need_to_fetch_row) ||
1522         table->key_read)
1523     {
1524       if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
1525       {
1526         QUICK_GROUP_MIN_MAX_SELECT *qgs=
1527           (QUICK_GROUP_MIN_MAX_SELECT *) select->quick;
1528         StringBuffer<64> buff(cs);
1529         qgs->append_loose_scan_type(&buff);
1530         if (push_extra(ET_USING_INDEX_FOR_GROUP_BY, buff))
1531           return true;
1532       }
1533       else
1534       {
1535         if (push_extra(ET_USING_INDEX))
1536           return true;
1537       }
1538     }
1539 
1540     if (explain_tmptable_and_filesort(need_tmp_table, need_order))
1541       return true;
1542     need_tmp_table= need_order= false;
1543 
1544     if (distinct && test_all_bits(used_tables, thd->lex->used_tables) &&
1545         push_extra(ET_DISTINCT))
1546       return true;
1547 
1548     if (tab->do_loosescan() && push_extra(ET_LOOSESCAN))
1549       return true;
1550 
1551     if (tab->starts_weedout())
1552     {
1553       if (!fmt->is_hierarchical() && push_extra(ET_START_TEMPORARY))
1554         return true;
1555     }
1556     if (tab->finishes_weedout())
1557     {
1558       if (!fmt->is_hierarchical() && push_extra(ET_END_TEMPORARY))
1559         return true;
1560     }
1561     else if (tab->do_firstmatch())
1562     {
1563       if (tab->firstmatch_return == join->join_tab - 1)
1564       {
1565         if (push_extra(ET_FIRST_MATCH))
1566           return true;
1567       }
1568       else
1569       {
1570         StringBuffer<64> buff(cs);
1571         TABLE *prev_table= tab->firstmatch_return->table;
1572         if (prev_table->pos_in_table_list->query_block_id() &&
1573             !fmt->is_hierarchical() &&
1574             prev_table->pos_in_table_list->derived)
1575         {
1576           char namebuf[NAME_LEN];
1577           /* Derived table name generation */
1578           int len= my_snprintf(namebuf, sizeof(namebuf)-1,
1579               "<derived%u>",
1580               prev_table->pos_in_table_list->query_block_id());
1581           buff.append(namebuf, len);
1582         }
1583         else
1584           buff.append(prev_table->pos_in_table_list->alias);
1585         if (push_extra(ET_FIRST_MATCH, buff))
1586           return true;
1587       }
1588     }
1589 
1590     if (tab->has_guarded_conds() && push_extra(ET_FULL_SCAN_ON_NULL_KEY))
1591       return true;
1592 
1593     if (tabnum > 0 && tab->use_join_cache != JOIN_CACHE::ALG_NONE)
1594     {
1595       StringBuffer<64> buff(cs);
1596       if ((tab->use_join_cache & JOIN_CACHE::ALG_BNL))
1597         buff.append("Block Nested Loop");
1598       else if ((tab->use_join_cache & JOIN_CACHE::ALG_BKA))
1599         buff.append("Batched Key Access");
1600       else if ((tab->use_join_cache & JOIN_CACHE::ALG_BKA_UNIQUE))
1601         buff.append("Batched Key Access (unique)");
1602       else
1603         DBUG_ASSERT(0); /* purecov: inspected */
1604       if (push_extra(ET_USING_JOIN_BUFFER, buff))
1605         return true;
1606     }
1607   }
1608   return false;
1609 }
1610 
1611 
1612 /* Explain_table class functions **********************************************/
1613 
explain_modify_flags()1614 bool Explain_table::explain_modify_flags()
1615 {
1616   if (!fmt->is_hierarchical())
1617       return false;
1618   if (is_update)
1619     fmt->entry()->is_update= true;
1620   else
1621     fmt->entry()->is_delete= true;
1622   return false;
1623 }
1624 
1625 
explain_tmptable_and_filesort(bool need_tmp_table_arg,bool need_sort_arg)1626 bool Explain_table::explain_tmptable_and_filesort(bool need_tmp_table_arg,
1627                                                   bool need_sort_arg)
1628 {
1629   if (fmt->is_hierarchical())
1630   {
1631     /*
1632       For hierarchical EXPLAIN we output "using_temporary_table" and
1633       "using_filesort" with related ORDER BY, GROUP BY or DISTINCT
1634       (excluding the single-table UPDATE command that updates used key --
1635       in this case we output "using_temporary_table: for update"
1636       at the "table" node)
1637     */
1638     if (need_tmp_table_arg)
1639     {
1640       DBUG_ASSERT(used_key_is_modified || order_list);
1641       if (used_key_is_modified && push_extra(ET_USING_TEMPORARY, "for update"))
1642         return true;
1643     }
1644   }
1645   else
1646   {
1647     if (need_tmp_table_arg && push_extra(ET_USING_TEMPORARY))
1648       return true;
1649 
1650     if (need_sort_arg && push_extra(ET_USING_FILESORT))
1651       return true;
1652   }
1653 
1654   return false;
1655 }
1656 
1657 
shallow_explain()1658 bool Explain_table::shallow_explain()
1659 {
1660   Explain_format_flags flags;
1661   if (order_list)
1662   {
1663     flags.set(ESC_ORDER_BY, ESP_EXISTS);
1664     if (need_sort)
1665       flags.set(ESC_ORDER_BY, ESP_USING_FILESORT);
1666     if (!used_key_is_modified && need_tmp_table)
1667       flags.set(ESC_ORDER_BY, ESP_USING_TMPTABLE);
1668   }
1669 
1670   if (order_list && fmt->begin_context(CTX_ORDER_BY, NULL, &flags))
1671     return true;
1672 
1673   if (fmt->begin_context(CTX_JOIN_TAB))
1674     return true;
1675 
1676   if (Explain::shallow_explain() ||
1677       mark_subqueries(select_lex()->where, fmt->entry(), CTX_WHERE))
1678     return true;
1679 
1680   if (fmt->end_context(CTX_JOIN_TAB))
1681     return true;
1682 
1683   if (order_list && fmt->end_context(CTX_ORDER_BY))
1684     return true;
1685 
1686   return false;
1687 }
1688 
1689 
explain_table_name()1690 bool Explain_table::explain_table_name()
1691 {
1692   return fmt->entry()->col_table_name.set(table->alias);
1693 }
1694 
1695 
explain_join_type()1696 bool Explain_table::explain_join_type()
1697 {
1698   join_type jt;
1699   if (select && select->quick)
1700     jt= calc_join_type(select->quick->get_type());
1701   else if (key != MAX_KEY)
1702     jt= JT_INDEX_SCAN;
1703   else
1704     jt= JT_ALL;
1705 
1706   fmt->entry()->col_join_type.set_const(join_type_str[jt]);
1707   return false;
1708 }
1709 
1710 
explain_ref()1711 bool Explain_table::explain_ref()
1712 {
1713   if (select && select->quick)
1714   {
1715     int key_parts= select->quick->used_key_parts;
1716     while(key_parts--)
1717     {
1718       fmt->entry()->col_ref.push_back("const");
1719     }
1720   }
1721   return false;
1722 }
1723 
1724 
explain_key_and_len()1725 bool Explain_table::explain_key_and_len()
1726 {
1727   if (select && select->quick)
1728     return explain_key_and_len_quick(select);
1729   else if (key != MAX_KEY)
1730     return explain_key_and_len_index(key);
1731   return false;
1732 }
1733 
1734 
explain_rows_and_filtered()1735 bool Explain_table::explain_rows_and_filtered()
1736 {
1737   double examined_rows;
1738   if (select && select->quick)
1739     examined_rows= rows2double(select->quick->records);
1740   else if (!select && !need_sort && limit != HA_POS_ERROR)
1741     examined_rows= rows2double(limit);
1742   else
1743   {
1744     table->pos_in_table_list->fetch_number_of_rows();
1745     examined_rows= rows2double(table->file->stats.records);
1746 
1747   }
1748   fmt->entry()->col_rows.set(static_cast<long long>(examined_rows));
1749 
1750   if (describe(DESCRIBE_EXTENDED))
1751     fmt->entry()->col_filtered.set(100.0);
1752 
1753   return false;
1754 }
1755 
1756 
explain_extra()1757 bool Explain_table::explain_extra()
1758 {
1759   const uint keyno= (select && select->quick) ? select->quick->index : key;
1760   const int quick_type= (select && select->quick) ? select->quick->get_type()
1761                                                   : -1;
1762   return (explain_extra_common(select, NULL, quick_type, keyno) ||
1763           explain_tmptable_and_filesort(need_tmp_table, need_sort));
1764 }
1765 
1766 
1767 /**
1768   EXPLAIN functionality for insert_select, multi_update and multi_delete
1769 
1770   This class objects substitute insert_select, multi_update and multi_delete
1771   data interceptor objects to implement EXPLAIN for INSERT, REPLACE and
1772   multi-table UPDATE and DELETE queries.
1773   explain_send class object initializes tables like insert_select, multi_update
1774   or multi_delete data interceptor do, but it suppress table data modification
1775   by the underlying interceptor object.
1776   Thus, we can use explain_send object in the context of EXPLAIN INSERT/
1777   REPLACE/UPDATE/DELETE query like we use select_send in the context of
1778   EXPLAIN SELECT command:
1779     1) in presence of lex->describe flag we pass explain_send object to the
1780        mysql_select() function,
1781     2) it call prepare(), prepare2() and initialize_tables() functions to
1782        mark modified tables etc.
1783 
1784 */
1785 
1786 class explain_send : public select_send {
1787 protected:
1788   /*
1789     As far as we use explain_send object in a place of select_send, explain_send
1790     have to pass multiple invocation of its prepare(), prepare2() and
1791     initialize_tables() functions, since JOIN::exec() of subqueries runs
1792     these functions of select_send multiple times by design.
1793     insert_select, multi_update and multi_delete class functions are not intended
1794     for multiple invocations, so "prepared", "prepared2" and "initialized" flags
1795     guard data interceptor object from function re-invocation.
1796   */
1797   bool prepared;    ///< prepare() is done
1798   bool prepared2;   ///< prepare2() is done
1799   bool initialized; ///< initialize_tables() is done
1800 
1801   /**
1802     Pointer to underlying insert_select, multi_update or multi_delete object
1803   */
1804   select_result_interceptor *interceptor;
1805 
1806 public:
explain_send(select_result_interceptor * interceptor_arg)1807   explain_send(select_result_interceptor *interceptor_arg)
1808   : prepared(false), prepared2(false), initialized(false),
1809     interceptor(interceptor_arg)
1810   {}
1811 
1812 protected:
prepare(List<Item> & list,SELECT_LEX_UNIT * u)1813   virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u)
1814   {
1815     if (prepared)
1816       return false;
1817     prepared= true;
1818     return select_send::prepare(list, u) || interceptor->prepare(list, u);
1819   }
1820 
prepare2(void)1821   virtual int prepare2(void)
1822   {
1823     if (prepared2)
1824       return false;
1825     prepared2= true;
1826     return select_send::prepare2() || interceptor->prepare2();
1827   }
1828 
initialize_tables(JOIN * join)1829   virtual bool initialize_tables(JOIN *join)
1830   {
1831     if (initialized)
1832       return false;
1833     initialized= true;
1834     return select_send::initialize_tables(join) ||
1835            interceptor->initialize_tables(join);
1836   }
1837 
cleanup()1838   virtual void cleanup()
1839   {
1840     select_send::cleanup();
1841     interceptor->cleanup();
1842   }
1843 };
1844 
1845 
1846 /******************************************************************************
1847   External function implementations
1848 ******************************************************************************/
1849 
1850 
1851 /**
1852   Send a message as an "extra" column value
1853 
1854   This function forms the 1st row of the QEP output with a simple text message.
1855   This is useful to explain such trivial cases as "No tables used" etc.
1856 
1857   @note Also this function explains the rest of QEP (subqueries or joined
1858         tables if any).
1859 
1860   @param thd      current THD
1861   @param join     JOIN
1862   @param message  text message for the "extra" column.
1863 
1864   @return false if success, true if error
1865 */
1866 
explain_no_table(THD * thd,JOIN * join,const char * message)1867 bool explain_no_table(THD *thd, JOIN *join, const char *message)
1868 {
1869   DBUG_ENTER("explain_no_table");
1870   const bool ret= Explain_no_table(thd, join, message).send();
1871   DBUG_RETURN(ret);
1872 }
1873 
1874 
1875 /**
1876   Send a message as an "extra" column value
1877 
1878   This function forms the 1st row of the QEP output with a simple text message.
1879   This is useful to explain such trivial cases as "No tables used" etc.
1880 
1881   @note Also this function explains the rest of QEP (subqueries if any).
1882 
1883   @param thd      current THD
1884   @param message  text message for the "extra" column.
1885   @param rows     HA_POS_ERROR or a value for the "rows" column.
1886 
1887   @return false if success, true if error
1888 */
1889 
explain_no_table(THD * thd,const char * message,ha_rows rows)1890 bool explain_no_table(THD *thd, const char *message, ha_rows rows)
1891 {
1892   DBUG_ENTER("explain_no_table");
1893   const bool ret= Explain_no_table(thd, message, rows).send();
1894   DBUG_RETURN(ret);
1895 }
1896 
1897 
1898 /**
1899   EXPLAIN handling for single-table UPDATE and DELETE queries
1900 
1901   Send to the client a QEP data set for single-table EXPLAIN UPDATE/DELETE
1902   queries. As far as single-table UPDATE/DELETE are implemented without
1903   the regular JOIN tree, we can't reuse explain_unit() directly,
1904   thus we deal with this single table in a special way and then call
1905   explain_unit() for subqueries (if any).
1906 
1907   @param thd            current THD
1908   @param table          TABLE object to update/delete rows in the UPDATE/DELETE
1909                         query.
1910   @param select         SQL_SELECT object that represents quick access functions
1911                         and WHERE clause.
1912   @param key            MAX_KEY or and index number of the key that was chosen
1913                         to access table data.
1914   @param limit          HA_POS_ERROR or LIMIT value.
1915   @param need_tmp_table true if it requires temporary table -- "Using temporary"
1916                         string in the "extra" column.
1917   @param need_sort      true if it requires filesort() -- "Using filesort"
1918                         string in the "extra" column.
1919   @param is_update      is_update ? UPDATE command : DELETE command
1920   @param used_key_is_modified   UPDATE updates used key column
1921 
1922   @return false if success, true if error
1923 */
1924 
explain_single_table_modification(THD * thd,TABLE * table,const SQL_SELECT * select,uint key,ha_rows limit,bool need_tmp_table,bool need_sort,bool is_update,bool used_key_is_modified)1925 bool explain_single_table_modification(THD *thd,
1926                                        TABLE *table,
1927                                        const SQL_SELECT *select,
1928                                        uint key,
1929                                        ha_rows limit,
1930                                        bool need_tmp_table,
1931                                        bool need_sort,
1932                                        bool is_update,
1933                                        bool used_key_is_modified)
1934 {
1935   DBUG_ENTER("explain_single_table_modification");
1936   const bool ret= Explain_table(thd, table, select, key, limit,
1937                                 need_tmp_table, need_sort, is_update,
1938                                 used_key_is_modified).send();
1939   DBUG_RETURN(ret);
1940 }
1941 
1942 
1943 /**
1944   EXPLAIN handling for EXPLAIN SELECT queries
1945 
1946   Send QEP to the client.
1947 
1948   @param thd             current THD
1949   @param join            JOIN
1950   @param need_tmp_table  true if it requires a temporary table --
1951                          "Using temporary" string in the "extra" column.
1952   @param need_order      true if it requires filesort() -- "Using filesort"
1953                          string in the "extra" column.
1954   @param distinct        true if there is the DISTINCT clause (not optimized
1955                          out) -- "Distinct" string in the "extra" column.
1956 
1957   @return false if success, true if error
1958 */
1959 
explain_query_specification(THD * thd,JOIN * join)1960 bool explain_query_specification(THD *thd, JOIN *join)
1961 {
1962   const Explain_format_flags *flags= &join->explain_flags;
1963   const bool need_tmp_table= flags->any(ESP_USING_TMPTABLE);
1964   const bool need_order= flags->any(ESP_USING_FILESORT);
1965   const bool distinct= flags->get(ESC_DISTINCT, ESP_EXISTS);
1966 
1967   DBUG_ENTER("explain_query_specification");
1968   DBUG_PRINT("info", ("Select %p, type %s",
1969                       join->select_lex, join->select_lex->get_type_str(thd)));
1970   bool ret;
1971   if (join->select_lex == join->unit->fake_select_lex)
1972     ret= Explain_union_result(thd, join).send();
1973   else
1974     ret= Explain_join(thd, join, need_tmp_table, need_order, distinct).send();
1975   DBUG_RETURN(ret);
1976 }
1977 
1978 
1979 /**
1980   EXPLAIN handling for INSERT, REPLACE and multi-table UPDATE/DELETE queries
1981 
1982   Send to the client a QEP data set for data-modifying commands those have a
1983   regular JOIN tree (INSERT...SELECT, REPLACE...SELECT and multi-table
1984   UPDATE and DELETE queries) like mysql_select() does for SELECT queries in
1985   the "describe" mode.
1986 
1987   @note see explain_single_table_modification() for single-table
1988         UPDATE/DELETE EXPLAIN handling.
1989 
1990   @note Unlike the mysql_select function, explain_multi_table_modification
1991         calls abort_result_set() itself in the case of failure (OOM etc.)
1992         since explain_multi_table_modification() uses internally created
1993         select_result stream.
1994 
1995   @param thd     current THD
1996   @param result  pointer to select_insert, multi_delete or multi_update object:
1997                  the function uses it to call result->prepare(),
1998                  result->prepare2() and result->initialize_tables() only but
1999                  not to modify table data or to send a result to client.
2000   @return false if success, true if error
2001 */
2002 
explain_multi_table_modification(THD * thd,select_result_interceptor * result)2003 bool explain_multi_table_modification(THD *thd,
2004                                       select_result_interceptor *result)
2005 {
2006   DBUG_ENTER("explain_multi_table_modification");
2007   explain_send explain(result);
2008   bool res= explain_query_expression(thd, &explain);
2009   DBUG_RETURN(res);
2010 }
2011 
2012 
2013 /**
2014   EXPLAIN handling for SELECT and table-modifying queries that have JOIN
2015 
2016   Send to the client a QEP data set for SELECT or data-modifying commands
2017   those have a regular JOIN tree (INSERT...SELECT, REPLACE...SELECT and
2018   multi-table UPDATE and DELETE queries) like mysql_select() does for SELECT
2019   queries in the "describe" mode.
2020 
2021   @note see explain_single_table_modification() for single-table
2022         UPDATE/DELETE EXPLAIN handling.
2023 
2024   @note explain_query_expression() calls abort_result_set() itself in the
2025         case of failure (OOM etc.) since explain_multi_table_modification()
2026         uses internally created select_result stream.
2027 
2028   @param thd     current THD
2029   @param result  pointer to select_result, select_insert, multi_delete or
2030                  multi_update object: the function uses it to call
2031                  result->prepare(), result->prepare2() and
2032                  result->initialize_tables() only but not to modify table data
2033                  or to send a result to client.
2034   @return false if success, true if error
2035 */
2036 
explain_query_expression(THD * thd,select_result * result)2037 bool explain_query_expression(THD *thd, select_result *result)
2038 {
2039   DBUG_ENTER("explain_query_expression");
2040   const bool res= thd->lex->explain_format->send_headers(result) ||
2041                   mysql_explain_unit(thd, &thd->lex->unit, result) ||
2042                   thd->is_error();
2043   /*
2044     The code which prints the extended description is not robust
2045     against malformed queries, so skip it if we have an error.
2046   */
2047   if (!res && (thd->lex->describe & DESCRIBE_EXTENDED) &&
2048       thd->lex->sql_command == SQLCOM_SELECT) // TODO: implement for INSERT/etc
2049   {
2050     StringBuffer<1024> str;
2051     /*
2052       The warnings system requires input in utf8, see mysqld_show_warnings().
2053     */
2054     thd->lex->unit.print(&str, enum_query_type(QT_TO_SYSTEM_CHARSET |
2055                                                QT_SHOW_SELECT_NUMBER));
2056     str.append('\0');
2057     push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_YES, str.ptr());
2058   }
2059   if (res)
2060     result->abort_result_set();
2061   else
2062     result->send_eof();
2063   DBUG_RETURN(res);
2064 }
2065 
2066 
2067 /**
2068   Set SELECT_DESCRIBE flag for all unit's SELECT_LEXes
2069 
2070   @param thd    THD
2071   @param unit   unit of SELECT_LEXes
2072 */
propagate_explain_option(THD * thd,SELECT_LEX_UNIT * unit)2073 static void propagate_explain_option(THD *thd, SELECT_LEX_UNIT *unit)
2074 {
2075   for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
2076     sl->options|= SELECT_DESCRIBE;
2077 }
2078 
2079 
2080 /**
2081   Explain UNION or subqueries of the unit
2082 
2083   If the unit is a UNION, explain it as a UNION. Otherwise explain nested
2084   subselects.
2085 
2086   @param thd            thread object
2087   @param unit           unit object
2088   @param result         result stream to send QEP dataset
2089 
2090   @return false if success, true if error
2091 */
mysql_explain_unit(THD * thd,SELECT_LEX_UNIT * unit,select_result * result)2092 bool mysql_explain_unit(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
2093 {
2094   DBUG_ENTER("mysql_explain_unit");
2095   bool res= 0;
2096 
2097   propagate_explain_option(thd, unit);
2098 
2099   if (unit->is_union())
2100   {
2101     unit->fake_select_lex->select_number= UINT_MAX; // just for initialization
2102     unit->fake_select_lex->options|= SELECT_DESCRIBE;
2103 
2104     res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE);
2105 
2106     if (res)
2107       DBUG_RETURN(res);
2108 
2109     /*
2110       If tables are not locked at this point, it means that we have delayed
2111       this step until after prepare stage (now), in order to do better
2112       partition pruning.
2113 
2114       We need to lock tables now in order to proceed with the remaning
2115       stages of query optimization.
2116     */
2117     if (! thd->lex->is_query_tables_locked() &&
2118         lock_tables(thd, thd->lex->query_tables, thd->lex->table_count, 0))
2119       DBUG_RETURN(true);
2120 
2121     res= unit->optimize();
2122 
2123     if (!res)
2124       res= unit->explain();
2125   }
2126   else
2127   {
2128     SELECT_LEX *first= unit->first_select();
2129     thd->lex->current_select= first;
2130     unit->set_limit(unit->global_parameters);
2131     res= mysql_select(thd,
2132                       first->table_list.first,
2133                       first->with_wild, first->item_list,
2134                       first->where,
2135                       &first->order_list,
2136                       &first->group_list,
2137                       first->having,
2138                       first->options | thd->variables.option_bits | SELECT_DESCRIBE,
2139                       result, unit, first);
2140   }
2141   DBUG_RETURN(res || thd->is_error());
2142 }
2143 
2144 
2145