[SHOW] EXPLAIN UPDATE/DELETE, code re-structuring

- Make EXPLAIN UPDATE/DELETE use "Query Plan Footprints", too.
This commit is contained in:
Sergey Petrunya 2013-06-18 21:08:34 +04:00
parent 1c6fc3f6b9
commit 1951d40a88
6 changed files with 152 additions and 115 deletions

View file

@ -12,6 +12,7 @@
QPF_query::QPF_query() QPF_query::QPF_query()
{ {
upd_del_plan= NULL;
memset(&unions, 0, sizeof(unions)); memset(&unions, 0, sizeof(unions));
memset(&selects, 0, sizeof(selects)); memset(&selects, 0, sizeof(selects));
} }
@ -19,6 +20,7 @@ QPF_query::QPF_query()
QPF_query::~QPF_query() QPF_query::~QPF_query()
{ {
delete upd_del_plan;
uint i; uint i;
for (i=0 ; i < MAX_TABLES; i++) for (i=0 ; i < MAX_TABLES; i++)
delete unions[i]; delete unions[i];
@ -70,9 +72,17 @@ void QPF_query::add_node(QPF_node *node)
int QPF_query::print_explain(select_result_sink *output, int QPF_query::print_explain(select_result_sink *output,
uint8 explain_flags) uint8 explain_flags)
{ {
// Start with id=1 if (upd_del_plan)
QPF_node *node= get_node(1); {
return node->print_explain(this, output, explain_flags); upd_del_plan->print_explain(output, explain_flags);
return 0;
}
else
{
// Start with id=1
QPF_node *node= get_node(1);
return node->print_explain(this, output, explain_flags);
}
} }

View file

@ -161,6 +161,9 @@ public:
/* 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); QPF_select *get_select(uint select_id);
/* Delete_plan inherits from Update_plan */
Update_plan *upd_del_plan;
private: private:
QPF_union *unions[MAX_TABLES]; QPF_union *unions[MAX_TABLES];
@ -269,10 +272,10 @@ public:
key_map range_checked_map; key_map range_checked_map;
// valid with ET_USING_MRR // valid with ET_USING_MRR
StringBuffer <64> mrr_type; StringBuffer<64> mrr_type;
// valid with ET_USING_JOIN_BUFFER // valid with ET_USING_JOIN_BUFFER
StringBuffer <64> join_buffer_type; StringBuffer<64> join_buffer_type;
//TABLE *firstmatch_table; //TABLE *firstmatch_table;
StringBuffer<64> firstmatch_table_name; StringBuffer<64> firstmatch_table_name;

View file

@ -51,8 +51,7 @@
invoked on a running DELETE statement. invoked on a running DELETE statement.
*/ */
int Delete_plan::print_explain(select_result_sink *output, uint8 explain_flags, int Delete_plan::print_explain(select_result_sink *output, uint8 explain_flags)
bool *printed_anything)
{ {
if (deleting_all_rows) if (deleting_all_rows)
{ {
@ -62,37 +61,15 @@ int Delete_plan::print_explain(select_result_sink *output, uint8 explain_flags,
{ {
return 1; return 1;
} }
*printed_anything= true;
return 0; return 0;
} }
return Update_plan::print_explain(output, explain_flags, printed_anything); return Update_plan::print_explain(output, explain_flags);
} }
void Update_plan::save_query_plan_footprint()
int Update_plan::print_explain(select_result_sink *output, uint8 explain_flags,
bool *printed_anything)
{ {
if (impossible_where) select_lex->set_explain_type(TRUE);
{
const char *msg= "Impossible where";
if (print_explain_message_line(output, explain_flags, 1/*select number*/,
"SIMPLE", msg))
{
return 1;
}
*printed_anything= true;
return 0;
}
select_lex->set_explain_type(FALSE);
/*
Print an EXPLAIN line. We dont have join, so we can't directly use
JOIN::print_explain.
We do have a SELECT_LEX (TODO but how is it useful? it has select_type..
and that's it?)
*/
enum join_type jtype;
if (select && select->quick) if (select && select->quick)
{ {
int quick_type= select->quick->get_type(); int quick_type= select->quick->get_type();
@ -112,35 +89,53 @@ int Update_plan::print_explain(select_result_sink *output, uint8 explain_flags,
jtype= JT_NEXT; jtype= JT_NEXT;
} }
StringBuffer<128> possible_keys_line; using_where= test(select && select->cond);
//using_filesort is already set
make_possible_keys_line(table, possible_keys, &possible_keys_line); make_possible_keys_line(table, possible_keys, &possible_keys_line);
const char *key_name;
const char *key_len;
StringBuffer<128> key_str;
StringBuffer<128> key_len_str;
StringBuffer<128> extra_str;
/* Calculate key_len */ /* Calculate key_len */
if (select && select->quick) if (select && select->quick)
{ {
select->quick->add_keys_and_lengths(&key_str, &key_len_str); select->quick->add_keys_and_lengths(&key_str, &key_len_str);
key_name= key_str.c_ptr();
key_len= key_len_str.c_ptr();
} }
else else
{ {
key_name= (index == MAX_KEY)? NULL : table->key_info[index].name; if (index != MAX_KEY)
key_len= NULL; {
key_str.append(table->key_info[index].name);
}
// key_len stays NULL
} }
if (select && select->cond)
extra_str.append(STRING_WITH_LEN("Using where"));
if (select && select->quick && if (select && select->quick &&
select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE) select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE)
{ {
explain_append_mrr_info((QUICK_RANGE_SELECT*)select->quick, &extra_str); explain_append_mrr_info((QUICK_RANGE_SELECT*)select->quick, &mrr_type);
}
}
int Update_plan::print_explain(select_result_sink *output, uint8 explain_flags)
{
StringBuffer<64> extra_str;
if (impossible_where)
{
const char *msg= "Impossible where";
if (print_explain_message_line(output, explain_flags, 1/*select number*/,
"SIMPLE", msg))
{
return 1;
}
return 0;
}
if (using_where)
extra_str.append(STRING_WITH_LEN("Using where"));
if (mrr_type.length() != 0)
{
if (extra_str.length() !=0)
extra_str.append(STRING_WITH_LEN("; "));
extra_str.append(mrr_type);
} }
if (using_filesort) if (using_filesort)
@ -160,15 +155,14 @@ int Update_plan::print_explain(select_result_sink *output, uint8 explain_flags,
select_lex->type, select_lex->type,
table->pos_in_table_list->alias, table->pos_in_table_list->alias,
// partitions, // partitions,
jtype, (enum join_type) jtype,
possible_keys_line.length()? possible_keys_line.c_ptr(): NULL, possible_keys_line.length()? possible_keys_line.c_ptr(): NULL,
key_name, key_str.length()? key_str.c_ptr() : NULL,
key_len, key_len_str.length() ? key_len_str.c_ptr() : NULL,
NULL, /* 'ref' is always NULL in single-table EXPLAIN DELETE */ NULL, /* 'ref' is always NULL in single-table EXPLAIN DELETE */
select ? select->records : table_rows, select ? select->records : table_rows,
extra_str.c_ptr()); extra_str.c_ptr());
*printed_anything= true;
/* /*
psergey-todo: handle all this through saving QPF. psergey-todo: handle all this through saving QPF.
@ -211,10 +205,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
killed_state killed_status= NOT_KILLED; killed_state killed_status= NOT_KILLED;
THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE; THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
Delete_plan query_plan; Delete_plan *query_plan = new Delete_plan;
query_plan.index= MAX_KEY; query_plan->index= MAX_KEY;
query_plan.using_filesort= FALSE; query_plan->using_filesort= FALSE;
DBUG_ENTER("mysql_delete"); DBUG_ENTER("mysql_delete");
if (open_and_lock_tables(thd, table_list, TRUE, 0)) if (open_and_lock_tables(thd, table_list, TRUE, 0))
@ -238,8 +232,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
} }
thd_proc_info(thd, "init"); thd_proc_info(thd, "init");
table->map=1; table->map=1;
query_plan.select_lex= &thd->lex->select_lex; query_plan->select_lex= &thd->lex->select_lex;
query_plan.table= table; query_plan->table= table;
if (mysql_prepare_delete(thd, table_list, &conds)) if (mysql_prepare_delete(thd, table_list, &conds))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
@ -314,7 +308,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
ha_rows const maybe_deleted= table->file->stats.records; ha_rows const maybe_deleted= table->file->stats.records;
DBUG_PRINT("debug", ("Trying to use delete_all_rows()")); DBUG_PRINT("debug", ("Trying to use delete_all_rows()"));
query_plan.set_delete_all_rows(maybe_deleted); query_plan->set_delete_all_rows(maybe_deleted);
if (thd->lex->describe) if (thd->lex->describe)
goto exit_without_my_ok; goto exit_without_my_ok;
@ -344,7 +338,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (result == Item::COND_FALSE) // Impossible where if (result == Item::COND_FALSE) // Impossible where
{ {
limit= 0; limit= 0;
query_plan.set_impossible_where(); query_plan->set_impossible_where();
if (thd->lex->describe) if (thd->lex->describe)
goto exit_without_my_ok; goto exit_without_my_ok;
} }
@ -372,7 +366,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if ((select && select->check_quick(thd, safe_update, limit)) || !limit) if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
{ {
query_plan.set_impossible_where(); query_plan->set_impossible_where();
if (thd->lex->describe) if (thd->lex->describe)
goto exit_without_my_ok; goto exit_without_my_ok;
@ -413,20 +407,22 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (select && select->quick && select->quick->unique_key_range()) if (select && select->quick && select->quick->unique_key_range())
{ // Single row select (always "ordered") { // Single row select (always "ordered")
query_plan.using_filesort= FALSE; query_plan->using_filesort= FALSE;
query_plan.index= MAX_KEY; query_plan->index= MAX_KEY;
} }
else else
query_plan.index= get_index_for_order(order, table, select, limit, query_plan->index= get_index_for_order(order, table, select, limit,
&query_plan.using_filesort, &query_plan->using_filesort,
&reverse); &reverse);
} }
query_plan.select= select; query_plan->select= select;
query_plan.possible_keys= table->quick_keys; query_plan->possible_keys= table->quick_keys;
query_plan.table_rows= table->file->stats.records; query_plan->table_rows= table->file->stats.records;
thd->lex->upd_del_plan= &query_plan;
thd->lex->query_plan_footprint= new QPF_query;
thd->lex->query_plan_footprint->upd_del_plan= query_plan;
/* /*
Ok, we have generated a query plan for the DELETE. Ok, we have generated a query plan for the DELETE.
- if we're running EXPLAIN DELETE, goto produce explain output - if we're running EXPLAIN DELETE, goto produce explain output
@ -435,11 +431,12 @@ 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_query_plan_footprint();
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",
dbug_serve_apcs(thd, 1);); dbug_serve_apcs(thd, 1););
if (query_plan.using_filesort) if (query_plan->using_filesort)
{ {
ha_rows examined_rows; ha_rows examined_rows;
ha_rows found_rows; ha_rows found_rows;
@ -447,7 +444,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
SORT_FIELD *sortorder; SORT_FIELD *sortorder;
{ {
DBUG_ASSERT(query_plan.index == MAX_KEY); DBUG_ASSERT(query_plan->index == MAX_KEY);
table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE), table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL | MYF(MY_FAE | MY_ZEROFILL |
MY_THREAD_SPECIFIC)); MY_THREAD_SPECIFIC));
@ -483,7 +480,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
thd->apc_target.disable(); thd->apc_target.disable();
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
if (query_plan.index == MAX_KEY || (select && select->quick)) if (query_plan->index == MAX_KEY || (select && select->quick))
{ {
if (init_read_record(&info, thd, table, select, 1, 1, FALSE)) if (init_read_record(&info, thd, table, select, 1, 1, FALSE))
{ {
@ -494,7 +491,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
} }
} }
else else
init_read_record_idx(&info, thd, table, 1, query_plan.index, reverse); init_read_record_idx(&info, thd, table, 1, query_plan->index, reverse);
init_ftfuncs(thd, select_lex, 1); init_ftfuncs(thd, select_lex, 1);
thd_proc_info(thd, "updating"); thd_proc_info(thd, "updating");
@ -587,6 +584,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
(void) table->file->extra(HA_EXTRA_NORMAL); (void) table->file->extra(HA_EXTRA_NORMAL);
thd->apc_target.disable(); thd->apc_target.disable();
if (thd->lex->query_plan_footprint)
{
delete thd->lex->query_plan_footprint;
thd->lex->query_plan_footprint= NULL;
}
cleanup: cleanup:
/* /*
Invalidate the table in the query cache if something changed. This must Invalidate the table in the query cache if something changed. This must
@ -650,21 +652,25 @@ cleanup:
/* Special exits */ /* Special exits */
exit_without_my_ok: exit_without_my_ok:
thd->lex->upd_del_plan= &query_plan; query_plan->save_query_plan_footprint();
thd->lex->query_plan_footprint->upd_del_plan= query_plan;
select_send *result; select_send *result;
bool printed_anything;
if (!(result= new select_send())) if (!(result= new select_send()))
return 1; /* purecov: inspected */ return 1; /* purecov: inspected */
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->print_explain(result, 0 /* explain flags*/, &printed_anything); int err2= thd->lex->query_plan_footprint->print_explain(result, 0);
if (err2) if (err2)
result->abort_result_set(); result->abort_result_set();
else else
result->send_eof(); result->send_eof();
delete thd->lex->query_plan_footprint;
thd->lex->query_plan_footprint= NULL;
delete select; delete select;
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);

View file

@ -448,7 +448,6 @@ void lex_start(THD *thd)
lex->thd= lex->unit.thd= thd; lex->thd= lex->unit.thd= thd;
lex->upd_del_plan= NULL;
lex->context_stack.empty(); lex->context_stack.empty();
lex->unit.init_query(); lex->unit.init_query();
lex->unit.init_select(); lex->unit.init_select();
@ -2561,7 +2560,6 @@ LEX::LEX()
INITIAL_LEX_PLUGIN_LIST_SIZE, 0); INITIAL_LEX_PLUGIN_LIST_SIZE, 0);
reset_query_tables_list(TRUE); reset_query_tables_list(TRUE);
mi.init(); mi.init();
upd_del_plan= NULL;
} }
@ -4176,11 +4174,11 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor)
int LEX::print_explain(select_result_sink *output, uint8 explain_flags, int LEX::print_explain(select_result_sink *output, uint8 explain_flags,
bool *printed_anything) bool *printed_anything)
{ {
if (upd_del_plan) /* if (upd_del_plan)
{ {
upd_del_plan->print_explain(output, explain_flags, printed_anything); upd_del_plan->print_explain(output, explain_flags, printed_anything);
return 0; return 0;
} }*/
//int res= unit.print_explain(output, explain_flags, printed_anything); //int res= unit.print_explain(output, explain_flags, printed_anything);
//psergey-todo: here, we should make Query Plan Footprint, and then produce //psergey-todo: here, we should make Query Plan Footprint, and then produce

View file

@ -2378,6 +2378,7 @@ public:
SQL_SELECT *select; SQL_SELECT *select;
uint index; uint index;
ha_rows table_rows; /* Use if select==NULL */ ha_rows table_rows; /* Use if select==NULL */
/* /*
Top-level select_lex. Most of its fields are not used, we need it only to Top-level select_lex. Most of its fields are not used, we need it only to
get to the subqueries. get to the subqueries.
@ -2390,11 +2391,20 @@ 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; }
virtual int print_explain(select_result_sink *output, uint8 explain_flags, virtual int print_explain(select_result_sink *output, uint8 explain_flags);
bool *printed_anything);
virtual ~Update_plan() {} virtual ~Update_plan() {}
Update_plan() : impossible_where(false), using_filesort(false) {} Update_plan() : impossible_where(false), using_filesort(false) {}
void save_query_plan_footprint();
/* Query Plan Footprint fields */
// cant use it here: enum join_type
int jtype;
bool using_where;
StringBuffer<128> possible_keys_line;
StringBuffer<128> key_str;
StringBuffer<128> key_len_str;
StringBuffer<64> mrr_type;
}; };
@ -2414,8 +2424,7 @@ public:
deleting_all_rows= true; deleting_all_rows= true;
table_rows= rows_arg; table_rows= rows_arg;
} }
int print_explain(select_result_sink *output, uint8 explain_flags, int print_explain(select_result_sink *output, uint8 explain_flags);
bool *printed_anything);
}; };
@ -2432,7 +2441,6 @@ struct LEX: public Query_tables_list
SELECT_LEX *all_selects_list; SELECT_LEX *all_selects_list;
/* For single-table DELETE: its query plan */ /* For single-table DELETE: its query plan */
Update_plan *upd_del_plan;
QPF_query *query_plan_footprint; QPF_query *query_plan_footprint;
char *length,*dec,*change; char *length,*dec,*change;

View file

@ -276,9 +276,7 @@ int mysql_update(THD *thd,
ulonglong id; ulonglong id;
List<Item> all_fields; List<Item> all_fields;
killed_state killed_status= NOT_KILLED; killed_state killed_status= NOT_KILLED;
Update_plan query_plan; Update_plan *query_plan;
query_plan.index= MAX_KEY;
query_plan.using_filesort= FALSE;
bool apc_target_enabled= false; // means was enabled *by code this function* bool apc_target_enabled= false; // means was enabled *by code this function*
DBUG_ENTER("mysql_update"); DBUG_ENTER("mysql_update");
@ -317,9 +315,12 @@ int mysql_update(THD *thd,
/* Calculate "table->covering_keys" based on the WHERE */ /* Calculate "table->covering_keys" based on the WHERE */
table->covering_keys= table->s->keys_in_use; table->covering_keys= table->s->keys_in_use;
table->quick_keys.clear_all(); table->quick_keys.clear_all();
query_plan.select_lex= &thd->lex->select_lex; query_plan= new Update_plan;
query_plan.table= table; query_plan->index= MAX_KEY;
query_plan->using_filesort= FALSE;
query_plan->select_lex= &thd->lex->select_lex;
query_plan->table= table;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Force privilege re-checking for views after they have been opened. */ /* Force privilege re-checking for views after they have been opened. */
want_privilege= (table_list->view ? UPDATE_ACL : want_privilege= (table_list->view ? UPDATE_ACL :
@ -378,7 +379,7 @@ int mysql_update(THD *thd,
if (cond_value == Item::COND_FALSE) if (cond_value == Item::COND_FALSE)
{ {
limit= 0; // Impossible WHERE limit= 0; // Impossible WHERE
query_plan.set_impossible_where(); query_plan->set_impossible_where();
if (thd->lex->describe) if (thd->lex->describe)
goto exit_without_my_ok; goto exit_without_my_ok;
} }
@ -411,7 +412,7 @@ int mysql_update(THD *thd,
if (error || !limit || thd->is_error() || if (error || !limit || thd->is_error() ||
(select && select->check_quick(thd, safe_update, limit))) (select && select->check_quick(thd, safe_update, limit)))
{ {
query_plan.set_impossible_where(); query_plan->set_impossible_where();
if (thd->lex->describe) if (thd->lex->describe)
goto exit_without_my_ok; goto exit_without_my_ok;
@ -453,16 +454,16 @@ int mysql_update(THD *thd,
if (select && select->quick && select->quick->unique_key_range()) if (select && select->quick && select->quick->unique_key_range())
{ // Single row select (always "ordered"): Ok to use with key field UPDATE { // Single row select (always "ordered"): Ok to use with key field UPDATE
need_sort= FALSE; need_sort= FALSE;
query_plan.index= MAX_KEY; query_plan->index= MAX_KEY;
used_key_is_modified= FALSE; used_key_is_modified= FALSE;
} }
else else
{ {
query_plan.index= get_index_for_order(order, table, select, limit, query_plan->index= get_index_for_order(order, table, select, limit,
&need_sort, &reverse); &need_sort, &reverse);
if (select && select->quick) if (select && select->quick)
{ {
DBUG_ASSERT(need_sort || query_plan.index == select->quick->index); DBUG_ASSERT(need_sort || query_plan->index == select->quick->index);
used_key_is_modified= (!select->quick->unique_key_range() && used_key_is_modified= (!select->quick->unique_key_range() &&
select->quick->is_keys_used(table->write_set)); select->quick->is_keys_used(table->write_set));
} }
@ -470,11 +471,11 @@ int mysql_update(THD *thd,
{ {
if (need_sort) if (need_sort)
{ // Assign table scan index to check below for modified key fields: { // Assign table scan index to check below for modified key fields:
query_plan.index= table->file->key_used_on_scan; query_plan->index= table->file->key_used_on_scan;
} }
if (query_plan.index != MAX_KEY) if (query_plan->index != MAX_KEY)
{ // Check if we are modifying a key that we are used to search with: { // Check if we are modifying a key that we are used to search with:
used_key_is_modified= is_key_used(table, query_plan.index, table->write_set); used_key_is_modified= is_key_used(table, query_plan->index, table->write_set);
} }
} }
} }
@ -484,10 +485,11 @@ int mysql_update(THD *thd,
- Save the decisions in the query plan - Save the decisions in the query plan
- if we're running EXPLAIN UPDATE, get out - if we're running EXPLAIN UPDATE, get out
*/ */
query_plan.select= select; query_plan->select= select;
query_plan.possible_keys= table->quick_keys; query_plan->possible_keys= table->quick_keys;
query_plan.table_rows= table->file->stats.records; query_plan->table_rows= table->file->stats.records;
thd->lex->upd_del_plan= &query_plan; thd->lex->query_plan_footprint= new QPF_query;
thd->lex->query_plan_footprint->upd_del_plan= query_plan;
/* /*
Ok, we have generated a query plan for the UPDATE. Ok, we have generated a query plan for the UPDATE.
@ -496,7 +498,8 @@ 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_query_plan_footprint();
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",
@ -515,8 +518,8 @@ int mysql_update(THD *thd,
DBUG_ASSERT(table->read_set == &table->def_read_set); DBUG_ASSERT(table->read_set == &table->def_read_set);
DBUG_ASSERT(table->write_set == &table->def_write_set); DBUG_ASSERT(table->write_set == &table->def_write_set);
if (query_plan.index < MAX_KEY && old_covering_keys.is_set(query_plan.index)) if (query_plan->index < MAX_KEY && old_covering_keys.is_set(query_plan->index))
table->add_read_columns_used_by_index(query_plan.index); table->add_read_columns_used_by_index(query_plan->index);
else else
table->use_all_columns(); table->use_all_columns();
@ -582,13 +585,13 @@ int mysql_update(THD *thd,
Full index scan must be started with init_read_record_idx Full index scan must be started with init_read_record_idx
*/ */
if (query_plan.index == MAX_KEY || (select && select->quick)) if (query_plan->index == MAX_KEY || (select && select->quick))
{ {
if (init_read_record(&info, thd, table, select, 0, 1, FALSE)) if (init_read_record(&info, thd, table, select, 0, 1, FALSE))
goto err; goto err;
} }
else else
init_read_record_idx(&info, thd, table, 1, query_plan.index, reverse); init_read_record_idx(&info, thd, table, 1, query_plan->index, reverse);
thd_proc_info(thd, "Searching rows for update"); thd_proc_info(thd, "Searching rows for update");
ha_rows tmp_limit= limit; ha_rows tmp_limit= limit;
@ -1002,6 +1005,12 @@ err:
if (apc_target_enabled) if (apc_target_enabled)
thd->apc_target.disable(); thd->apc_target.disable();
if (thd->lex->query_plan_footprint)
{
delete thd->lex->query_plan_footprint;
thd->lex->query_plan_footprint= NULL;
}
delete select; delete select;
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
table->disable_keyread(); table->disable_keyread();
@ -1010,22 +1019,25 @@ err:
exit_without_my_ok: exit_without_my_ok:
DBUG_ASSERT(!apc_target_enabled); DBUG_ASSERT(!apc_target_enabled);
thd->lex->upd_del_plan= &query_plan; query_plan->save_query_plan_footprint();
thd->lex->query_plan_footprint->upd_del_plan= query_plan;
select_send *result; select_send *result;
bool printed_anything;
if (!(result= new select_send())) if (!(result= new select_send()))
return 1; /* purecov: inspected */ return 1; /* purecov: inspected */
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->print_explain(result, 0 /* explain flags*/, &printed_anything); int err2= thd->lex->query_plan_footprint->print_explain(result, 0);
if (err2) if (err2)
result->abort_result_set(); result->abort_result_set();
else else
result->send_eof(); result->send_eof();
delete thd->lex->query_plan_footprint;
thd->lex->query_plan_footprint= NULL;
delete select; delete select;
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0); DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0);