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