Commit ab4a13b2 authored by Sergey Petrunya's avatar Sergey Petrunya

Switching [EXPLAIN] UPDATE/DELETE to rely on query plan footprints.

This requires that subselect's footprints are saved before it is deleted.

Attempt to save select's QPF exposes one to a variety of edge cases:
- the select may be a UNION's "fake select" which has no valid id
- optimization may fail in the middle (but subsequent JOIN::optimize() calls
  will succeed, despite the fact that there never was a query plan)
parent 52cfa54c
...@@ -4341,7 +4341,8 @@ int st_select_lex_unit::save_qpf(QPF_query *output) ...@@ -4341,7 +4341,8 @@ int st_select_lex_unit::save_qpf(QPF_query *output)
if (!first->next_select()) if (!first->next_select())
{ {
/* This is a 1-way UNION, i.e. not really a UNION */ /* This is a 1-way UNION, i.e. not really a UNION */
first->save_qpf(output); if (!output->get_select(first->select_number))
first->save_qpf(output);
return 0; return 0;
} }
...@@ -4371,7 +4372,8 @@ int st_select_lex_unit::save_qpf(QPF_query *output) ...@@ -4371,7 +4372,8 @@ int st_select_lex_unit::save_qpf(QPF_query *output)
for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
{ {
sl->save_qpf(output); if (!output->get_select(sl->select_number))
sl->save_qpf(output);
qpfu->add_select(sl->select_number); qpfu->add_select(sl->select_number);
} }
......
...@@ -1005,17 +1005,26 @@ err: ...@@ -1005,17 +1005,26 @@ err:
int JOIN::optimize() int JOIN::optimize()
{ {
bool was_optimized= optimized;
int res= optimize_inner(); int res= optimize_inner();
/* /*
If we're inside a non-correlated subquery, this function may be If we're inside a non-correlated subquery, this function may be
called for the second time after the subquery has been executed called for the second time after the subquery has been executed
and deleted. The second call will not produce a valid query plan, it will and deleted. The second call will not produce a valid query plan, it will
short-circuit because optimized==TRUE. short-circuit because optimized==TRUE.
"was_optimized != optimized" is here to handle this case:
- first optimization starts, gets an error (from a const. cheap
subquery), returns 1
- another JOIN::optimize() call made, and now join->optimize() will
return 0, even though we never had a query plan.
*/ */
if (!res && have_query_plan != QEP_DELETED) if (was_optimized != optimized && !res && have_query_plan != QEP_DELETED)
have_query_plan= QEP_AVAILABLE; have_query_plan= QEP_AVAILABLE;
return res; return res;
} }
/** /**
global select optimisation. global select optimisation.
...@@ -2301,7 +2310,6 @@ void JOIN::exec() ...@@ -2301,7 +2310,6 @@ void JOIN::exec()
select_lex->select_number)) select_lex->select_number))
dbug_serve_apcs(thd, 1); dbug_serve_apcs(thd, 1);
); );
thd->apc_target.disable(); thd->apc_target.disable();
} }
...@@ -11099,7 +11107,33 @@ void JOIN::cleanup(bool full) ...@@ -11099,7 +11107,33 @@ void JOIN::cleanup(bool full)
DBUG_PRINT("enter", ("full %u", (uint) full)); DBUG_PRINT("enter", ("full %u", (uint) full));
if (full) if (full)
{
//
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 &&
!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
}
//
have_query_plan= QEP_DELETED; //psergey: this is a problem! have_query_plan= QEP_DELETED; //psergey: this is a problem!
}
if (table) if (table)
{ {
......
...@@ -1462,12 +1462,6 @@ public: ...@@ -1462,12 +1462,6 @@ public:
{ {
return (unit->item && unit->item->is_in_predicate()); return (unit->item && unit->item->is_in_predicate());
} }
/*
int print_explain(select_result_sink *result, uint8 explain_flags,
bool on_the_fly,
bool need_tmp_table, bool need_order,
bool distinct,const char *message);
*/
int save_qpf(QPF_query *output, bool need_tmp_table, bool need_order, int save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
bool distinct, const char *message); bool distinct, const char *message);
private: private:
......
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