Commit a1114cf7 authored by Sergey Petrunya's avatar Sergey Petrunya

MDEV-3798: EXPLAIN UPDATE/DELETE

- Fix a problem with EXPLAIN multi_table UPDATE: 
  = Do use multi_update object, because multi_update::prepare() does
    various setup, e.g. it disables index-only for the tables to be updated.
  = Protect multi_update::prepare() from being invoked multiple times. 
    If the query has subqueries, they may try to invoke it, for some reason.
parent 2227eee4
...@@ -100,7 +100,7 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -100,7 +100,7 @@ id select_type table type possible_keys key key_len ref rows Extra
explain update t0, t1 set t1.a=t1.a+1 where t0.a = t1.a; explain update t0, t1 set t1.a=t1.a+1 where t0.a = t1.a;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 8 Using where 1 SIMPLE t0 ALL NULL NULL NULL NULL 8 Using where
1 SIMPLE t1 ref a a 5 test.t0.a 4 Using index 1 SIMPLE t1 ref a a 5 test.t0.a 4
drop table t0, t1; drop table t0, t1;
# #
# Try DELETE ... RETURNING ... # Try DELETE ... RETURNING ...
......
...@@ -4181,7 +4181,9 @@ class multi_update :public select_result_interceptor ...@@ -4181,7 +4181,9 @@ class multi_update :public select_result_interceptor
so that afterward send_error() needs to find out that. so that afterward send_error() needs to find out that.
*/ */
bool error_handled; bool error_handled;
/* Need this to protect against multiple prepare() calls */
bool prepared;
public: public:
multi_update(TABLE_LIST *ut, List<TABLE_LIST> *leaves_list, multi_update(TABLE_LIST *ut, List<TABLE_LIST> *leaves_list,
List<Item> *fields, List<Item> *values, List<Item> *fields, List<Item> *values,
......
...@@ -1464,32 +1464,14 @@ bool mysql_multi_update(THD *thd, ...@@ -1464,32 +1464,14 @@ bool mysql_multi_update(THD *thd,
multi_update **result) multi_update **result)
{ {
bool res; bool res;
select_result *output;
bool explain= test(thd->lex->describe);
DBUG_ENTER("mysql_multi_update"); DBUG_ENTER("mysql_multi_update");
if (explain) if (!(*result= new multi_update(table_list,
&thd->lex->select_lex.leaf_tables,
fields, values,
handle_duplicates, ignore)))
{ {
/* Handle EXPLAIN UPDATE */ DBUG_RETURN(TRUE);
if (!(output= new select_send()) ||
thd->send_explain_fields(output))
{
delete output;
DBUG_RETURN(TRUE);
}
select_lex->set_explain_type(FALSE);
*result= NULL; /* no multi_update object */
}
else
{
if (!(*result= new multi_update(table_list,
&thd->lex->select_lex.leaf_tables,
fields, values,
handle_duplicates, ignore)))
{
DBUG_RETURN(TRUE);
}
output= *result;
} }
thd->abort_on_warning= test(thd->variables.sql_mode & thd->abort_on_warning= test(thd->variables.sql_mode &
...@@ -1504,7 +1486,7 @@ bool mysql_multi_update(THD *thd, ...@@ -1504,7 +1486,7 @@ bool mysql_multi_update(THD *thd,
(ORDER *)NULL, (ORDER *)NULL,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE, OPTION_SETUP_TABLES_DONE,
output, unit, select_lex); *result, unit, select_lex);
DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error())); DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error()));
res|= thd->is_error(); res|= thd->is_error();
...@@ -1512,12 +1494,8 @@ bool mysql_multi_update(THD *thd, ...@@ -1512,12 +1494,8 @@ bool mysql_multi_update(THD *thd,
(*result)->abort_result_set(); (*result)->abort_result_set();
else else
{ {
if (explain) if (thd->lex->describe)
{ res= thd->lex->explain->send_explain(thd);
thd->lex->explain->print_explain(output, thd->lex->describe);
output->send_eof();
delete output;
}
} }
thd->abort_on_warning= 0; thd->abort_on_warning= 0;
DBUG_RETURN(res); DBUG_RETURN(res);
...@@ -1533,7 +1511,7 @@ multi_update::multi_update(TABLE_LIST *table_list, ...@@ -1533,7 +1511,7 @@ multi_update::multi_update(TABLE_LIST *table_list,
tmp_tables(0), updated(0), found(0), fields(field_list), tmp_tables(0), updated(0), found(0), fields(field_list),
values(value_list), table_count(0), copy_field(0), values(value_list), table_count(0), copy_field(0),
handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1), handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1),
transactional_tables(0), ignore(ignore_arg), error_handled(0) transactional_tables(0), ignore(ignore_arg), error_handled(0), prepared(0)
{} {}
...@@ -1556,6 +1534,10 @@ int multi_update::prepare(List<Item> &not_used_values, ...@@ -1556,6 +1534,10 @@ int multi_update::prepare(List<Item> &not_used_values,
List_iterator<TABLE_LIST> ti(*leaves); List_iterator<TABLE_LIST> ti(*leaves);
DBUG_ENTER("multi_update::prepare"); DBUG_ENTER("multi_update::prepare");
if (prepared)
DBUG_RETURN(0);
prepared= true;
thd->count_cuted_fields= CHECK_FIELD_WARN; thd->count_cuted_fields= CHECK_FIELD_WARN;
thd->cuted_fields=0L; thd->cuted_fields=0L;
thd_proc_info(thd, "updating main table"); thd_proc_info(thd, "updating main table");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment