MDEV-3798: EXPLAIN UPDATE/DELETE

- Address review feedback: rename nearly any name used by the new EXPLAIN code.
This commit is contained in:
Sergey Petrunya 2013-10-05 09:58:22 +04:00
parent f5fba6564b
commit fedf769f0b
19 changed files with 273 additions and 289 deletions

View file

@ -2826,11 +2826,11 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
thd->query_plan_fsort_passes) == (size_t) -1)
tmp_errno= errno;
if (thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_EXPLAIN &&
thd->lex->query_plan_footprint)
thd->lex->explain)
{
StringBuffer<128> buf;
DBUG_ASSERT(!thd->free_list);
if (!print_qpf_query(thd->lex, thd, &buf))
if (!print_explain_query(thd->lex, thd, &buf))
my_b_printf(&log_file, "%s", buf.c_ptr_safe());
thd->free_items();
}

View file

@ -9151,7 +9151,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
call might reset the value of current_stmt_binlog_format, so
we need to do any changes to that value after this function.
*/
delete_qpf_query(thd->lex);
delete_explain_query(thd->lex);
lex_start(thd);
mysql_reset_thd_for_next_command(thd, 0);
/*

View file

@ -22,14 +22,14 @@
#include "sql_select.h"
QPF_query::QPF_query()
Explain_query::Explain_query()
{
upd_del_plan= NULL;
operations= 0;
}
QPF_query::~QPF_query()
Explain_query::~Explain_query()
{
delete upd_del_plan;
uint i;
@ -40,37 +40,37 @@ QPF_query::~QPF_query()
}
QPF_node *QPF_query::get_node(uint select_id)
Explain_node *Explain_query::get_node(uint select_id)
{
QPF_union *u;
Explain_union *u;
if ((u= get_union(select_id)))
return u;
else
return get_select(select_id);
}
QPF_union *QPF_query::get_union(uint select_id)
Explain_union *Explain_query::get_union(uint select_id)
{
return (unions.elements() > select_id) ? unions.at(select_id) : NULL;
}
QPF_select *QPF_query::get_select(uint select_id)
Explain_select *Explain_query::get_select(uint select_id)
{
return (selects.elements() > select_id) ? selects.at(select_id) : NULL;
}
void QPF_query::add_node(QPF_node *node)
void Explain_query::add_node(Explain_node *node)
{
operations++;
if (node->get_type() == QPF_node::QPF_UNION)
if (node->get_type() == Explain_node::EXPLAIN_UNION)
{
QPF_union *u= (QPF_union*)node;
Explain_union *u= (Explain_union*)node;
uint select_id= u->get_select_id();
if (unions.elements() <= select_id)
unions.resize(max(select_id+1, unions.elements()*2), NULL);
QPF_union *old_node;
Explain_union *old_node;
if ((old_node= get_union(select_id)))
delete old_node;
@ -78,15 +78,15 @@ void QPF_query::add_node(QPF_node *node)
}
else
{
QPF_select *sel= (QPF_select*)node;
if (sel->select_id == (int)UINT_MAX)
Explain_select *sel= (Explain_select*)node;
if (sel->select_id == FAKE_SELECT_LEX_ID)
{
DBUG_ASSERT(0); // this is a "fake select" from a UNION.
}
else
{
uint select_id= sel->select_id;
QPF_select *old_node;
Explain_select *old_node;
if (selects.elements() <= select_id)
selects.resize(max(select_id+1, selects.elements()*2), NULL);
@ -104,7 +104,7 @@ void QPF_query::add_node(QPF_node *node)
The main entry point to print EXPLAIN of the entire query
*/
int QPF_query::print_explain(select_result_sink *output,
int Explain_query::print_explain(select_result_sink *output,
uint8 explain_flags)
{
if (upd_del_plan)
@ -115,7 +115,7 @@ int QPF_query::print_explain(select_result_sink *output,
else
{
/* Start printing from node with id=1 */
QPF_node *node= get_node(1);
Explain_node *node= get_node(1);
if (!node)
return 1; /* No query plan */
return node->print_explain(this, output, explain_flags);
@ -123,13 +123,13 @@ int QPF_query::print_explain(select_result_sink *output,
}
bool print_qpf_query(LEX *lex, THD *thd, String *str)
bool print_explain_query(LEX *lex, THD *thd, String *str)
{
return lex->query_plan_footprint->print_explain_str(thd, str);
return lex->explain->print_explain_str(thd, str);
}
bool QPF_query::print_explain_str(THD *thd, String *out_str)
bool Explain_query::print_explain_str(THD *thd, String *out_str)
{
List<Item> fields;
thd->make_explain_field_list(fields);
@ -157,13 +157,14 @@ static void push_string(List<Item> *item_list, String *str)
}
int QPF_union::print_explain(QPF_query *query, select_result_sink *output,
uint8 explain_flags)
int Explain_union::print_explain(Explain_query *query,
select_result_sink *output,
uint8 explain_flags)
{
/* print all UNION children, in order */
for (int i= 0; i < (int) union_members.elements(); i++)
{
QPF_select *sel= query->get_select(union_members.at(i));
Explain_select *sel= query->get_select(union_members.at(i));
sel->print_explain(query, output, explain_flags);
}
@ -257,13 +258,13 @@ int QPF_union::print_explain(QPF_query *query, select_result_sink *output,
Print EXPLAINs for all children nodes (i.e. for subqueries)
*/
int QPF_node::print_explain_for_children(QPF_query *query,
int Explain_node::print_explain_for_children(Explain_query *query,
select_result_sink *output,
uint8 explain_flags)
{
for (int i= 0; i < (int) children.elements(); i++)
{
QPF_node *node= query->get_node(children.at(i));
Explain_node *node= query->get_node(children.at(i));
if (node->print_explain(query, output, explain_flags))
return 1;
}
@ -271,7 +272,7 @@ int QPF_node::print_explain_for_children(QPF_query *query,
}
QPF_select::~QPF_select()
Explain_select::~Explain_select()
{
if (join_tabs)
{
@ -282,8 +283,9 @@ QPF_select::~QPF_select()
}
int QPF_select::print_explain(QPF_query *query, select_result_sink *output,
uint8 explain_flags)
int Explain_select::print_explain(Explain_query *query,
select_result_sink *output,
uint8 explain_flags)
{
if (message)
{
@ -330,13 +332,13 @@ int QPF_select::print_explain(QPF_query *query, select_result_sink *output,
}
void QPF_table_access::push_extra(enum Extra_tag extra_tag)
void Explain_table_access::push_extra(enum explain_extra_tag extra_tag)
{
extra_tags.append(extra_tag);
}
int QPF_table_access::print_explain(select_result_sink *output, uint8 explain_flags,
int Explain_table_access::print_explain(select_result_sink *output, uint8 explain_flags,
uint select_id, const char *select_type,
bool using_temporary, bool using_filesort)
{
@ -551,7 +553,7 @@ const char * extra_tag_text[]=
};
void QPF_table_access::append_tag_name(String *str, enum Extra_tag tag)
void Explain_table_access::append_tag_name(String *str, enum explain_extra_tag tag)
{
switch (tag) {
case ET_USING:
@ -618,13 +620,13 @@ void QPF_table_access::append_tag_name(String *str, enum Extra_tag tag)
/*
This is called for top-level QPF_quick_select only. The point of this
This is called for top-level Explain_quick_select only. The point of this
function is:
- index_merge should print $index_merge_type (child, ...)
- 'range' should not print anything.
*/
void QPF_quick_select::print_extra(String *str)
void Explain_quick_select::print_extra(String *str)
{
if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
@ -637,7 +639,7 @@ void QPF_quick_select::print_extra(String *str)
}
void QPF_quick_select::print_extra_recursive(String *str)
void Explain_quick_select::print_extra_recursive(String *str)
{
if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC)
@ -648,8 +650,8 @@ void QPF_quick_select::print_extra_recursive(String *str)
{
str->append(get_name_by_type());
str->append('(');
List_iterator_fast<QPF_quick_select> it (children);
QPF_quick_select* child;
List_iterator_fast<Explain_quick_select> it (children);
Explain_quick_select* child;
bool first= true;
while ((child = it++))
{
@ -665,7 +667,7 @@ void QPF_quick_select::print_extra_recursive(String *str)
}
const char * QPF_quick_select::get_name_by_type()
const char * Explain_quick_select::get_name_by_type()
{
switch (quick_type) {
case QUICK_SELECT_I::QS_TYPE_INDEX_MERGE:
@ -687,7 +689,7 @@ const char * QPF_quick_select::get_name_by_type()
This prints a comma-separated list of used indexes, ignoring nesting
*/
void QPF_quick_select::print_key(String *str)
void Explain_quick_select::print_key(String *str)
{
if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
@ -699,8 +701,8 @@ void QPF_quick_select::print_key(String *str)
}
else
{
List_iterator_fast<QPF_quick_select> it (children);
QPF_quick_select* child;
List_iterator_fast<Explain_quick_select> it (children);
Explain_quick_select* child;
while ((child = it++))
{
child->print_key(str);
@ -713,7 +715,7 @@ void QPF_quick_select::print_key(String *str)
This prints a comma-separated list of used key_lengths, ignoring nesting
*/
void QPF_quick_select::print_key_len(String *str)
void Explain_quick_select::print_key_len(String *str)
{
if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
@ -728,8 +730,8 @@ void QPF_quick_select::print_key_len(String *str)
}
else
{
List_iterator_fast<QPF_quick_select> it (children);
QPF_quick_select* child;
List_iterator_fast<Explain_quick_select> it (children);
Explain_quick_select* child;
while ((child = it++))
{
child->print_key_len(str);
@ -738,7 +740,7 @@ void QPF_quick_select::print_key_len(String *str)
}
int QPF_delete::print_explain(QPF_query *query, select_result_sink *output,
int QPF_delete::print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags)
{
if (deleting_all_rows)
@ -757,7 +759,7 @@ int QPF_delete::print_explain(QPF_query *query, select_result_sink *output,
}
int QPF_update::print_explain(QPF_query *query, select_result_sink *output,
int QPF_update::print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags)
{
StringBuffer<64> extra_str;
@ -809,18 +811,18 @@ int QPF_update::print_explain(QPF_query *query, select_result_sink *output,
}
void delete_qpf_query(LEX *lex)
void delete_explain_query(LEX *lex)
{
delete lex->query_plan_footprint;
lex->query_plan_footprint= NULL;
delete lex->explain;
lex->explain= NULL;
}
void create_qpf_query(LEX *lex, MEM_ROOT *mem_root)
void create_explain_query(LEX *lex, MEM_ROOT *mem_root)
{
DBUG_ASSERT(!lex->query_plan_footprint);
lex->query_plan_footprint= new QPF_query;
DBUG_ASSERT(!lex->explain);
lex->explain= new Explain_query;
DBUG_ASSERT(mem_root == current_thd->mem_root);
lex->query_plan_footprint->mem_root= mem_root;
lex->explain->mem_root= mem_root;
}

View file

@ -17,33 +17,35 @@
/**************************************************************************************
Query Plan Footprint (QPF) structures
Data structures for producing EXPLAIN outputs.
These structures
- Can be produced in-expensively from query plan.
- Store sufficient information to produce either a tabular or a json EXPLAIN
output
- Can be produced inexpensively from query plan.
- Store sufficient information to produce a tabular and/or a json EXPLAIN
- Have methods that produce a tabular output.
*************************************************************************************/
class QPF_query;
const int FAKE_SELECT_LEX_ID= (int)UINT_MAX;
class Explain_query;
/*
A node can be either a SELECT, or a UNION.
*/
class QPF_node : public Sql_alloc
class Explain_node : public Sql_alloc
{
public:
enum qpf_node_type {QPF_UNION, QPF_SELECT, QPF_UPDATE, QPF_DELETE };
virtual enum qpf_node_type get_type()= 0;
enum explain_node_type {EXPLAIN_UNION, EXPLAIN_SELECT, EXPLAIN_UPDATE, EXPLAIN_DELETE };
virtual enum explain_node_type get_type()= 0;
virtual int get_select_id()= 0;
/*
A node may have children nodes. When a node's QPF (Query Plan Footprint) is
created, children nodes may not yet have QPFs. This is why we store ids.
A node may have children nodes. When a node's explain structure is
created, children nodes may not yet have QPFs. This is why we store ids.
*/
Dynamic_array<int> children;
void add_child(int select_no)
@ -51,20 +53,20 @@ public:
children.append(select_no);
}
virtual int print_explain(QPF_query *query, select_result_sink *output,
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags)=0;
int print_explain_for_children(QPF_query *query, select_result_sink *output,
int print_explain_for_children(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
virtual ~QPF_node(){}
virtual ~Explain_node(){}
};
class QPF_table_access;
class Explain_table_access;
/*
Query Plan Footprint of a SELECT.
EXPLAIN structure for a SELECT.
A select can be:
1. A degenerate case. In this case, message!=NULL, and it contains a
@ -74,27 +76,27 @@ class QPF_table_access;
In the non-degenerate case, a SELECT may have a GROUP BY/ORDER BY operation.
In both cases, the select may have children nodes. class QPF_node provides
In both cases, the select may have children nodes. class Explain_node provides
a way get node's children.
*/
class QPF_select : public QPF_node
class Explain_select : public Explain_node
{
public:
enum qpf_node_type get_type() { return QPF_SELECT; }
enum explain_node_type get_type() { return EXPLAIN_SELECT; }
QPF_select() :
Explain_select() :
message(NULL), join_tabs(NULL),
using_temporary(false), using_filesort(false)
{}
~QPF_select();
~Explain_select();
bool add_table(QPF_table_access *tab)
bool add_table(Explain_table_access *tab)
{
if (!join_tabs)
{
join_tabs= (QPF_table_access**) my_malloc(sizeof(QPF_table_access*) *
join_tabs= (Explain_table_access**) my_malloc(sizeof(Explain_table_access*) *
MAX_TABLES, MYF(0));
n_join_tabs= 0;
}
@ -115,31 +117,31 @@ public:
const char *message;
/*
A flat array of Query Plan Footprints. The order is "just like EXPLAIN
A flat array of Explain structs for tables. The order is "just like EXPLAIN
would print them".
*/
QPF_table_access** join_tabs;
Explain_table_access** join_tabs;
uint n_join_tabs;
/* Global join attributes. In tabular form, they are printed on the first row */
bool using_temporary;
bool using_filesort;
int print_explain(QPF_query *query, select_result_sink *output,
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
};
/*
Query Plan Footprint of a UNION.
Explain structure for a UNION.
A UNION may or may not have "Using filesort".
*/
class QPF_union : public QPF_node
class Explain_union : public Explain_node
{
public:
enum qpf_node_type get_type() { return QPF_UNION; }
enum explain_node_type get_type() { return EXPLAIN_UNION; }
int get_select_id()
{
@ -163,7 +165,7 @@ public:
{
union_members.append(select_no);
}
int print_explain(QPF_query *query, select_result_sink *output,
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
const char *fake_select_type;
@ -174,7 +176,7 @@ class QPF_delete;
/*
Query Plan Footprint (QPF) for a query (i.e. a statement).
Explain structure for a query (i.e. a statement).
This should be able to survive when the query plan was deleted. Currently,
we do not intend for it survive until after query's MEM_ROOT is freed. It
@ -208,21 +210,21 @@ class QPF_delete;
*/
class QPF_query : public Sql_alloc
class Explain_query : public Sql_alloc
{
public:
QPF_query();
~QPF_query();
Explain_query();
~Explain_query();
/* Add a new node */
void add_node(QPF_node *node);
void add_node(Explain_node *node);
/* This will return a select, or a union */
QPF_node *get_node(uint select_id);
Explain_node *get_node(uint select_id);
/* This will return a select (even if there is a union with this id) */
QPF_select *get_select(uint select_id);
Explain_select *get_select(uint select_id);
QPF_union *get_union(uint select_id);
Explain_union *get_union(uint select_id);
/* QPF_delete inherits from QPF_update */
QPF_update *upd_del_plan;
@ -237,8 +239,8 @@ public:
bool have_query_plan() { return upd_del_plan!= NULL || get_node(1) != NULL; }
MEM_ROOT *mem_root;
private:
Dynamic_array<QPF_union*> unions;
Dynamic_array<QPF_select*> selects;
Dynamic_array<Explain_union*> unions;
Dynamic_array<Explain_select*> selects;
/*
Debugging aid: count how many times add_node() was called. Ideally, it
@ -252,10 +254,10 @@ private:
/*
Some of the tags have matching text. See extra_tag_text for text names, and
QPF_table_access::append_tag_name() for code to convert from tag form to text
Explain_table_access::append_tag_name() for code to convert from tag form to text
form.
*/
enum Extra_tag
enum explain_extra_tag
{
ET_none= 0, /* not-a-tag */
ET_USING_INDEX_CONDITION,
@ -296,19 +298,19 @@ enum Extra_tag
};
typedef struct st_qpf_bka_type
typedef struct st_explain_bka_type
{
bool incremental;
const char *join_alg;
StringBuffer<64> mrr_type;
} QPF_BKA_TYPE;
} EXPLAIN_BKA_TYPE;
/*
Data about how an index is used by some access method
*/
class QPF_index_use : public Sql_alloc
class Explain_index_use : public Sql_alloc
{
char *key_name;
uint key_len;
@ -336,16 +338,16 @@ public:
/*
QPF for quick range selects, as well as index_merge select
*/
class QPF_quick_select : public Sql_alloc
class Explain_quick_select : public Sql_alloc
{
public:
int quick_type;
/* This is used when quick_type == QUICK_SELECT_I::QS_TYPE_RANGE */
QPF_index_use range;
Explain_index_use range;
/* Used in all other cases */
List<QPF_quick_select> children;
List<Explain_quick_select> children;
void print_extra(String *str);
void print_key(String *str);
@ -359,20 +361,20 @@ private:
/*
Query Plan Footprint for a JOIN_TAB.
*/
class QPF_table_access : public Sql_alloc
class Explain_table_access : public Sql_alloc
{
public:
void push_extra(enum Extra_tag extra_tag);
void push_extra(enum explain_extra_tag extra_tag);
/* Internals */
public:
/*
0 means this tab is not inside SJM nest and should use QPF_select's id
0 means this tab is not inside SJM nest and should use Explain_select's id
other value means the tab is inside an SJM nest.
*/
int sjm_nest_select_id;
/* id and 'select_type' are cared-of by the parent QPF_select */
/* id and 'select_type' are cared-of by the parent Explain_select */
StringBuffer<32> table_name;
enum join_type type;
@ -391,13 +393,13 @@ public:
key.key_name == NULL means 'NULL' will be shown in tabular output.
key.key_len == (uint)-1 means 'NULL' will be shown in tabular output.
*/
QPF_index_use key;
Explain_index_use key;
/*
when type==JT_HASH_NEXT, 'key' stores the hash join pseudo-key.
hash_next_key stores the table's key.
*/
QPF_index_use hash_next_key;
Explain_index_use hash_next_key;
bool ref_set; /* not set means 'NULL' should be printed */
StringBuffer<32> ref;
@ -412,10 +414,10 @@ public:
Contents of the 'Extra' column. Some are converted into strings, some have
parameters, values for which are stored below.
*/
Dynamic_array<enum Extra_tag> extra_tags;
Dynamic_array<enum explain_extra_tag> extra_tags;
// Valid if ET_USING tag is present
QPF_quick_select *quick_info;
Explain_quick_select *quick_info;
// Valid if ET_USING_INDEX_FOR_GROUP_BY is present
bool loose_scan_is_scanning;
@ -427,7 +429,7 @@ public:
StringBuffer<32> mrr_type;
// valid with ET_USING_JOIN_BUFFER
QPF_BKA_TYPE bka_type;
EXPLAIN_BKA_TYPE bka_type;
StringBuffer<32> firstmatch_table_name;
@ -435,21 +437,21 @@ public:
uint select_id, const char *select_type,
bool using_temporary, bool using_filesort);
private:
void append_tag_name(String *str, enum Extra_tag tag);
void append_tag_name(String *str, enum explain_extra_tag tag);
};
/*
Query Plan Footprint for single-table UPDATE.
This is similar to QPF_table_access, except that it is more restrictive.
This is similar to Explain_table_access, except that it is more restrictive.
Also, it can have UPDATE operation options, but currently there aren't any.
*/
class QPF_update : public QPF_node
class QPF_update : public Explain_node
{
public:
virtual enum qpf_node_type get_type() { return QPF_UPDATE; }
virtual enum explain_node_type get_type() { return EXPLAIN_UPDATE; }
virtual int get_select_id() { return 1; /* always root */ }
const char *select_type;
@ -471,7 +473,7 @@ public:
bool using_filesort;
virtual int print_explain(QPF_query *query, select_result_sink *output,
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
};
@ -489,10 +491,10 @@ public:
*/
bool deleting_all_rows;
virtual enum qpf_node_type get_type() { return QPF_DELETE; }
virtual enum explain_node_type get_type() { return EXPLAIN_DELETE; }
virtual int get_select_id() { return 1; /* always root */ }
virtual int print_explain(QPF_query *query, select_result_sink *output,
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags);
};

View file

@ -11940,37 +11940,39 @@ void QUICK_SELECT_I::add_key_name(String *str, bool *first)
}
void QUICK_RANGE_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *qpf)
void QUICK_RANGE_SELECT::save_info(MEM_ROOT *alloc, Explain_quick_select *qpf)
{
qpf->quick_type= QS_TYPE_RANGE;
qpf->range.set(alloc, head->key_info[index].name, max_used_key_length);
}
void QUICK_GROUP_MIN_MAX_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *qpf)
void QUICK_GROUP_MIN_MAX_SELECT::save_info(MEM_ROOT *alloc,
Explain_quick_select *qpf)
{
qpf->quick_type= QS_TYPE_GROUP_MIN_MAX;
qpf->range.set(alloc, head->key_info[index].name, max_used_key_length);
}
void QUICK_INDEX_SORT_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *qpf)
void QUICK_INDEX_SORT_SELECT::save_info(MEM_ROOT *alloc,
Explain_quick_select *qpf)
{
qpf->quick_type= get_type();
QUICK_RANGE_SELECT *quick;
QPF_quick_select *child_qpf;
Explain_quick_select *child_qpf;
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
while ((quick= it++))
{
child_qpf= new QPF_quick_select;
child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf);
quick->save_info(alloc, child_qpf);
}
if (pk_quick_select)
{
child_qpf= new QPF_quick_select;
child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf);
pk_quick_select->save_info(alloc, child_qpf);
}
@ -11980,14 +11982,15 @@ void QUICK_INDEX_SORT_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *qpf)
Same as QUICK_INDEX_SORT_SELECT::save_info(), but primary key is printed
first
*/
void QUICK_INDEX_INTERSECT_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *qpf)
void QUICK_INDEX_INTERSECT_SELECT::save_info(MEM_ROOT *alloc,
Explain_quick_select *qpf)
{
qpf->quick_type= get_type();
QPF_quick_select *child_qpf;
Explain_quick_select *child_qpf;
if (pk_quick_select)
{
child_qpf= new QPF_quick_select;
child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf);
pk_quick_select->save_info(alloc, child_qpf);
}
@ -11996,7 +11999,7 @@ void QUICK_INDEX_INTERSECT_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
while ((quick= it++))
{
child_qpf= new QPF_quick_select;
child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf);
quick->save_info(alloc, child_qpf);
}
@ -12004,7 +12007,8 @@ void QUICK_INDEX_INTERSECT_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *
}
void QUICK_ROR_INTERSECT_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *qpf)
void QUICK_ROR_INTERSECT_SELECT::save_info(MEM_ROOT *alloc,
Explain_quick_select *qpf)
{
qpf->quick_type= get_type();
@ -12012,21 +12016,22 @@ void QUICK_ROR_INTERSECT_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *qp
List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
while ((qr= it++))
{
QPF_quick_select *child_qpf= new QPF_quick_select;
Explain_quick_select *child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf);
qr->quick->save_info(alloc, child_qpf);
}
if (cpk_quick)
{
QPF_quick_select *child_qpf= new QPF_quick_select;
Explain_quick_select *child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf);
cpk_quick->save_info(alloc, child_qpf);
}
}
void QUICK_ROR_UNION_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *qpf)
void QUICK_ROR_UNION_SELECT::save_info(MEM_ROOT *alloc,
Explain_quick_select *qpf)
{
qpf->quick_type= get_type();
@ -12034,7 +12039,7 @@ void QUICK_ROR_UNION_SELECT::save_info(MEM_ROOT *alloc, QPF_quick_select *qpf)
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
while ((quick= it++))
{
QPF_quick_select *child_qpf= new QPF_quick_select;
Explain_quick_select *child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf);
quick->save_info(alloc, child_qpf);
}

View file

@ -52,7 +52,7 @@ typedef struct st_key_part {
Field::imagetype image_type;
} KEY_PART;
class QPF_quick_select;
class Explain_quick_select;
/*
A "MIN_TUPLE < tbl.key_tuple < MAX_TUPLE" interval.
@ -346,7 +346,7 @@ public:
void add_key_name(String *str, bool *first);
/* Save information about quick select's query plan */
virtual void save_info(MEM_ROOT *alloc, QPF_quick_select *qpf)= 0;
virtual void save_info(MEM_ROOT *alloc, Explain_quick_select *qpf)= 0;
/*
Return 1 if any index used by this quick select
@ -473,7 +473,7 @@ public:
{ file->position(record); }
int get_type() { return QS_TYPE_RANGE; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
void save_info(MEM_ROOT *alloc, QPF_quick_select *qpf);
void save_info(MEM_ROOT *alloc, Explain_quick_select *qpf);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
@ -610,7 +610,7 @@ public:
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
void save_info(MEM_ROOT *alloc, QPF_quick_select *qpf);
void save_info(MEM_ROOT *alloc, Explain_quick_select *qpf);
bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
@ -674,7 +674,7 @@ public:
int get_next();
int get_type() { return QS_TYPE_INDEX_INTERSECT; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
void save_info(MEM_ROOT *alloc, QPF_quick_select *qpf);
void save_info(MEM_ROOT *alloc, Explain_quick_select *qpf);
};
@ -712,7 +712,7 @@ public:
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_ROR_INTERSECT; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
void save_info(MEM_ROOT *alloc, QPF_quick_select *qpf);
void save_info(MEM_ROOT *alloc, Explain_quick_select *qpf);
bool is_keys_used(const MY_BITMAP *fields);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
@ -791,7 +791,7 @@ public:
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_ROR_UNION; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
void save_info(MEM_ROOT *alloc, QPF_quick_select *qpf);
void save_info(MEM_ROOT *alloc, Explain_quick_select *qpf);
bool is_keys_used(const MY_BITMAP *fields);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
@ -940,7 +940,7 @@ public:
#endif
bool is_agg_distinct() { return have_agg_distinct; }
bool loose_scan_is_scanning() { return is_index_scan; }
void save_info(MEM_ROOT *alloc, QPF_quick_select *qpf);
void save_info(MEM_ROOT *alloc, Explain_quick_select *qpf);
};

View file

@ -3034,7 +3034,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
thd->mdl_context.release_statement_locks();
}
delete_qpf_query(m_lex);
delete_explain_query(m_lex);
if (m_lex->query_tables_own_last)
{
@ -3242,7 +3242,7 @@ sp_instr_set::execute(THD *thd, uint *nextp)
int
sp_instr_set::exec_core(THD *thd, uint *nextp)
{
create_qpf_query(thd->lex, thd->mem_root);
create_explain_query(thd->lex, thd->mem_root);
int res= thd->spcont->set_variable(thd, m_offset, &m_value);
if (res)
@ -3255,7 +3255,7 @@ sp_instr_set::exec_core(THD *thd, uint *nextp)
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
}
}
delete_qpf_query(thd->lex);
delete_explain_query(thd->lex);
*nextp = m_ip+1;
return res;

View file

@ -51,7 +51,7 @@
invoked on a running DELETE statement.
*/
void Delete_plan::save_qpf(QPF_query *query)
void Delete_plan::save_explain_data(Explain_query *query)
{
QPF_delete* qpf= new QPF_delete;
@ -63,22 +63,22 @@ void Delete_plan::save_qpf(QPF_query *query)
else
{
qpf->deleting_all_rows= false;
Update_plan::save_qpf_intern(query, qpf);
Update_plan::save_explain_data_intern(query, qpf);
}
query->upd_del_plan= qpf;
}
void Update_plan::save_qpf(QPF_query *query)
void Update_plan::save_explain_data(Explain_query *query)
{
QPF_update* qpf= new QPF_update;
save_qpf_intern(query, qpf);
save_explain_data_intern(query, qpf);
query->upd_del_plan= qpf;
}
void Update_plan::save_qpf_intern(QPF_query *query, QPF_update *qpf)
void Update_plan::save_explain_data_intern(Explain_query *query, QPF_update *qpf)
{
qpf->select_type= "SIMPLE";
qpf->table_name.append(table->pos_in_table_list->alias);
@ -434,7 +434,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (thd->lex->describe)
goto exit_without_my_ok;
query_plan.save_qpf(thd->lex->query_plan_footprint);
query_plan.save_explain_data(thd->lex->explain);
thd->apc_target.enable();
DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start",
@ -667,7 +667,7 @@ cleanup:
/* Special exits */
exit_without_my_ok:
query_plan.save_qpf(thd->lex->query_plan_footprint);
query_plan.save_explain_data(thd->lex->explain);
select_send *result2;
if (!(result2= new select_send()))
@ -675,7 +675,7 @@ exit_without_my_ok:
List<Item> dummy; /* note: looked in 5.6 and they too use a dummy list like this */
result2->prepare(dummy, &thd->lex->unit);
thd->send_explain_fields(result2);
int err2= thd->lex->query_plan_footprint->print_explain(result2, thd->lex->describe);
int err2= thd->lex->explain->print_explain(result2, thd->lex->describe);
if (err2)
result2->abort_result_set();

View file

@ -2568,7 +2568,7 @@ finish:
none
*/
void JOIN_CACHE::save_qpf(struct st_qpf_bka_type *qpf)
void JOIN_CACHE::save_explain_data(struct st_explain_bka_type *qpf)
{
qpf->incremental= test(prev_cache);
@ -2613,16 +2613,16 @@ static void add_mrr_explain_info(String *str, uint mrr_mode, handler *file)
}
}
void JOIN_CACHE_BKA::save_qpf(struct st_qpf_bka_type *qpf)
void JOIN_CACHE_BKA::save_explain_data(struct st_explain_bka_type *qpf)
{
JOIN_CACHE::save_qpf(qpf);
JOIN_CACHE::save_explain_data(qpf);
add_mrr_explain_info(&qpf->mrr_type, mrr_mode, join_tab->table->file);
}
void JOIN_CACHE_BKAH::save_qpf(struct st_qpf_bka_type *qpf)
void JOIN_CACHE_BKAH::save_explain_data(struct st_explain_bka_type *qpf)
{
JOIN_CACHE::save_qpf(qpf);
JOIN_CACHE::save_explain_data(qpf);
add_mrr_explain_info(&qpf->mrr_type, mrr_mode, join_tab->table->file);
}

View file

@ -63,7 +63,7 @@ typedef struct st_cache_field {
class JOIN_TAB_SCAN;
struct st_qpf_bka_type;
struct st_explain_bka_type;
/*
JOIN_CACHE is the base class to support the implementations of
@ -658,7 +658,7 @@ public:
enum_nested_loop_state join_records(bool skip_last);
/* Add a comment on the join algorithm employed by the join cache */
virtual void save_qpf(struct st_qpf_bka_type *qpf);
virtual void save_explain_data(struct st_explain_bka_type *qpf);
THD *thd();
@ -1336,7 +1336,7 @@ public:
/* Check index condition of the joined table for a record from BKA cache */
bool skip_index_tuple(range_id_t range_info);
void save_qpf(struct st_qpf_bka_type *qpf);
void save_explain_data(struct st_explain_bka_type *qpf);
};
@ -1427,5 +1427,5 @@ public:
/* Check index condition of the joined table for a record from BKAH cache */
bool skip_index_tuple(range_id_t range_info);
void save_qpf(struct st_qpf_bka_type *qpf);
void save_explain_data(struct st_explain_bka_type *qpf);
};

View file

@ -448,7 +448,7 @@ void lex_start(THD *thd)
lex->thd= lex->unit.thd= thd;
lex->query_plan_footprint= NULL;
lex->explain= NULL;
lex->context_stack.empty();
lex->unit.init_query();
@ -2572,7 +2572,7 @@ void Query_tables_list::destroy_query_tables_list()
*/
LEX::LEX()
: query_plan_footprint(NULL),
: explain(NULL),
result(0), option_type(OPT_DEFAULT), is_lex_started(0),
limit_rows_examined_cnt(ULONGLONG_MAX)
{
@ -3515,18 +3515,18 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only)
is_correlated_unit|= sl->is_correlated;
inner_join->select_options= save_options;
un->thd->lex->current_select= save_select;
/// psergey:
QPF_query *qpf;
if ((qpf= inner_join->thd->lex->query_plan_footprint))
Explain_query *qpf;
if ((qpf= inner_join->thd->lex->explain))
{
QPF_select *qp_sel;
Explain_select *qp_sel;
if ((qp_sel= qpf->get_select(inner_join->select_lex->select_number)))
{
sl->set_explain_type(TRUE);
qp_sel->select_type= sl->type;
}
}
///
if (empty_union_result)
{
/*
@ -4215,9 +4215,9 @@ int LEX::print_explain(select_result_sink *output, uint8 explain_flags,
bool *printed_anything)
{
int res;
if (query_plan_footprint && query_plan_footprint->have_query_plan())
if (explain && explain->have_query_plan())
{
res= query_plan_footprint->print_explain(output, explain_flags);
res= explain->print_explain(output, explain_flags);
*printed_anything= true;
}
else
@ -4230,10 +4230,10 @@ int LEX::print_explain(select_result_sink *output, uint8 explain_flags,
/*
Save query plan of a UNION. The only variable member is whether the union has
"Using filesort".
Save explain structures of a UNION. The only variable member is whether the
union has "Using filesort".
There is also save_union_qpf_part2() function, which is called before we read
There is also save_union_explain_part2() function, which is called before we read
UNION's output.
The reason for it is examples like this:
@ -4245,10 +4245,10 @@ int LEX::print_explain(select_result_sink *output, uint8 explain_flags,
stage in execution.
*/
int st_select_lex_unit::save_union_qpf(QPF_query *output)
int st_select_lex_unit::save_union_explain(Explain_query *output)
{
SELECT_LEX *first= first_select();
QPF_union *qpfu= new (output->mem_root) QPF_union;
Explain_union *eu= new (output->mem_root) Explain_union;
/*
TODO: The following code should be eliminated. If we have a capability to
@ -4264,30 +4264,34 @@ int st_select_lex_unit::save_union_qpf(QPF_query *output)
const char *msg="Query plan already deleted";
first->set_explain_type(TRUE/* on_the_fly */);
QPF_select *qp_sel= new (output->mem_root)QPF_select;
Explain_select *qp_sel= new (output->mem_root)Explain_select;
qp_sel->select_id= first->select_number;
qp_sel->select_type= first->type;
qp_sel->message= msg;
output->add_node(qp_sel);
qpfu->add_select(qp_sel->select_id);
eu->add_select(qp_sel->select_id);
return 0;
}
for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
qpfu->add_select(sl->select_number);
eu->add_select(sl->select_number);
// Save the UNION node
output->add_node(qpfu);
output->add_node(eu);
qpfu->fake_select_type= "UNION RESULT";
qpfu->using_filesort= test(global_parameters->order_list.first);
eu->fake_select_type= "UNION RESULT";
eu->using_filesort= test(global_parameters->order_list.first);
return 0;
}
int st_select_lex_unit::save_union_qpf_part2(QPF_query *output)
/*
@see st_select_lex_unit::save_union_explain
*/
int st_select_lex_unit::save_union_explain_part2(Explain_query *output)
{
QPF_union *qpfu= output->get_union(first_select()->select_number);
Explain_union *eu= output->get_union(first_select()->select_number);
if (fake_select_lex)
{
for (SELECT_LEX_UNIT *unit= fake_select_lex->first_inner_unit();
@ -4295,7 +4299,7 @@ int st_select_lex_unit::save_union_qpf_part2(QPF_query *output)
{
if (!(unit->item && unit->item->eliminated))
{
qpfu->add_child(unit->first_select()->select_number);
eu->add_child(unit->first_select()->select_number);
}
}
}

View file

@ -618,11 +618,11 @@ class select_result;
class JOIN;
class select_union;
class Procedure;
class QPF_query;
class Explain_query;
void delete_qpf_query(LEX *lex);
void create_qpf_query(LEX *lex, MEM_ROOT *mem_root);
bool print_qpf_query(LEX *lex, THD *thd, String *str);
void delete_explain_query(LEX *lex);
void create_explain_query(LEX *lex, MEM_ROOT *mem_root);
bool print_explain_query(LEX *lex, THD *thd, String *str);
class st_select_lex_unit: public st_select_lex_node {
protected:
@ -734,8 +734,8 @@ public:
List<Item> *get_unit_column_types();
int save_union_qpf(QPF_query *output);
int save_union_qpf_part2(QPF_query *output);
int save_union_explain(Explain_query *output);
int save_union_explain_part2(Explain_query *output);
};
typedef class st_select_lex_unit SELECT_LEX_UNIT;
@ -2368,7 +2368,7 @@ protected:
class Delete_plan;
class SQL_SELECT;
class QPF_query;
class Explain_query;
class QPF_update;
/*
@ -2398,8 +2398,8 @@ public:
/* Set this plan to be a plan to do nothing because of impossible WHRE*/
void set_impossible_where() { impossible_where= true; }
void save_qpf(QPF_query *query);
void save_qpf_intern(QPF_query *query, QPF_update *qpf);
void save_explain_data(Explain_query *query);
void save_explain_data_intern(Explain_query *query, QPF_update *qpf);
virtual ~Update_plan() {}
Update_plan() : impossible_where(false), using_filesort(false) {}
@ -2423,7 +2423,7 @@ public:
table_rows= rows_arg;
}
void save_qpf(QPF_query *query);
void save_explain_data(Explain_query *query);
};
@ -2439,7 +2439,7 @@ struct LEX: public Query_tables_list
SELECT_LEX *all_selects_list;
/* Query Plan Footprint of a currently running select */
QPF_query *query_plan_footprint;
Explain_query *explain;
char *length,*dec,*change;
LEX_STRING name;

View file

@ -598,7 +598,7 @@ static void handle_bootstrap_impl(THD *thd)
#if defined(ENABLED_PROFILING)
thd->profiling.finish_current_query();
#endif
delete_qpf_query(thd->lex);
delete_explain_query(thd->lex);
if (bootstrap_error)
break;
@ -1526,7 +1526,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/*
@note
This function must call delete_qpf_query().
This function must call delete_explain_query().
*/
void log_slow_statement(THD *thd)
{
@ -1547,7 +1547,7 @@ void log_slow_statement(THD *thd)
(thd->variables.log_slow_filter
&& !(thd->variables.log_slow_filter & thd->query_plan_flags)))
{
delete_qpf_query(thd->lex);
delete_explain_query(thd->lex);
DBUG_VOID_RETURN;
}
@ -1573,7 +1573,7 @@ void log_slow_statement(THD *thd)
thd_proc_info(thd, 0);
}
delete_qpf_query(thd->lex);
delete_explain_query(thd->lex);
DBUG_VOID_RETURN;
}
@ -2201,7 +2201,7 @@ mysql_execute_command(THD *thd)
thd->mdl_context.release_transactional_locks();
}
create_qpf_query(thd->lex, thd->mem_root);
create_explain_query(thd->lex, thd->mem_root);
#ifndef DBUG_OFF
if (lex->sql_command != SQLCOM_SET_OPTION)
@ -3252,7 +3252,7 @@ end_with_restore_list:
select_result *result= new select_send();
LEX *lex= thd->lex;
if (thd->send_explain_fields(result) ||
lex->query_plan_footprint->print_explain(result, lex->describe) ||
lex->explain->print_explain(result, lex->describe) ||
result->send_eof())
res= 1;
}
@ -3361,7 +3361,7 @@ end_with_restore_list:
select_result *result= new select_send();
LEX *lex= thd->lex;
if (thd->send_explain_fields(result) ||
lex->query_plan_footprint->print_explain(result, lex->describe) ||
lex->explain->print_explain(result, lex->describe) ||
result->send_eof())
res= 1;
}
@ -4901,8 +4901,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
top-level LIMIT
*/
result->reset_offset_limit();
thd->lex->query_plan_footprint->print_explain(result,
thd->lex->describe);
thd->lex->explain->print_explain(result, thd->lex->describe);
if (lex->describe & DESCRIBE_EXTENDED)
{
char buff[1024];

View file

@ -2491,7 +2491,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
object and because of this can be used in different threads.
*/
lex->thd= thd;
DBUG_ASSERT(!lex->query_plan_footprint);
DBUG_ASSERT(!lex->explain);
if (lex->empty_field_list_on_rset)
{
@ -3931,8 +3931,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (! cursor)
cleanup_stmt();
//psergey: TODO the "EXECUTE problem" is here
delete_qpf_query(thd->lex);
delete_explain_query(thd->lex);
thd->set_statement(&stmt_backup);
thd->stmt_arena= old_stmt_arena;

View file

@ -2305,9 +2305,8 @@ void join_save_qpf(JOIN *join)
join->have_query_plan != JOIN::QEP_NOT_PRESENT_YET &&
join->have_query_plan != JOIN::QEP_DELETED && // this happens when there was no QEP ever, but then
//cleanup() is called multiple times
thd->lex->query_plan_footprint && // for "SET" command in SPs.
!thd->lex->query_plan_footprint->get_select(join->select_lex->select_number))
thd->lex->explain && // for "SET" command in SPs.
!thd->lex->explain->get_select(join->select_lex->select_number))
{
const char *message= NULL;
@ -2317,12 +2316,12 @@ void join_save_qpf(JOIN *join)
message= join->zero_result_cause ? join->zero_result_cause : "No tables used";
}
join->save_qpf(thd->lex->query_plan_footprint,
join->need_tmp, // need_tmp_table
!join->skip_sort_order && !join->no_order &&
(join->order || join->group_list), // bool need_order
join->select_distinct, // bool distinct
message); // message
join->save_explain_data(thd->lex->explain,
join->need_tmp,
!join->skip_sort_order && !join->no_order &&
(join->order || join->group_list),
join->select_distinct,
message);
}
}
@ -2347,34 +2346,29 @@ void JOIN::exec()
exec_inner();
if (!exec_qpf_saved)
if (!exec_saved_explain)
{
if (select_lex->select_number != UINT_MAX &&
select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
have_query_plan != QEP_NOT_PRESENT_YET &&
have_query_plan != QEP_DELETED && // this happens when there was no QEP ever, but then
//cleanup() is called multiple times
thd->lex->query_plan_footprint //&& // for "SET" command in SPs.
/*!thd->lex->query_plan_footprint->get_select(select_lex->select_number)*/)
thd->lex->explain)// for "SET" command in SPs.
{
const char *message= NULL;
if (!table_count || !tables_list || zero_result_cause)
{
/* It's a degenerate join */
message= zero_result_cause ? zero_result_cause : "No tables used";
}
save_qpf(thd->lex->query_plan_footprint,
need_tmp, // need_tmp_table
// !skip_sort_order && !no_order &&
// (order || group_list), // bool need_order
order != 0 && !skip_sort_order,
select_distinct, // bool distinct
message); // message
save_explain_data(thd->lex->explain,
need_tmp,
order != 0 && !skip_sort_order,
select_distinct,
message);
}
exec_qpf_saved= true;
exec_saved_explain= true;
}
DBUG_EXECUTE_IF("show_explain_probe_join_exec_end",
@ -11170,37 +11164,7 @@ void JOIN::cleanup(bool full)
DBUG_PRINT("enter", ("full %u", (uint) full));
if (full)
{
/* Save it again */
#if 0
psergey-todo: remove?
if (select_lex->select_number != UINT_MAX &&
select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
have_query_plan != QEP_NOT_PRESENT_YET &&
have_query_plan != QEP_DELETED && // this happens when there was no QEP ever, but then
//cleanup() is called multiple times
thd->lex->query_plan_footprint //&& // for "SET" command in SPs.
/*!thd->lex->query_plan_footprint->get_select(select_lex->select_number)*/)
{
const char *message= NULL;
if (!table_count || !tables_list || zero_result_cause)
{
/* It's a degenerate join */
message= zero_result_cause ? zero_result_cause : "No tables used";
}
save_qpf(thd->lex->query_plan_footprint,
need_tmp, // need_tmp_table
!skip_sort_order && !no_order &&
(order || group_list), // bool need_order
select_distinct, // bool distinct
message); // message
}
#endif
have_query_plan= QEP_DELETED; //psergey: this is a problem!
}
have_query_plan= QEP_DELETED;
if (table)
{
@ -22522,16 +22486,17 @@ void append_possible_keys(String *str, TABLE *table, key_map possible_keys)
Currently, this function may be called multiple times
*/
int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
bool distinct, const char *message)
int JOIN::save_explain_data(Explain_query *output, bool need_tmp_table,
bool need_order, bool distinct,
const char *message)
{
QPF_node *qp_node;
Explain_node *qp_node;
JOIN *join= this; /* Legacy: this code used to be a non-member function */
THD *thd=join->thd;
const CHARSET_INFO *cs= system_charset_info;
int quick_type;
int error= 0;
DBUG_ENTER("JOIN::save_qpf");
DBUG_ENTER("JOIN::save_explain_data");
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
(ulong)join->select_lex, join->select_lex->type,
message ? message : "NULL"));
@ -22540,8 +22505,8 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
if (message)
{
QPF_select *qp_sel;
qp_node= qp_sel= new (output->mem_root) QPF_select;
Explain_select *qp_sel;
qp_node= qp_sel= new (output->mem_root) Explain_select;
join->select_lex->set_explain_type(true);
qp_sel->select_id= join->select_lex->select_number;
@ -22552,13 +22517,13 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
}
else if (join->select_lex == join->unit->fake_select_lex)
{
/* Do nothing, QPF_union will create and print fake_select_lex */
/* Do nothing, Explain_union will create and print fake_select_lex */
}
else if (!join->select_lex->master_unit()->derived ||
join->select_lex->master_unit()->derived->is_materialized_derived())
{
QPF_select *qp_sel;
qp_node= qp_sel= new (output->mem_root) QPF_select;
Explain_select *qp_sel;
qp_node= qp_sel= new (output->mem_root) Explain_select;
table_map used_tables=0;
join->select_lex->set_explain_type(true);
@ -22606,7 +22571,7 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
tab= pre_sort_join_tab;
}
QPF_table_access *qpt= new (output->mem_root) QPF_table_access;
Explain_table_access *qpt= new (output->mem_root) Explain_table_access;
qp_sel->add_table(qpt);
qpt->key.set(thd->mem_root, NULL, (uint)-1);
qpt->quick_info= NULL;
@ -22701,7 +22666,7 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
*/
if (tab->select && tab->select->quick && tab_type != JT_CONST)
{
qpt->quick_info= new QPF_quick_select;
qpt->quick_info= new Explain_quick_select;
tab->select->quick->save_info(thd->mem_root, qpt->quick_info);
}
@ -22981,7 +22946,7 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
if (tab->cache)
{
qpt->push_extra(ET_USING_JOIN_BUFFER);
tab->cache->save_qpf(&qpt->bka_type);
tab->cache->save_explain_data(&qpt->bka_type);
}
}
@ -23039,9 +23004,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
DBUG_ENTER("select_describe");
/* Update the QPF with latest values of using_temporary, using_filesort */
QPF_select *qp;
Explain_select *qp;
uint select_nr= join->select_lex->select_number;
if ((qp= thd->lex->query_plan_footprint->get_select(select_nr)))
if ((qp= thd->lex->explain->get_select(select_nr)))
{
qp->using_temporary= need_tmp_table;
qp->using_filesort= need_order;
@ -23095,7 +23060,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
if (unit->is_union())
{
unit->fake_select_lex->select_number= UINT_MAX; // jost for initialization
unit->fake_select_lex->select_number= FAKE_SELECT_LEX_ID; // jost for initialization
unit->fake_select_lex->type= "UNION RESULT";
unit->fake_select_lex->options|= SELECT_DESCRIBE;
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))

View file

@ -258,7 +258,7 @@ typedef struct st_join_table {
JOIN_TAB_RANGE *bush_children;
/* Special content for EXPLAIN 'Extra' column or NULL if none */
enum Extra_tag info;
enum explain_extra_tag info;
/*
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
@ -1336,7 +1336,7 @@ public:
emb_sjm_nest= NULL;
sjm_lookup_tables= 0;
exec_qpf_saved= false;
exec_saved_explain= false;
/*
The following is needed because JOIN::cleanup(true) may be called for
joins for which JOIN::optimize was aborted with an error before a proper
@ -1344,7 +1344,13 @@ public:
*/
table_access_tabs= NULL;
}
bool exec_qpf_saved;
/*
TRUE <=> There was a JOIN::exec() call, which saved this JOIN's EXPLAIN.
The idea is that we also save at the end of JOIN::optimize(), but that
might not be the final plan.
*/
bool exec_saved_explain;
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
COND *conds, uint og_num, ORDER *order, ORDER *group,
@ -1470,8 +1476,8 @@ public:
{
return (unit->item && unit->item->is_in_predicate());
}
int save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
bool distinct, const char *message);
int save_explain_data(Explain_query *output, bool need_tmp_table,
bool need_order, bool distinct, const char *message);
private:
/**
TRUE if the query contains an aggregate function but has no GROUP

View file

@ -630,8 +630,8 @@ bool st_select_lex_unit::exec()
saved_error= optimize();
if (!was_executed && thd->lex->query_plan_footprint)
save_union_qpf(thd->lex->query_plan_footprint);
if (!was_executed && thd->lex->explain)
save_union_explain(thd->lex->explain);
if (uncacheable || !item || !item->assigned() || describe)
{
@ -780,8 +780,8 @@ bool st_select_lex_unit::exec()
if (!fake_select_lex->ref_pointer_array)
fake_select_lex->n_child_sum_items+= global_parameters->n_sum_items;
if (!was_executed && thd->lex->query_plan_footprint)
save_union_qpf_part2(thd->lex->query_plan_footprint);
if (!was_executed && thd->lex->explain)
save_union_explain_part2(thd->lex->explain);
saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
&result_table_list,

View file

@ -500,7 +500,7 @@ int mysql_update(THD *thd,
if (thd->lex->describe)
goto exit_without_my_ok;
query_plan.save_qpf(thd->lex->query_plan_footprint);
query_plan.save_explain_data(thd->lex->explain);
thd->apc_target.enable();
apc_target_enabled= true;
DBUG_EXECUTE_IF("show_explain_probe_update_exec_start",
@ -1031,7 +1031,7 @@ err:
exit_without_my_ok:
DBUG_ASSERT(!apc_target_enabled);
query_plan.save_qpf(thd->lex->query_plan_footprint);
query_plan.save_explain_data(thd->lex->explain);
select_send *result;
if (!(result= new select_send()))
@ -1039,7 +1039,7 @@ exit_without_my_ok:
List<Item> dummy; /* note: looked in 5.6 and they too use a dummy list like this */
result->prepare(dummy, &thd->lex->unit);
thd->send_explain_fields(result);
int err2= thd->lex->query_plan_footprint->print_explain(result,
int err2= thd->lex->explain->print_explain(result,
thd->lex->describe);
if (err2)
result->abort_result_set();
@ -1518,7 +1518,7 @@ bool mysql_multi_update(THD *thd,
{
if (explain)
{
thd->lex->query_plan_footprint->print_explain(output, thd->lex->describe);
thd->lex->explain->print_explain(output, thd->lex->describe);
output->send_eof();
delete output;
}

View file

@ -1661,6 +1661,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
definer_opt no_definer definer
parse_vcol_expr vcol_opt_specifier vcol_opt_attribute
vcol_opt_attribute_list vcol_attribute
explainable_command
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@ -12029,14 +12030,14 @@ describe:
}
| describe_command opt_extended_describe
{ Lex->describe|= DESCRIBE_NORMAL; }
explanable_command
explainable_command
{
LEX *lex=Lex;
lex->select_lex.options|= SELECT_DESCRIBE;
}
;
explanable_command:
explainable_command:
select
| insert
| replace