MDEV-3798: [SHOW] EXPLAIN UPDATE/DELETE, Memory leak in binlog.binlog_base64_flag:

- It turns out, there are statements that will call lex_start(thd->lex) 
  after parsing has been finished. lex_start() will set lex->explain=NULL,
  which will lose the pointer to already allocated Explain_plan object.
- To get rid of this, switch to lazy creation of lex->explain.  Now, it is 
  created only when we get a part ot query plan.
This commit is contained in:
Sergey Petrunya 2013-10-16 12:13:51 +04:00
parent 207f008220
commit 4bed7aa858
11 changed files with 18 additions and 7 deletions

View File

@ -86,6 +86,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
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_explain_query(thd->lex);
lex_start(ev_thd); lex_start(ev_thd);
mysql_reset_thd_for_next_command(ev_thd, 0); mysql_reset_thd_for_next_command(ev_thd, 0);

View File

@ -3246,7 +3246,6 @@ 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_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)

View File

@ -228,6 +228,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
query_plan.using_filesort= FALSE; query_plan.using_filesort= FALSE;
DBUG_ENTER("mysql_delete"); DBUG_ENTER("mysql_delete");
create_explain_query(thd->lex, thd->mem_root);
if (open_and_lock_tables(thd, table_list, TRUE, 0)) if (open_and_lock_tables(thd, table_list, TRUE, 0))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
@ -457,7 +458,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_explain_data(thd->lex->explain); query_plan.save_explain_data(thd->lex->explain);
DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start", DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start",

View File

@ -946,3 +946,9 @@ void create_explain_query(LEX *lex, MEM_ROOT *mem_root)
lex->explain->mem_root= mem_root; lex->explain->mem_root= mem_root;
} }
void create_explain_query_if_not_exists(LEX *lex, MEM_ROOT *mem_root)
{
if (!lex->explain)
create_explain_query(lex, mem_root);
}

View File

@ -719,6 +719,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
Item *unused_conds= 0; Item *unused_conds= 0;
DBUG_ENTER("mysql_insert"); DBUG_ENTER("mysql_insert");
create_explain_query(thd->lex, thd->mem_root);
/* /*
Upgrade lock type if the requested lock is incompatible with Upgrade lock type if the requested lock is incompatible with
the current connection mode or table operation. the current connection mode or table operation.

View File

@ -448,7 +448,7 @@ void lex_start(THD *thd)
lex->thd= lex->unit.thd= thd; lex->thd= lex->unit.thd= thd;
lex->explain= NULL; DBUG_ASSERT(!lex->explain);
lex->context_stack.empty(); lex->context_stack.empty();
lex->unit.init_query(); lex->unit.init_query();

View File

@ -622,6 +622,7 @@ class Explain_query;
void delete_explain_query(LEX *lex); void delete_explain_query(LEX *lex);
void create_explain_query(LEX *lex, MEM_ROOT *mem_root); void create_explain_query(LEX *lex, MEM_ROOT *mem_root);
void create_explain_query_if_not_exists(LEX *lex, MEM_ROOT *mem_root);
bool print_explain_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 {

View File

@ -2201,8 +2201,6 @@ mysql_execute_command(THD *thd)
thd->mdl_context.release_transactional_locks(); thd->mdl_context.release_transactional_locks();
} }
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)
DEBUG_SYNC(thd,"before_execute_sql_command"); DEBUG_SYNC(thd,"before_execute_sql_command");

View File

@ -1020,6 +1020,7 @@ int JOIN::optimize()
*/ */
if (was_optimized != optimized && !res && have_query_plan != QEP_DELETED) if (was_optimized != optimized && !res && have_query_plan != QEP_DELETED)
{ {
create_explain_query_if_not_exists(thd->lex, thd->mem_root);
have_query_plan= QEP_AVAILABLE; have_query_plan= QEP_AVAILABLE;
save_explain_data(thd->lex->explain, false /* can overwrite */, save_explain_data(thd->lex->explain, false /* can overwrite */,
need_tmp, need_tmp,

View File

@ -631,8 +631,10 @@ bool st_select_lex_unit::exec()
item->make_const(); item->make_const();
saved_error= optimize(); saved_error= optimize();
create_explain_query_if_not_exists(thd->lex, thd->mem_root);
if (!saved_error && !was_executed && thd->lex->explain) if (!saved_error && !was_executed)
save_union_explain(thd->lex->explain); save_union_explain(thd->lex->explain);
if (uncacheable || !item || !item->assigned() || describe) if (uncacheable || !item || !item->assigned() || describe)
@ -782,7 +784,7 @@ 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->explain) if (!was_executed)
save_union_explain_part2(thd->lex->explain); 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,

View File

@ -281,6 +281,7 @@ int mysql_update(THD *thd,
query_plan.using_filesort= FALSE; query_plan.using_filesort= FALSE;
DBUG_ENTER("mysql_update"); DBUG_ENTER("mysql_update");
create_explain_query(thd->lex, thd->mem_root);
if (open_tables(thd, &table_list, &table_count, 0)) if (open_tables(thd, &table_list, &table_count, 0))
DBUG_RETURN(1); DBUG_RETURN(1);