[Commits] d5fbfb9: EXPLAIN FORMAT=JSON: Add support for single-table UPDATE/DELETE.

Sergei Petrunia psergey at askmonty.org
Fri Nov 28 01:36:31 EET 2014


revision-id: d5fbfb9a93704ebe4b1df37f74850a7464140991
parent(s): 461dbd80d2ea96034f330dd238282d2167ed2c4d
committer: Sergei Petrunia
branch nick: 10.1-explain-json-r5
timestamp: 2014-11-28 02:36:31 +0300
message:

EXPLAIN FORMAT=JSON: Add support for single-table UPDATE/DELETE.

---
 mysql-test/r/explain_json.result |   59 ++++++-
 mysql-test/t/explain_json.test   |   10 ++
 sql/sql_delete.cc                |   26 ++--
 sql/sql_explain.cc               |  313 +++++++++++++++++++++++++++++++++++---
 sql/sql_explain.h                |   35 +++--
 sql/sql_lex.h                    |    7 +-
 sql/sql_select.cc                |  132 +---------------
 sql/sql_select.h                 |   20 +--
 sql/sql_update.cc                |    4 +-
 9 files changed, 409 insertions(+), 197 deletions(-)

diff --git a/mysql-test/r/explain_json.result b/mysql-test/r/explain_json.result
index ec775c8..fff80d9 100644
--- a/mysql-test/r/explain_json.result
+++ b/mysql-test/r/explain_json.result
@@ -199,7 +199,7 @@ EXPLAIN
         },
         {
           "query_block": {
-            "select_id": 1,
+            "select_id": 2,
             "table": {
               "table_name": "B",
               "access_type": "ALL",
@@ -233,7 +233,7 @@ EXPLAIN
         },
         {
           "query_block": {
-            "select_id": 1,
+            "select_id": 2,
             "table": {
               "table_name": "B",
               "access_type": "ALL",
@@ -265,7 +265,7 @@ EXPLAIN
     "subqueries": [
       {
         "query_block": {
-          "select_id": 1,
+          "select_id": 2,
           "table": {
             "table_name": "t1",
             "access_type": "ALL",
@@ -295,7 +295,7 @@ EXPLAIN
     "subqueries": [
       {
         "query_block": {
-          "select_id": 1,
+          "select_id": 2,
           "table": {
             "table_name": "t1",
             "access_type": "ALL",
@@ -342,4 +342,55 @@ EXPLAIN
   }
 }
 drop table t1;
+#
+# Single-table UPDATE/DELETE
+#
+explain format=json delete from t0;
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "message": "Deleting all rows"
+    }
+  }
+}
+explain format=json delete from t0 where 1 > 2;
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "message": "Impossible WHERE"
+    }
+  }
+}
+explain format=json delete from t0 where a < 3;
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "delete": 1,
+      "table_name": "t0",
+      "access_type": "ALL",
+      "rows": 10,
+      "attached_condition": "(t0.a < 3)"
+    }
+  }
+}
+explain format=json update t0 set a=3 where a in (2,3,4);
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "update": 1,
+      "table_name": "t0",
+      "access_type": "ALL",
+      "rows": 10,
+      "attached_condition": "(t0.a in (2,3,4))"
+    }
+  }
+}
 drop table t0;
diff --git a/mysql-test/t/explain_json.test b/mysql-test/t/explain_json.test
index 6dc54f1..6a58796 100644
--- a/mysql-test/t/explain_json.test
+++ b/mysql-test/t/explain_json.test
@@ -70,5 +70,15 @@ select * from t1 A, t1 B where A.a=B.a and A.b < 3 and B.b < 5;
 
 drop table t1;
 
+--echo #
+--echo # Single-table UPDATE/DELETE
+--echo #
+explain format=json delete from t0;
+explain format=json delete from t0 where 1 > 2;
+
+explain format=json delete from t0 where a < 3;
+
+explain format=json update t0 set a=3 where a in (2,3,4);
+
 drop table t0;
 
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index da2f7b1..a4d88b5 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -51,7 +51,7 @@
     invoked on a running DELETE statement.
 */
 
-void Delete_plan::save_explain_data(Explain_query *query)
+void Delete_plan::save_explain_data(MEM_ROOT *mem_root, Explain_query *query)
 {
   Explain_delete* explain= new Explain_delete;
 
@@ -64,22 +64,23 @@ void Delete_plan::save_explain_data(Explain_query *query)
   else
   {
     explain->deleting_all_rows= false;
-    Update_plan::save_explain_data_intern(query, explain);
+    Update_plan::save_explain_data_intern(mem_root, query, explain);
   }
  
   query->add_upd_del_plan(explain);
 }
 
 
-void Update_plan::save_explain_data(Explain_query *query)
+void Update_plan::save_explain_data(MEM_ROOT *mem_root, Explain_query *query)
 {
   Explain_update* explain= new Explain_update;
-  save_explain_data_intern(query, explain);
+  save_explain_data_intern(mem_root, query, explain);
   query->add_upd_del_plan(explain);
 }
 
 
-void Update_plan::save_explain_data_intern(Explain_query *query, 
+void Update_plan::save_explain_data_intern(MEM_ROOT *mem_root,
+                                           Explain_query *query, 
                                            Explain_update *explain)
 {
   explain->select_type= "SIMPLE";
@@ -141,10 +142,12 @@ void Update_plan::save_explain_data_intern(Explain_query *query,
   }
 
   explain->using_where= MY_TEST(select && select->cond);
+  explain->where_cond= select? select->cond: NULL;
   explain->using_filesort= using_filesort;
   explain->using_io_buffer= using_io_buffer;
 
-  make_possible_keys_line(table, possible_keys, &explain->possible_keys_line);
+  append_possible_keys(mem_root, explain->possible_keys, table, 
+                       possible_keys);
 
   explain->quick_info= NULL;
 
@@ -157,11 +160,8 @@ void Update_plan::save_explain_data_intern(Explain_query *query,
   {
     if (index != MAX_KEY)
     {
-      explain->key_str.append(table->key_info[index].name);
-      char buf[64];
-      size_t length;
-      length= longlong10_to_str(table->key_info[index].key_length, buf, 10) - buf;
-      explain->key_len_str.append(buf, length);
+      explain->key.set(mem_root, &table->key_info[index],
+                       table->key_info[index].key_length);
     }
   }
   explain->rows= scanned_rows;
@@ -460,7 +460,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
   if (thd->lex->describe)
     goto produce_explain_and_leave;
   
-  query_plan.save_explain_data(thd->lex->explain);
+  query_plan.save_explain_data(thd->mem_root, thd->lex->explain);
 
   DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start", 
                   dbug_serve_apcs(thd, 1););
@@ -698,7 +698,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
     We come here for various "degenerate" query plans: impossible WHERE,
     no-partitions-used, impossible-range, etc.
   */
-  query_plan.save_explain_data(thd->lex->explain);
+  query_plan.save_explain_data(thd->mem_root, thd->lex->explain);
 
 send_nothing_and_leave:
   /* 
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index a37d324..f8a45b5 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -22,6 +22,10 @@
 #include "sql_select.h"
 #include "my_json_writer.h"
 
+const char * STR_DELETING_ALL_ROWS= "Deleting all rows";
+const char * STR_IMPOSSIBLE_WHERE= "Impossible WHERE";
+const char * STR_NO_ROWS_AFTER_PRUNING= "No matching rows after partition pruning";
+
 Explain_query::Explain_query(THD *thd_arg) : 
   upd_del_plan(NULL), insert_plan(NULL), thd(thd_arg), apc_enabled(false)
 {
@@ -188,10 +192,7 @@ void Explain_query::print_explain_json(select_result_sink *output, bool is_analy
   writer.start_object();
 
   if (upd_del_plan)
-  {
-    //upd_del_plan->print_explain(this, output, explain_flags, is_analyze);
-    DBUG_ASSERT(0);
-  }
+    upd_del_plan->print_explain_json(this, &writer, is_analyze);
   else if (insert_plan)
   {
     //insert_plan->print_explain(this, output, explain_flags, is_analyze);
@@ -270,6 +271,120 @@ static void push_string_list(List<Item> *item_list, String_list &lines,
 }
 
 
+/*
+  Print an EXPLAIN output row, based on information provided in the parameters
+
+  @note
+    Parameters that may have NULL value in EXPLAIN output, should be passed
+    (char*)NULL.
+
+  @return 
+    0  - OK
+    1  - OOM Error
+*/
+
+static
+int print_explain_row(select_result_sink *result,
+                      uint8 options, bool is_analyze,
+                      uint select_number,
+                      const char *select_type,
+                      const char *table_name,
+                      const char *partitions,
+                      enum join_type jtype,
+                      String_list *possible_keys,
+                      const char *index,
+                      const char *key_len,
+                      const char *ref,
+                      ha_rows *rows,
+                      ha_rows *r_rows,
+                      double r_filtered,
+                      const char *extra)
+{
+  Item *item_null= new Item_null();
+  List<Item> item_list;
+  Item *item;
+
+  item_list.push_back(new Item_int((int32) select_number));
+  item_list.push_back(new Item_string_sys(select_type));
+  item_list.push_back(new Item_string_sys(table_name));
+  if (options & DESCRIBE_PARTITIONS)
+  {
+    if (partitions)
+    {
+      item_list.push_back(new Item_string_sys(partitions));
+    }
+    else
+      item_list.push_back(item_null);
+  }
+  
+  const char *jtype_str= join_type_str[jtype];
+  item_list.push_back(new Item_string_sys(jtype_str));
+  
+  /* 'possible_keys' */
+  if (possible_keys && !possible_keys->is_empty())
+  {
+    StringBuffer<64> possible_keys_buf;
+    push_string_list(&item_list, *possible_keys, &possible_keys_buf);
+  }
+  else
+    item_list.push_back(item_null);
+  
+  /* 'index */
+  item= index ? new Item_string_sys(index) : item_null;
+  item_list.push_back(item);
+  
+  /* 'key_len */
+  item= key_len ? new Item_string_sys(key_len) : item_null;
+  item_list.push_back(item);
+  
+  /* 'ref' */
+  item= ref ? new Item_string_sys(ref) : item_null;
+  item_list.push_back(item);
+
+  /* 'rows' */
+  if (rows)
+  {
+    item_list.push_back(new Item_int(*rows, 
+                                     MY_INT64_NUM_DECIMAL_DIGITS));
+  }
+  else
+    item_list.push_back(item_null);
+  
+  /* 'r_rows' */
+  if (is_analyze)
+  {
+    if (r_rows)
+    {
+      item_list.push_back(new Item_int(*r_rows, 
+                                       MY_INT64_NUM_DECIMAL_DIGITS));
+    }
+    else
+      item_list.push_back(item_null);
+  }
+
+  /* 'filtered' */
+  const double filtered=100.0;
+  if (options & DESCRIBE_EXTENDED || is_analyze)
+    item_list.push_back(new Item_float(filtered, 2));
+  
+  /* 'r_filtered' */
+  if (is_analyze)
+    item_list.push_back(new Item_float(r_filtered, 2));
+  
+  /* 'Extra' */
+  if (extra)
+    item_list.push_back(new Item_string_sys(extra));
+  else
+    item_list.push_back(item_null);
+
+  if (result->send_data(item_list))
+    return 1;
+  return 0;
+}
+
+
+
+
 uint Explain_union::make_union_table_name(char *buf)
 {
   uint childno= 0;
@@ -538,7 +653,7 @@ void Explain_select::print_explain_json(Explain_query *query,
   Json_writer_nesting_guard guard(writer);
 
   writer->add_member("query_block").start_object();
-  writer->add_member("select_id").add_ll(1);
+  writer->add_member("select_id").add_ll(select_id);
   if (message)
   {
     writer->add_member("table").start_object();
@@ -565,7 +680,15 @@ void Explain_table_access::push_extra(enum explain_extra_tag extra_tag)
 }
 
 
-void Explain_table_access::fill_key_str(String *key_str, bool is_json)
+/*
+  Put the contents of 'key' field of EXPLAIN otuput into key_str.
+
+  It is surprisingly complex:
+  - hash join shows #hash#used_key
+  - quick selects that use single index will print index name
+*/
+
+void Explain_table_access::fill_key_str(String *key_str, bool is_json) const
 {
   const CHARSET_INFO *cs= system_charset_info;
   bool is_hj= (type == JT_HASH || type == JT_HASH_NEXT || 
@@ -607,7 +730,7 @@ void Explain_table_access::fill_key_str(String *key_str, bool is_json)
   the column legacy, it is superceded by used_key_parts.
 */
 
-void Explain_table_access::fill_key_len_str(String *key_len_str)
+void Explain_table_access::fill_key_len_str(String *key_len_str) const
 {
   bool is_hj= (type == JT_HASH || type == JT_HASH_NEXT || 
                type == JT_HASH_RANGE || type == JT_HASH_INDEX_MERGE);
@@ -996,9 +1119,6 @@ void Explain_table_access::print_explain_json(Json_writer *writer,
     writer->end_object();
   }
   
-
-  // TODO: here, if quick select is not basic, print its nested form.
-  
   /* `ref` */
   if (!ref_list.is_empty())
   {
@@ -1320,7 +1440,7 @@ int Explain_delete::print_explain(Explain_query *query,
 {
   if (deleting_all_rows)
   {
-    const char *msg= "Deleting all rows";
+    const char *msg= STR_DELETING_ALL_ROWS;
     int res= print_explain_message_line(output, explain_flags, is_analyze,
                                         1 /*select number*/,
                                         select_type, &rows, msg);
@@ -1335,6 +1455,27 @@ int Explain_delete::print_explain(Explain_query *query,
 }
 
 
+void Explain_delete::print_explain_json(Explain_query *query, 
+                                        Json_writer *writer,
+                                        bool is_analyze)
+{
+  Json_writer_nesting_guard guard(writer);
+
+  if (deleting_all_rows)
+  {
+    writer->add_member("query_block").start_object();
+    writer->add_member("select_id").add_ll(1);
+    writer->add_member("table").start_object();
+    // just like mysql-5.6, we don't print table name. Is this ok?
+    writer->add_member("message").add_str(STR_DELETING_ALL_ROWS);
+    writer->end_object(); // table
+    writer->end_object(); // query_block
+    return;
+  }
+  Explain_update::print_explain_json(query, writer, is_analyze);
+}
+
+
 int Explain_update::print_explain(Explain_query *query, 
                                   select_result_sink *output,
                                   uint8 explain_flags,
@@ -1346,8 +1487,8 @@ int Explain_update::print_explain(Explain_query *query,
   if (impossible_where || no_partitions)
   {
     const char *msg= impossible_where ? 
-                     "Impossible WHERE" : 
-                     "No matching rows after partition pruning";
+                     STR_IMPOSSIBLE_WHERE : 
+                     STR_NO_ROWS_AFTER_PRUNING;
     int res= print_explain_message_line(output, explain_flags, is_analyze,
                                         1 /*select number*/,
                                         select_type, 
@@ -1356,7 +1497,6 @@ int Explain_update::print_explain(Explain_query *query,
     return res;
   }
 
-  
   if (quick_info)
   {
     quick_info->print_key(&key_buf);
@@ -1370,10 +1510,13 @@ int Explain_update::print_explain(Explain_query *query,
       extra_str.append(quick_buf);
     }
   }
-  else
+  else if (key.get_key_name())
   {
-    key_buf.copy(key_str);
-    key_len_buf.copy(key_len_str);
+    const char *name= key.get_key_name();
+    key_buf.set(name, strlen(name), &my_charset_bin);
+    char buf[64];
+    size_t length= longlong10_to_str(key.get_key_len(), buf, 10) - buf;
+    key_len_buf.copy(buf, length, &my_charset_bin);
   }
 
   if (using_where)
@@ -1417,7 +1560,7 @@ int Explain_update::print_explain(Explain_query *query,
                     table_name.c_ptr(), 
                     used_partitions_set? used_partitions.c_ptr() : NULL,
                     jtype,
-                    possible_keys_line.length()? possible_keys_line.c_ptr(): NULL,
+                    &possible_keys,
                     key_buf.length()? key_buf.c_ptr() : NULL,
                     key_len_buf.length() ? key_len_buf.c_ptr() : NULL,
                     NULL, /* 'ref' is always NULL in single-table EXPLAIN DELETE */
@@ -1430,6 +1573,140 @@ int Explain_update::print_explain(Explain_query *query,
 }
 
 
+void Explain_update::print_explain_json(Explain_query *query,
+                                        Json_writer *writer,
+                                        bool is_analyze)
+{
+  Json_writer_nesting_guard guard(writer);
+
+  writer->add_member("query_block").start_object();
+  writer->add_member("select_id").add_ll(1);
+
+  if (impossible_where || no_partitions)
+  {
+    const char *msg= impossible_where ?  STR_IMPOSSIBLE_WHERE : 
+                                         STR_NO_ROWS_AFTER_PRUNING;
+    writer->add_member("table").start_object();
+    writer->add_member("message").add_str(msg);
+    writer->end_object(); // table
+    writer->end_object(); // query_block
+    return;
+  }
+
+  writer->add_member("table").start_object();
+
+  if (get_type() == EXPLAIN_UPDATE)
+    writer->add_member("update").add_ll(1);
+  else
+    writer->add_member("delete").add_ll(1);
+
+  writer->add_member("table_name").add_str(table_name);
+  writer->add_member("access_type").add_str(join_type_str[jtype]);
+
+  if (!possible_keys.is_empty())
+  {
+    List_iterator_fast<char> it(possible_keys);
+    const char *name;
+    writer->add_member("possible_keys").start_array();
+    while ((name= it++))
+      writer->add_str(name);
+    writer->end_array();
+  }
+
+  /* `key`, `key_length` */
+  if (quick_info && quick_info->is_basic())
+  {
+    StringBuffer<64> key_buf;
+    StringBuffer<64> key_len_buf;
+    quick_info->print_extra_recursive(&key_buf);
+    quick_info->print_key_len(&key_len_buf);
+    
+    writer->add_member("key").add_str(key_buf);
+    writer->add_member("key_length").add_str(key_len_buf);
+  }
+  else if (key.get_key_name())
+  {
+    writer->add_member("key").add_str(key.get_key_name());
+    writer->add_member("key_length").add_str(key.get_key_len());
+  }
+
+  /* `used_key_parts` */
+  String_list *parts_list= NULL;
+  if (quick_info && quick_info->is_basic())
+    parts_list= &quick_info->range.key_parts_list;
+  else
+    parts_list= &key.key_parts_list;
+
+  if (parts_list && !parts_list->is_empty())
+  {
+    List_iterator_fast<char> it(*parts_list);
+    const char *name;
+    writer->add_member("used_key_parts").start_array();
+    while ((name= it++))
+      writer->add_str(name);
+    writer->end_array();
+  }
+
+  if (quick_info && !quick_info->is_basic())
+  {
+    writer->add_member("index_merge").start_object();
+    quick_info->print_json(writer);
+    writer->end_object();
+  }
+  
+#if 0
+  /* `ref` */
+  if (!ref_list.is_empty())
+  {
+    List_iterator_fast<char> it(ref_list);
+    const char *str;
+    writer->add_member("ref").start_array();
+    while ((str= it++))
+      writer->add_str(str);
+    writer->end_array();
+  }
+#endif
+
+  /* `rows` */
+  writer->add_member("rows").add_ll(rows);
+
+  /* `r_rows` */
+  if (is_analyze && tracker.has_scans())
+  {
+    ha_rows avg_rows= tracker.get_avg_rows();
+    writer->add_member("r_rows").add_ll(avg_rows);
+  }
+ 
+  /* UPDATE/DELETE do not produce `filtered` estimate */
+
+  /* `r_filtered` */
+  if (is_analyze)
+  {
+    double r_filtered= tracker.get_filtered_after_where();
+    writer->add_member("r_filtered").add_double(r_filtered);
+  }
+
+  if (mrr_type.length() != 0)
+    writer->add_member("mrr_type").add_str(mrr_type.ptr());
+  
+  if (using_filesort)
+    writer->add_member("using_filesort").add_ll(1);
+
+  if (using_io_buffer)
+    writer->add_member("using_io_buffer").add_ll(1);
+
+  if (where_cond)
+  {
+    writer->add_member("attached_condition");
+    write_item(writer, where_cond);
+  }
+
+  writer->end_object(); // table
+  print_explain_json_for_children(query, writer, is_analyze);
+  writer->end_object(); // query_block
+}
+
+
 int Explain_insert::print_explain(Explain_query *query, 
                                   select_result_sink *output, 
                                   uint8 explain_flags,
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index 6cc8e01..5fd1d5e 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -432,6 +432,11 @@ class Explain_index_use : public Sql_alloc
 public:
   String_list key_parts_list;
   
+  Explain_index_use()
+  {
+    clear();
+  }
+
   void clear()
   {
     key_name= NULL;
@@ -440,8 +445,8 @@ class Explain_index_use : public Sql_alloc
   void set(MEM_ROOT *root, KEY *key_name, uint key_len_arg);
   void set_pseudo_key(MEM_ROOT *root, const char *key_name);
 
-  inline const char *get_key_name() { return key_name; }
-  inline uint get_key_len() { return key_len; }
+  inline const char *get_key_name() const { return key_name; }
+  inline uint get_key_len() const { return key_len; }
 };
 
 
@@ -584,8 +589,8 @@ class Explain_table_access : public Sql_alloc
 
 private:
   void append_tag_name(String *str, enum explain_extra_tag tag);
-  void fill_key_str(String *key_str, bool is_json);
-  void fill_key_len_str(String *key_len_str);
+  void fill_key_str(String *key_str, bool is_json) const;
+  void fill_key_len_str(String *key_len_str) const;
   double get_r_filtered();
   void tag_to_json(Json_writer *writer, enum explain_extra_tag tag);
 };
@@ -614,14 +619,22 @@ class Explain_update : public Explain_node
   StringBuffer<64> table_name;
 
   enum join_type jtype;
-  StringBuffer<128> possible_keys_line;
-  StringBuffer<128> key_str;
-  StringBuffer<128> key_len_str;
+  String_list possible_keys;
+
+  /* Used key when doing a full index scan (possibly with limit) */
+  Explain_index_use key;
+
+  /* 
+    MRR that's used with quick select. This should probably belong to the
+    quick select
+  */
   StringBuffer<64> mrr_type;
   
   Explain_quick_select *quick_info;
 
   bool using_where;
+  Item *where_cond;
+
   ha_rows rows;
 
   bool using_filesort;
@@ -632,8 +645,8 @@ class Explain_update : public Explain_node
 
   virtual int print_explain(Explain_query *query, select_result_sink *output, 
                             uint8 explain_flags, bool is_analyze);
-  virtual void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze)
-  { /* EXPLAIN_JSON_NOT_IMPL */}
+  virtual void print_explain_json(Explain_query *query, Json_writer *writer,
+                                  bool is_analyze);
 };
 
 
@@ -678,8 +691,8 @@ class Explain_delete: public Explain_update
 
   virtual int print_explain(Explain_query *query, select_result_sink *output, 
                             uint8 explain_flags, bool is_analyze);
-  virtual void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze)
-  { /* EXPLAIN_JSON_NOT_IMPL */}
+  virtual void print_explain_json(Explain_query *query, Json_writer *writer,
+                                  bool is_analyze);
 };
 
 
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 7910943..b9546d71 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2303,8 +2303,9 @@ class Update_plan
   void set_impossible_where() { impossible_where= true; }
   void set_no_partitions() { no_partitions= true; }
 
-  void save_explain_data(Explain_query *query);
-  void save_explain_data_intern(Explain_query *query, Explain_update *eu);
+  void save_explain_data(MEM_ROOT *mem_root, Explain_query *query);
+  void save_explain_data_intern(MEM_ROOT *mem_root, Explain_query *query,
+                                Explain_update *eu);
 
   virtual ~Update_plan() {}
 
@@ -2335,7 +2336,7 @@ class Delete_plan : public Update_plan
     scanned_rows= rows_arg;
   }
 
-  void save_explain_data(Explain_query *query);
+  void save_explain_data(MEM_ROOT *mem_root, Explain_query *query);
 };
 
 
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 185c092..f66525d 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -23126,135 +23126,7 @@ int print_explain_message_line(select_result_sink *result,
   return 0;
 }
 
-
-/*
-  Make a comma-separated list of possible_keys names and add it into the string
-*/ 
-
-void make_possible_keys_line(TABLE *table, key_map possible_keys, String *line)
-{
-  if (!possible_keys.is_clear_all())
-  {
-    uint j;
-    for (j=0 ; j < table->s->keys ; j++)
-    {
-      if (possible_keys.is_set(j))
-      {
-        if (line->length())
-          line->append(',');
-        line->append(table->key_info[j].name, 
-                     strlen(table->key_info[j].name),
-                     system_charset_info);
-      }
-    }
-  }
-}
-
-/*
-  Print an EXPLAIN output row, based on information provided in the parameters
-
-  @note
-    Parameters that may have NULL value in EXPLAIN output, should be passed
-    (char*)NULL.
-
-  @return 
-    0  - OK
-    1  - OOM Error
-*/
-
-int print_explain_row(select_result_sink *result,
-                      uint8 options, bool is_analyze,
-                      uint select_number,
-                      const char *select_type,
-                      const char *table_name,
-                      const char *partitions,
-                      enum join_type jtype,
-                      const char *possible_keys,
-                      const char *index,
-                      const char *key_len,
-                      const char *ref,
-                      ha_rows *rows,
-                      ha_rows *r_rows,
-                      double r_filtered,
-                      const char *extra)
-{
-  Item *item_null= new Item_null();
-  List<Item> item_list;
-  Item *item;
-
-  item_list.push_back(new Item_int((int32) select_number));
-  item_list.push_back(new Item_string_sys(select_type));
-  item_list.push_back(new Item_string_sys(table_name));
-  if (options & DESCRIBE_PARTITIONS)
-  {
-    if (partitions)
-    {
-      item_list.push_back(new Item_string_sys(partitions));
-    }
-    else
-      item_list.push_back(item_null);
-  }
-  
-  const char *jtype_str= join_type_str[jtype];
-  item_list.push_back(new Item_string_sys(jtype_str));
-  
-  item= possible_keys? new Item_string_sys(possible_keys) : item_null;
-  item_list.push_back(item);
-  
-  /* 'index */
-  item= index ? new Item_string_sys(index) : item_null;
-  item_list.push_back(item);
-  
-  /* 'key_len */
-  item= key_len ? new Item_string_sys(key_len) : item_null;
-  item_list.push_back(item);
-  
-  /* 'ref' */
-  item= ref ? new Item_string_sys(ref) : item_null;
-  item_list.push_back(item);
-
-  /* 'rows' */
-  if (rows)
-  {
-    item_list.push_back(new Item_int(*rows, 
-                                     MY_INT64_NUM_DECIMAL_DIGITS));
-  }
-  else
-    item_list.push_back(item_null);
-  
-  /* 'r_rows' */
-  if (is_analyze)
-  {
-    if (r_rows)
-    {
-      item_list.push_back(new Item_int(*r_rows, 
-                                       MY_INT64_NUM_DECIMAL_DIGITS));
-    }
-    else
-      item_list.push_back(item_null);
-  }
-
-  /* 'filtered' */
-  const double filtered=100.0;
-  if (options & DESCRIBE_EXTENDED || is_analyze)
-    item_list.push_back(new Item_float(filtered, 2));
-  
-  /* 'r_filtered' */
-  if (is_analyze)
-    item_list.push_back(new Item_float(r_filtered, 2));
-  
-  /* 'Extra' */
-  if (extra)
-    item_list.push_back(new Item_string_sys(extra));
-  else
-    item_list.push_back(item_null);
-
-  if (result->send_data(item_list))
-    return 1;
-  return 0;
-}
-
-
+#if 0
 int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly,
                                SELECT_LEX *select_lex, uint8 explain_flags)
 {
@@ -23327,7 +23199,7 @@ int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly,
     return 1;
   return 0;
 }
-
+#endif
 
 /*
   Append MRR information from quick select to the given string
diff --git a/sql/sql_select.h b/sql/sql_select.h
index ac1ea05..9463005 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1832,8 +1832,10 @@ inline bool optimizer_flag(THD *thd, uint flag)
   return (thd->variables.optimizer_switch & flag);
 }
 
+/*
 int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly,
                                SELECT_LEX *select_lex, uint8 select_options);
+*/
 
 uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
                          ha_rows limit, ha_rows *scanned_limit, 
@@ -1861,22 +1863,8 @@ int print_explain_message_line(select_result_sink *result,
                                ha_rows *rows,
                                const char *message);
 void explain_append_mrr_info(QUICK_RANGE_SELECT *quick, String *res);
-int print_explain_row(select_result_sink *result,
-                      uint8 options, bool is_analyze,
-                      uint select_number,
-                      const char *select_type,
-                      const char *table_name,
-                      const char *partitions,
-                      enum join_type jtype,
-                      const char *possible_keys,
-                      const char *index,
-                      const char *key_len,
-                      const char *ref,
-                      ha_rows *rows,
-                      ha_rows *r_rows,
-                      double r_filtered,
-                      const char *extra);
-void make_possible_keys_line(TABLE *table, key_map possible_keys, String *line);
+int append_possible_keys(MEM_ROOT *alloc, String_list &list, TABLE *table, 
+                         key_map possible_keys);
 
 /****************************************************************************
   Temporary table support for SQL Runtime
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index fa5b696..f4086bd 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -517,7 +517,7 @@ int mysql_update(THD *thd,
   */
   if (thd->lex->describe)
     goto produce_explain_and_leave;
-  query_plan.save_explain_data(thd->lex->explain);
+  query_plan.save_explain_data(thd->mem_root, thd->lex->explain);
 
   DBUG_EXECUTE_IF("show_explain_probe_update_exec_start", 
                   dbug_serve_apcs(thd, 1););
@@ -1037,7 +1037,7 @@ int mysql_update(THD *thd,
     We come here for various "degenerate" query plans: impossible WHERE,
     no-partitions-used, impossible-range, etc.
   */
-  query_plan.save_explain_data(thd->lex->explain);
+  query_plan.save_explain_data(thd->mem_root, thd->lex->explain);
 
 emit_explain_and_leave:
   int err2= thd->lex->explain->send_explain(thd);


More information about the commits mailing list