Commit 6519ca51 authored by Sergey Petrunya's avatar Sergey Petrunya

EXPLAIN UPDATE/DELETE

- Make EXPLAIN UPDATE/DELETE work inside SPs
- Return correct error code from mysql_delete()
- EXPLAIN <multi-DELETE> will create a multi_delete object (as it 
  affects the optimization). select_result will be only used for 
  producing EXPLAIN output.
parent e8eeb2e7
...@@ -49,7 +49,7 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -49,7 +49,7 @@ id select_type table type possible_keys key key_len ref rows Extra
explain delete t1 from t0, t1 where t0.a = t1.a; explain delete t1 from t0, t1 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;
# ################################################################### # ###################################################################
# ## EXPLAIN UPDATE tests # ## EXPLAIN UPDATE tests
......
...@@ -313,14 +313,26 @@ sp_get_flags_for_command(LEX *lex) ...@@ -313,14 +313,26 @@ sp_get_flags_for_command(LEX *lex)
flags= sp_head::HAS_COMMIT_OR_ROLLBACK; flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
break; break;
case SQLCOM_DELETE: case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
{ {
if (lex->select_lex.item_list.is_empty()) /*
DELETE normally doesn't return resultset, but there are two exceptions:
- DELETE ... RETURNING
- EXPLAIN DELETE ...
*/
if (lex->select_lex.item_list.is_empty() && !lex->describe)
flags= 0;
else
flags= sp_head::MULTI_RESULTS;
break;
}
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
{
if (!lex->describe)
flags= 0; flags= 0;
else else
{
/* This is DELETE ... RETURNING ... */
flags= sp_head::MULTI_RESULTS; flags= sp_head::MULTI_RESULTS;
}
break; break;
} }
default: default:
...@@ -2988,7 +3000,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, ...@@ -2988,7 +3000,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
} }
reinit_stmt_before_use(thd, m_lex); reinit_stmt_before_use(thd, m_lex);
// not here, but inside every instr: create_qpf_query(m_lex);
if (open_tables) if (open_tables)
res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables); res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
......
...@@ -183,7 +183,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -183,7 +183,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
bool const_cond_result; bool const_cond_result;
ha_rows deleted= 0; ha_rows deleted= 0;
bool reverse= FALSE; bool reverse= FALSE;
bool err= true;
ORDER *order= (ORDER *) ((order_list && order_list->elements) ? ORDER *order= (ORDER *) ((order_list && order_list->elements) ?
order_list->first : NULL); order_list->first : NULL);
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
...@@ -659,7 +658,7 @@ exit_without_my_ok: ...@@ -659,7 +658,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, 0 /* explain flags*/); int err2= thd->lex->query_plan_footprint->print_explain(result2, thd->lex->describe);
if (err2) if (err2)
result2->abort_result_set(); result2->abort_result_set();
...@@ -669,7 +668,7 @@ exit_without_my_ok: ...@@ -669,7 +668,7 @@ exit_without_my_ok:
delete select; delete select;
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
//table->set_keyread(false); //table->set_keyread(false);
DBUG_RETURN((err || thd->is_error() || thd->killed) ? 1 : 0); DBUG_RETURN((err2 || thd->is_error() || thd->killed) ? 1 : 0);
} }
......
...@@ -3332,18 +3332,7 @@ end_with_restore_list: ...@@ -3332,18 +3332,7 @@ end_with_restore_list:
if (!thd->is_fatal_error) if (!thd->is_fatal_error)
{ {
if (explain) result= new multi_delete(aux_tables, lex->table_count);
{
result= new select_send();
if (thd->send_explain_fields(result))
{
delete result;
result= NULL;
}
}
else
result= new multi_delete(aux_tables, lex->table_count);
if (result) if (result)
{ {
res= mysql_select(thd, &select_lex->ref_pointer_array, res= mysql_select(thd, &select_lex->ref_pointer_array,
...@@ -3362,20 +3351,22 @@ end_with_restore_list: ...@@ -3362,20 +3351,22 @@ end_with_restore_list:
if (!explain) if (!explain)
{ {
MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted()); MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted());
if (res)
result->abort_result_set(); /* for both DELETE and EXPLAIN DELETE */
} }
else else
{ {
result->reset_offset_limit(); if (!res)
thd->lex->query_plan_footprint->print_explain(result, {
thd->lex->describe); select_result *result= new select_send();
} LEX *lex= thd->lex;
if (thd->send_explain_fields(result) ||
if (res) lex->query_plan_footprint->print_explain(result, lex->describe) ||
result->abort_result_set(); /* for both DELETE and EXPLAIN DELETE */ result->send_eof())
else res= 1;
{ }
if (explain) else
result->send_eof(); result->abort_result_set(); /* for both DELETE and EXPLAIN DELETE */
} }
delete result; delete result;
} }
......
...@@ -22990,10 +22990,13 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order, ...@@ -22990,10 +22990,13 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
unit= unit->next_unit()) unit= unit->next_unit())
{ {
/* /*
Display subqueries only if they are not parts of eliminated WHERE/ON Display subqueries only if
clauses. (1) they are not parts of ON clauses that were eliminated by table
elimination.
(2) they are not merged derived tables
*/ */
if (!(unit->item && unit->item->eliminated)) if (!(unit->item && unit->item->eliminated) && // (1)
(!unit->derived || unit->derived->is_materialized_derived())) // (2)
{ {
qp_node->add_child(unit->first_select()->select_number); qp_node->add_child(unit->first_select()->select_number);
} }
......
...@@ -1039,8 +1039,8 @@ exit_without_my_ok: ...@@ -1039,8 +1039,8 @@ 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, 0 /* explain flags*/); int err2= thd->lex->query_plan_footprint->print_explain(result,
thd->lex->describe);
if (err2) if (err2)
result->abort_result_set(); result->abort_result_set();
else else
...@@ -1048,7 +1048,7 @@ exit_without_my_ok: ...@@ -1048,7 +1048,7 @@ exit_without_my_ok:
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((err2 || thd->is_error()) ? 1 : 0);
} }
/* /*
...@@ -1518,7 +1518,7 @@ bool mysql_multi_update(THD *thd, ...@@ -1518,7 +1518,7 @@ bool mysql_multi_update(THD *thd,
{ {
if (explain) if (explain)
{ {
thd->lex->query_plan_footprint->print_explain(output, 0); thd->lex->query_plan_footprint->print_explain(output, thd->lex->describe);
output->send_eof(); output->send_eof();
delete output; delete output;
} }
......
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