From 43c6953fa1ba3aad4f065bfbd63cca6b5d0c5ce7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik <sergii@pisem.net> Date: Mon, 21 Jan 2013 10:52:39 +0100 Subject: [PATCH] MDEV-4029 SELECT on information_schema using a subquery locks up the information_schema table due to incorrect mutexes handling Early evaluation of subqueries in the WHERE conditions on I_S.*_STATUS tables, otherwise the subquery on this same table will try to acquire LOCK_status twice. --- mysql-test/r/information_schema2.result | 8 ++++++++ mysql-test/t/information_schema2.test | 9 +++++++++ sql/sql_show.cc | 18 ++++++++++++------ 3 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 mysql-test/r/information_schema2.result create mode 100644 mysql-test/t/information_schema2.test diff --git a/mysql-test/r/information_schema2.result b/mysql-test/r/information_schema2.result new file mode 100644 index 0000000000..60a2094483 --- /dev/null +++ b/mysql-test/r/information_schema2.result @@ -0,0 +1,8 @@ +select variable_name from information_schema.session_status where variable_name = +(select variable_name from information_schema.session_status where variable_name = 'uptime'); +variable_name +UPTIME +select variable_name from information_schema.session_variables where variable_name = +(select variable_name from information_schema.session_variables where variable_name = 'basedir'); +variable_name +BASEDIR diff --git a/mysql-test/t/information_schema2.test b/mysql-test/t/information_schema2.test new file mode 100644 index 0000000000..c2479087f4 --- /dev/null +++ b/mysql-test/t/information_schema2.test @@ -0,0 +1,9 @@ + +# +# MDEV-4029 SELECT on information_schema using a subquery locks up the information_schema table due to incorrect mutexes handling +# +select variable_name from information_schema.session_status where variable_name = +(select variable_name from information_schema.session_status where variable_name = 'uptime'); +select variable_name from information_schema.session_variables where variable_name = +(select variable_name from information_schema.session_variables where variable_name = 'basedir'); + diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d544ff4c52..f9c2d11459 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2260,7 +2260,6 @@ static bool show_status_array(THD *thd, const char *wild, int len; LEX_STRING null_lex_str; SHOW_VAR tmp, *var; - COND *partial_cond= 0; enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; bool res= FALSE; CHARSET_INFO *charset= system_charset_info; @@ -2274,7 +2273,6 @@ static bool show_status_array(THD *thd, const char *wild, if (*prefix) *prefix_end++= '_'; len=name_buffer + sizeof(name_buffer) - prefix_end; - partial_cond= make_cond_for_info_schema(cond, table->pos_in_table_list); for (; variables->name; variables++) { @@ -2297,13 +2295,13 @@ static bool show_status_array(THD *thd, const char *wild, if (show_type == SHOW_ARRAY) { show_status_array(thd, wild, (SHOW_VAR *) var->value, value_type, - status_var, name_buffer, table, ucase_names, partial_cond); + status_var, name_buffer, table, ucase_names, cond); } else { if (!(wild && wild[0] && wild_case_compare(system_charset_info, name_buffer, wild)) && - (!partial_cond || partial_cond->val_int())) + (!cond || cond->val_int())) { char *value=var->value; const char *pos, *end; // We assign a lot of const's @@ -5562,9 +5560,12 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) schema_table_idx == SCH_GLOBAL_VARIABLES) option_type= OPT_GLOBAL; + COND *partial_cond= make_cond_for_info_schema(cond, tables); + rw_rdlock(&LOCK_system_variables_hash); res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars), - option_type, NULL, "", tables->table, upper_case_names, cond); + option_type, NULL, "", tables->table, upper_case_names, + partial_cond); rw_unlock(&LOCK_system_variables_hash); DBUG_RETURN(res); } @@ -5601,13 +5602,18 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) tmp1= &thd->status_var; } + COND *partial_cond= make_cond_for_info_schema(cond, tables); + // Evaluate and cache const subqueries now, before the mutex. + if (partial_cond) + partial_cond->val_int(); + pthread_mutex_lock(&LOCK_status); if (option_type == OPT_GLOBAL) calc_sum_of_all_status(&tmp); res= show_status_array(thd, wild, (SHOW_VAR *)all_status_vars.buffer, option_type, tmp1, "", tables->table, - upper_case_names, cond); + upper_case_names, partial_cond); pthread_mutex_unlock(&LOCK_status); DBUG_RETURN(res); } -- 2.30.9