mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
EXPLAIN FORMAT=JSON: Add support for single-table UPDATE/DELETE.
This commit is contained in:
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 @@ produce_explain_and_leave:
|
||||
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:
|
||||
/*
|
||||
|
@ -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,
|
||||
|
@ -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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -2303,8 +2303,9 @@ public:
|
||||
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 @@ public:
|
||||
scanned_rows= rows_arg;
|
||||
}
|
||||
|
||||
void save_explain_data(Explain_query *query);
|
||||
void save_explain_data(MEM_ROOT *mem_root, Explain_query *query);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 @@ produce_explain_and_leave:
|
||||
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);
|
||||
|
Reference in New Issue
Block a user