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) thd->query_plan_fsort_passes) == (size_t) -1)
tmp_errno= errno; tmp_errno= errno;
if (thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_EXPLAIN && if (thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_EXPLAIN &&
thd->lex->query_plan_footprint) thd->lex->explain)
{ {
StringBuffer<128> buf; StringBuffer<128> buf;
DBUG_ASSERT(!thd->free_list); 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()); my_b_printf(&log_file, "%s", buf.c_ptr_safe());
thd->free_items(); 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 call might reset the value of current_stmt_binlog_format, so
we need to do any changes to that value after this function. 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); lex_start(thd);
mysql_reset_thd_for_next_command(thd, 0); mysql_reset_thd_for_next_command(thd, 0);
/* /*

View File

@ -22,14 +22,14 @@
#include "sql_select.h" #include "sql_select.h"
QPF_query::QPF_query() Explain_query::Explain_query()
{ {
upd_del_plan= NULL; upd_del_plan= NULL;
operations= 0; operations= 0;
} }
QPF_query::~QPF_query() Explain_query::~Explain_query()
{ {
delete upd_del_plan; delete upd_del_plan;
uint i; 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))) if ((u= get_union(select_id)))
return u; return u;
else else
return get_select(select_id); 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; 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; 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++; 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(); uint select_id= u->get_select_id();
if (unions.elements() <= select_id) if (unions.elements() <= select_id)
unions.resize(max(select_id+1, unions.elements()*2), NULL); 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))) if ((old_node= get_union(select_id)))
delete old_node; delete old_node;
@ -78,15 +78,15 @@ void QPF_query::add_node(QPF_node *node)
} }
else else
{ {
QPF_select *sel= (QPF_select*)node; Explain_select *sel= (Explain_select*)node;
if (sel->select_id == (int)UINT_MAX) if (sel->select_id == FAKE_SELECT_LEX_ID)
{ {
DBUG_ASSERT(0); // this is a "fake select" from a UNION. DBUG_ASSERT(0); // this is a "fake select" from a UNION.
} }
else else
{ {
uint select_id= sel->select_id; uint select_id= sel->select_id;
QPF_select *old_node; Explain_select *old_node;
if (selects.elements() <= select_id) if (selects.elements() <= select_id)
selects.resize(max(select_id+1, selects.elements()*2), NULL); 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 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) uint8 explain_flags)
{ {
if (upd_del_plan) if (upd_del_plan)
@ -115,7 +115,7 @@ int QPF_query::print_explain(select_result_sink *output,
else else
{ {
/* Start printing from node with id=1 */ /* Start printing from node with id=1 */
QPF_node *node= get_node(1); Explain_node *node= get_node(1);
if (!node) if (!node)
return 1; /* No query plan */ return 1; /* No query plan */
return node->print_explain(this, output, explain_flags); 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; List<Item> fields;
thd->make_explain_field_list(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, int Explain_union::print_explain(Explain_query *query,
uint8 explain_flags) select_result_sink *output,
uint8 explain_flags)
{ {
/* print all UNION children, in order */ /* print all UNION children, in order */
for (int i= 0; i < (int) union_members.elements(); i++) 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); 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) 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, select_result_sink *output,
uint8 explain_flags) uint8 explain_flags)
{ {
for (int i= 0; i < (int) children.elements(); i++) 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)) if (node->print_explain(query, output, explain_flags))
return 1; 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) if (join_tabs)
{ {
@ -282,8 +283,9 @@ QPF_select::~QPF_select()
} }
int QPF_select::print_explain(QPF_query *query, select_result_sink *output, int Explain_select::print_explain(Explain_query *query,
uint8 explain_flags) select_result_sink *output,
uint8 explain_flags)
{ {
if (message) 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); 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, uint select_id, const char *select_type,
bool using_temporary, bool using_filesort) 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) { switch (tag) {
case ET_USING: 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: function is:
- index_merge should print $index_merge_type (child, ...) - index_merge should print $index_merge_type (child, ...)
- 'range' should not print anything. - '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 || if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC || 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 || if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC) 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(get_name_by_type());
str->append('('); str->append('(');
List_iterator_fast<QPF_quick_select> it (children); List_iterator_fast<Explain_quick_select> it (children);
QPF_quick_select* child; Explain_quick_select* child;
bool first= true; bool first= true;
while ((child = it++)) 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) { switch (quick_type) {
case QUICK_SELECT_I::QS_TYPE_INDEX_MERGE: 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 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 || if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC || quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
@ -699,8 +701,8 @@ void QPF_quick_select::print_key(String *str)
} }
else else
{ {
List_iterator_fast<QPF_quick_select> it (children); List_iterator_fast<Explain_quick_select> it (children);
QPF_quick_select* child; Explain_quick_select* child;
while ((child = it++)) while ((child = it++))
{ {
child->print_key(str); 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 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 || if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC || quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
@ -728,8 +730,8 @@ void QPF_quick_select::print_key_len(String *str)
} }
else else
{ {
List_iterator_fast<QPF_quick_select> it (children); List_iterator_fast<Explain_quick_select> it (children);
QPF_quick_select* child; Explain_quick_select* child;
while ((child = it++)) while ((child = it++))
{ {
child->print_key_len(str); 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) uint8 explain_flags)
{ {
if (deleting_all_rows) 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) uint8 explain_flags)
{ {
StringBuffer<64> extra_str; 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; delete lex->explain;
lex->query_plan_footprint= NULL; 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); DBUG_ASSERT(!lex->explain);
lex->query_plan_footprint= new QPF_query; lex->explain= new Explain_query;
DBUG_ASSERT(mem_root == current_thd->mem_root); 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 These structures
- Can be produced in-expensively from query plan. - Can be produced inexpensively from query plan.
- Store sufficient information to produce either a tabular or a json EXPLAIN - Store sufficient information to produce a tabular and/or a json EXPLAIN
output
- Have methods that produce a tabular output. - 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. A node can be either a SELECT, or a UNION.
*/ */
class QPF_node : public Sql_alloc class Explain_node : public Sql_alloc
{ {
public: public:
enum qpf_node_type {QPF_UNION, QPF_SELECT, QPF_UPDATE, QPF_DELETE }; enum explain_node_type {EXPLAIN_UNION, EXPLAIN_SELECT, EXPLAIN_UPDATE, EXPLAIN_DELETE };
virtual enum qpf_node_type get_type()= 0; virtual enum explain_node_type get_type()= 0;
virtual int get_select_id()= 0; virtual int get_select_id()= 0;
/* /*
A node may have children nodes. When a node's QPF (Query Plan Footprint) is 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. created, children nodes may not yet have QPFs. This is why we store ids.
*/ */
Dynamic_array<int> children; Dynamic_array<int> children;
void add_child(int select_no) void add_child(int select_no)
@ -51,20 +53,20 @@ public:
children.append(select_no); 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; 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); 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: A select can be:
1. A degenerate case. In this case, message!=NULL, and it contains a 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 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. a way get node's children.
*/ */
class QPF_select : public QPF_node class Explain_select : public Explain_node
{ {
public: 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), message(NULL), join_tabs(NULL),
using_temporary(false), using_filesort(false) 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) 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)); MAX_TABLES, MYF(0));
n_join_tabs= 0; n_join_tabs= 0;
} }
@ -115,31 +117,31 @@ public:
const char *message; 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". would print them".
*/ */
QPF_table_access** join_tabs; Explain_table_access** join_tabs;
uint n_join_tabs; uint n_join_tabs;
/* Global join attributes. In tabular form, they are printed on the first row */ /* Global join attributes. In tabular form, they are printed on the first row */
bool using_temporary; bool using_temporary;
bool using_filesort; 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); uint8 explain_flags);
}; };
/* /*
Query Plan Footprint of a UNION. Explain structure for a UNION.
A UNION may or may not have "Using filesort". A UNION may or may not have "Using filesort".
*/ */
class QPF_union : public QPF_node class Explain_union : public Explain_node
{ {
public: public:
enum qpf_node_type get_type() { return QPF_UNION; } enum explain_node_type get_type() { return EXPLAIN_UNION; }
int get_select_id() int get_select_id()
{ {
@ -163,7 +165,7 @@ public:
{ {
union_members.append(select_no); 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); uint8 explain_flags);
const char *fake_select_type; 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, 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 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: public:
QPF_query(); Explain_query();
~QPF_query(); ~Explain_query();
/* Add a new node */ /* Add a new node */
void add_node(QPF_node *node); void add_node(Explain_node *node);
/* This will return a select, or a union */ /* 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) */ /* 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_delete inherits from QPF_update */
QPF_update *upd_del_plan; QPF_update *upd_del_plan;
@ -237,8 +239,8 @@ public:
bool have_query_plan() { return upd_del_plan!= NULL || get_node(1) != NULL; } bool have_query_plan() { return upd_del_plan!= NULL || get_node(1) != NULL; }
MEM_ROOT *mem_root; MEM_ROOT *mem_root;
private: private:
Dynamic_array<QPF_union*> unions; Dynamic_array<Explain_union*> unions;
Dynamic_array<QPF_select*> selects; Dynamic_array<Explain_select*> selects;
/* /*
Debugging aid: count how many times add_node() was called. Ideally, it 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 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. form.
*/ */
enum Extra_tag enum explain_extra_tag
{ {
ET_none= 0, /* not-a-tag */ ET_none= 0, /* not-a-tag */
ET_USING_INDEX_CONDITION, 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; bool incremental;
const char *join_alg; const char *join_alg;
StringBuffer<64> mrr_type; StringBuffer<64> mrr_type;
} QPF_BKA_TYPE; } EXPLAIN_BKA_TYPE;
/* /*
Data about how an index is used by some access method 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; char *key_name;
uint key_len; uint key_len;
@ -336,16 +338,16 @@ public:
/* /*
QPF for quick range selects, as well as index_merge select 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: public:
int quick_type; int quick_type;
/* This is used when quick_type == QUICK_SELECT_I::QS_TYPE_RANGE */ /* 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 */ /* Used in all other cases */
List<QPF_quick_select> children; List<Explain_quick_select> children;
void print_extra(String *str); void print_extra(String *str);
void print_key(String *str); void print_key(String *str);
@ -359,20 +361,20 @@ private:
/* /*
Query Plan Footprint for a JOIN_TAB. Query Plan Footprint for a JOIN_TAB.
*/ */
class QPF_table_access : public Sql_alloc class Explain_table_access : public Sql_alloc
{ {
public: public:
void push_extra(enum Extra_tag extra_tag); void push_extra(enum explain_extra_tag extra_tag);
/* Internals */ /* Internals */
public: 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. other value means the tab is inside an SJM nest.
*/ */
int sjm_nest_select_id; 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; StringBuffer<32> table_name;
enum join_type type; enum join_type type;
@ -391,13 +393,13 @@ public:
key.key_name == NULL means 'NULL' will be shown in tabular output. 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. 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. when type==JT_HASH_NEXT, 'key' stores the hash join pseudo-key.
hash_next_key stores the table's 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 */ bool ref_set; /* not set means 'NULL' should be printed */
StringBuffer<32> ref; StringBuffer<32> ref;
@ -412,10 +414,10 @@ public:
Contents of the 'Extra' column. Some are converted into strings, some have Contents of the 'Extra' column. Some are converted into strings, some have
parameters, values for which are stored below. 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 // 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 // Valid if ET_USING_INDEX_FOR_GROUP_BY is present
bool loose_scan_is_scanning; bool loose_scan_is_scanning;
@ -427,7 +429,7 @@ public:
StringBuffer<32> mrr_type; StringBuffer<32> mrr_type;
// valid with ET_USING_JOIN_BUFFER // valid with ET_USING_JOIN_BUFFER
QPF_BKA_TYPE bka_type; EXPLAIN_BKA_TYPE bka_type;
StringBuffer<32> firstmatch_table_name; StringBuffer<32> firstmatch_table_name;
@ -435,21 +437,21 @@ public:
uint select_id, const char *select_type, uint select_id, const char *select_type,
bool using_temporary, bool using_filesort); bool using_temporary, bool using_filesort);
private: 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. 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. 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: 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 */ } virtual int get_select_id() { return 1; /* always root */ }
const char *select_type; const char *select_type;
@ -471,7 +473,7 @@ public:
bool using_filesort; 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); uint8 explain_flags);
}; };
@ -489,10 +491,10 @@ public:
*/ */
bool deleting_all_rows; 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 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); 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->quick_type= QS_TYPE_RANGE;
qpf->range.set(alloc, head->key_info[index].name, max_used_key_length); 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->quick_type= QS_TYPE_GROUP_MIN_MAX;
qpf->range.set(alloc, head->key_info[index].name, max_used_key_length); 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(); qpf->quick_type= get_type();
QUICK_RANGE_SELECT *quick; QUICK_RANGE_SELECT *quick;
QPF_quick_select *child_qpf; Explain_quick_select *child_qpf;
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
while ((quick= it++)) while ((quick= it++))
{ {
child_qpf= new QPF_quick_select; child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf); qpf->children.push_back(child_qpf);
quick->save_info(alloc, child_qpf); quick->save_info(alloc, child_qpf);
} }
if (pk_quick_select) if (pk_quick_select)
{ {
child_qpf= new QPF_quick_select; child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf); qpf->children.push_back(child_qpf);
pk_quick_select->save_info(alloc, 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 Same as QUICK_INDEX_SORT_SELECT::save_info(), but primary key is printed
first 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_type= get_type();
QPF_quick_select *child_qpf; Explain_quick_select *child_qpf;
if (pk_quick_select) if (pk_quick_select)
{ {
child_qpf= new QPF_quick_select; child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf); qpf->children.push_back(child_qpf);
pk_quick_select->save_info(alloc, 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); List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
while ((quick= it++)) while ((quick= it++))
{ {
child_qpf= new QPF_quick_select; child_qpf= new Explain_quick_select;
qpf->children.push_back(child_qpf); qpf->children.push_back(child_qpf);
quick->save_info(alloc, 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(); 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); List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
while ((qr= it++)) 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); qpf->children.push_back(child_qpf);
qr->quick->save_info(alloc, child_qpf); qr->quick->save_info(alloc, child_qpf);
} }
if (cpk_quick) 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); qpf->children.push_back(child_qpf);
cpk_quick->save_info(alloc, 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(); 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); List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
while ((quick= it++)) 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); qpf->children.push_back(child_qpf);
quick->save_info(alloc, child_qpf); quick->save_info(alloc, child_qpf);
} }

View File

@ -52,7 +52,7 @@ typedef struct st_key_part {
Field::imagetype image_type; Field::imagetype image_type;
} KEY_PART; } KEY_PART;
class QPF_quick_select; class Explain_quick_select;
/* /*
A "MIN_TUPLE < tbl.key_tuple < MAX_TUPLE" interval. A "MIN_TUPLE < tbl.key_tuple < MAX_TUPLE" interval.
@ -346,7 +346,7 @@ public:
void add_key_name(String *str, bool *first); void add_key_name(String *str, bool *first);
/* Save information about quick select's query plan */ /* 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 Return 1 if any index used by this quick select
@ -473,7 +473,7 @@ public:
{ file->position(record); } { file->position(record); }
int get_type() { return QS_TYPE_RANGE; } int get_type() { return QS_TYPE_RANGE; }
void add_keys_and_lengths(String *key_names, String *used_lengths); 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 #ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose); void dbug_dump(int indent, bool verbose);
#endif #endif
@ -610,7 +610,7 @@ public:
#ifndef DBUG_OFF #ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose); void dbug_dump(int indent, bool verbose);
#endif #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); bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
@ -674,7 +674,7 @@ public:
int get_next(); int get_next();
int get_type() { return QS_TYPE_INDEX_INTERSECT; } int get_type() { return QS_TYPE_INDEX_INTERSECT; }
void add_keys_and_lengths(String *key_names, String *used_lengths); 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; } bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_ROR_INTERSECT; } int get_type() { return QS_TYPE_ROR_INTERSECT; }
void add_keys_and_lengths(String *key_names, String *used_lengths); 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); bool is_keys_used(const MY_BITMAP *fields);
#ifndef DBUG_OFF #ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose); void dbug_dump(int indent, bool verbose);
@ -791,7 +791,7 @@ public:
bool unique_key_range() { return false; } bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_ROR_UNION; } int get_type() { return QS_TYPE_ROR_UNION; }
void add_keys_and_lengths(String *key_names, String *used_lengths); 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); bool is_keys_used(const MY_BITMAP *fields);
#ifndef DBUG_OFF #ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose); void dbug_dump(int indent, bool verbose);
@ -940,7 +940,7 @@ public:
#endif #endif
bool is_agg_distinct() { return have_agg_distinct; } bool is_agg_distinct() { return have_agg_distinct; }
bool loose_scan_is_scanning() { return is_index_scan; } 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(); thd->mdl_context.release_statement_locks();
} }
delete_qpf_query(m_lex); delete_explain_query(m_lex);
if (m_lex->query_tables_own_last) if (m_lex->query_tables_own_last)
{ {
@ -3242,7 +3242,7 @@ sp_instr_set::execute(THD *thd, uint *nextp)
int int
sp_instr_set::exec_core(THD *thd, uint *nextp) 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); int res= thd->spcont->set_variable(thd, m_offset, &m_value);
if (res) if (res)
@ -3255,7 +3255,7 @@ sp_instr_set::exec_core(THD *thd, uint *nextp)
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
} }
} }
delete_qpf_query(thd->lex); delete_explain_query(thd->lex);
*nextp = m_ip+1; *nextp = m_ip+1;
return res; return res;

View File

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

View File

@ -2568,7 +2568,7 @@ finish:
none 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); 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); 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); 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; 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 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); enum_nested_loop_state join_records(bool skip_last);
/* Add a comment on the join algorithm employed by the join cache */ /* 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(); THD *thd();
@ -1336,7 +1336,7 @@ public:
/* Check index condition of the joined table for a record from BKA cache */ /* Check index condition of the joined table for a record from BKA cache */
bool skip_index_tuple(range_id_t range_info); 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 */ /* Check index condition of the joined table for a record from BKAH cache */
bool skip_index_tuple(range_id_t range_info); 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->thd= lex->unit.thd= thd;
lex->query_plan_footprint= NULL; lex->explain= NULL;
lex->context_stack.empty(); lex->context_stack.empty();
lex->unit.init_query(); lex->unit.init_query();
@ -2572,7 +2572,7 @@ void Query_tables_list::destroy_query_tables_list()
*/ */
LEX::LEX() LEX::LEX()
: query_plan_footprint(NULL), : explain(NULL),
result(0), option_type(OPT_DEFAULT), is_lex_started(0), result(0), option_type(OPT_DEFAULT), is_lex_started(0),
limit_rows_examined_cnt(ULONGLONG_MAX) 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; is_correlated_unit|= sl->is_correlated;
inner_join->select_options= save_options; inner_join->select_options= save_options;
un->thd->lex->current_select= save_select; un->thd->lex->current_select= save_select;
/// psergey:
QPF_query *qpf; Explain_query *qpf;
if ((qpf= inner_join->thd->lex->query_plan_footprint)) 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))) if ((qp_sel= qpf->get_select(inner_join->select_lex->select_number)))
{ {
sl->set_explain_type(TRUE); sl->set_explain_type(TRUE);
qp_sel->select_type= sl->type; qp_sel->select_type= sl->type;
} }
} }
///
if (empty_union_result) if (empty_union_result)
{ {
/* /*
@ -4215,9 +4215,9 @@ int LEX::print_explain(select_result_sink *output, uint8 explain_flags,
bool *printed_anything) bool *printed_anything)
{ {
int res; 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; *printed_anything= true;
} }
else 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 Save explain structures of a UNION. The only variable member is whether the
"Using filesort". 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. UNION's output.
The reason for it is examples like this: 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. 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(); 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 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"; const char *msg="Query plan already deleted";
first->set_explain_type(TRUE/* on_the_fly */); 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_id= first->select_number;
qp_sel->select_type= first->type; qp_sel->select_type= first->type;
qp_sel->message= msg; qp_sel->message= msg;
output->add_node(qp_sel); output->add_node(qp_sel);
qpfu->add_select(qp_sel->select_id); eu->add_select(qp_sel->select_id);
return 0; return 0;
} }
for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) 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 // Save the UNION node
output->add_node(qpfu); output->add_node(eu);
qpfu->fake_select_type= "UNION RESULT"; eu->fake_select_type= "UNION RESULT";
qpfu->using_filesort= test(global_parameters->order_list.first); eu->using_filesort= test(global_parameters->order_list.first);
return 0; 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) if (fake_select_lex)
{ {
for (SELECT_LEX_UNIT *unit= fake_select_lex->first_inner_unit(); 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)) 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 JOIN;
class select_union; class select_union;
class Procedure; class Procedure;
class QPF_query; class Explain_query;
void delete_qpf_query(LEX *lex); void delete_explain_query(LEX *lex);
void create_qpf_query(LEX *lex, MEM_ROOT *mem_root); void create_explain_query(LEX *lex, MEM_ROOT *mem_root);
bool print_qpf_query(LEX *lex, THD *thd, String *str); bool print_explain_query(LEX *lex, THD *thd, String *str);
class st_select_lex_unit: public st_select_lex_node { class st_select_lex_unit: public st_select_lex_node {
protected: protected:
@ -734,8 +734,8 @@ public:
List<Item> *get_unit_column_types(); List<Item> *get_unit_column_types();
int save_union_qpf(QPF_query *output); int save_union_explain(Explain_query *output);
int save_union_qpf_part2(QPF_query *output); int save_union_explain_part2(Explain_query *output);
}; };
typedef class st_select_lex_unit SELECT_LEX_UNIT; typedef class st_select_lex_unit SELECT_LEX_UNIT;
@ -2368,7 +2368,7 @@ protected:
class Delete_plan; class Delete_plan;
class SQL_SELECT; class SQL_SELECT;
class QPF_query; class Explain_query;
class QPF_update; class QPF_update;
/* /*
@ -2398,8 +2398,8 @@ public:
/* Set this plan to be a plan to do nothing because of impossible WHRE*/ /* Set this plan to be a plan to do nothing because of impossible WHRE*/
void set_impossible_where() { impossible_where= true; } void set_impossible_where() { impossible_where= true; }
void save_qpf(QPF_query *query); void save_explain_data(Explain_query *query);
void save_qpf_intern(QPF_query *query, QPF_update *qpf); void save_explain_data_intern(Explain_query *query, QPF_update *qpf);
virtual ~Update_plan() {} virtual ~Update_plan() {}
Update_plan() : impossible_where(false), using_filesort(false) {} Update_plan() : impossible_where(false), using_filesort(false) {}
@ -2423,7 +2423,7 @@ public:
table_rows= rows_arg; 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; SELECT_LEX *all_selects_list;
/* Query Plan Footprint of a currently running select */ /* Query Plan Footprint of a currently running select */
QPF_query *query_plan_footprint; Explain_query *explain;
char *length,*dec,*change; char *length,*dec,*change;
LEX_STRING name; LEX_STRING name;

View File

@ -598,7 +598,7 @@ static void handle_bootstrap_impl(THD *thd)
#if defined(ENABLED_PROFILING) #if defined(ENABLED_PROFILING)
thd->profiling.finish_current_query(); thd->profiling.finish_current_query();
#endif #endif
delete_qpf_query(thd->lex); delete_explain_query(thd->lex);
if (bootstrap_error) if (bootstrap_error)
break; break;
@ -1526,7 +1526,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* /*
@note @note
This function must call delete_qpf_query(). This function must call delete_explain_query().
*/ */
void log_slow_statement(THD *thd) 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->variables.log_slow_filter & thd->query_plan_flags))) && !(thd->variables.log_slow_filter & thd->query_plan_flags)))
{ {
delete_qpf_query(thd->lex); delete_explain_query(thd->lex);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@ -1573,7 +1573,7 @@ void log_slow_statement(THD *thd)
thd_proc_info(thd, 0); thd_proc_info(thd, 0);
} }
delete_qpf_query(thd->lex); delete_explain_query(thd->lex);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@ -2201,7 +2201,7 @@ mysql_execute_command(THD *thd)
thd->mdl_context.release_transactional_locks(); 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 #ifndef DBUG_OFF
if (lex->sql_command != SQLCOM_SET_OPTION) if (lex->sql_command != SQLCOM_SET_OPTION)
@ -3252,7 +3252,7 @@ end_with_restore_list:
select_result *result= new select_send(); select_result *result= new select_send();
LEX *lex= thd->lex; LEX *lex= thd->lex;
if (thd->send_explain_fields(result) || 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()) result->send_eof())
res= 1; res= 1;
} }
@ -3361,7 +3361,7 @@ end_with_restore_list:
select_result *result= new select_send(); select_result *result= new select_send();
LEX *lex= thd->lex; LEX *lex= thd->lex;
if (thd->send_explain_fields(result) || 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()) result->send_eof())
res= 1; res= 1;
} }
@ -4901,8 +4901,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
top-level LIMIT top-level LIMIT
*/ */
result->reset_offset_limit(); result->reset_offset_limit();
thd->lex->query_plan_footprint->print_explain(result, thd->lex->explain->print_explain(result, thd->lex->describe);
thd->lex->describe);
if (lex->describe & DESCRIBE_EXTENDED) if (lex->describe & DESCRIBE_EXTENDED)
{ {
char buff[1024]; 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. object and because of this can be used in different threads.
*/ */
lex->thd= thd; lex->thd= thd;
DBUG_ASSERT(!lex->query_plan_footprint); DBUG_ASSERT(!lex->explain);
if (lex->empty_field_list_on_rset) if (lex->empty_field_list_on_rset)
{ {
@ -3931,8 +3931,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (! cursor) if (! cursor)
cleanup_stmt(); 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->set_statement(&stmt_backup);
thd->stmt_arena= old_stmt_arena; 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_NOT_PRESENT_YET &&
join->have_query_plan != JOIN::QEP_DELETED && // this happens when there was no QEP ever, but then join->have_query_plan != JOIN::QEP_DELETED && // this happens when there was no QEP ever, but then
//cleanup() is called multiple times //cleanup() is called multiple times
thd->lex->explain && // for "SET" command in SPs.
thd->lex->query_plan_footprint && // for "SET" command in SPs. !thd->lex->explain->get_select(join->select_lex->select_number))
!thd->lex->query_plan_footprint->get_select(join->select_lex->select_number))
{ {
const char *message= NULL; 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"; message= join->zero_result_cause ? join->zero_result_cause : "No tables used";
} }
join->save_qpf(thd->lex->query_plan_footprint, join->save_explain_data(thd->lex->explain,
join->need_tmp, // need_tmp_table join->need_tmp,
!join->skip_sort_order && !join->no_order && !join->skip_sort_order && !join->no_order &&
(join->order || join->group_list), // bool need_order (join->order || join->group_list),
join->select_distinct, // bool distinct join->select_distinct,
message); // message message);
} }
} }
@ -2347,34 +2346,29 @@ void JOIN::exec()
exec_inner(); exec_inner();
if (!exec_qpf_saved) if (!exec_saved_explain)
{ {
if (select_lex->select_number != UINT_MAX && if (select_lex->select_number != UINT_MAX &&
select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ && 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_NOT_PRESENT_YET &&
have_query_plan != QEP_DELETED && // this happens when there was no QEP ever, but then have_query_plan != QEP_DELETED && // this happens when there was no QEP ever, but then
//cleanup() is called multiple times //cleanup() is called multiple times
thd->lex->explain)// for "SET" command in SPs.
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; const char *message= NULL;
if (!table_count || !tables_list || zero_result_cause) if (!table_count || !tables_list || zero_result_cause)
{ {
/* It's a degenerate join */ /* It's a degenerate join */
message= zero_result_cause ? zero_result_cause : "No tables used"; message= zero_result_cause ? zero_result_cause : "No tables used";
} }
save_qpf(thd->lex->query_plan_footprint, save_explain_data(thd->lex->explain,
need_tmp, // need_tmp_table need_tmp,
// !skip_sort_order && !no_order && order != 0 && !skip_sort_order,
// (order || group_list), // bool need_order select_distinct,
order != 0 && !skip_sort_order, message);
select_distinct, // bool distinct
message); // message
} }
exec_qpf_saved= true; exec_saved_explain= true;
} }
DBUG_EXECUTE_IF("show_explain_probe_join_exec_end", 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)); DBUG_PRINT("enter", ("full %u", (uint) full));
if (full) if (full)
{ have_query_plan= QEP_DELETED;
/* 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!
}
if (table) 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 Currently, this function may be called multiple times
*/ */
int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order, int JOIN::save_explain_data(Explain_query *output, bool need_tmp_table,
bool distinct, const char *message) 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 */ JOIN *join= this; /* Legacy: this code used to be a non-member function */
THD *thd=join->thd; THD *thd=join->thd;
const CHARSET_INFO *cs= system_charset_info; const CHARSET_INFO *cs= system_charset_info;
int quick_type; int quick_type;
int error= 0; int error= 0;
DBUG_ENTER("JOIN::save_qpf"); DBUG_ENTER("JOIN::save_explain_data");
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s", DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
(ulong)join->select_lex, join->select_lex->type, (ulong)join->select_lex, join->select_lex->type,
message ? message : "NULL")); message ? message : "NULL"));
@ -22540,8 +22505,8 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
if (message) if (message)
{ {
QPF_select *qp_sel; Explain_select *qp_sel;
qp_node= qp_sel= new (output->mem_root) QPF_select; qp_node= qp_sel= new (output->mem_root) Explain_select;
join->select_lex->set_explain_type(true); join->select_lex->set_explain_type(true);
qp_sel->select_id= join->select_lex->select_number; 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) 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 || else if (!join->select_lex->master_unit()->derived ||
join->select_lex->master_unit()->derived->is_materialized_derived()) join->select_lex->master_unit()->derived->is_materialized_derived())
{ {
QPF_select *qp_sel; Explain_select *qp_sel;
qp_node= qp_sel= new (output->mem_root) QPF_select; qp_node= qp_sel= new (output->mem_root) Explain_select;
table_map used_tables=0; table_map used_tables=0;
join->select_lex->set_explain_type(true); 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; 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); qp_sel->add_table(qpt);
qpt->key.set(thd->mem_root, NULL, (uint)-1); qpt->key.set(thd->mem_root, NULL, (uint)-1);
qpt->quick_info= NULL; 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) 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); 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) if (tab->cache)
{ {
qpt->push_extra(ET_USING_JOIN_BUFFER); 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"); DBUG_ENTER("select_describe");
/* Update the QPF with latest values of using_temporary, using_filesort */ /* 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; 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_temporary= need_tmp_table;
qp->using_filesort= need_order; 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()) 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->type= "UNION RESULT";
unit->fake_select_lex->options|= SELECT_DESCRIBE; unit->fake_select_lex->options|= SELECT_DESCRIBE;
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | 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; JOIN_TAB_RANGE *bush_children;
/* Special content for EXPLAIN 'Extra' column or NULL if none */ /* 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' Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
@ -1336,7 +1336,7 @@ public:
emb_sjm_nest= NULL; emb_sjm_nest= NULL;
sjm_lookup_tables= 0; sjm_lookup_tables= 0;
exec_qpf_saved= false; exec_saved_explain= false;
/* /*
The following is needed because JOIN::cleanup(true) may be called for 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 joins for which JOIN::optimize was aborted with an error before a proper
@ -1344,7 +1344,13 @@ public:
*/ */
table_access_tabs= NULL; 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, int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
COND *conds, uint og_num, ORDER *order, ORDER *group, COND *conds, uint og_num, ORDER *order, ORDER *group,
@ -1470,8 +1476,8 @@ public:
{ {
return (unit->item && unit->item->is_in_predicate()); return (unit->item && unit->item->is_in_predicate());
} }
int save_qpf(QPF_query *output, bool need_tmp_table, bool need_order, int save_explain_data(Explain_query *output, bool need_tmp_table,
bool distinct, const char *message); bool need_order, bool distinct, const char *message);
private: private:
/** /**
TRUE if the query contains an aggregate function but has no GROUP 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(); saved_error= optimize();
if (!was_executed && thd->lex->query_plan_footprint) if (!was_executed && thd->lex->explain)
save_union_qpf(thd->lex->query_plan_footprint); save_union_explain(thd->lex->explain);
if (uncacheable || !item || !item->assigned() || describe) if (uncacheable || !item || !item->assigned() || describe)
{ {
@ -780,8 +780,8 @@ bool st_select_lex_unit::exec()
if (!fake_select_lex->ref_pointer_array) if (!fake_select_lex->ref_pointer_array)
fake_select_lex->n_child_sum_items+= global_parameters->n_sum_items; fake_select_lex->n_child_sum_items+= global_parameters->n_sum_items;
if (!was_executed && thd->lex->query_plan_footprint) if (!was_executed && thd->lex->explain)
save_union_qpf_part2(thd->lex->query_plan_footprint); save_union_explain_part2(thd->lex->explain);
saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array, saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
&result_table_list, &result_table_list,

View File

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

View File

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