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