1 /* Copyright (c) 2011, 2021, Oracle and/or its affiliates.
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 #include "opt_trace.h"
24 #include "opt_explain_json.h"
25
26 /**
27 Property names, former parts of traditional "extra" column
28
29 This array must be in sync with Extra_tag enum.
30 */
31 static const char *json_extra_tags[ET_total]=
32 {
33 NULL, // ET_none
34 "using_temporary_table", // ET_USING_TEMPORARY
35 "using_filesort", // ET_USING_FILESORT
36 "index_condition", // ET_USING_INDEX_CONDITION
37 NULL, // ET_USING
38 "range_checked_for_each_record", // ET_RANGE_CHECKED_FOR_EACH_RECORD
39 "pushed_condition", // ET_USING_WHERE_WITH_PUSHED_CONDITION
40 "using_where", // ET_USING_WHERE
41 "not_exists", // ET_NOT_EXISTS
42 "using_MRR", // ET_USING_MRR
43 "using_index", // ET_USING_INDEX
44 "full_scan_on_NULL_key", // ET_FULL_SCAN_ON_NULL_KEY
45 "skip_open_table", // ET_SKIP_OPEN_TABLE
46 "open_frm_only", // ET_OPEN_FRM_ONLY
47 "open_full_table", // ET_OPEN_FULL_TABLE
48 "scanned_databases", // ET_SCANNED_DATABASES
49 "using_index_for_group_by", // ET_USING_INDEX_FOR_GROUP_BY
50 "distinct", // ET_DISTINCT
51 "loosescan", // ET_LOOSESCAN
52 NULL, // ET_START_TEMPORARY
53 NULL, // ET_END_TEMPORARY
54 "first_match", // ET_FIRST_MATCH
55 NULL, // ET_MATERIALIZE
56 NULL, // ET_START_MATERIALIZE
57 NULL, // ET_END_MATERIALIZE
58 NULL, // ET_SCAN
59 "using_join_buffer", // ET_USING_JOIN_BUFFER
60 "const_row_not_found", // ET_CONST_ROW_NOT_FOUND
61 "unique_row_not_found", // ET_UNIQUE_ROW_NOT_FOUND
62 "impossible_on_condition", // ET_IMPOSSIBLE_ON_CONDITION
63 "pushed_join", // ET_PUSHED_JOIN
64 "ft_hints" // ET_FT_HINTS
65 };
66
67
68 // JSON key names
69 static const char K_ACCESS_TYPE[]= "access_type";
70 static const char K_ATTACHED_CONDITION[]= "attached_condition";
71 static const char K_ATTACHED_SUBQUERIES[]= "attached_subqueries";
72 static const char K_BUFFER_RESULT[]= "buffer_result";
73 static const char K_CACHEABLE[]= "cacheable";
74 static const char K_DEPENDENT[]= "dependent";
75 static const char K_DUPLICATES_REMOVAL[]= "duplicates_removal";
76 static const char K_FILTERED[]= "filtered";
77 static const char K_GROUPING_OPERATION[]= "grouping_operation";
78 static const char K_GROUP_BY_SUBQUERIES[]= "group_by_subqueries";
79 static const char K_HAVING_SUBQUERIES[]= "having_subqueries";
80 static const char K_KEY[]= "key";
81 static const char K_KEY_LENGTH[]= "key_length";
82 static const char K_MATERIALIZED_FROM_SUBQUERY[]= "materialized_from_subquery";
83 static const char K_MESSAGE[]= "message";
84 static const char K_NESTED_LOOP[]= "nested_loop";
85 static const char K_OPTIMIZED_AWAY_SUBQUERIES[]= "optimized_away_subqueries";
86 static const char K_ORDERING_OPERATION[]= "ordering_operation";
87 static const char K_ORDER_BY_SUBQUERIES[]= "order_by_subqueries";
88 static const char K_PARTITIONS[]= "partitions";
89 static const char K_POSSIBLE_KEYS[]= "possible_keys";
90 static const char K_QUERY_BLOCK[]= "query_block";
91 static const char K_QUERY_SPECIFICATIONS[]= "query_specifications";
92 static const char K_REF[]= "ref";
93 static const char K_SELECT_ID[]= "select_id";
94 static const char K_SELECT_LIST_SUBQUERIES[]= "select_list_subqueries";
95 static const char K_TABLE[]= "table";
96 static const char K_TABLE_NAME[]= "table_name";
97 static const char K_UNION_RESULT[]= "union_result";
98 static const char K_UPDATE_VALUE_SUBQUERIES[]= "update_value_subqueries";
99 static const char K_USED_KEY_PARTS[]= "used_key_parts";
100 static const char K_USING_FILESORT[]= "using_filesort";
101 static const char K_USING_TMP_TABLE[]= "using_temporary_table";
102
103 static const char K_ROWS[]= "rows_examined_per_scan";
104 static const char K_PREFIX_ROWS[]= "rows_produced_per_join";
105
106 static const char K_COST_INFO[]= "cost_info";
107 static const char K_READ_TIME[]= "read_cost";
108 static const char K_PREFIX_COST[]= "prefix_cost";
109 static const char K_COND_COST[]= "eval_cost";
110 static const char K_SORT_COST[]= "sort_cost";
111 static const char K_QUERY_COST[]= "query_cost";
112 static const char K_DATA_SIZE_QUERY[]= "data_read_per_join";
113 static const char K_USED_COLUMNS[]= "used_columns";
114
115 static const char *mod_type_name[]=
116 {
117 "", "insert", "update", "delete", "replace"
118 };
119
120 /*
121 see commentary at the beginning of opt_trace.cc
122 */
123 namespace opt_explain_json_namespace
124 {
125
126 class joinable_ctx;
127 class sort_ctx;
128 class subquery_ctx;
129 class union_result_ctx;
130
131 /**
132 @note Keep in sync with the @c list_names array.
133 */
134 enum subquery_list_enum
135 {
136 SQ_SELECT_LIST, ///< SELECT list subqueries
137 SQ_UPDATE_VALUE, ///< UPDATE ... SET field=(subquery)
138 SQ_HAVING, ///< HAVING clause subqueries
139 SQ_OPTIMIZED_AWAY,///< "optimized_away_subqueries"
140 //--------------
141 SQ_toplevel, ///< SQ array size for unit_ctx
142 //--------------
143 SQ_ORDER_BY, ///< ORDER BY clause subqueries
144 SQ_GROUP_BY, ///< GROUP BY clause subqueries
145 //--------------
146 SQ_total
147 };
148
149 /**
150 @note Keep in sync with @c subquery_list_enum.
151 */
152 static const char *list_names[SQ_total]=
153 {
154 K_SELECT_LIST_SUBQUERIES,
155 K_UPDATE_VALUE_SUBQUERIES,
156 K_HAVING_SUBQUERIES,
157 K_OPTIMIZED_AWAY_SUBQUERIES,
158 "",
159 K_ORDER_BY_SUBQUERIES,
160 K_GROUP_BY_SUBQUERIES,
161 };
162
163
164 /**
165 Base class for all intermediate tree nodes
166 */
167
168 class context : public Explain_context
169 {
170 protected:
171 const char *name;
172
173 public:
174 context *parent; ///< link to parent node or NULL
175
context(enum_parsing_context type_arg,const char * name_arg,context * parent_arg)176 context(enum_parsing_context type_arg, const char *name_arg,
177 context *parent_arg)
178 : Explain_context(type_arg),
179 name(name_arg),
180 parent(parent_arg)
181 {}
182
~context()183 virtual ~context() {}
184
185 /**
186 Pass the node with its child nodes to a JSON formatter
187
188 @param json Formatter
189
190 @retval false Ok
191 @retval true Error
192
193 @note The @c join_ctx class overloads this function.
194 */
format(Opt_trace_context * json)195 virtual bool format(Opt_trace_context *json)
196 {
197 Opt_trace_object obj(json, name);
198 return format_body(json, &obj);
199 }
200
is_query_block() const201 bool is_query_block() const { return name == K_QUERY_BLOCK; }
202
203 private:
204 /**
205 Format JSON object body
206
207 @param json Formatter
208 @param obj Object of this body
209
210 @retval false Ok
211 @retval true Error
212 */
213 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)= 0;
214
215 public:
216 /**
217 Analogue of the "id" column in the traditional EXPLAIN output
218
219 @param hide if true, ban the output of K_SELECT_ID JSON property
220 in the underlying table_with_where_and_derived_ctx
221 objects
222
223 @returns "Select number" that is associated with this node
224 */
225 virtual size_t id(bool hide= false)= 0;
226
cacheable()227 virtual bool cacheable() { assert(0); return true; }
dependent()228 virtual bool dependent() { assert(0); return false; }
229
entry()230 virtual class qep_row *entry() { assert(0); return NULL; }
get_mod_type()231 virtual enum_mod_type get_mod_type() { return MT_NONE; }
232
233 /**
234 Associate a child node with this node
235
236 This function is to be overloaded by subquery_ctx.
237 */
set_child(context * child)238 virtual void set_child(context *child) {}
239
240 /// associate CTX_UNION_RESULT node with CTX_UNION node
set_union_result(union_result_ctx * ctx)241 virtual void set_union_result(union_result_ctx *ctx) { assert(0); }
242
243 /**
244 Append a subquery node to the specified list of the unit node
245
246 @param subquery_type Describes the Item tree where the subquery exists
247 @param ctx Subquery node
248
249 @retval false Ok
250 @retval true Error
251 */
add_subquery(subquery_list_enum subquery_type,subquery_ctx * ctx)252 virtual bool add_subquery(subquery_list_enum subquery_type,
253 subquery_ctx *ctx) { assert(0);return true; }
254 /**
255 Format nested loop join subtree (if any) to JSON formatter
256
257 @param json Formatter
258
259 @retval false Ok
260 @retval true Error
261 */
format_nested_loop(Opt_trace_context * json)262 virtual bool format_nested_loop(Opt_trace_context *json)
263 { assert(0); return true; }
264
265 /**
266 Add a CTX_QEP_TAB node to a CTX_JOIN node
267
268 @param ctx CTX_QEP_TAB node
269
270 @retval false Ok
271 @retval true Error
272 */
add_join_tab(joinable_ctx * ctx)273 virtual bool add_join_tab(joinable_ctx *ctx) { assert(0);return true; }
274
275 /**
276 Set nested ORDER BY/GROUP BY/DISTINCT node to @c ctx
277
278 @param json Formatter
279
280 @retval false Ok
281 @retval true Error
282 */
set_sort(sort_ctx * ctx)283 virtual void set_sort(sort_ctx *ctx) { assert(0); }
284
285 /**
286 Add a query specification node to the CTX_UNION node
287
288 @param ctx query specification node
289
290 @retval false Ok
291 @retval true Error
292 */
add_query_spec(context * ctx)293 virtual bool add_query_spec(context *ctx) { assert(0); return true; }
294
295 /**
296 Try to associate a derived subquery node with this or underlying node
297
298 @param subquery Derived subquery node
299
300 @retval true Success
301 @retval false Can't associate: this node or its child nodes are not
302 derived from the subquery
303 */
find_and_set_derived(context * subquery)304 virtual bool find_and_set_derived(context *subquery)
305 {
306 assert(0);
307 return false;
308 }
309
310 /**
311 Associate WHERE subqueries of given context and unit with this object
312
313 @param ctx Context of WHERE subquery
314 @param subquery For CTX_QEP_TAB: match given unit with a previously
315 collected by the register_where_subquery function.
316 @returns
317 -1 subquery wasn't found
318 0 subqusery were added
319 1 error occured
320 */
add_where_subquery(subquery_ctx * ctx,SELECT_LEX_UNIT * subquery)321 virtual int add_where_subquery(subquery_ctx *ctx,
322 SELECT_LEX_UNIT *subquery)
323 {
324 assert(0);
325 return false;
326 }
327
328 /// Helper function to format output for derived subquery if any
format_derived(Opt_trace_context * json)329 virtual bool format_derived(Opt_trace_context *json) { return false; }
330
331 /// Helper function to format output for associated WHERE subqueries if any
format_where(Opt_trace_context * json)332 virtual bool format_where(Opt_trace_context *json) { return false; }
333
334 /// Helper function to format output for HAVING, ORDER/GROUP BY subqueries
format_unit(Opt_trace_context * json)335 virtual bool format_unit(Opt_trace_context *json) { return false; }
336 };
337
338
339 /**
340 Node class to wrap a subquery node tree
341
342 Implements CTX_WHERE, CTX_HAVING, CTX_ORDER_BY_SQ, CTX_GROUP_BY_SQ and
343 CTX_OPTIMIZED_AWAY_SUBQUERY context nodes.
344 This class hosts underlying join_ctx or uion_ctx.
345 */
346
347 class subquery_ctx : virtual public context, public qep_row
348 {
349 /*
350 TODO: After the conversion from multiple inheritace to templates
351 convert "context" to "unit_ctx" (common base of uion_ctx & join_ctx).
352 */
353 context *subquery; ///< hosted subquery tree: CTX_JOIN or CTX_UNION
354
355 public:
subquery_ctx(enum_parsing_context type_arg,const char * name_arg,context * parent_arg)356 subquery_ctx(enum_parsing_context type_arg,
357 const char *name_arg, context *parent_arg)
358 : context(type_arg, name_arg, parent_arg),
359 subquery(NULL)
360 {}
361
entry()362 virtual qep_row *entry() { return this; }
363
364 /*
365 Materialized subquery statuses of dependency on the outer query and
366 cacheability may differ from the source subquery, for example, if
367 we "push down" the outer look up value for SJ.
368 Thus, for materialized subqueries return direct is_cacheable and
369 is_dependent values instead of source subquery statuses:
370 */
cacheable()371 virtual bool cacheable()
372 {
373 return is_materialized_from_subquery ? is_cacheable : subquery->cacheable();
374 }
dependent()375 virtual bool dependent()
376 {
377 return is_materialized_from_subquery ? is_dependent : subquery->dependent();
378 }
379
format(Opt_trace_context * json)380 virtual bool format(Opt_trace_context *json)
381 {
382 if (name)
383 return context::format(json);
384 else
385 {
386 /*
387 Subquery is always a homogeneous array element,
388 create anonymous wrapper object:
389 */
390 Opt_trace_object anonymous_wrapper(json);
391 return format_body(json, &anonymous_wrapper);
392 }
393 }
394
395 private:
format_body(Opt_trace_context * json,Opt_trace_object * obj)396 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
397 {
398 if (type == CTX_DERIVED)
399 {
400 obj->add(K_USING_TMP_TABLE, true);
401 obj->add(K_DEPENDENT, dependent());
402 obj->add(K_CACHEABLE, cacheable());
403 return subquery->format(json);
404 }
405 else if (using_temporary)
406 {
407 if (!is_materialized_from_subquery)
408 {
409 obj->add(K_USING_TMP_TABLE, true);
410 obj->add(K_DEPENDENT, dependent());
411 obj->add(K_CACHEABLE, cacheable());
412 }
413
414 {
415 Opt_trace_object tmp_table(json, K_TABLE);
416
417 if (!col_table_name.is_empty())
418 obj->add_utf8(K_TABLE_NAME, col_table_name.str);
419 if (!col_join_type.is_empty())
420 tmp_table.add_alnum(K_ACCESS_TYPE, col_join_type.str);
421 if (!col_key.is_empty())
422 tmp_table.add_utf8(K_KEY, col_key.str);
423 if (!col_key_len.is_empty())
424 obj->add_alnum(K_KEY_LENGTH, col_key_len.str);
425 if (!col_rows.is_empty())
426 tmp_table.add(K_ROWS, col_rows.value);
427
428 if (is_materialized_from_subquery)
429 {
430 Opt_trace_object materialized(json, K_MATERIALIZED_FROM_SUBQUERY);
431 obj->add(K_USING_TMP_TABLE, true);
432 obj->add(K_DEPENDENT, dependent());
433 obj->add(K_CACHEABLE, cacheable());
434 return format_query_block(json);
435 }
436 }
437 return format_query_block(json);
438 }
439 else
440 {
441 obj->add(K_DEPENDENT, dependent());
442 obj->add(K_CACHEABLE, cacheable());
443 return subquery->format(json);
444 }
445 }
446
format_query_block(Opt_trace_context * json)447 bool format_query_block(Opt_trace_context *json)
448 {
449 if (subquery->is_query_block())
450 return subquery->format(json);
451
452 Opt_trace_object query_block(json, K_QUERY_BLOCK);
453 return subquery->format(json);
454 }
455
456
457 public:
set_child(context * child)458 virtual void set_child(context *child)
459 {
460 assert(subquery == NULL);
461 assert(child->type == CTX_JOIN || child->type == CTX_UNION);
462 subquery= child;
463 }
464
id(bool hide)465 virtual size_t id(bool hide) { return subquery->id(hide); }
466 };
467
468
469 /**
470 Helper function to pass a subquery list to a JSON formatter
471
472 @param json output formatter
473 @param subqueries subquery list to output
474 @param name name for the output section
475
476 @retval false Ok
477 @retval true Error
478 */
format_list(Opt_trace_context * json,List<subquery_ctx> & subqueries,const char * name)479 static bool format_list(Opt_trace_context *json,
480 List<subquery_ctx> &subqueries,
481 const char *name)
482 {
483 if (!subqueries.is_empty())
484 {
485 Opt_trace_array subs(json, name);
486
487 List_iterator<subquery_ctx> it(subqueries);
488 subquery_ctx *t;
489 while ((t= it++))
490 {
491 // Homogeneous array: additional anonymous wrapper object is not needed
492 if (t->format(json))
493 return true;
494 }
495 }
496 return false;
497 }
498
499
500 /**
501 Helper base class to host HAVING, ORDER BY and GROUP BY subquery nodes
502 */
503 class unit_ctx : virtual public context
504 {
505 List<subquery_ctx> subquery_lists[SQ_total];
506
507 public:
unit_ctx(enum_parsing_context type_arg,const char * name_arg,context * parent_arg)508 unit_ctx(enum_parsing_context type_arg, const char *name_arg,
509 context *parent_arg)
510 : context(type_arg, name_arg, parent_arg)
511 {}
512
513 /**
514 Helper function to distinguish subquery-less nodes
515
516 @retval true Node hosts no subqueries
517 @retval false Node hosts some subqueries
518 */
has_no_subqueries() const519 bool has_no_subqueries() const
520 {
521 for (size_t i= 0; i < SQ_total; i++)
522 {
523 if (!subquery_lists[i].is_empty())
524 return false;
525 }
526 return true;
527 }
528
format_unit(Opt_trace_context * json)529 virtual bool format_unit(Opt_trace_context *json)
530 {
531 for (size_t i= 0; i < SQ_total; i++)
532 {
533 if (format_list(json, subquery_lists[i], list_names[i]))
534 return true;
535 }
536 return false;
537 }
538
add_subquery(subquery_list_enum subquery_type,subquery_ctx * ctx)539 virtual bool add_subquery(subquery_list_enum subquery_type,
540 subquery_ctx *ctx)
541 {
542 return subquery_lists[subquery_type].push_back(ctx);
543 }
544 };
545
546
547 class table_base_ctx : virtual public context, virtual public qep_row
548 {
549 protected:
550 bool is_hidden_id; //< if true, don't output K_SELECT_ID property
551
552 public:
table_base_ctx(enum_parsing_context type_arg,const char * name_arg,context * parent_arg)553 table_base_ctx(enum_parsing_context type_arg,
554 const char *name_arg, context *parent_arg)
555 : context(type_arg, name_arg, parent_arg), is_hidden_id(false)
556 {}
557
entry()558 virtual qep_row *entry() { return this; }
559
560 protected:
561 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj);
562
563 public:
id(bool hide)564 virtual size_t id(bool hide)
565 {
566 return col_id.is_empty() ? 0 : col_id.value;
567 }
568
cacheable()569 virtual bool cacheable() { return is_cacheable; }
dependent()570 virtual bool dependent() { return is_dependent; }
571 };
572
573
add_string_array(Opt_trace_context * json,const char * list_name,List<const char> & strings)574 static void add_string_array(Opt_trace_context *json, const char *list_name,
575 List<const char> &strings)
576 {
577 if (!strings.is_empty())
578 {
579 Opt_trace_array extra(json, list_name);
580
581 List_iterator<const char> it(strings);
582 const char *s;
583 while ((s= it++))
584 extra.add_utf8(s);
585 }
586 }
587
print_cost(char * buf,uint buf_len,double cost)588 static void print_cost(char *buf, uint buf_len, double cost)
589 {
590 if (cost < 100000000000000.0)
591 my_snprintf(buf, buf_len, "%.2f", cost);
592 else
593 my_snprintf(buf, buf_len, "%.14g", cost);
594 }
595
print_filtered(char * buf,uint buf_len,double filtered)596 static void print_filtered(char *buf, uint buf_len, double filtered)
597 {
598 my_snprintf(buf, buf_len, "%.2f", filtered);
599 }
600
601
format_body(Opt_trace_context * json,Opt_trace_object * obj)602 bool table_base_ctx::format_body(Opt_trace_context *json, Opt_trace_object *obj)
603 {
604 StringBuffer<64> buff;
605
606 if (mod_type != MT_NONE)
607 obj->add(mod_type_name[mod_type], true);
608
609 if (!col_id.is_empty() && !is_hidden_id)
610 obj->add(K_SELECT_ID, col_id.value);
611
612 if (!col_table_name.is_empty())
613 obj->add_utf8(K_TABLE_NAME, col_table_name.str);
614
615 add_string_array(json, K_PARTITIONS, col_partitions);
616
617 if (!col_join_type.is_empty())
618 obj->add_alnum(K_ACCESS_TYPE, col_join_type.str);
619
620 add_string_array(json, K_POSSIBLE_KEYS, col_possible_keys);
621
622 if (!col_key.is_empty())
623 obj->add_utf8(K_KEY, col_key.str);
624
625 if (!col_key_parts.is_empty())
626 add_string_array(json, K_USED_KEY_PARTS, col_key_parts);
627
628 if (!col_key_len.is_empty())
629 obj->add_alnum(K_KEY_LENGTH, col_key_len.str);
630
631 add_string_array(json, K_REF, col_ref);
632
633 if (!col_rows.is_empty())
634 obj->add(K_ROWS, col_rows.value);
635 if (!col_prefix_rows.is_empty())
636 obj->add(K_PREFIX_ROWS, col_prefix_rows.value);
637
638 if (!col_filtered.is_empty())
639 {
640 char buf[32]; // 32 is enough for digits of a double
641 print_filtered(buf, sizeof(buf), col_filtered.value);
642 obj->add_utf8(K_FILTERED, buf);
643 }
644
645 if (!col_extra.is_empty())
646 {
647 List_iterator<qep_row::extra> it(col_extra);
648 qep_row::extra *e;
649 while ((e= it++))
650 {
651 assert(json_extra_tags[e->tag] != NULL);
652 if (e->data)
653 obj->add_utf8(json_extra_tags[e->tag], e->data);
654 else
655 obj->add(json_extra_tags[e->tag], true);
656 }
657 }
658
659 if (!col_read_cost.is_empty())
660 {
661 Opt_trace_object cost_info(json, K_COST_INFO);
662 char buf[32]; // 32 is enough for digits of a double
663
664 print_cost(buf, sizeof(buf), col_read_cost.value);
665 cost_info.add_utf8(K_READ_TIME, buf);
666
667 if (!col_cond_cost.is_empty())
668 {
669 print_cost(buf, sizeof(buf), col_cond_cost.value);
670 cost_info.add_utf8(K_COND_COST, buf);
671 }
672 if (!col_prefix_cost.is_empty())
673 {
674 print_cost(buf, sizeof(buf), col_prefix_cost.value);
675 cost_info.add_utf8(K_PREFIX_COST, buf);
676 }
677 if (!col_data_size_query.is_empty())
678 cost_info.add_utf8(K_DATA_SIZE_QUERY, col_data_size_query.str);
679 }
680
681 if (!col_used_columns.is_empty())
682 add_string_array(json, K_USED_COLUMNS, col_used_columns);
683
684 if (!col_message.is_empty() && type != CTX_MESSAGE)
685 {
686 assert(col_extra.is_empty());
687 obj->add_alnum(K_MESSAGE, col_message.str);
688 }
689
690 { // Keep together for better output readability
691 if (!col_attached_condition.is_empty())
692 obj->add_utf8(K_ATTACHED_CONDITION, col_attached_condition.str);
693 if (format_where(json))
694 return true;
695 }
696
697 return format_derived(json) || format_unit(json);
698 }
699
700
701 /**
702 Node class for the CTX_UNION_RESULT
703 */
704 class union_result_ctx : public table_base_ctx, public unit_ctx
705 {
706 List<context> *query_specs; ///< query specification nodes (inner selects)
707 List<subquery_ctx> order_by_subqueries;
708 List<subquery_ctx> optimized_away_subqueries;
709 joinable_ctx *message;
710
711 public:
union_result_ctx(context * parent_arg)712 explicit union_result_ctx(context *parent_arg)
713 : context(CTX_UNION_RESULT, K_UNION_RESULT, parent_arg),
714 table_base_ctx(CTX_UNION_RESULT, K_UNION_RESULT, parent_arg),
715 unit_ctx(CTX_UNION_RESULT, K_UNION_RESULT, parent_arg),
716 message(NULL)
717 {}
718
719 // Remove warnings: 'inherits ... from ... via dominance'
id(bool hide)720 virtual size_t id(bool hide) { return table_base_ctx::id(hide); }
cacheable()721 virtual bool cacheable() { return table_base_ctx::cacheable(); }
dependent()722 virtual bool dependent() { return table_base_ctx::dependent(); }
entry()723 virtual qep_row *entry() { return table_base_ctx::entry(); }
format_unit(Opt_trace_context * json)724 virtual bool format_unit(Opt_trace_context *json)
725 { return table_base_ctx::format_unit(json); }
726
push_down_query_specs(List<context> * specs)727 void push_down_query_specs(List<context> *specs) { query_specs= specs; }
728
add_subquery(subquery_list_enum subquery_type,subquery_ctx * ctx)729 virtual bool add_subquery(subquery_list_enum subquery_type,
730 subquery_ctx *ctx)
731 {
732 switch (subquery_type) {
733 case SQ_ORDER_BY:
734 return order_by_subqueries.push_back(ctx);
735 case SQ_OPTIMIZED_AWAY:
736 return optimized_away_subqueries.push_back(ctx);
737 default:
738 assert(!"Unknown query type!");
739 return false; // ignore in production
740 }
741 }
742
add_join_tab(joinable_ctx * ctx)743 virtual bool add_join_tab(joinable_ctx *ctx)
744 {
745 assert(!message);
746 message= ctx;
747 return false;
748 }
749
750 virtual bool format(Opt_trace_context *json);
751
752 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj);
753 };
754
755
756 /**
757 Common part of CTX_QEP_TAB and CTX_MESSAGE nodes
758
759 This class implements functionality for WHERE and derived subqueries that
760 are associated with the table node.
761 */
762 class table_with_where_and_derived : public table_base_ctx
763 {
764 public:
765 List<subquery_ctx> where_subqueries; ///< associated WHERE clause subqueries
766
table_with_where_and_derived(enum_parsing_context type_arg,const char * name_arg,context * parent_arg)767 table_with_where_and_derived(enum_parsing_context type_arg,
768 const char *name_arg, context *parent_arg)
769 : context(type_arg, name_arg, parent_arg),
770 table_base_ctx(type_arg, name_arg, parent_arg)
771 {}
772
id(bool hide)773 virtual size_t id(bool hide)
774 {
775 if (hide)
776 is_hidden_id= true;
777 return table_base_ctx::id(hide);
778 }
779
format_where(Opt_trace_context * json)780 virtual bool format_where(Opt_trace_context *json)
781 {
782 return format_list(json, where_subqueries, K_ATTACHED_SUBQUERIES);
783 }
784
format_derived(Opt_trace_context * json)785 virtual bool format_derived(Opt_trace_context *json)
786 {
787 if (derived_from.elements == 0)
788 return false;
789 else if (derived_from.elements == 1)
790 return derived_from.head()->format(json);
791 else
792 {
793 Opt_trace_array loops(json, K_NESTED_LOOP);
794
795 List_iterator<context> it(derived_from);
796 context *c;
797 while((c= it++))
798 {
799 Opt_trace_object anonymous_wrapper(json);
800 if (c->format(json))
801 return true;
802 }
803 }
804 return false;
805 }
806 };
807
808
809 /**
810 Base for CTX_QEP_TAB, CTX_DUPLICATES_WEEDOUT and CTX_MATERIALIZATION nodes
811
812 This class implements a base to explain individual JOIN_TABs as well
813 as JOIN_TAB groups like in semi-join materialization.
814 */
815 class joinable_ctx : virtual public context
816 {
817 public:
joinable_ctx(enum_parsing_context type_arg,const char * name_arg,context * parent_arg)818 joinable_ctx(enum_parsing_context type_arg, const char *name_arg,
819 context *parent_arg)
820 : context(type_arg, name_arg, parent_arg)
821 {}
822 };
823
824
825 /**
826 Node class for CTX_MESSAGE
827
828 This class is designed to represent fake tables with some messages in the
829 "extra" column ("Impossible where" etc).
830 We do EXPLAIN of these fake tables to replace explanation of:
831 1) usual actual JOIN_TABs of the whole JOIN or
832 2) a modifying TABLE of single-table UPDATE/DELETE/etc.
833 So, message_ctx always represent a single half-empty fake table in a
834 "query_block" node with optional subqueries.
835 */
836 class message_ctx : public joinable_ctx,
837 public table_with_where_and_derived
838 {
839 public:
message_ctx(context * parent_arg)840 explicit message_ctx(context *parent_arg)
841 : context(CTX_MESSAGE, K_TABLE, parent_arg),
842 joinable_ctx(CTX_MESSAGE, K_TABLE, parent_arg),
843 table_with_where_and_derived(CTX_MESSAGE, K_TABLE, parent_arg)
844 {}
845
846 // Remove warnings: 'inherits ... from ... via dominance'
format_body(Opt_trace_context * json,Opt_trace_object * obj)847 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
848 { return table_base_ctx::format_body(json, obj); }
id(bool hide)849 virtual size_t id(bool hide)
850 { return table_with_where_and_derived::id(hide); }
cacheable()851 virtual bool cacheable() { return table_base_ctx::cacheable(); }
dependent()852 virtual bool dependent() { return table_base_ctx::dependent(); }
entry()853 virtual qep_row *entry() { return table_base_ctx::entry(); }
format_derived(Opt_trace_context * json)854 virtual bool format_derived(Opt_trace_context *json)
855 { return table_with_where_and_derived::format_derived(json); }
format_where(Opt_trace_context * json)856 virtual bool format_where(Opt_trace_context *json)
857 { return table_with_where_and_derived::format_where(json); }
858
find_and_set_derived(context * subquery)859 virtual bool find_and_set_derived(context *subquery)
860 {
861 /*
862 message_ctx is designed to represent a single fake JOIN_TAB in the JOIN,
863 so if the JOIN have a derived table, then this message_ctx represent this
864 derived table.
865 Unconditionally add subquery:
866 */
867 derived_from.push_back(subquery);
868 return true;
869 }
870
add_where_subquery(subquery_ctx * ctx,SELECT_LEX_UNIT * subquery)871 virtual int add_where_subquery(subquery_ctx *ctx,
872 SELECT_LEX_UNIT *subquery)
873 {
874 return where_subqueries.push_back(ctx);
875 }
876 };
877
878
879 /**
880 Node class for the CTX_QEP_TAB context
881 */
882 class join_tab_ctx : public joinable_ctx,
883 public table_with_where_and_derived
884 {
885 /**
886 Subquery units that are associated with this JOIN_TAB's condition
887
888 This list is used to match with the @c subquery parameter of
889 the @c add_where_subquery function.
890 */
891 List<SELECT_LEX_UNIT> where_subquery_units;
892
893 public:
join_tab_ctx(enum_parsing_context type_arg,context * parent_arg)894 join_tab_ctx(enum_parsing_context type_arg, context *parent_arg)
895 : context(type_arg, K_TABLE, parent_arg),
896 joinable_ctx(type_arg, K_TABLE, parent_arg),
897 table_with_where_and_derived(type_arg, K_TABLE, parent_arg)
898 {}
899
900 // Remove warnings: 'inherits ... from ... via dominance'
format_body(Opt_trace_context * json,Opt_trace_object * obj)901 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
902 { return table_base_ctx::format_body(json, obj); }
id(bool hide)903 virtual size_t id(bool hide)
904 { return table_with_where_and_derived::id(hide); }
cacheable()905 virtual bool cacheable() { return table_base_ctx::cacheable(); }
dependent()906 virtual bool dependent() { return table_base_ctx::dependent(); }
entry()907 virtual qep_row *entry() { return table_base_ctx::entry(); }
format_derived(Opt_trace_context * json)908 virtual bool format_derived(Opt_trace_context *json)
909 { return table_with_where_and_derived::format_derived(json); }
format_where(Opt_trace_context * json)910 virtual bool format_where(Opt_trace_context *json)
911 { return table_with_where_and_derived::format_where(json); }
912
register_where_subquery(SELECT_LEX_UNIT * subquery)913 virtual void register_where_subquery(SELECT_LEX_UNIT *subquery)
914 {
915 List_iterator<SELECT_LEX_UNIT> it(where_subquery_units);
916 SELECT_LEX_UNIT *u;
917 while ((u= it++))
918 {
919 /*
920 The server may transform (x = (SELECT FROM DUAL)) to
921 (x <=> (SELECT FROM DUAL) AND x = (SELECT FROM DUAL)),
922 so ignore duplicates:
923 */
924 if(u == subquery)
925 return;
926 }
927 where_subquery_units.push_back(subquery);
928 }
929
add_where_subquery(subquery_ctx * ctx,SELECT_LEX_UNIT * subquery)930 virtual int add_where_subquery(subquery_ctx *ctx,
931 SELECT_LEX_UNIT *subquery)
932 {
933 List_iterator<SELECT_LEX_UNIT> it(where_subquery_units);
934 SELECT_LEX_UNIT *u;
935 while ((u= it++))
936 {
937 if (u == subquery)
938 return where_subqueries.push_back(ctx);
939 }
940 return -1;
941 }
942
find_and_set_derived(context * subquery)943 virtual bool find_and_set_derived(context *subquery)
944 {
945 if (query_block_id == subquery->id())
946 {
947 derived_from.push_back(subquery);
948 return true;
949 }
950 return false;
951 }
get_mod_type()952 virtual enum_mod_type get_mod_type() { return entry()->mod_type; }
953 };
954
955
956 /**
957 Base class for CTX_ORDER_BY, CTX_GROUP_BY and node class for CTX_DISTINCT
958
959 This class represents context for simple ORDER BY/GROUP BY/DISTINCT clauses
960 (the clause is effective for the single JOIN_TAB).
961 */
962
963 class simple_sort_ctx : public joinable_ctx
964 {
965 protected:
966 joinable_ctx *join_tab; //< single JOIN_TAB that we sort
967
968 private:
969 const bool using_tmptable; //< true if the clause creates intermediate table
970 const bool using_filesort; //< true if the clause uses filesort
971
972 public:
simple_sort_ctx(enum_parsing_context type_arg,const char * name_arg,context * parent_arg,const Explain_format_flags * flags,Explain_sort_clause clause)973 simple_sort_ctx(enum_parsing_context type_arg, const char *name_arg,
974 context *parent_arg,
975 const Explain_format_flags *flags,
976 Explain_sort_clause clause)
977 : context(type_arg, name_arg, parent_arg),
978 joinable_ctx(type_arg, name_arg, parent_arg),
979 join_tab(NULL),
980 using_tmptable(flags->get(clause, ESP_USING_TMPTABLE)),
981 using_filesort(flags->get(clause, ESP_USING_FILESORT))
982 {}
983
add_join_tab(joinable_ctx * ctx)984 virtual bool add_join_tab(joinable_ctx *ctx)
985 {
986 join_tab= ctx;
987 return false;
988 }
989
add_where_subquery(subquery_ctx * ctx,SELECT_LEX_UNIT * subquery)990 virtual int add_where_subquery(subquery_ctx *ctx,
991 SELECT_LEX_UNIT *subquery)
992 {
993 return join_tab->add_where_subquery(ctx, subquery);
994 }
995
find_and_set_derived(context * subquery)996 virtual bool find_and_set_derived(context *subquery)
997 {
998 return join_tab->find_and_set_derived(subquery);
999 }
1000
id(bool hide)1001 virtual size_t id(bool hide) { return join_tab->id(hide); }
cacheable()1002 virtual bool cacheable() { return join_tab->cacheable(); }
dependent()1003 virtual bool dependent() { return join_tab->dependent(); }
1004
1005 protected:
format_body(Opt_trace_context * json,Opt_trace_object * obj)1006 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1007 {
1008 if (using_tmptable)
1009 obj->add(K_USING_TMP_TABLE, true);
1010 obj->add(K_USING_FILESORT, using_filesort);
1011 return join_tab->format(json);
1012 }
1013 };
1014
1015
1016 /**
1017 Node class for "simple" CTX_ORDER_BY and CTX_GROUP_BY
1018
1019 This class represents context for simple ORDER BY or GROUP BY clauses
1020 (the clause is effective for the single JOIN_TAB).
1021 */
1022
1023 class simple_sort_with_subqueries_ctx : public simple_sort_ctx
1024 {
1025 const subquery_list_enum subquery_type; //< type of this clause subqueries
1026 List<subquery_ctx> subqueries;
1027
1028 public:
simple_sort_with_subqueries_ctx(enum_parsing_context type_arg,const char * name_arg,context * parent_arg,subquery_list_enum subquery_type_arg,const Explain_format_flags * flags,Explain_sort_clause clause)1029 simple_sort_with_subqueries_ctx(enum_parsing_context type_arg,
1030 const char *name_arg,
1031 context *parent_arg,
1032 subquery_list_enum subquery_type_arg,
1033 const Explain_format_flags *flags,
1034 Explain_sort_clause clause)
1035 : context(type_arg, name_arg, parent_arg),
1036 simple_sort_ctx(type_arg, name_arg, parent_arg, flags, clause),
1037 subquery_type(subquery_type_arg)
1038 {}
1039
add_subquery(subquery_list_enum subquery_type_arg,subquery_ctx * ctx)1040 virtual bool add_subquery(subquery_list_enum subquery_type_arg,
1041 subquery_ctx *ctx)
1042 {
1043 if (subquery_type != subquery_type_arg)
1044 return simple_sort_ctx::add_subquery(subquery_type_arg, ctx);
1045 else
1046 return subqueries.push_back(ctx);
1047 }
1048
1049 private:
format_body(Opt_trace_context * json,Opt_trace_object * obj)1050 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1051 {
1052 return (simple_sort_ctx::format_body(json, obj) ||
1053 (format_list(json, subqueries, list_names[subquery_type])));
1054 }
1055 };
1056
1057
1058 /**
1059 Node class for the CTX_JOIN context
1060 */
1061
1062 class join_ctx : public unit_ctx, virtual public qep_row
1063 {
1064 protected:
1065 List<joinable_ctx> join_tabs; ///< hosted JOIN_TAB nodes
1066 sort_ctx *sort;
1067
1068 public:
join_ctx(enum_parsing_context type_arg,const char * name_arg,context * parent_arg)1069 join_ctx(enum_parsing_context type_arg, const char *name_arg,
1070 context *parent_arg)
1071 : context(type_arg, name_arg, parent_arg),
1072 unit_ctx(type_arg, name_arg, parent_arg),
1073 sort(0)
1074 {}
1075
add_join_tab(joinable_ctx * ctx)1076 virtual bool add_join_tab(joinable_ctx *ctx)
1077 {
1078 return join_tabs.push_back(ctx);
1079 }
1080
set_sort(sort_ctx * ctx)1081 virtual void set_sort(sort_ctx *ctx)
1082 {
1083 assert(!sort);
1084 sort= ctx;
1085 }
entry()1086 virtual qep_row *entry() { return this; }
1087
1088 /**
1089 Associate a CTX_DERIVED node with its CTX_QEP_TAB node
1090
1091 @param subquery derived subquery tree
1092 */
1093 virtual bool find_and_set_derived(context *subquery);
1094
1095 virtual bool add_subquery(subquery_list_enum subquery_type,
1096 subquery_ctx *ctx);
1097 protected:
1098 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj);
1099 bool format_body_inner(Opt_trace_context *json, Opt_trace_object *obj);
get_cost_tag()1100 virtual const char *get_cost_tag() { return K_QUERY_COST; }
1101
1102 public:
1103 virtual bool format_nested_loop(Opt_trace_context *json);
1104 virtual size_t id(bool hide);
1105 virtual bool cacheable();
1106 virtual bool dependent();
1107 virtual int add_where_subquery(subquery_ctx *ctx, SELECT_LEX_UNIT *subquery);
1108 };
1109
1110
1111 /**
1112 Node class for CTX_SIMPLE_ORDER_BY, CTX_SIMPLE_GROUP_BY and CTX_SIMPLE_DISTINCT
1113
1114 CTX_JOIN context (see join_ctx class) may contain nested loop join node *or*
1115 ORDER BY/GROUP BY/DISTINCT node that is represented by this class:
1116
1117 join: { nested_loop: [ ... ] }
1118 or
1119 join: { order_by|group_by|distinct : { ... } }
1120
1121 CTX_ORDER_BY may contain nested loop join tree *or* GROUP BY/DISTINCT node:
1122
1123 order_by: { nested_loop|group_by|distinct: ... }
1124
1125 CTX_DISTINCT context structure:
1126
1127 distinct: { nested_loop|group_by: ... }
1128
1129 CTX_GROUP_BY:
1130
1131 group_by: { nested_loop: [ ... ] }
1132
1133 I.e. the most complex CTX_JOIN may have such a structure of JSON output as:
1134
1135 join: {
1136 order_by: {
1137 distinct: {
1138 group_by: {
1139 nested_loop: [ ... ]
1140 }
1141 }
1142 }
1143 }
1144 TODO
1145 */
1146
1147 class sort_ctx : public join_ctx
1148 {
1149 const bool using_tmptable; //< the clause creates temporary table
1150 const bool using_filesort; //< the clause uses filesort
1151
1152 public:
sort_ctx(enum_parsing_context type_arg,const char * name_arg,context * parent_arg,const Explain_format_flags * flags,Explain_sort_clause clause)1153 sort_ctx(enum_parsing_context type_arg, const char *name_arg,
1154 context *parent_arg,
1155 const Explain_format_flags *flags,
1156 Explain_sort_clause clause)
1157 : context(type_arg, name_arg, parent_arg),
1158 join_ctx(type_arg, name_arg, parent_arg),
1159 using_tmptable(flags->get(clause, ESP_USING_TMPTABLE)),
1160 using_filesort(flags->get(clause, ESP_USING_FILESORT))
1161 {}
1162
1163 protected:
format_body(Opt_trace_context * json,Opt_trace_object * obj)1164 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1165 {
1166 assert(!sort || join_tabs.is_empty());
1167
1168 if (using_tmptable)
1169 obj->add(K_USING_TMP_TABLE, true);
1170 if (type != CTX_BUFFER_RESULT)
1171 obj->add(K_USING_FILESORT, using_filesort);
1172
1173 return join_ctx::format_body(json, obj);
1174 }
get_cost_tag()1175 const char *get_cost_tag() { return K_SORT_COST; }
1176 };
1177
1178
1179 class sort_with_subqueries_ctx : public sort_ctx
1180 {
1181 const subquery_list_enum subquery_type; //< subquery type for this clause
1182 List<subquery_ctx> subqueries;
1183
1184 public:
sort_with_subqueries_ctx(enum_parsing_context type_arg,const char * name_arg,context * parent_arg,subquery_list_enum subquery_type_arg,const Explain_format_flags * flags,Explain_sort_clause clause)1185 sort_with_subqueries_ctx(enum_parsing_context type_arg, const char *name_arg,
1186 context *parent_arg,
1187 subquery_list_enum subquery_type_arg,
1188 const Explain_format_flags *flags,
1189 Explain_sort_clause clause)
1190 : context(type_arg, name_arg, parent_arg),
1191 sort_ctx(type_arg, name_arg, parent_arg, flags, clause),
1192 subquery_type(subquery_type_arg)
1193 {}
1194
add_subquery(subquery_list_enum subquery_type_arg,subquery_ctx * ctx)1195 virtual bool add_subquery(subquery_list_enum subquery_type_arg,
1196 subquery_ctx *ctx)
1197 {
1198 if (subquery_type_arg != subquery_type)
1199 return sort_ctx::add_subquery(subquery_type_arg, ctx);
1200 else
1201 return subqueries.push_back(ctx);
1202 return false;
1203 }
1204
1205 private:
format_body(Opt_trace_context * json,Opt_trace_object * obj)1206 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1207 {
1208 return (sort_ctx::format_body(json, obj) ||
1209 format_list(json, subqueries, list_names[subquery_type]));
1210 }
1211 };
1212
1213
find_and_set_derived(context * subquery)1214 bool join_ctx::find_and_set_derived(context *subquery)
1215 {
1216 assert(subquery->id() != 0);
1217
1218 if (sort)
1219 return sort->find_and_set_derived(subquery);
1220
1221 List_iterator<joinable_ctx> it(join_tabs);
1222 joinable_ctx *t;
1223 while ((t= it++))
1224 {
1225 if (t->find_and_set_derived(subquery))
1226 return true;
1227 }
1228 return false;
1229 }
1230
1231
add_subquery(subquery_list_enum subquery_type,subquery_ctx * ctx)1232 bool join_ctx::add_subquery(subquery_list_enum subquery_type,
1233 subquery_ctx *ctx)
1234 {
1235 if (sort)
1236 return sort->add_subquery(subquery_type, ctx);
1237 if (subquery_type > SQ_toplevel)
1238 {
1239 List_iterator<joinable_ctx> it(join_tabs);
1240 joinable_ctx *j;
1241 while ((j= it++))
1242 {
1243 switch (j->type) {
1244 case CTX_ORDER_BY:
1245 case CTX_DISTINCT:
1246 case CTX_GROUP_BY:
1247 case CTX_SIMPLE_ORDER_BY:
1248 case CTX_SIMPLE_DISTINCT:
1249 case CTX_SIMPLE_GROUP_BY:
1250 return j->add_subquery(subquery_type, ctx);
1251 case CTX_MESSAGE: // The 'no plan' case
1252 assert(subquery_type == SQ_ORDER_BY ||
1253 subquery_type == SQ_GROUP_BY);
1254 return unit_ctx::add_subquery(subquery_type, ctx);
1255 default:
1256 assert(0); /* purecov: inspected */
1257 }
1258 }
1259 }
1260 else
1261 return unit_ctx::add_subquery(subquery_type, ctx);
1262 return true; /* purecov: inspected */
1263 }
1264
1265
format_body(Opt_trace_context * json,Opt_trace_object * obj)1266 bool join_ctx::format_body(Opt_trace_context *json, Opt_trace_object *obj)
1267 {
1268 if (type == CTX_JOIN)
1269 obj->add(K_SELECT_ID, id(true));
1270 if (!col_read_cost.is_empty())
1271 {
1272 char buf[32]; // 32 is enough for digits of a double
1273
1274 Opt_trace_object cost_info(json, K_COST_INFO);
1275 print_cost(buf, sizeof(buf), col_read_cost.value);
1276 cost_info.add_utf8(get_cost_tag(), buf);
1277 }
1278 // Print target table for INSERT/REPLACE SELECT outside of nested loop
1279 if (join_tabs.elements &&
1280 (join_tabs.head()->get_mod_type() == MT_INSERT ||
1281 join_tabs.head()->get_mod_type() == MT_REPLACE))
1282 {
1283 join_tabs.head()->format(json);
1284 if (sort || join_tabs.elements > 1)
1285 {
1286 Opt_trace_object insert_from(json, "insert_from");
1287 if (format_body_inner(json, obj))
1288 return true; /* purecov: inspected */
1289 }
1290 }
1291 else if (format_body_inner(json, obj))
1292 return true; /* purecov: inspected */
1293 return format_unit(json);
1294 }
1295
1296
format_body_inner(Opt_trace_context * json,Opt_trace_object * obj)1297 bool join_ctx::format_body_inner(Opt_trace_context *json, Opt_trace_object *obj)
1298 {
1299 if (sort)
1300 {
1301 if (sort->format(json))
1302 return true; /* purecov: inspected */
1303 }
1304 else if (join_tabs.elements && join_tabs.head()->type == CTX_MESSAGE)
1305 {
1306 // Could be only 1 message per join
1307 assert(join_tabs.elements == 1);
1308 message_ctx *msg= (message_ctx*)join_tabs.head();
1309 obj->add_alnum(K_MESSAGE, msg->entry()->col_message.str);
1310 if (msg->derived_from.elements)
1311 msg->format(json);
1312 else if (msg->where_subqueries.elements)
1313 msg->format_where(json);
1314 }
1315 else if (format_nested_loop(json))
1316 return true;
1317 return false;
1318 }
1319
1320
format_nested_loop(Opt_trace_context * json)1321 bool join_ctx::format_nested_loop(Opt_trace_context *json)
1322 {
1323 List_iterator<joinable_ctx> it(join_tabs);
1324 uint join_tab_num= join_tabs.elements;
1325 assert(join_tabs.elements > 0);
1326
1327 if (join_tabs.head()->get_mod_type() == MT_INSERT ||
1328 join_tabs.head()->get_mod_type() == MT_REPLACE)
1329 {
1330 it++;
1331 join_tab_num--;
1332 }
1333 /*
1334 For single table skip "nested_loop" object creation and
1335 format its contents only (the 1st join_tab).
1336 */
1337 if (join_tab_num == 1)
1338 return (it++)->format(json);
1339
1340 Opt_trace_array loops(json, K_NESTED_LOOP);
1341
1342 joinable_ctx *t;
1343 while ((t= it++))
1344 {
1345 Opt_trace_object anonymous_wrapper(json);
1346 if (t->format(json))
1347 return true;
1348 }
1349 return false;
1350 }
1351
1352
format_body(Opt_trace_context * json,Opt_trace_object * obj)1353 bool union_result_ctx::format_body(Opt_trace_context *json,
1354 Opt_trace_object *obj)
1355 {
1356 obj->add(K_USING_TMP_TABLE, true);
1357
1358 if (table_base_ctx::format_body(json, obj))
1359 return true; /* purecov: inspected */
1360
1361 if (message)
1362 {
1363 message_ctx *msg= (message_ctx*)message;
1364 obj->add_alnum(K_MESSAGE, msg->entry()->col_message.str);
1365 }
1366
1367 Opt_trace_array specs(json, K_QUERY_SPECIFICATIONS);
1368
1369 List_iterator<context> it(*query_specs);
1370 context *ctx;
1371 while ((ctx= it++))
1372 {
1373 if (ctx->format(json))
1374 return true; /* purecov: inspected */
1375 }
1376 return false;
1377 }
1378
1379
1380 /**
1381 Auxiliary function to walk through the list and propagate "hide" value
1382
1383 @param list list of context (*_ctx) objects
1384 @param hide if true, ban the output of K_SELECT_ID JSON property
1385 in the underlying table_with_where_and_derived_ctx
1386 and materialize_ctx objects
1387
1388 @return id of underlying objects
1389 */
1390 template<typename T>
get_id(List<T> & list,bool hide)1391 static size_t get_id(List<T> &list, bool hide)
1392 {
1393 if (!hide)
1394 return list.head()->id();
1395
1396 List_iterator<T> it(list);
1397 T *j;
1398 size_t ret= 0;
1399 while ((j= it++))
1400 ret= j->id(hide);
1401 return ret;
1402 }
1403
1404
id(bool hide)1405 size_t join_ctx::id(bool hide)
1406 {
1407 return sort ? sort->id(hide) : get_id(join_tabs, hide);
1408 }
1409
1410
cacheable()1411 bool join_ctx::cacheable()
1412 {
1413 return sort ? sort->cacheable() : join_tabs.head()->cacheable();
1414 }
1415
1416
dependent()1417 bool join_ctx::dependent()
1418 {
1419 return sort ? sort->dependent() : join_tabs.head()->dependent();
1420 }
1421
1422
add_where_subquery(subquery_ctx * ctx,SELECT_LEX_UNIT * subquery)1423 int join_ctx::add_where_subquery(subquery_ctx *ctx,
1424 SELECT_LEX_UNIT *subquery)
1425 {
1426 if (sort)
1427 return sort->join_ctx::add_where_subquery(ctx, subquery);
1428
1429 List_iterator<joinable_ctx> it(join_tabs);
1430 joinable_ctx *j;
1431 bool found= false;
1432 while ((j= it++))
1433 {
1434 int ret= j->add_where_subquery(ctx, subquery);
1435 if (ret > 0)
1436 return true;
1437 found|= (ret == 0);
1438 }
1439 if (!found)
1440 return add_subquery(SQ_OPTIMIZED_AWAY, ctx);
1441 return false;
1442 }
1443
1444
1445 /**
1446 Context class to group materialized JOIN_TABs to "matirealized" array
1447 */
1448
1449 class materialize_ctx : public joinable_ctx, public join_ctx,
1450 public table_base_ctx
1451 {
1452 public:
materialize_ctx(context * parent_arg)1453 explicit materialize_ctx(context *parent_arg)
1454 : context(CTX_MATERIALIZATION, K_TABLE, parent_arg),
1455 joinable_ctx(CTX_MATERIALIZATION, K_TABLE, parent_arg),
1456 join_ctx(CTX_MATERIALIZATION, K_TABLE, parent_arg),
1457 table_base_ctx(CTX_MATERIALIZATION, K_TABLE, parent_arg)
1458 {}
1459
id(bool hide)1460 virtual size_t id(bool hide)
1461 {
1462 if (hide)
1463 {
1464 is_hidden_id= true;
1465 /* Set the materizlize table's id to hide */
1466 join_ctx::id(hide);
1467 }
1468 return table_base_ctx::id(hide);
1469 }
cacheable()1470 virtual bool cacheable() { return join_ctx::cacheable(); }
dependent()1471 virtual bool dependent() { return join_ctx::dependent(); }
1472
1473 // Remove warnings: 'inherits ... from ... via dominance'
entry()1474 virtual qep_row *entry() { return table_base_ctx::entry(); }
add_subquery(subquery_list_enum subquery_type,subquery_ctx * ctx)1475 virtual bool add_subquery(subquery_list_enum subquery_type, subquery_ctx *ctx)
1476 { return join_ctx::add_subquery(subquery_type, ctx); }
add_join_tab(joinable_ctx * ctx)1477 virtual bool add_join_tab(joinable_ctx *ctx)
1478 { return join_ctx::add_join_tab(ctx); }
add_where_subquery(subquery_ctx * ctx,SELECT_LEX_UNIT * subquery)1479 virtual int add_where_subquery(subquery_ctx *ctx, SELECT_LEX_UNIT *subquery)
1480 { return join_ctx::add_where_subquery(ctx, subquery); }
find_and_set_derived(context * subquery)1481 virtual bool find_and_set_derived(context *subquery)
1482 { return join_ctx::find_and_set_derived(subquery); }
format_unit(Opt_trace_context * json)1483 virtual bool format_unit(Opt_trace_context *json)
1484 { return unit_ctx::format_unit(json); }
format_nested_loop(Opt_trace_context * json)1485 virtual bool format_nested_loop(Opt_trace_context *json)
1486 { return join_ctx::format_nested_loop(json); }
set_sort(sort_ctx * ctx)1487 virtual void set_sort(sort_ctx *ctx)
1488 { return join_ctx::set_sort(ctx); }
1489
1490 private:
format_body(Opt_trace_context * json,Opt_trace_object * obj)1491 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1492 {
1493 assert(!col_join_type.is_empty());
1494
1495 if (!col_table_name.is_empty())
1496 obj->add_utf8(K_TABLE_NAME, col_table_name.str);
1497
1498 obj->add_alnum(K_ACCESS_TYPE, col_join_type.str);
1499
1500 if (!col_key.is_empty())
1501 obj->add_utf8(K_KEY, col_key.str);
1502
1503 if (!col_key_len.is_empty())
1504 obj->add_alnum(K_KEY_LENGTH, col_key_len.str);
1505
1506 add_string_array(json, K_REF, col_ref);
1507
1508 if (!col_rows.is_empty())
1509 obj->add(K_ROWS, col_rows.value);
1510
1511 /*
1512 Currently K-REF/col_ref is not shown; it would always be "func", since
1513 {subquery,semijoin} materialization use store_key_item; using
1514 get_store_key() instead would allow "const" and outer column's name,
1515 if applicable.
1516 The looked up expression can anyway be inferred from the condition:
1517 */
1518 if (!col_attached_condition.is_empty())
1519 obj->add_utf8(K_ATTACHED_CONDITION, col_attached_condition.str);
1520 if (format_where(json))
1521 return true;
1522
1523 Opt_trace_object m(json, K_MATERIALIZED_FROM_SUBQUERY);
1524 obj->add(K_USING_TMP_TABLE, true);
1525 Opt_trace_object q(json, K_QUERY_BLOCK);
1526 return format_nested_loop(json);
1527 }
1528 };
1529
1530
1531 /**
1532 Context class to represent JOIN_TABs in duplication weedout sequence
1533 */
1534
1535 class duplication_weedout_ctx : public joinable_ctx, public join_ctx
1536 {
1537 public:
duplication_weedout_ctx(context * parent_arg)1538 explicit duplication_weedout_ctx(context *parent_arg)
1539 : context(CTX_DUPLICATES_WEEDOUT, K_DUPLICATES_REMOVAL, parent_arg),
1540 joinable_ctx(CTX_DUPLICATES_WEEDOUT, K_DUPLICATES_REMOVAL, parent_arg),
1541 join_ctx(CTX_DUPLICATES_WEEDOUT, K_DUPLICATES_REMOVAL, parent_arg)
1542 {}
1543
id(bool hide)1544 virtual size_t id(bool hide) { return join_ctx::id(hide); }
cacheable()1545 virtual bool cacheable() { return join_ctx::cacheable(); }
dependent()1546 virtual bool dependent() { return join_ctx::dependent(); }
1547
1548 // Remove warnings: 'inherits ... from ... via dominance'
add_join_tab(joinable_ctx * ctx)1549 virtual bool add_join_tab(joinable_ctx *ctx)
1550 { return join_ctx::add_join_tab(ctx); }
add_subquery(subquery_list_enum subquery_type,subquery_ctx * ctx)1551 virtual bool add_subquery(subquery_list_enum subquery_type, subquery_ctx *ctx)
1552 { return join_ctx::add_subquery(subquery_type, ctx); }
add_where_subquery(subquery_ctx * ctx,SELECT_LEX_UNIT * subquery)1553 virtual int add_where_subquery(subquery_ctx *ctx, SELECT_LEX_UNIT *subquery)
1554 { return join_ctx::add_where_subquery(ctx, subquery); }
find_and_set_derived(context * subquery)1555 virtual bool find_and_set_derived(context *subquery)
1556 { return join_ctx::find_and_set_derived(subquery); }
format_nested_loop(Opt_trace_context * json)1557 virtual bool format_nested_loop(Opt_trace_context *json)
1558 { return join_ctx::format_nested_loop(json); }
format_unit(Opt_trace_context * json)1559 virtual bool format_unit(Opt_trace_context *json)
1560 { return unit_ctx::format_unit(json); }
set_sort(sort_ctx * ctx)1561 virtual void set_sort(sort_ctx *ctx)
1562 { return join_ctx::set_sort(ctx); }
entry()1563 virtual qep_row *entry()
1564 { return join_ctx::entry(); }
1565
1566 private:
format_body(Opt_trace_context * json,Opt_trace_object * obj)1567 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1568 {
1569 obj->add(K_USING_TMP_TABLE, true);
1570 return format_nested_loop(json);
1571 }
1572 };
1573
1574
1575 /**
1576 Node class for UNION (query expression)
1577 */
1578
1579 class union_ctx : public unit_ctx
1580 {
1581 union_result_ctx *union_result; ///< associated CTX_UNION_RESULT node
1582 List<context> query_specs; ///< query specification nodes (inner selects)
1583
1584 public:
union_ctx(context * parent_arg)1585 explicit union_ctx(context * parent_arg)
1586 : context(CTX_UNION, K_QUERY_BLOCK, parent_arg),
1587 unit_ctx(CTX_UNION, K_QUERY_BLOCK, parent_arg),
1588 union_result(NULL)
1589 {}
1590
1591 private:
format_body(Opt_trace_context * json,Opt_trace_object * obj)1592 virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1593 {
1594 if (union_result)
1595 return (union_result->format(json)) || format_unit(json);
1596 else
1597 {
1598 /*
1599 UNION without temporary table. There is no union_result since
1600 there is no fake_select_lex.
1601 */
1602 Opt_trace_object union_res(json, K_UNION_RESULT);
1603 union_res.add(K_USING_TMP_TABLE, false);
1604 Opt_trace_array specs(json, K_QUERY_SPECIFICATIONS);
1605 List_iterator<context> it(query_specs);
1606 context *ctx;
1607 while ((ctx= it++))
1608 {
1609 if (ctx->format(json))
1610 return true; /* purecov: inspected */
1611 }
1612 return format_unit(json);
1613 }
1614 }
1615
1616 public:
id(bool hide)1617 virtual size_t id(bool hide) { return get_id(query_specs, hide); }
cacheable()1618 virtual bool cacheable() { return query_specs.head()->cacheable(); }
dependent()1619 virtual bool dependent() { return query_specs.head()->dependent(); }
1620
set_union_result(union_result_ctx * ctx)1621 virtual void set_union_result(union_result_ctx *ctx)
1622 {
1623 assert(union_result == NULL);
1624 union_result= ctx;
1625 union_result->push_down_query_specs(&query_specs);
1626 }
add_query_spec(context * ctx)1627 virtual bool add_query_spec(context *ctx)
1628 { return query_specs.push_back(ctx); }
1629 };
1630
format(Opt_trace_context * json)1631 bool union_result_ctx::format(Opt_trace_context *json)
1632 {
1633 if (order_by_subqueries.is_empty() && optimized_away_subqueries.is_empty())
1634 return table_base_ctx::format(json);
1635
1636 Opt_trace_object order_by(json, K_ORDERING_OPERATION);
1637
1638 order_by.add(K_USING_FILESORT, !order_by_subqueries.is_empty());
1639
1640 if (table_base_ctx::format(json))
1641 return true; /* purecov: inspected */
1642
1643 if (!order_by_subqueries.is_empty() &&
1644 format_list(json, order_by_subqueries, K_ORDER_BY_SUBQUERIES))
1645 return true; /* purecov: inspected */
1646
1647 if (!optimized_away_subqueries.is_empty() &&
1648 format_list(json, optimized_away_subqueries,
1649 K_OPTIMIZED_AWAY_SUBQUERIES))
1650 return true; /* purecov: inspected */
1651
1652 return false;
1653 }
1654
1655 } // namespace
1656
1657
entry()1658 qep_row *Explain_format_JSON::entry()
1659 {
1660 return current_context->entry();
1661 }
1662
1663
begin_context(enum_parsing_context ctx,SELECT_LEX_UNIT * subquery,const Explain_format_flags * flags)1664 bool Explain_format_JSON::begin_context(enum_parsing_context ctx,
1665 SELECT_LEX_UNIT *subquery,
1666 const Explain_format_flags *flags)
1667 {
1668 using namespace opt_explain_json_namespace;
1669
1670 context *prev_context= current_context;
1671 switch(ctx) {
1672 case CTX_JOIN:
1673 assert(current_context == NULL ||
1674 // subqueries:
1675 current_context->type == CTX_SELECT_LIST ||
1676 current_context->type == CTX_UPDATE_VALUE_LIST ||
1677 current_context->type == CTX_DERIVED ||
1678 current_context->type == CTX_OPTIMIZED_AWAY_SUBQUERY ||
1679 current_context->type == CTX_WHERE ||
1680 current_context->type == CTX_HAVING ||
1681 current_context->type == CTX_ORDER_BY_SQ ||
1682 current_context->type == CTX_GROUP_BY_SQ ||
1683 current_context->type == CTX_QUERY_SPEC);
1684 if ((current_context=
1685 new join_ctx(CTX_JOIN, K_QUERY_BLOCK, current_context)) == NULL)
1686 return true;
1687 break;
1688 case CTX_ORDER_BY:
1689 {
1690 assert(current_context->type == CTX_JOIN);
1691 sort_ctx *ctx= new sort_with_subqueries_ctx(CTX_ORDER_BY,
1692 K_ORDERING_OPERATION,
1693 current_context,
1694 SQ_ORDER_BY, flags,
1695 ESC_ORDER_BY);
1696 if (ctx == NULL)
1697 return true;
1698 current_context->set_sort(ctx);
1699 current_context= ctx;
1700 break;
1701 }
1702 case CTX_GROUP_BY:
1703 {
1704 assert(current_context->type == CTX_JOIN ||
1705 current_context->type == CTX_ORDER_BY ||
1706 current_context->type == CTX_DISTINCT);
1707 sort_ctx *ctx= new sort_with_subqueries_ctx(CTX_GROUP_BY,
1708 K_GROUPING_OPERATION,
1709 current_context,
1710 SQ_GROUP_BY, flags,
1711 ESC_GROUP_BY);
1712 if (ctx == NULL)
1713 return true;
1714 current_context->set_sort(ctx);
1715 current_context= ctx;
1716 break;
1717 }
1718 case CTX_DISTINCT:
1719 {
1720 assert(current_context->type == CTX_JOIN ||
1721 current_context->type == CTX_ORDER_BY);
1722 sort_ctx *ctx= new sort_ctx(CTX_DISTINCT, K_DUPLICATES_REMOVAL,
1723 current_context, flags, ESC_DISTINCT);
1724 if (ctx == NULL)
1725 return true;
1726 current_context->set_sort(ctx);
1727 current_context= ctx;
1728 break;
1729 }
1730 case CTX_BUFFER_RESULT:
1731 {
1732 assert(current_context->type == CTX_JOIN ||
1733 current_context->type == CTX_ORDER_BY ||
1734 current_context->type == CTX_DISTINCT ||
1735 current_context->type == CTX_GROUP_BY);
1736 sort_ctx *ctx= new sort_ctx(CTX_BUFFER_RESULT, K_BUFFER_RESULT,
1737 current_context, flags, ESC_BUFFER_RESULT);
1738 if (ctx == NULL)
1739 return true;
1740 current_context->set_sort(ctx);
1741 current_context= ctx;
1742 break;
1743 }
1744 case CTX_QEP_TAB:
1745 {
1746 assert(current_context->type == CTX_JOIN ||
1747 current_context->type == CTX_MATERIALIZATION ||
1748 current_context->type == CTX_DUPLICATES_WEEDOUT ||
1749 current_context->type == CTX_GROUP_BY ||
1750 current_context->type == CTX_ORDER_BY ||
1751 current_context->type == CTX_DISTINCT ||
1752 current_context->type == CTX_BUFFER_RESULT ||
1753 current_context->type == CTX_SIMPLE_GROUP_BY ||
1754 current_context->type == CTX_SIMPLE_ORDER_BY ||
1755 current_context->type == CTX_SIMPLE_DISTINCT);
1756 join_tab_ctx *ctx= new join_tab_ctx(CTX_QEP_TAB, current_context);
1757 if (ctx == NULL || current_context->add_join_tab(ctx))
1758 return true;
1759 current_context= ctx;
1760 break;
1761 }
1762 case CTX_SIMPLE_ORDER_BY:
1763 {
1764 assert(current_context->type == CTX_JOIN ||
1765 current_context->type == CTX_MATERIALIZATION ||
1766 current_context->type == CTX_DUPLICATES_WEEDOUT ||
1767 current_context->type == CTX_GROUP_BY ||
1768 current_context->type == CTX_ORDER_BY ||
1769 current_context->type == CTX_BUFFER_RESULT ||
1770 current_context->type == CTX_DISTINCT);
1771 simple_sort_ctx *ctx=
1772 new simple_sort_with_subqueries_ctx(CTX_SIMPLE_ORDER_BY,
1773 K_ORDERING_OPERATION,
1774 current_context, SQ_ORDER_BY, flags,
1775 ESC_ORDER_BY);
1776
1777 if (ctx == NULL || current_context->add_join_tab(ctx))
1778 return true;
1779 current_context= ctx;
1780 break;
1781 }
1782 case CTX_SIMPLE_GROUP_BY:
1783 {
1784 assert(current_context->type == CTX_JOIN ||
1785 current_context->type == CTX_MATERIALIZATION ||
1786 current_context->type == CTX_DUPLICATES_WEEDOUT ||
1787 current_context->type == CTX_GROUP_BY ||
1788 current_context->type == CTX_ORDER_BY ||
1789 current_context->type == CTX_DISTINCT ||
1790 current_context->type == CTX_BUFFER_RESULT ||
1791 current_context->type == CTX_SIMPLE_ORDER_BY ||
1792 current_context->type == CTX_SIMPLE_DISTINCT);
1793 simple_sort_ctx *ctx=
1794 new simple_sort_with_subqueries_ctx(CTX_SIMPLE_GROUP_BY,
1795 K_GROUPING_OPERATION,
1796 current_context, SQ_GROUP_BY, flags,
1797 ESC_GROUP_BY);
1798 if (ctx == NULL || current_context->add_join_tab(ctx))
1799 return true;
1800 current_context= ctx;
1801 break;
1802 }
1803 case CTX_SIMPLE_DISTINCT:
1804 {
1805 assert(current_context->type == CTX_JOIN ||
1806 current_context->type == CTX_MATERIALIZATION ||
1807 current_context->type == CTX_DUPLICATES_WEEDOUT ||
1808 current_context->type == CTX_GROUP_BY ||
1809 current_context->type == CTX_ORDER_BY ||
1810 current_context->type == CTX_DISTINCT ||
1811 current_context->type == CTX_BUFFER_RESULT ||
1812 current_context->type == CTX_SIMPLE_ORDER_BY);
1813 simple_sort_ctx *ctx=
1814 new simple_sort_ctx(CTX_SIMPLE_DISTINCT, K_DUPLICATES_REMOVAL,
1815 current_context, flags, ESC_DISTINCT);
1816 if (ctx == NULL || current_context->add_join_tab(ctx))
1817 return true;
1818 current_context= ctx;
1819 break;
1820 }
1821 case CTX_MATERIALIZATION:
1822 {
1823 assert(current_context->type == CTX_JOIN ||
1824 current_context->type == CTX_GROUP_BY ||
1825 current_context->type == CTX_ORDER_BY ||
1826 current_context->type == CTX_DISTINCT ||
1827 current_context->type == CTX_BUFFER_RESULT ||
1828 current_context->type == CTX_DUPLICATES_WEEDOUT);
1829 materialize_ctx *ctx= new materialize_ctx(current_context);
1830 if (ctx == NULL || current_context->add_join_tab(ctx))
1831 return true;
1832 current_context= ctx;
1833 break;
1834 }
1835 case CTX_DUPLICATES_WEEDOUT:
1836 {
1837 assert(current_context->type == CTX_JOIN ||
1838 current_context->type == CTX_GROUP_BY ||
1839 current_context->type == CTX_ORDER_BY ||
1840 current_context->type == CTX_DISTINCT ||
1841 current_context->type == CTX_BUFFER_RESULT ||
1842 current_context->type == CTX_MATERIALIZATION);
1843 duplication_weedout_ctx *ctx=
1844 new duplication_weedout_ctx(current_context);
1845 if (ctx == NULL || current_context->add_join_tab(ctx))
1846 return true;
1847 current_context= ctx;
1848 break;
1849 }
1850 case CTX_SELECT_LIST:
1851 {
1852 subquery_ctx *ctx= new subquery_ctx(CTX_SELECT_LIST, NULL,
1853 current_context);
1854 if (ctx == NULL ||
1855 current_context->add_subquery(SQ_SELECT_LIST, ctx))
1856 return true;
1857 current_context= ctx;
1858 break;
1859 }
1860 case CTX_UPDATE_VALUE_LIST:
1861 {
1862 subquery_ctx *ctx= new subquery_ctx(CTX_UPDATE_VALUE_LIST, NULL,
1863 current_context);
1864 if (ctx == NULL ||
1865 current_context->add_subquery(SQ_UPDATE_VALUE, ctx))
1866 return true;
1867 current_context= ctx;
1868 break;
1869 }
1870 case CTX_DERIVED:
1871 {
1872 current_context= new subquery_ctx(CTX_DERIVED,
1873 K_MATERIALIZED_FROM_SUBQUERY,
1874 current_context);
1875 if (current_context == NULL)
1876 return true;
1877 break;
1878 }
1879 case CTX_OPTIMIZED_AWAY_SUBQUERY:
1880 {
1881 subquery_ctx *ctx= new subquery_ctx(CTX_OPTIMIZED_AWAY_SUBQUERY, NULL,
1882 current_context);
1883 if (ctx == NULL ||
1884 current_context->add_subquery(SQ_OPTIMIZED_AWAY, ctx))
1885 return true;
1886 current_context= ctx;
1887 break;
1888 }
1889 case CTX_WHERE:
1890 {
1891 assert(subquery != NULL);
1892 subquery_ctx *ctx= new subquery_ctx(CTX_WHERE, NULL, current_context);
1893 if (ctx == NULL ||
1894 current_context->add_where_subquery(ctx, subquery))
1895 return true;
1896 current_context= ctx;
1897 break;
1898 }
1899 case CTX_HAVING:
1900 {
1901 subquery_ctx *ctx= new subquery_ctx(CTX_HAVING, NULL, current_context);
1902 if (ctx == NULL || current_context->add_subquery(SQ_HAVING, ctx))
1903 return true;
1904 current_context= ctx;
1905 break;
1906 }
1907 case CTX_ORDER_BY_SQ:
1908 {
1909 subquery_ctx *ctx= new subquery_ctx(CTX_ORDER_BY_SQ, NULL,
1910 current_context);
1911 if (ctx == NULL || current_context->add_subquery(SQ_ORDER_BY, ctx))
1912 return true;
1913 current_context= ctx;
1914 break;
1915 }
1916 case CTX_GROUP_BY_SQ:
1917 {
1918 subquery_ctx *ctx= new subquery_ctx(CTX_GROUP_BY_SQ, NULL,
1919 current_context);
1920 if (ctx == NULL || current_context->add_subquery(SQ_GROUP_BY, ctx))
1921 return true;
1922 current_context= ctx;
1923 break;
1924 }
1925 case CTX_UNION:
1926 assert(current_context == NULL ||
1927 // subqueries:
1928 current_context->type == CTX_SELECT_LIST ||
1929 current_context->type == CTX_UPDATE_VALUE_LIST ||
1930 current_context->type == CTX_DERIVED ||
1931 current_context->type == CTX_OPTIMIZED_AWAY_SUBQUERY ||
1932 current_context->type == CTX_WHERE ||
1933 current_context->type == CTX_HAVING ||
1934 current_context->type == CTX_ORDER_BY_SQ ||
1935 current_context->type == CTX_GROUP_BY_SQ ||
1936 current_context->type == CTX_QUERY_SPEC);
1937 current_context= new union_ctx(current_context);
1938 if (current_context == NULL)
1939 return true;
1940 break;
1941 case CTX_UNION_RESULT:
1942 {
1943 assert(current_context->type == CTX_UNION);
1944 union_result_ctx *ctx= new union_result_ctx(current_context);
1945 if (ctx == NULL)
1946 return true;
1947 current_context->set_union_result(ctx);
1948 current_context= ctx;
1949 break;
1950 }
1951 case CTX_QUERY_SPEC:
1952 {
1953 assert(current_context->type == CTX_UNION);
1954 subquery_ctx *ctx= new subquery_ctx(CTX_QUERY_SPEC, NULL,
1955 current_context);
1956 if (ctx == NULL || current_context->add_query_spec(ctx))
1957 return true;
1958 current_context= ctx;
1959 break;
1960 }
1961 case CTX_MESSAGE:
1962 {
1963 /*
1964 Like CTX_QEP_TAB:
1965 */
1966 assert(current_context->type == CTX_JOIN ||
1967 current_context->type == CTX_MATERIALIZATION ||
1968 current_context->type == CTX_DUPLICATES_WEEDOUT ||
1969 current_context->type == CTX_GROUP_BY ||
1970 current_context->type == CTX_ORDER_BY ||
1971 current_context->type == CTX_DISTINCT ||
1972 current_context->type == CTX_BUFFER_RESULT ||
1973 current_context->type == CTX_SIMPLE_GROUP_BY ||
1974 current_context->type == CTX_SIMPLE_ORDER_BY ||
1975 current_context->type == CTX_SIMPLE_DISTINCT ||
1976 current_context->type == CTX_UNION_RESULT);
1977 joinable_ctx *ctx= new message_ctx(current_context);
1978 if (ctx == NULL || current_context->add_join_tab(ctx))
1979 return true;
1980 current_context= ctx;
1981 break;
1982 }
1983 default:
1984 assert(!"Unknown EXPLAIN context!");
1985 return true;
1986 }
1987
1988 if (prev_context)
1989 prev_context->set_child(current_context);
1990
1991 return false;
1992 }
1993
1994
end_context(enum_parsing_context ctx)1995 bool Explain_format_JSON::end_context(enum_parsing_context ctx)
1996 {
1997 assert(current_context->type == ctx);
1998
1999 bool ret= false;
2000 if (current_context->parent == NULL)
2001 {
2002 Item* item;
2003 #ifdef OPTIMIZER_TRACE
2004 Opt_trace_context json;
2005 const size_t max_size= ULONG_MAX;
2006 if (json.start(true, // support_I_S (enable JSON generation)
2007 false, // support_dbug_or_missing_priv
2008 current_thd->variables.end_markers_in_json, // end_marker
2009 false, // one_line
2010 0, // offset
2011 1, // limit
2012 max_size, // max_mem_size
2013 Opt_trace_context::MISC))
2014 return true;
2015
2016 {
2017 Opt_trace_object braces(&json);
2018
2019 if (current_context->format(&json))
2020 return true;
2021 }
2022 json.end();
2023
2024 Opt_trace_iterator it(&json);
2025 if (!it.at_end())
2026 {
2027 Opt_trace_info info;
2028 it.get_value(&info);
2029 item= new Item_string(info.trace_ptr,
2030 static_cast<uint>(info.trace_length),
2031 system_charset_info);
2032 }
2033 else
2034 #endif
2035 item= new Item_null();
2036
2037 List<Item> field_list;
2038 ret= (item == NULL ||
2039 field_list.push_back(item) ||
2040 output->send_data(field_list));
2041 }
2042 else if (ctx == CTX_DERIVED)
2043 {
2044 if (!current_context->parent->find_and_set_derived(current_context))
2045 {
2046 assert(!"No derived table found!");
2047 return true;
2048 }
2049 }
2050
2051 current_context= current_context->parent;
2052 return ret;
2053 }
2054
2055
send_headers(Query_result * result)2056 bool Explain_format_JSON::send_headers(Query_result *result)
2057 {
2058 output= result;
2059 if (Explain_format::send_headers(result))
2060 return true;
2061
2062 List<Item> field_list;
2063 Item *item= new Item_empty_string("EXPLAIN", 78, system_charset_info);
2064 if (item == NULL || field_list.push_back(item))
2065 return true;
2066 return result->send_result_set_metadata(field_list,
2067 Protocol::SEND_NUM_ROWS |
2068 Protocol::SEND_EOF);
2069 }
2070
2071