MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
opt_explain_json.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_trace.h"
17 #include "opt_explain_json.h"
18 
24 static const char *json_extra_tags[ET_total]=
25 {
26  NULL, // ET_none
27  "using_temporary_table", // ET_USING_TEMPORARY
28  "using_filesort", // ET_USING_FILESORT
29  "index_condition", // ET_USING_INDEX_CONDITION
30  NULL, // ET_USING
31  "range_checked_for_each_record", // ET_RANGE_CHECKED_FOR_EACH_RECORD
32  "pushed_condition", // ET_USING_WHERE_WITH_PUSHED_CONDITION
33  NULL, // ET_USING_WHERE
34  "not_exists", // ET_NOT_EXISTS
35  "using_MRR", // ET_USING_MRR
36  "using_index", // ET_USING_INDEX
37  "full_scan_on_NULL_key", // ET_FULL_SCAN_ON_NULL_KEY
38  "skip_open_table", // ET_SKIP_OPEN_TABLE
39  "open_frm_only", // ET_OPEN_FRM_ONLY
40  "open_full_table", // ET_OPEN_FULL_TABLE
41  "scanned_databases", // ET_SCANNED_DATABASES
42  "using_index_for_group_by", // ET_USING_INDEX_FOR_GROUP_BY
43  "distinct", // ET_DISTINCT
44  "loosescan", // ET_LOOSESCAN
45  NULL, // ET_START_TEMPORARY
46  NULL, // ET_END_TEMPORARY
47  "first_match", // ET_FIRST_MATCH
48  NULL, // ET_MATERIALIZE
49  NULL, // ET_START_MATERIALIZE
50  NULL, // ET_END_MATERIALIZE
51  NULL, // ET_SCAN
52  "using_join_buffer", // ET_USING_JOIN_BUFFER
53  "const_row_not_found", // ET_CONST_ROW_NOT_FOUND
54  "unique_row_not_found", // ET_UNIQUE_ROW_NOT_FOUND
55  "impossible_on_condition", // ET_IMPOSSIBLE_ON_CONDITION
56  "pushed_join" // ET_PUSHED_JOIN
57 };
58 
59 
60 // JSON key names
61 static const char K_ACCESS_TYPE[]= "access_type";
62 static const char K_ATTACHED_CONDITION[]= "attached_condition";
63 static const char K_ATTACHED_SUBQUERIES[]= "attached_subqueries";
64 static const char K_BUFFER_RESULT[]= "buffer_result";
65 static const char K_CACHEABLE[]= "cacheable";
66 static const char K_DEPENDENT[]= "dependent";
67 static const char K_DUPLICATES_REMOVAL[]= "duplicates_removal";
68 static const char K_FILTERED[]= "filtered";
69 static const char K_GROUPING_OPERATION[]= "grouping_operation";
70 static const char K_GROUP_BY_SUBQUERIES[]= "group_by_subqueries";
71 static const char K_HAVING_SUBQUERIES[]= "having_subqueries";
72 static const char K_KEY[]= "key";
73 static const char K_KEY_LENGTH[]= "key_length";
74 static const char K_MATERIALIZED_FROM_SUBQUERY[]= "materialized_from_subquery";
75 static const char K_MESSAGE[]= "message";
76 static const char K_NESTED_LOOP[]= "nested_loop";
77 static const char K_OPTIMIZATION_TIME_SUBQUERIES[]= "optimized_away_subqueries";
78 static const char K_ORDERING_OPERATION[]= "ordering_operation";
79 static const char K_ORDER_BY_SUBQUERIES[]= "order_by_subqueries";
80 static const char K_PARTITIONS[]= "partitions";
81 static const char K_POSSIBLE_KEYS[]= "possible_keys";
82 static const char K_QUERY_BLOCK[]= "query_block";
83 static const char K_QUERY_SPECIFICATIONS[]= "query_specifications";
84 static const char K_REF[]= "ref";
85 static const char K_ROWS[]= "rows";
86 static const char K_SELECT_ID[]= "select_id";
87 static const char K_SELECT_LIST_SUBQUERIES[]= "select_list_subqueries";
88 static const char K_TABLE[]= "table";
89 static const char K_TABLE_NAME[]= "table_name";
90 static const char K_UNION_RESULT[]= "union_result";
91 static const char K_UPDATE_VALUE_SUBQUERIES[]= "update_value_subqueries";
92 static const char K_USED_KEY_PARTS[]= "used_key_parts";
93 static const char K_USING_FILESORT[]= "using_filesort";
94 static const char K_USING_TMP_TABLE[]= "using_temporary_table";
95 
96 
97 /*
98  see commentary at the beginning of opt_trace.cc
99 */
100 namespace opt_explain_json_namespace
101 {
102 
103 class joinable_ctx;
104 class sort_ctx;
105 class subquery_ctx;
106 class union_result_ctx;
107 
111 enum subquery_list_enum
112 {
113  SQ_SELECT_LIST,
114  SQ_UPDATE_VALUE,
115  SQ_HAVING,
116  SQ_HOMELESS,
117  //--------------
118  SQ_toplevel,
119  //--------------
120  SQ_ORDER_BY,
121  SQ_GROUP_BY,
122  //--------------
123  SQ_total
124 };
125 
129 static const char *list_names[SQ_total]=
130 {
131  K_SELECT_LIST_SUBQUERIES,
132  K_UPDATE_VALUE_SUBQUERIES,
133  K_HAVING_SUBQUERIES,
134  K_OPTIMIZATION_TIME_SUBQUERIES,
135  "",
136  K_ORDER_BY_SUBQUERIES,
137  K_GROUP_BY_SUBQUERIES,
138 };
139 
140 
145 class context : public Explain_context
146 {
147 protected:
148  const char *name;
149 
150 public:
152 
153  context(Explain_context_enum type_arg, const char *name_arg,
154  context *parent_arg)
155  : Explain_context(type_arg),
156  name(name_arg),
157  parent(parent_arg)
158  {}
159 
160  virtual ~context() {}
161 
172  virtual bool format(Opt_trace_context *json)
173  {
174  Opt_trace_object obj(json, name);
175  return format_body(json, &obj);
176  }
177 
178  bool is_query_block() const { return name == K_QUERY_BLOCK; }
179 
180 private:
190  virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)= 0;
191 
192 public:
202  virtual size_t id(bool hide= false)= 0;
203 
204  virtual bool cacheable() { DBUG_ASSERT(0); return true; }
205  virtual bool dependent() { DBUG_ASSERT(0); return false; }
206 
207  virtual class qep_row *entry() { DBUG_ASSERT(0); return NULL; }
208 
214  virtual void set_child(context *child) {}
215 
217  virtual void set_union_result(union_result_ctx *ctx) { DBUG_ASSERT(0); }
218 
228  virtual bool add_subquery(subquery_list_enum subquery_type,
229  subquery_ctx *ctx) { DBUG_ASSERT(0);return true; }
239  { DBUG_ASSERT(0); return true; }
240 
249  virtual bool add_join_tab(joinable_ctx *ctx) { DBUG_ASSERT(0);return true; }
250 
259  virtual void set_sort(sort_ctx *ctx) { DBUG_ASSERT(0); }
260 
269  virtual bool add_query_spec(context *ctx) { DBUG_ASSERT(0); return true; }
270 
280  virtual bool find_and_set_derived(context *subquery)
281  {
282  DBUG_ASSERT(0);
283  return false;
284  }
285 
293  virtual bool add_where_subquery(subquery_ctx *ctx,
294  SELECT_LEX_UNIT *subquery)
295  {
296  DBUG_ASSERT(0);
297  return false;
298  }
299 
301  virtual bool format_derived(Opt_trace_context *json) { return false; }
302 
304  virtual bool format_where(Opt_trace_context *json) { return false; }
305 
307  virtual bool format_unit(Opt_trace_context *json) { return false; }
308 };
309 
310 
319 class subquery_ctx : virtual public context, public qep_row
320 {
321  /*
322  TODO: After the conversion from multiple inheritace to templates
323  convert "context" to "unit_ctx" (common base of uion_ctx & join_ctx).
324  */
325  context *subquery;
326 
327 public:
328  subquery_ctx(Explain_context_enum type_arg,
329  const char *name_arg, context *parent_arg)
330  : context(type_arg, name_arg, parent_arg),
331  subquery(NULL)
332  {}
333 
334  virtual qep_row *entry() { return this; }
335 
336  /*
337  Materialized subquery statuses of dependency on the outer query and
338  cacheability may differ from the source subquery, for example, if
339  we "push down" the outer look up value for SJ.
340  Thus, for materialized subqueries return direct is_cacheable and
341  is_dependent values instead of source subquery statuses:
342  */
343  virtual bool cacheable()
344  {
345  return is_materialized_from_subquery ? is_cacheable : subquery->cacheable();
346  }
347  virtual bool dependent()
348  {
349  return is_materialized_from_subquery ? is_dependent : subquery->dependent();
350  }
351 
352  virtual bool format(Opt_trace_context *json)
353  {
354  if (name)
355  return context::format(json);
356  else
357  {
358  /*
359  Subquery is always a homogeneous array element,
360  create anonymous wrapper object:
361  */
362  Opt_trace_object anonymous_wrapper(json);
363  return format_body(json, &anonymous_wrapper);
364  }
365  }
366 
367 private:
368  virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
369  {
370  if (type == CTX_DERIVED)
371  {
372  obj->add(K_USING_TMP_TABLE, true);
373  obj->add(K_DEPENDENT, dependent());
374  obj->add(K_CACHEABLE, cacheable());
375  return subquery->format(json);
376  }
377  else if (using_temporary)
378  {
379  if (!is_materialized_from_subquery)
380  {
381  obj->add(K_USING_TMP_TABLE, true);
382  obj->add(K_DEPENDENT, dependent());
383  obj->add(K_CACHEABLE, cacheable());
384  }
385 
386  {
387  Opt_trace_object tmp_table(json, K_TABLE);
388 
389  if (!col_table_name.is_empty())
390  obj->add_utf8(K_TABLE_NAME, col_table_name.str);
391  if (!col_join_type.is_empty())
392  tmp_table.add_alnum(K_ACCESS_TYPE, col_join_type.str);
393  if (!col_key.is_empty())
394  tmp_table.add_utf8(K_KEY, col_key.str);
395  if (!col_key_len.is_empty())
396  obj->add_alnum(K_KEY_LENGTH, col_key_len.str);
397  if (!col_rows.is_empty())
398  tmp_table.add(K_ROWS, col_rows.value);
399 
400  if (is_materialized_from_subquery)
401  {
402  Opt_trace_object materialized(json, K_MATERIALIZED_FROM_SUBQUERY);
403  obj->add(K_USING_TMP_TABLE, true);
404  obj->add(K_DEPENDENT, dependent());
405  obj->add(K_CACHEABLE, cacheable());
406  return format_query_block(json);
407  }
408  }
409  return format_query_block(json);
410  }
411  else
412  {
413  obj->add(K_DEPENDENT, dependent());
414  obj->add(K_CACHEABLE, cacheable());
415  return subquery->format(json);
416  }
417  }
418 
419  bool format_query_block(Opt_trace_context *json)
420  {
421  if (subquery->is_query_block())
422  return subquery->format(json);
423 
424  Opt_trace_object query_block(json, K_QUERY_BLOCK);
425  return subquery->format(json);
426  }
427 
428 
429 public:
430  virtual void set_child(context *child)
431  {
432  DBUG_ASSERT(subquery == NULL);
433  DBUG_ASSERT(child->type == CTX_JOIN || child->type == CTX_UNION);
434  subquery= child;
435  }
436 
437  virtual size_t id(bool hide) { return subquery->id(hide); }
438 };
439 
440 
451 static bool format_list(Opt_trace_context *json,
452  List<subquery_ctx> &subqueries,
453  const char *name)
454 {
455  if (!subqueries.is_empty())
456  {
457  Opt_trace_array subs(json, name);
458 
459  List_iterator<subquery_ctx> it(subqueries);
460  subquery_ctx *t;
461  while ((t= it++))
462  {
463  // Homogeneous array: additional anonymous wrapper object is not needed
464  if (t->format(json))
465  return true;
466  }
467  }
468  return false;
469 }
470 
471 
475 class unit_ctx : virtual public context
476 {
477  List<subquery_ctx> subquery_lists[SQ_toplevel];
478 
479 public:
480  unit_ctx(Explain_context_enum type_arg, const char *name_arg,
481  context *parent_arg)
482  : context(type_arg, name_arg, parent_arg)
483  {}
484 
491  bool has_no_subqueries() const
492  {
493  for (size_t i= 0; i < SQ_toplevel; i++)
494  {
495  if (!subquery_lists[i].is_empty())
496  return false;
497  }
498  return true;
499  }
500 
501  virtual bool format_unit(Opt_trace_context *json)
502  {
503  for (size_t i= 0; i < SQ_toplevel; i++)
504  {
505  if (format_list(json, subquery_lists[i], list_names[i]))
506  return true;
507  }
508  return false;
509  }
510 
511  virtual bool add_subquery(subquery_list_enum subquery_type,
512  subquery_ctx *ctx)
513  {
514  DBUG_ASSERT(subquery_type < SQ_toplevel);
515  return subquery_lists[subquery_type].push_back(ctx);
516  }
517 };
518 
519 
520 class table_base_ctx : virtual public context, public qep_row
521 {
522 protected:
523  bool is_hidden_id; //< if true, don't output K_SELECT_ID property
524 
525 public:
526  table_base_ctx(Explain_context_enum type_arg,
527  const char *name_arg, context *parent_arg)
528  : context(type_arg, name_arg, parent_arg), is_hidden_id(false)
529  {}
530 
531  virtual qep_row *entry() { return this; }
532 
533 protected:
534  virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj);
535 
536 public:
537  virtual size_t id(bool hide)
538  {
539  return col_id.is_empty() ? 0 : col_id.value;
540  }
541 
542  virtual bool cacheable() { return is_cacheable; }
543  virtual bool dependent() { return is_dependent; }
544 };
545 
546 
547 static void add_string_array(Opt_trace_context *json, const char *list_name,
548  List<const char> &strings)
549 {
550  if (!strings.is_empty())
551  {
552  Opt_trace_array extra(json, list_name);
553 
554  List_iterator<const char> it(strings);
555  const char *s;
556  while ((s= it++))
557  extra.add_utf8(s);
558  }
559 }
560 
562 {
563  StringBuffer<64> buff;
564 
565  if (is_update)
566  obj->add("update", true);
567 
568  if (is_delete)
569  obj->add("delete", true);
570 
571  if (!col_id.is_empty() && !is_hidden_id)
572  obj->add(K_SELECT_ID, col_id.value);
573 
574  if (!col_table_name.is_empty())
575  obj->add_utf8(K_TABLE_NAME, col_table_name.str);
576 
577  add_string_array(json, K_PARTITIONS, col_partitions);
578 
579  if (!col_join_type.is_empty())
580  obj->add_alnum(K_ACCESS_TYPE, col_join_type.str);
581 
582  add_string_array(json, K_POSSIBLE_KEYS, col_possible_keys);
583 
584  if (!col_key.is_empty())
585  obj->add_utf8(K_KEY, col_key.str);
586 
587  if (!col_key_parts.is_empty())
588  add_string_array(json, K_USED_KEY_PARTS, col_key_parts);
589 
590  if (!col_key_len.is_empty())
591  obj->add_alnum(K_KEY_LENGTH, col_key_len.str);
592 
593  add_string_array(json, K_REF, col_ref);
594 
595  if (!col_rows.is_empty())
596  obj->add(K_ROWS, col_rows.value);
597 
598  if (!col_filtered.is_empty())
599  obj->add(K_FILTERED, col_filtered.value);
600 
601  if (!col_extra.is_empty())
602  {
604  qep_row::extra *e;
605  while ((e= it++))
606  {
607  DBUG_ASSERT(json_extra_tags[e->tag] != NULL);
608  if (e->data)
609  obj->add_utf8(json_extra_tags[e->tag], e->data);
610  else
611  obj->add(json_extra_tags[e->tag], true);
612  }
613  }
614 
615  if (!col_message.is_empty())
616  {
617  DBUG_ASSERT(col_extra.is_empty());
618  obj->add_alnum(K_MESSAGE, col_message.str);
619  }
620 
621  { // Keep together for better output readability
622  if (!col_attached_condition.is_empty())
623  obj->add_utf8(K_ATTACHED_CONDITION, col_attached_condition.str);
624  if (format_where(json))
625  return true;
626  }
627 
628  return format_derived(json) || format_unit(json);
629 }
630 
631 
636 {
637  List<context> *query_specs;
638  List<subquery_ctx> order_by_subqueries;
639  List<subquery_ctx> homeless_subqueries;
640 
641 public:
642  explicit union_result_ctx(context *parent_arg)
643  : context(CTX_UNION_RESULT, K_UNION_RESULT, parent_arg),
644  table_base_ctx(CTX_UNION_RESULT, K_UNION_RESULT, parent_arg),
645  unit_ctx(CTX_UNION_RESULT, K_UNION_RESULT, parent_arg)
646  {}
647 
648  // Remove warnings: 'inherits ... from ... via dominance'
649  virtual size_t id(bool hide) { return table_base_ctx::id(hide); }
650  virtual bool cacheable() { return table_base_ctx::cacheable(); }
651  virtual bool dependent() { return table_base_ctx::dependent(); }
652  virtual qep_row *entry() { return table_base_ctx::entry(); }
653  virtual bool format_unit(Opt_trace_context *json)
654  { return table_base_ctx::format_unit(json); }
655 
656  void push_down_query_specs(List<context> *specs) { query_specs= specs; }
657 
658  virtual bool add_subquery(subquery_list_enum subquery_type,
659  subquery_ctx *ctx)
660  {
661  switch (subquery_type) {
662  case SQ_ORDER_BY:
663  return order_by_subqueries.push_back(ctx);
664  case SQ_HOMELESS:
665  return homeless_subqueries.push_back(ctx);
666  default:
667  DBUG_ASSERT(!"Unknown query type!");
668  return false; // ignore in production
669  }
670  }
671 
672  virtual bool format(Opt_trace_context *json)
673  {
674  if (order_by_subqueries.is_empty() && homeless_subqueries.is_empty())
675  return table_base_ctx::format(json);
676 
677  Opt_trace_object order_by(json, K_ORDERING_OPERATION);
678 
679  order_by.add(K_USING_FILESORT, !order_by_subqueries.is_empty());
680 
681  if (table_base_ctx::format(json))
682  return true;
683 
684  if (!order_by_subqueries.is_empty() &&
685  format_list(json, order_by_subqueries, K_ORDER_BY_SUBQUERIES))
686  return true;
687 
688  if (!homeless_subqueries.is_empty() &&
689  format_list(json, homeless_subqueries, K_OPTIMIZATION_TIME_SUBQUERIES))
690  return true;
691 
692  return false;
693  }
694 
696  {
697  obj->add(K_USING_TMP_TABLE, true);
698 
699  if (table_base_ctx::format_body(json, obj))
700  return true;
701 
702  Opt_trace_array specs(json, K_QUERY_SPECIFICATIONS);
703 
704  List_iterator<context> it(*query_specs);
705  context *ctx;
706  while ((ctx= it++))
707  {
708  if (ctx->format(json))
709  return true;
710  }
711  return false;
712  }
713 };
714 
715 
723 {
724 protected:
726 
727 public:
728  table_with_where_and_derived(Explain_context_enum type_arg,
729  const char *name_arg, context *parent_arg)
730  : context(type_arg, name_arg, parent_arg),
731  table_base_ctx(type_arg, name_arg, parent_arg)
732  {}
733 
734  virtual size_t id(bool hide)
735  {
736  if (hide)
737  is_hidden_id= true;
738  return table_base_ctx::id(hide);
739  }
740 
741  virtual bool format_where(Opt_trace_context *json)
742  {
743  return format_list(json, where_subqueries, K_ATTACHED_SUBQUERIES);
744  }
745 
746  virtual bool format_derived(Opt_trace_context *json)
747  {
748  if (derived_from.elements == 0)
749  return false;
750  else if (derived_from.elements == 1)
751  return derived_from.head()->format(json);
752  else
753  {
754  Opt_trace_array loops(json, K_NESTED_LOOP);
755 
757  context *c;
758  while((c= it++))
759  {
760  Opt_trace_object anonymous_wrapper(json);
761  if (c->format(json))
762  return true;
763  }
764  }
765  return false;
766  }
767 };
768 
769 
776 class joinable_ctx : virtual public context
777 {
778 public:
779  joinable_ctx(Explain_context_enum type_arg, const char *name_arg,
780  context *parent_arg)
781  : context(type_arg, name_arg, parent_arg)
782  {}
783 };
784 
785 
797 class message_ctx : public joinable_ctx,
799 {
800 public:
801  explicit message_ctx(context *parent_arg)
802  : context(CTX_MESSAGE, K_TABLE, parent_arg),
803  joinable_ctx(CTX_MESSAGE, K_TABLE, parent_arg),
804  table_with_where_and_derived(CTX_MESSAGE, K_TABLE, parent_arg)
805  {}
806 
807  // Remove warnings: 'inherits ... from ... via dominance'
809  { return table_base_ctx::format_body(json, obj); }
810  virtual size_t id(bool hide)
811  { return table_with_where_and_derived::id(hide); }
812  virtual bool cacheable() { return table_base_ctx::cacheable(); }
813  virtual bool dependent() { return table_base_ctx::dependent(); }
814  virtual qep_row *entry() { return table_base_ctx::entry(); }
815  virtual bool format_derived(Opt_trace_context *json)
817  virtual bool format_where(Opt_trace_context *json)
819 
820  virtual bool find_and_set_derived(context *subquery)
821  {
822  /*
823  message_ctx is designed to represent a single fake JOIN_TAB in the JOIN,
824  so if the JOIN have a derived table, then this message_ctx represent this
825  derived table.
826  Unconditionally add subquery:
827  */
828  derived_from.push_back(subquery);
829  return true;
830  }
831 
832  virtual bool add_where_subquery(subquery_ctx *ctx,
833  SELECT_LEX_UNIT *subquery)
834  {
835  return where_subqueries.push_back(ctx);
836  }
837 };
838 
839 
843 class join_tab_ctx : public joinable_ctx,
845 {
852  List<SELECT_LEX_UNIT> where_subquery_units;
853 
854 public:
855  join_tab_ctx(Explain_context_enum type_arg, context *parent_arg)
856  : context(type_arg, K_TABLE, parent_arg),
857  joinable_ctx(type_arg, K_TABLE, parent_arg),
858  table_with_where_and_derived(type_arg, K_TABLE, parent_arg)
859  {}
860 
861  // Remove warnings: 'inherits ... from ... via dominance'
863  { return table_base_ctx::format_body(json, obj); }
864  virtual size_t id(bool hide)
865  { return table_with_where_and_derived::id(hide); }
866  virtual bool cacheable() { return table_base_ctx::cacheable(); }
867  virtual bool dependent() { return table_base_ctx::dependent(); }
868  virtual qep_row *entry() { return table_base_ctx::entry(); }
869  virtual bool format_derived(Opt_trace_context *json)
871  virtual bool format_where(Opt_trace_context *json)
873 
874  virtual void register_where_subquery(SELECT_LEX_UNIT *subquery)
875  {
876  List_iterator<SELECT_LEX_UNIT> it(where_subquery_units);
877  SELECT_LEX_UNIT *u;
878  while ((u= it++))
879  {
880  /*
881  The server may transform (x = (SELECT FROM DUAL)) to
882  (x <=> (SELECT FROM DUAL) AND x = (SELECT FROM DUAL)),
883  so ignore duplicates:
884  */
885  if(u == subquery)
886  return;
887  }
888  where_subquery_units.push_back(subquery);
889  }
890 
891  virtual bool add_where_subquery(subquery_ctx *ctx,
892  SELECT_LEX_UNIT *subquery)
893  {
894  List_iterator<SELECT_LEX_UNIT> it(where_subquery_units);
895  SELECT_LEX_UNIT *u;
896  while ((u= it++))
897  {
898  if (u == subquery)
899  return where_subqueries.push_back(ctx);
900  }
901  return false;
902  }
903 
904  virtual bool find_and_set_derived(context *subquery)
905  {
906  if (query_block_id == subquery->id())
907  {
908  derived_from.push_back(subquery);
909  return true;
910  }
911  return false;
912  }
913 };
914 
915 
924 {
925 protected:
926  joinable_ctx *join_tab; //< single JOIN_TAB that we sort
927 
928 private:
929  const bool using_tmptable; //< true if the clause creates intermediate table
930  const bool using_filesort; //< true if the clause uses filesort
931 
932 public:
933  simple_sort_ctx(Explain_context_enum type_arg, const char *name_arg,
934  context *parent_arg,
936  Explain_sort_clause clause)
937  : context(type_arg, name_arg, parent_arg),
938  joinable_ctx(type_arg, name_arg, parent_arg),
939  join_tab(NULL),
940  using_tmptable(flags->get(clause, ESP_USING_TMPTABLE)),
941  using_filesort(flags->get(clause, ESP_USING_FILESORT))
942  {}
943 
944  virtual bool add_join_tab(joinable_ctx *ctx)
945  {
946  join_tab= ctx;
947  return false;
948  }
949 
950  virtual bool add_where_subquery(subquery_ctx *ctx,
951  SELECT_LEX_UNIT *subquery)
952  {
953  return join_tab->add_where_subquery(ctx, subquery);
954  }
955 
956  virtual bool find_and_set_derived(context *subquery)
957  {
958  return join_tab->find_and_set_derived(subquery);
959  }
960 
961  virtual size_t id(bool hide) { return join_tab->id(hide); }
962  virtual bool cacheable() { return join_tab->cacheable(); }
963  virtual bool dependent() { return join_tab->dependent(); }
964 
965 protected:
967  {
968  if (using_tmptable)
969  obj->add(K_USING_TMP_TABLE, true);
970  obj->add(K_USING_FILESORT, using_filesort);
971  return join_tab->format(json);
972  }
973 };
974 
975 
984 {
985  const subquery_list_enum subquery_type; //< type of this clause subqueries
986  List<subquery_ctx> subqueries;
987 
988 public:
989  simple_sort_with_subqueries_ctx(Explain_context_enum type_arg,
990  const char *name_arg,
991  context *parent_arg,
992  subquery_list_enum subquery_type_arg,
993  const Explain_format_flags *flags,
994  Explain_sort_clause clause)
995  : context(type_arg, name_arg, parent_arg),
996  simple_sort_ctx(type_arg, name_arg, parent_arg, flags, clause),
997  subquery_type(subquery_type_arg)
998  {}
999 
1000  virtual bool add_subquery(subquery_list_enum subquery_type_arg,
1001  subquery_ctx *ctx)
1002  {
1003  if (subquery_type != subquery_type_arg)
1004  return simple_sort_ctx::add_subquery(subquery_type_arg, ctx);
1005  else
1006  return subqueries.push_back(ctx);
1007  }
1008 
1009 private:
1010  virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1011  {
1012  return (simple_sort_ctx::format_body(json, obj) ||
1013  (format_list(json, subqueries, list_names[subquery_type])));
1014  }
1015 };
1016 
1017 
1022 class join_ctx : public unit_ctx
1023 {
1024 protected:
1026  sort_ctx *sort;
1027 
1028 public:
1029  join_ctx(Explain_context_enum type_arg, const char *name_arg,
1030  context *parent_arg)
1031  : context(type_arg, name_arg, parent_arg),
1032  unit_ctx(type_arg, name_arg, parent_arg),
1033  sort(0)
1034  {}
1035 
1036  virtual bool add_join_tab(joinable_ctx *ctx)
1037  {
1038  return join_tabs.push_back(ctx);
1039  }
1040 
1041  virtual void set_sort(sort_ctx *ctx)
1042  {
1043  DBUG_ASSERT(!sort);
1044  sort= ctx;
1045  }
1046 
1052  virtual bool find_and_set_derived(context *subquery);
1053 
1054  virtual bool add_subquery(subquery_list_enum subquery_type,
1055  subquery_ctx *ctx);
1056 protected:
1057  virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj);
1058 
1059 public:
1060  virtual bool format_nested_loop(Opt_trace_context *json);
1061  virtual size_t id(bool hide);
1062  virtual bool cacheable();
1063  virtual bool dependent();
1064  virtual bool add_where_subquery(subquery_ctx *ctx,
1065  SELECT_LEX_UNIT *subquery);
1066 };
1067 
1068 
1105 class sort_ctx : public join_ctx
1106 {
1107  const bool using_tmptable; //< the clause creates temporary table
1108  const bool using_filesort; //< the clause uses filesort
1109 
1110 public:
1111  sort_ctx(Explain_context_enum type_arg, const char *name_arg,
1112  context *parent_arg,
1113  const Explain_format_flags *flags,
1114  Explain_sort_clause clause)
1115  : context(type_arg, name_arg, parent_arg),
1116  join_ctx(type_arg, name_arg, parent_arg),
1117  using_tmptable(flags->get(clause, ESP_USING_TMPTABLE)),
1118  using_filesort(flags->get(clause, ESP_USING_FILESORT))
1119  {}
1120 
1121 protected:
1123  {
1124  DBUG_ASSERT(!sort || join_tabs.is_empty());
1125 
1126  if (using_tmptable)
1127  obj->add(K_USING_TMP_TABLE, true);
1128  if (type != CTX_BUFFER_RESULT)
1129  obj->add(K_USING_FILESORT, using_filesort);
1130 
1131  return join_ctx::format_body(json, obj);
1132  }
1133 };
1134 
1135 
1137 {
1138  const subquery_list_enum subquery_type; //< subquery type for this clause
1139  List<subquery_ctx> subqueries;
1140 
1141 public:
1142  sort_with_subqueries_ctx(Explain_context_enum type_arg, const char *name_arg,
1143  context *parent_arg,
1144  subquery_list_enum subquery_type_arg,
1145  const Explain_format_flags *flags,
1146  Explain_sort_clause clause)
1147  : context(type_arg, name_arg, parent_arg),
1148  sort_ctx(type_arg, name_arg, parent_arg, flags, clause),
1149  subquery_type(subquery_type_arg)
1150  {}
1151 
1152  virtual bool add_subquery(subquery_list_enum subquery_type_arg,
1153  subquery_ctx *ctx)
1154  {
1155  if (subquery_type_arg != subquery_type)
1156  return sort_ctx::add_subquery(subquery_type_arg, ctx);
1157  else
1158  return subqueries.push_back(ctx);
1159  return false;
1160  }
1161 
1162 private:
1163  virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1164  {
1165  return (sort_ctx::format_body(json, obj) ||
1166  format_list(json, subqueries, list_names[subquery_type]));
1167  }
1168 };
1169 
1170 
1172 {
1173  DBUG_ASSERT(subquery->id() != 0);
1174 
1175  if (sort)
1176  return sort->find_and_set_derived(subquery);
1177 
1179  joinable_ctx *t;
1180  while ((t= it++))
1181  {
1182  if (t->find_and_set_derived(subquery))
1183  return true;
1184  }
1185  return false;
1186 }
1187 
1188 
1189 bool join_ctx::add_subquery(subquery_list_enum subquery_type,
1190  subquery_ctx *ctx)
1191 {
1192  if (sort)
1193  return sort->add_subquery(subquery_type, ctx);
1194  if (subquery_type > SQ_toplevel)
1195  {
1197  joinable_ctx *j;
1198  while ((j= it++))
1199  {
1200  switch (j->type) {
1201  case CTX_ORDER_BY:
1202  case CTX_DISTINCT:
1203  case CTX_GROUP_BY:
1204  case CTX_SIMPLE_ORDER_BY:
1205  case CTX_SIMPLE_DISTINCT:
1206  case CTX_SIMPLE_GROUP_BY:
1207  return j->add_subquery(subquery_type, ctx);
1208  case CTX_MESSAGE:
1209  DBUG_ASSERT(subquery_type == SQ_ORDER_BY || subquery_type == SQ_GROUP_BY);
1210  /* As far as CTX_MESSAGE is actually an "optimized out" subquery,
1211  so ORDER/GROUP BY subqueries of such a subquery are "optimized out" as well,
1212  so we can replace ORDER/GROUP BY subquery type to SQ_HOMELESS:
1213  */
1214  return unit_ctx::add_subquery(SQ_HOMELESS, ctx);
1215  default: ;
1216  }
1217  }
1218  DBUG_ASSERT(0);
1219  }
1220  else
1221  return unit_ctx::add_subquery(subquery_type, ctx);
1222  return true;
1223 }
1224 
1225 
1227 {
1228  DBUG_ASSERT(!sort || join_tabs.is_empty());
1229  if (type == CTX_JOIN)
1230  obj->add(K_SELECT_ID, id(true));
1231  if (sort ? sort->format(json) : format_nested_loop(json))
1232  return true;
1233  return format_unit(json);
1234 }
1235 
1236 
1238 {
1239  DBUG_ASSERT(join_tabs.elements > 0);
1240 
1241  /*
1242  For single table skip "nested_loop" object creation and
1243  format its contents only (the 1st join_tab).
1244  */
1245  if (join_tabs.elements == 1)
1246  return join_tabs.head()->format(json);
1247 
1248  Opt_trace_array loops(json, K_NESTED_LOOP);
1249 
1251  joinable_ctx *t;
1252  while ((t= it++))
1253  {
1254  Opt_trace_object anonymous_wrapper(json);
1255  if (t->format(json))
1256  return true;
1257  }
1258  return false;
1259 }
1260 
1261 
1272 template<typename T>
1273 static size_t get_id(List<T> &list, bool hide)
1274 {
1275  if (!hide)
1276  return list.head()->id();
1277 
1278  List_iterator<T> it(list);
1279  T *j;
1280  size_t ret= 0;
1281  while ((j= it++))
1282  ret= j->id(hide);
1283  return ret;
1284 }
1285 
1286 
1287 size_t join_ctx::id(bool hide)
1288 {
1289  return sort ? sort->id(hide) : get_id(join_tabs, hide);
1290 }
1291 
1292 
1293 bool join_ctx::cacheable()
1294 {
1295  return sort ? sort->cacheable() : join_tabs.head()->cacheable();
1296 }
1297 
1298 
1299 bool join_ctx::dependent()
1300 {
1301  return sort ? sort->dependent() : join_tabs.head()->dependent();
1302 }
1303 
1304 
1306  SELECT_LEX_UNIT *subquery)
1307 {
1308  if (sort)
1309  return sort->join_ctx::add_where_subquery(ctx, subquery);
1310 
1312  joinable_ctx *j;
1313  while ((j= it++))
1314  {
1315  if (j->add_where_subquery(ctx, subquery))
1316  return true;
1317  }
1318  return false;
1319 }
1320 
1321 
1326 class materialize_ctx : public joinable_ctx, public join_ctx,
1327  public table_base_ctx
1328 {
1329 public:
1330  explicit materialize_ctx(context *parent_arg)
1331  : context(CTX_MATERIALIZATION, K_TABLE, parent_arg),
1332  joinable_ctx(CTX_MATERIALIZATION, K_TABLE, parent_arg),
1333  join_ctx(CTX_MATERIALIZATION, K_TABLE, parent_arg),
1334  table_base_ctx(CTX_MATERIALIZATION, K_TABLE, parent_arg)
1335  {}
1336 
1337  virtual size_t id(bool hide) { return join_ctx::id(hide); }
1338  virtual bool cacheable() { return join_ctx::cacheable(); }
1339  virtual bool dependent() { return join_ctx::dependent(); }
1340 
1341  // Remove warnings: 'inherits ... from ... via dominance'
1342  virtual qep_row *entry() { return table_base_ctx::entry(); }
1343  virtual bool add_subquery(subquery_list_enum subquery_type, subquery_ctx *ctx)
1344  { return join_ctx::add_subquery(subquery_type, ctx); }
1345  virtual bool add_join_tab(joinable_ctx *ctx)
1346  { return join_ctx::add_join_tab(ctx); }
1347  virtual bool add_where_subquery(subquery_ctx *ctx, SELECT_LEX_UNIT *subquery)
1348  { return join_ctx::add_where_subquery(ctx, subquery); }
1349  virtual bool find_and_set_derived(context *subquery)
1350  { return join_ctx::find_and_set_derived(subquery); }
1351  virtual bool format_unit(Opt_trace_context *json)
1352  { return unit_ctx::format_unit(json); }
1354  { return join_ctx::format_nested_loop(json); }
1355  virtual void set_sort(sort_ctx *ctx)
1356  { return join_ctx::set_sort(ctx); }
1357 
1358 private:
1359  virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1360  {
1361  DBUG_ASSERT(!col_join_type.is_empty());
1362 
1363  if (!col_table_name.is_empty())
1364  obj->add_utf8(K_TABLE_NAME, col_table_name.str);
1365 
1366  obj->add_alnum(K_ACCESS_TYPE, col_join_type.str);
1367 
1368  if (!col_key.is_empty())
1369  obj->add_utf8(K_KEY, col_key.str);
1370 
1371  if (!col_key_len.is_empty())
1372  obj->add_alnum(K_KEY_LENGTH, col_key_len.str);
1373 
1374  add_string_array(json, K_REF, col_ref);
1375 
1376  if (!col_rows.is_empty())
1377  obj->add(K_ROWS, col_rows.value);
1378 
1379  /*
1380  Currently K-REF/col_ref is not shown; it would always be "func", since
1381  {subquery,semijoin} materialization use store_key_item; using
1382  get_store_key() instead would allow "const" and outer column's name,
1383  if applicable.
1384  The looked up expression can anyway be inferred from the condition:
1385  */
1386  if (!col_attached_condition.is_empty())
1387  obj->add_utf8(K_ATTACHED_CONDITION, col_attached_condition.str);
1388  if (format_where(json))
1389  return true;
1390 
1391  Opt_trace_object m(json, K_MATERIALIZED_FROM_SUBQUERY);
1392  obj->add(K_USING_TMP_TABLE, true);
1393  Opt_trace_object q(json, K_QUERY_BLOCK);
1394  return format_nested_loop(json);
1395  }
1396 };
1397 
1398 
1404 {
1405 public:
1406  explicit duplication_weedout_ctx(context *parent_arg)
1407  : context(CTX_DUPLICATES_WEEDOUT, K_DUPLICATES_REMOVAL, parent_arg),
1408  joinable_ctx(CTX_DUPLICATES_WEEDOUT, K_DUPLICATES_REMOVAL, parent_arg),
1409  join_ctx(CTX_DUPLICATES_WEEDOUT, K_DUPLICATES_REMOVAL, parent_arg)
1410  {}
1411 
1412  virtual size_t id(bool hide) { return join_ctx::id(hide); }
1413  virtual bool cacheable() { return join_ctx::cacheable(); }
1414  virtual bool dependent() { return join_ctx::dependent(); }
1415 
1416  // Remove warnings: 'inherits ... from ... via dominance'
1417  virtual bool add_join_tab(joinable_ctx *ctx)
1418  { return join_ctx::add_join_tab(ctx); }
1419  virtual bool add_subquery(subquery_list_enum subquery_type, subquery_ctx *ctx)
1420  { return join_ctx::add_subquery(subquery_type, ctx); }
1421  virtual bool add_where_subquery(subquery_ctx *ctx, SELECT_LEX_UNIT *subquery)
1422  { return join_ctx::add_where_subquery(ctx, subquery); }
1423  virtual bool find_and_set_derived(context *subquery)
1424  { return join_ctx::find_and_set_derived(subquery); }
1426  { return join_ctx::format_nested_loop(json); }
1427  virtual bool format_unit(Opt_trace_context *json)
1428  { return unit_ctx::format_unit(json); }
1429  virtual void set_sort(sort_ctx *ctx)
1430  { return join_ctx::set_sort(ctx); }
1431 
1432 private:
1433  virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1434  {
1435  obj->add(K_USING_TMP_TABLE, true);
1436  return format_nested_loop(json);
1437  }
1438 };
1439 
1440 
1445 class union_ctx : public unit_ctx
1446 {
1447  union_result_ctx *union_result;
1448  List<context> query_specs;
1449 
1450 public:
1451  explicit union_ctx(context * parent_arg)
1452  : context(CTX_UNION, K_QUERY_BLOCK, parent_arg),
1453  unit_ctx(CTX_UNION, K_QUERY_BLOCK, parent_arg),
1454  union_result(NULL)
1455  {}
1456 
1457 private:
1458  virtual bool format_body(Opt_trace_context *json, Opt_trace_object *obj)
1459  {
1460  return union_result->format(json) || format_unit(json);
1461  }
1462 
1463 public:
1464  virtual size_t id(bool hide) { return get_id(query_specs, hide); }
1465  virtual bool cacheable() { return query_specs.head()->cacheable(); }
1466  virtual bool dependent() { return query_specs.head()->dependent(); }
1467 
1469  {
1470  DBUG_ASSERT(union_result == NULL);
1471  union_result= ctx;
1472  union_result->push_down_query_specs(&query_specs);
1473  }
1474  virtual bool add_query_spec(context *ctx)
1475  { return query_specs.push_back(ctx); }
1476 };
1477 
1478 } // namespace
1479 
1480 
1482 {
1483  return current_context->entry();
1484 }
1485 
1486 
1487 bool Explain_format_JSON::begin_context(Explain_context_enum ctx,
1488  SELECT_LEX_UNIT *subquery,
1489  const Explain_format_flags *flags)
1490 {
1491  using namespace opt_explain_json_namespace;
1492 
1493  context *prev_context= current_context;
1494  switch(ctx) {
1495  case CTX_JOIN:
1496  DBUG_ASSERT(current_context == NULL ||
1497  // subqueries:
1498  current_context->type == CTX_SELECT_LIST ||
1499  current_context->type == CTX_UPDATE_VALUE_LIST ||
1500  current_context->type == CTX_DERIVED ||
1501  current_context->type == CTX_OPTIMIZED_AWAY_SUBQUERY ||
1502  current_context->type == CTX_WHERE ||
1503  current_context->type == CTX_HAVING ||
1504  current_context->type == CTX_ORDER_BY_SQ ||
1505  current_context->type == CTX_GROUP_BY_SQ ||
1506  current_context->type == CTX_QUERY_SPEC);
1507  if ((current_context=
1508  new join_ctx(CTX_JOIN, K_QUERY_BLOCK, current_context)) == NULL)
1509  return true;
1510  break;
1511  case CTX_ORDER_BY:
1512  {
1513  DBUG_ASSERT(current_context->type == CTX_JOIN);
1514  sort_ctx *ctx= new sort_with_subqueries_ctx(CTX_ORDER_BY,
1515  K_ORDERING_OPERATION,
1516  current_context,
1517  SQ_ORDER_BY, flags,
1518  ESC_ORDER_BY);
1519  if (ctx == NULL)
1520  return true;
1521  current_context->set_sort(ctx);
1522  current_context= ctx;
1523  break;
1524  }
1525  case CTX_GROUP_BY:
1526  {
1527  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1528  current_context->type == CTX_ORDER_BY ||
1529  current_context->type == CTX_DISTINCT);
1530  sort_ctx *ctx= new sort_with_subqueries_ctx(CTX_GROUP_BY,
1531  K_GROUPING_OPERATION,
1532  current_context,
1533  SQ_GROUP_BY, flags,
1534  ESC_GROUP_BY);
1535  if (ctx == NULL)
1536  return true;
1537  current_context->set_sort(ctx);
1538  current_context= ctx;
1539  break;
1540  }
1541  case CTX_DISTINCT:
1542  {
1543  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1544  current_context->type == CTX_ORDER_BY);
1545  sort_ctx *ctx= new sort_ctx(CTX_DISTINCT, K_DUPLICATES_REMOVAL,
1546  current_context, flags, ESC_DISTINCT);
1547  if (ctx == NULL)
1548  return true;
1549  current_context->set_sort(ctx);
1550  current_context= ctx;
1551  break;
1552  }
1553  case CTX_BUFFER_RESULT:
1554  {
1555  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1556  current_context->type == CTX_ORDER_BY ||
1557  current_context->type == CTX_DISTINCT ||
1558  current_context->type == CTX_GROUP_BY);
1559  sort_ctx *ctx= new sort_ctx(CTX_BUFFER_RESULT, K_BUFFER_RESULT,
1560  current_context, flags, ESC_BUFFER_RESULT);
1561  if (ctx == NULL)
1562  return true;
1563  current_context->set_sort(ctx);
1564  current_context= ctx;
1565  break;
1566  }
1567  case CTX_JOIN_TAB:
1568  {
1569  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1570  current_context->type == CTX_MATERIALIZATION ||
1571  current_context->type == CTX_DUPLICATES_WEEDOUT ||
1572  current_context->type == CTX_GROUP_BY ||
1573  current_context->type == CTX_ORDER_BY ||
1574  current_context->type == CTX_DISTINCT ||
1575  current_context->type == CTX_BUFFER_RESULT ||
1576  current_context->type == CTX_SIMPLE_GROUP_BY ||
1577  current_context->type == CTX_SIMPLE_ORDER_BY ||
1578  current_context->type == CTX_SIMPLE_DISTINCT);
1579  join_tab_ctx *ctx= new join_tab_ctx(CTX_JOIN_TAB, current_context);
1580  if (ctx == NULL || current_context->add_join_tab(ctx))
1581  return true;
1582  current_context= ctx;
1583  break;
1584  }
1585  case CTX_SIMPLE_ORDER_BY:
1586  {
1587  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1588  current_context->type == CTX_MATERIALIZATION ||
1589  current_context->type == CTX_DUPLICATES_WEEDOUT ||
1590  current_context->type == CTX_GROUP_BY ||
1591  current_context->type == CTX_ORDER_BY ||
1592  current_context->type == CTX_BUFFER_RESULT ||
1593  current_context->type == CTX_DISTINCT);
1594  simple_sort_ctx *ctx=
1595  new simple_sort_with_subqueries_ctx(CTX_SIMPLE_ORDER_BY,
1596  K_ORDERING_OPERATION,
1597  current_context, SQ_ORDER_BY, flags,
1598  ESC_ORDER_BY);
1599 
1600  if (ctx == NULL || current_context->add_join_tab(ctx))
1601  return true;
1602  current_context= ctx;
1603  break;
1604  }
1605  case CTX_SIMPLE_GROUP_BY:
1606  {
1607  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1608  current_context->type == CTX_MATERIALIZATION ||
1609  current_context->type == CTX_DUPLICATES_WEEDOUT ||
1610  current_context->type == CTX_GROUP_BY ||
1611  current_context->type == CTX_ORDER_BY ||
1612  current_context->type == CTX_DISTINCT ||
1613  current_context->type == CTX_BUFFER_RESULT ||
1614  current_context->type == CTX_SIMPLE_ORDER_BY ||
1615  current_context->type == CTX_SIMPLE_DISTINCT);
1616  simple_sort_ctx *ctx=
1617  new simple_sort_with_subqueries_ctx(CTX_SIMPLE_GROUP_BY,
1618  K_GROUPING_OPERATION,
1619  current_context, SQ_GROUP_BY, flags,
1620  ESC_GROUP_BY);
1621  if (ctx == NULL || current_context->add_join_tab(ctx))
1622  return true;
1623  current_context= ctx;
1624  break;
1625  }
1626  case CTX_SIMPLE_DISTINCT:
1627  {
1628  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1629  current_context->type == CTX_MATERIALIZATION ||
1630  current_context->type == CTX_DUPLICATES_WEEDOUT ||
1631  current_context->type == CTX_GROUP_BY ||
1632  current_context->type == CTX_ORDER_BY ||
1633  current_context->type == CTX_DISTINCT ||
1634  current_context->type == CTX_BUFFER_RESULT ||
1635  current_context->type == CTX_SIMPLE_ORDER_BY);
1636  simple_sort_ctx *ctx=
1637  new simple_sort_ctx(CTX_SIMPLE_DISTINCT, K_DUPLICATES_REMOVAL,
1638  current_context, flags, ESC_DISTINCT);
1639  if (ctx == NULL || current_context->add_join_tab(ctx))
1640  return true;
1641  current_context= ctx;
1642  break;
1643  }
1644  case CTX_MATERIALIZATION:
1645  {
1646  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1647  current_context->type == CTX_GROUP_BY ||
1648  current_context->type == CTX_ORDER_BY ||
1649  current_context->type == CTX_DISTINCT ||
1650  current_context->type == CTX_BUFFER_RESULT ||
1651  current_context->type == CTX_DUPLICATES_WEEDOUT);
1652  materialize_ctx *ctx= new materialize_ctx(current_context);
1653  if (ctx == NULL || current_context->add_join_tab(ctx))
1654  return true;
1655  current_context= ctx;
1656  break;
1657  }
1658  case CTX_DUPLICATES_WEEDOUT:
1659  {
1660  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1661  current_context->type == CTX_GROUP_BY ||
1662  current_context->type == CTX_ORDER_BY ||
1663  current_context->type == CTX_DISTINCT ||
1664  current_context->type == CTX_BUFFER_RESULT ||
1665  current_context->type == CTX_MATERIALIZATION);
1667  new duplication_weedout_ctx(current_context);
1668  if (ctx == NULL || current_context->add_join_tab(ctx))
1669  return true;
1670  current_context= ctx;
1671  break;
1672  }
1673  case CTX_SELECT_LIST:
1674  {
1675  subquery_ctx *ctx= new subquery_ctx(CTX_SELECT_LIST, NULL,
1676  current_context);
1677  if (ctx == NULL ||
1678  current_context->add_subquery(SQ_SELECT_LIST, ctx))
1679  return true;
1680  current_context= ctx;
1681  break;
1682  }
1683  case CTX_UPDATE_VALUE_LIST:
1684  {
1685  subquery_ctx *ctx= new subquery_ctx(CTX_UPDATE_VALUE_LIST, NULL,
1686  current_context);
1687  if (ctx == NULL ||
1688  current_context->add_subquery(SQ_UPDATE_VALUE, ctx))
1689  return true;
1690  current_context= ctx;
1691  break;
1692  }
1693  case CTX_DERIVED:
1694  {
1695  current_context= new subquery_ctx(CTX_DERIVED,
1696  K_MATERIALIZED_FROM_SUBQUERY,
1697  current_context);
1698  if (current_context == NULL)
1699  return true;
1700  break;
1701  }
1702  case CTX_OPTIMIZED_AWAY_SUBQUERY:
1703  {
1704  subquery_ctx *ctx= new subquery_ctx(CTX_OPTIMIZED_AWAY_SUBQUERY, NULL,
1705  current_context);
1706  if (ctx == NULL || current_context->add_subquery(SQ_HOMELESS, ctx))
1707  return true;
1708  current_context= ctx;
1709  break;
1710  }
1711  case CTX_WHERE:
1712  {
1713  DBUG_ASSERT(subquery != NULL);
1714  subquery_ctx *ctx= new subquery_ctx(CTX_WHERE, NULL, current_context);
1715  if (ctx == NULL ||
1716  current_context->add_where_subquery(ctx, subquery))
1717  return true;
1718  current_context= ctx;
1719  break;
1720  }
1721  case CTX_HAVING:
1722  {
1723  subquery_ctx *ctx= new subquery_ctx(CTX_HAVING, NULL, current_context);
1724  if (ctx == NULL || current_context->add_subquery(SQ_HAVING, ctx))
1725  return true;
1726  current_context= ctx;
1727  break;
1728  }
1729  case CTX_ORDER_BY_SQ:
1730  {
1731  subquery_ctx *ctx= new subquery_ctx(CTX_ORDER_BY_SQ, NULL,
1732  current_context);
1733  if (ctx == NULL || current_context->add_subquery(SQ_ORDER_BY, ctx))
1734  return true;
1735  current_context= ctx;
1736  break;
1737  }
1738  case CTX_GROUP_BY_SQ:
1739  {
1740  subquery_ctx *ctx= new subquery_ctx(CTX_GROUP_BY_SQ, NULL,
1741  current_context);
1742  if (ctx == NULL || current_context->add_subquery(SQ_GROUP_BY, ctx))
1743  return true;
1744  current_context= ctx;
1745  break;
1746  }
1747  case CTX_UNION:
1748  DBUG_ASSERT(current_context == NULL ||
1749  // subqueries:
1750  current_context->type == CTX_SELECT_LIST ||
1751  current_context->type == CTX_UPDATE_VALUE_LIST ||
1752  current_context->type == CTX_DERIVED ||
1753  current_context->type == CTX_OPTIMIZED_AWAY_SUBQUERY ||
1754  current_context->type == CTX_WHERE ||
1755  current_context->type == CTX_HAVING ||
1756  current_context->type == CTX_ORDER_BY_SQ ||
1757  current_context->type == CTX_GROUP_BY_SQ ||
1758  current_context->type == CTX_QUERY_SPEC);
1759  current_context= new union_ctx(current_context);
1760  if (current_context == NULL)
1761  return true;
1762  break;
1763  case CTX_UNION_RESULT:
1764  {
1765  DBUG_ASSERT(current_context->type == CTX_UNION);
1766  union_result_ctx *ctx= new union_result_ctx(current_context);
1767  if (ctx == NULL)
1768  return true;
1769  current_context->set_union_result(ctx);
1770  current_context= ctx;
1771  break;
1772  }
1773  case CTX_QUERY_SPEC:
1774  {
1775  DBUG_ASSERT(current_context->type == CTX_UNION);
1776  subquery_ctx *ctx= new subquery_ctx(CTX_QUERY_SPEC, NULL,
1777  current_context);
1778  if (ctx == NULL || current_context->add_query_spec(ctx))
1779  return true;
1780  current_context= ctx;
1781  break;
1782  }
1783  case CTX_MESSAGE:
1784  {
1785  /*
1786  Like CTX_JOIN_TAB:
1787  */
1788  DBUG_ASSERT(current_context->type == CTX_JOIN ||
1789  current_context->type == CTX_MATERIALIZATION ||
1790  current_context->type == CTX_DUPLICATES_WEEDOUT ||
1791  current_context->type == CTX_GROUP_BY ||
1792  current_context->type == CTX_ORDER_BY ||
1793  current_context->type == CTX_DISTINCT ||
1794  current_context->type == CTX_BUFFER_RESULT ||
1795  current_context->type == CTX_SIMPLE_GROUP_BY ||
1796  current_context->type == CTX_SIMPLE_ORDER_BY ||
1797  current_context->type == CTX_SIMPLE_DISTINCT);
1798  joinable_ctx *ctx= new message_ctx(current_context);
1799  if (ctx == NULL || current_context->add_join_tab(ctx))
1800  return true;
1801  current_context= ctx;
1802  break;
1803  }
1804  default:
1805  DBUG_ASSERT(!"Unknown EXPLAIN context!");
1806  return true;
1807  }
1808 
1809  if (prev_context)
1810  prev_context->set_child(current_context);
1811 
1812  return false;
1813 }
1814 
1815 
1816 bool Explain_format_JSON::end_context(Explain_context_enum ctx)
1817 {
1818  DBUG_ASSERT(current_context->type == ctx);
1819 
1820  bool ret= false;
1821  if (current_context->parent == NULL)
1822  {
1823  Item* item;
1824 #ifdef OPTIMIZER_TRACE
1825  Opt_trace_context json;
1826  const size_t max_size= ULONG_MAX;
1827  if (json.start(true, // support_I_S (enable JSON generation)
1828  false, // support_dbug_or_missing_priv
1829  current_thd->variables.end_markers_in_json, // end_marker
1830  false, // one_line
1831  0, // offset
1832  1, // limit
1833  max_size, // max_mem_size
1834  Opt_trace_context::MISC))
1835  return true;
1836 
1837  {
1838  Opt_trace_object braces(&json);
1839 
1840  if (current_context->format(&json))
1841  return true;
1842  }
1843  json.end();
1844 
1845  Opt_trace_iterator it(&json);
1846  if (!it.at_end())
1847  {
1848  Opt_trace_info info;
1849  it.get_value(&info);
1850  item= new Item_string(info.trace_ptr,
1851  static_cast<uint>(info.trace_length),
1852  system_charset_info);
1853  }
1854  else
1855 #endif
1856  item= new Item_null();
1857 
1858  List<Item> field_list;
1859  ret= (item == NULL ||
1860  field_list.push_back(item) ||
1861  output->send_data(field_list));
1862  }
1863  else if (ctx == CTX_DERIVED)
1864  {
1865  if (!current_context->parent->find_and_set_derived(current_context))
1866  {
1867  DBUG_ASSERT(!"No derived table found!");
1868  return true;
1869  }
1870  }
1871 
1872  current_context= current_context->parent;
1873  return ret;
1874 }
1875 
1876 
1877 bool Explain_format_JSON::send_headers(select_result *result)
1878 {
1879  output= result;
1880  if (Explain_format::send_headers(result))
1881  return true;
1882 
1883  List<Item> field_list;
1884  Item *item= new Item_empty_string("EXPLAIN", 78, system_charset_info);
1885  if (item == NULL || field_list.push_back(item))
1886  return true;
1887  return result->send_result_set_metadata(field_list,
1888  Protocol::SEND_NUM_ROWS |
1889  Protocol::SEND_EOF);
1890 }
1891