MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
opt_explain_traditional.cc
1 /* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License 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 
16 #include "opt_explain_traditional.h"
17 
23 static const char *traditional_extra_tags[ET_total]=
24 {
25  NULL, // ET_none
26  "Using temporary", // ET_USING_TEMPORARY
27  "Using filesort", // ET_USING_FILESORT
28  "Using index condition", // ET_USING_INDEX_CONDITION
29  "Using", // ET_USING
30  "Range checked for each record", // ET_RANGE_CHECKED_FOR_EACH_RECORD
31  "Using where with pushed condition", // ET_USING_WHERE_WITH_PUSHED_CONDITION
32  "Using where", // ET_USING_WHERE
33  "Not exists", // ET_NOT_EXISTS
34  "Using MRR", // ET_USING_MRR
35  "Using index", // ET_USING_INDEX
36  "Full scan on NULL key", // ET_FULL_SCAN_ON_NULL_KEY
37  "Skip_open_table", // ET_SKIP_OPEN_TABLE
38  "Open_frm_only", // ET_OPEN_FRM_ONLY
39  "Open_full_table", // ET_OPEN_FULL_TABLE
40  "Scanned", // ET_SCANNED_DATABASES
41  "Using index for group-by", // ET_USING_INDEX_FOR_GROUP_BY
42  "Distinct", // ET_DISTINCT
43  "LooseScan", // ET_LOOSESCAN
44  "Start temporary", // ET_START_TEMPORARY
45  "End temporary", // ET_END_TEMPORARY
46  "FirstMatch", // ET_FIRST_MATCH
47  "Materialize", // ET_MATERIALIZE
48  "Start materialize", // ET_START_MATERIALIZE
49  "End materialize", // ET_END_MATERIALIZE
50  "Scan", // ET_SCAN
51  "Using join buffer", // ET_USING_JOIN_BUFFER
52  "const row not found", // ET_CONST_ROW_NOT_FOUND
53  "unique row not found", // ET_UNIQUE_ROW_NOT_FOUND
54  "Impossible ON condition", // ET_IMPOSSIBLE_ON_CONDITION
55  "" // ET_PUSHED_JOIN
56 };
57 
58 
59 
60 bool Explain_format_traditional::send_headers(select_result *result)
61 {
62  return ((nil= new Item_null) == NULL ||
64  current_thd->send_explain_fields(output));
65 }
66 
67 static bool push(List<Item> *items, qep_row::mem_root_str &s,
68  Item_null *nil)
69 {
70  if (s.is_empty())
71  return items->push_back(nil);
72  Item_string *item= new Item_string(s.str, s.length, system_charset_info);
73  return item == NULL || items->push_back(item);
74 }
75 
76 
77 static bool push(List<Item> *items, const char *s, size_t length)
78 {
79  Item_string *item= new Item_string(s, length, system_charset_info);
80  return item == NULL || items->push_back(item);
81 }
82 
83 static bool push(List<Item> *items, List<const char> &c, Item_null *nil)
84 {
85  if (c.is_empty())
86  return items->push_back(nil);
87 
88  StringBuffer<1024> buff;
90  const char *s;
91  while((s= it++))
92  {
93  buff.append(s);
94  buff.append(",");
95  }
96  if (!buff.is_empty())
97  buff.length(buff.length() - 1); // remove last ","
98  Item_string *item= new Item_string(buff.dup(current_thd->mem_root),
99  buff.length(), system_charset_info);
100  return item == NULL || items->push_back(item);
101 }
102 
103 
104 static bool push(List<Item> *items, const qep_row::column<uint> &c,
105  Item_null *nil)
106 {
107  if (c.is_empty())
108  return items->push_back(nil);
109  Item_uint *item= new Item_uint(c.get());
110  return item == NULL || items->push_back(item);
111 }
112 
113 
114 static bool push(List<Item> *items, const qep_row::column<longlong> &c,
115  Item_null *nil)
116 {
117  if (c.is_empty())
118  return items->push_back(nil);
119  Item_int *item= new Item_int(c.get(), MY_INT64_NUM_DECIMAL_DIGITS);
120  return item == NULL || items->push_back(item);
121 }
122 
123 
124 static bool push(List<Item> *items, const qep_row::column<float> &c,
125  Item_null *nil)
126 {
127  if (c.is_empty())
128  return items->push_back(nil);
129  Item_float *item= new Item_float(c.get(), 2);
130  return item == NULL || items->push_back(item);
131 }
132 
133 
134 bool Explain_format_traditional::push_select_type(List<Item> *items)
135 {
136  DBUG_ASSERT(!column_buffer.col_select_type.is_empty());
137  StringBuffer<32> buff;
138  if (column_buffer.is_dependent)
139  {
140  if (buff.append(STRING_WITH_LEN("DEPENDENT "), system_charset_info))
141  return true;
142  }
143  else if (!column_buffer.is_cacheable)
144  {
145  if (buff.append(STRING_WITH_LEN("UNCACHEABLE "), system_charset_info))
146  return true;
147  }
148  const char *type=
149  SELECT_LEX::get_type_str(column_buffer.col_select_type.get());
150  if (buff.append(type))
151  return true;
152  Item_string *item= new Item_string(buff.dup(current_thd->mem_root),
153  buff.length(), system_charset_info);
154  return item == NULL || items->push_back(item);
155 }
156 
157 
159 {
160  List<Item> items;
161  if (push(&items, column_buffer.col_id, nil) ||
162  push_select_type(&items) ||
163  push(&items, column_buffer.col_table_name, nil) ||
164  (current_thd->lex->describe & DESCRIBE_PARTITIONS &&
165  push(&items, column_buffer.col_partitions, nil)) ||
166  push(&items, column_buffer.col_join_type, nil) ||
167  push(&items, column_buffer.col_possible_keys, nil) ||
168  push(&items, column_buffer.col_key, nil) ||
169  push(&items, column_buffer.col_key_len, nil) ||
170  push(&items, column_buffer.col_ref, nil) ||
171  push(&items, column_buffer.col_rows, nil) ||
172  (current_thd->lex->describe & DESCRIBE_EXTENDED &&
173  push(&items, column_buffer.col_filtered, nil)))
174  return true;
175 
176  if (column_buffer.col_message.is_empty() &&
177  column_buffer.col_extra.is_empty())
178  {
179  if (items.push_back(nil))
180  return true;
181  }
182  else if (!column_buffer.col_extra.is_empty())
183  {
184  StringBuffer<64> buff(system_charset_info);
185  List_iterator<qep_row::extra> it(column_buffer.col_extra);
186  qep_row::extra *e;
187  while ((e= it++))
188  {
189  DBUG_ASSERT(traditional_extra_tags[e->tag] != NULL);
190  if (buff.append(traditional_extra_tags[e->tag]))
191  return true;
192  if (e->data)
193  {
194  bool brackets= false;
195  switch (e->tag) {
196  case ET_RANGE_CHECKED_FOR_EACH_RECORD:
197  case ET_USING_INDEX_FOR_GROUP_BY:
198  case ET_USING_JOIN_BUFFER:
199  case ET_FIRST_MATCH:
200  brackets= true; // for backward compatibility
201  break;
202  default:
203  break;
204  }
205  if (e->tag != ET_FIRST_MATCH && // for backward compatibility
206  e->tag != ET_PUSHED_JOIN &&
207  buff.append(" "))
208  return true;
209  if (brackets && buff.append("("))
210  return true;
211  if (buff.append(e->data))
212  return true;
213  if (e->tag == ET_SCANNED_DATABASES &&
214  buff.append(e->data[0] == '1' ? " database" : " databases"))
215  return true;
216  if (brackets && buff.append(")"))
217  return true;
218  }
219  if (buff.append("; "))
220  return true;
221  }
222  if (!buff.is_empty())
223  buff.length(buff.length() - 2); // remove last "; "
224  if (push(&items, buff.dup(current_thd->mem_root), buff.length()))
225  return true;
226  }
227  else
228  {
229  if (push(&items, column_buffer.col_message, nil))
230  return true;
231  }
232 
233  if (output->send_data(items))
234  return true;
235 
236  column_buffer.cleanup();
237  return false;
238 }