mirror of
https://github.com/MariaDB/server.git
synced 2025-01-28 01:34:17 +01:00
MDEV-3798: EXPLAIN UPDATE/DELETE
- Address review feedback: rename nearly any name used by the new EXPLAIN code.
This commit is contained in:
parent
f5fba6564b
commit
fedf769f0b
19 changed files with 273 additions and 289 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
/*
|
||||
|
|
102
sql/opt_qpf.cc
102
sql/opt_qpf.cc
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
130
sql/opt_qpf.h
130
sql/opt_qpf.h
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue