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