Bug#24630 Subselect query crashes mysqld

The crash happens because second filling of the same I_S table happens in
case of subselect with order by. table->sort.io_cache previously allocated
in create_sort_index() is deleted during second filling
(function get_schema_tables_result). There are two places where
I_S table can be filled: JOIN::exec and create_sort_index().
To fix the bug we should check if the table was already filled
in one of these places and skip processing of the table in second.
parent 0583c7c5
...@@ -1278,3 +1278,40 @@ table_name ...@@ -1278,3 +1278,40 @@ table_name
t1 t1
t2 t2
drop table t1,t2; drop table t1,t2;
select 1 as f1 from information_schema.tables where "CHARACTER_SETS"=
(select cast(table_name as char) from information_schema.tables
order by table_name limit 1) limit 1;
f1
1
select t.table_name, group_concat(t.table_schema, '.', t.table_name),
count(*) as num1
from information_schema.tables t
inner join information_schema.columns c1
on t.table_schema = c1.table_schema AND t.table_name = c1.table_name
where t.table_schema = 'information_schema' and
c1.ordinal_position =
(select isnull(c2.column_type) -
isnull(group_concat(c2.table_schema, '.', c2.table_name)) +
count(*) as num
from information_schema.columns c2 where
c2.table_schema='information_schema' and
(c2.column_type = 'varchar(7)' or c2.column_type = 'varchar(20)')
group by c2.column_type order by num limit 1)
group by t.table_name order by num1, t.table_name;
table_name group_concat(t.table_schema, '.', t.table_name) num1
CHARACTER_SETS information_schema.CHARACTER_SETS 1
COLLATIONS information_schema.COLLATIONS 1
COLLATION_CHARACTER_SET_APPLICABILITY information_schema.COLLATION_CHARACTER_SET_APPLICABILITY 1
COLUMNS information_schema.COLUMNS 1
COLUMN_PRIVILEGES information_schema.COLUMN_PRIVILEGES 1
KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1
ROUTINES information_schema.ROUTINES 1
SCHEMATA information_schema.SCHEMATA 1
SCHEMA_PRIVILEGES information_schema.SCHEMA_PRIVILEGES 1
STATISTICS information_schema.STATISTICS 1
TABLES information_schema.TABLES 1
TABLE_CONSTRAINTS information_schema.TABLE_CONSTRAINTS 1
TABLE_PRIVILEGES information_schema.TABLE_PRIVILEGES 1
TRIGGERS information_schema.TRIGGERS 1
USER_PRIVILEGES information_schema.USER_PRIVILEGES 1
VIEWS information_schema.VIEWS 1
...@@ -999,4 +999,28 @@ where table_schema = 'test' and table_name not in ...@@ -999,4 +999,28 @@ where table_schema = 'test' and table_name not in
where table_schema = 'test' and column_name = 'f3'); where table_schema = 'test' and column_name = 'f3');
drop table t1,t2; drop table t1,t2;
#
# Bug#24630 Subselect query crashes mysqld
#
select 1 as f1 from information_schema.tables where "CHARACTER_SETS"=
(select cast(table_name as char) from information_schema.tables
order by table_name limit 1) limit 1;
select t.table_name, group_concat(t.table_schema, '.', t.table_name),
count(*) as num1
from information_schema.tables t
inner join information_schema.columns c1
on t.table_schema = c1.table_schema AND t.table_name = c1.table_name
where t.table_schema = 'information_schema' and
c1.ordinal_position =
(select isnull(c2.column_type) -
isnull(group_concat(c2.table_schema, '.', c2.table_name)) +
count(*) as num
from information_schema.columns c2 where
c2.table_schema='information_schema' and
(c2.column_type = 'varchar(7)' or c2.column_type = 'varchar(20)')
group by c2.column_type order by num limit 1)
group by t.table_name order by num1, t.table_name;
# End of 5.0 tests. # End of 5.0 tests.
...@@ -932,7 +932,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond); ...@@ -932,7 +932,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
bool get_schema_tables_result(JOIN *join); bool get_schema_tables_result(JOIN *join,
enum enum_schema_table_state executed_place);
#define is_schema_db(X) \ #define is_schema_db(X) \
!my_strcasecmp(system_charset_info, information_schema_name.str, (X)) !my_strcasecmp(system_charset_info, information_schema_name.str, (X))
......
...@@ -1505,7 +1505,7 @@ JOIN::exec() ...@@ -1505,7 +1505,7 @@ JOIN::exec()
if ((curr_join->select_lex->options & OPTION_SCHEMA_TABLE) && if ((curr_join->select_lex->options & OPTION_SCHEMA_TABLE) &&
!thd->lex->describe && !thd->lex->describe &&
get_schema_tables_result(curr_join)) get_schema_tables_result(curr_join, PROCESSED_BY_JOIN_EXEC))
{ {
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -12372,7 +12372,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -12372,7 +12372,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
/* Fill schema tables with data before filesort if it's necessary */ /* Fill schema tables with data before filesort if it's necessary */
if ((join->select_lex->options & OPTION_SCHEMA_TABLE) && if ((join->select_lex->options & OPTION_SCHEMA_TABLE) &&
!thd->lex->describe && !thd->lex->describe &&
get_schema_tables_result(join)) get_schema_tables_result(join, PROCESSED_BY_CREATE_SORT_INDEX))
goto err; goto err;
if (table->s->tmp_table) if (table->s->tmp_table)
......
...@@ -3938,13 +3938,15 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, ...@@ -3938,13 +3938,15 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
SYNOPSIS SYNOPSIS
get_schema_tables_result() get_schema_tables_result()
join join which use schema tables join join which use schema tables
executed_place place where I_S table processed
RETURN RETURN
FALSE success FALSE success
TRUE error TRUE error
*/ */
bool get_schema_tables_result(JOIN *join) bool get_schema_tables_result(JOIN *join,
enum enum_schema_table_state executed_place)
{ {
JOIN_TAB *tmp_join_tab= join->join_tab+join->tables; JOIN_TAB *tmp_join_tab= join->join_tab+join->tables;
THD *thd= join->thd; THD *thd= join->thd;
...@@ -3964,14 +3966,24 @@ bool get_schema_tables_result(JOIN *join) ...@@ -3964,14 +3966,24 @@ bool get_schema_tables_result(JOIN *join)
bool is_subselect= (&lex->unit != lex->current_select->master_unit() && bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
lex->current_select->master_unit()->item); lex->current_select->master_unit()->item);
/* /*
The schema table is already processed and If schema table is already processed and
the statement is not a subselect. the statement is not a subselect then
So we don't need to handle this table again. we don't need to fill this table again.
If schema table is already processed and
schema_table_state != executed_place then
table is already processed and
we should skip second data processing.
*/ */
if (table_list->is_schema_table_processed && !is_subselect) if (table_list->schema_table_state &&
(!is_subselect || table_list->schema_table_state != executed_place))
continue; continue;
if (is_subselect) // is subselect /*
if table is used in a subselect and
table has been processed earlier with the same
'executed_place' value then we should refresh the table.
*/
if (table_list->schema_table_state && is_subselect)
{ {
table_list->table->file->extra(HA_EXTRA_NO_CACHE); table_list->table->file->extra(HA_EXTRA_NO_CACHE);
table_list->table->file->extra(HA_EXTRA_RESET_STATE); table_list->table->file->extra(HA_EXTRA_RESET_STATE);
...@@ -3988,10 +4000,10 @@ bool get_schema_tables_result(JOIN *join) ...@@ -3988,10 +4000,10 @@ bool get_schema_tables_result(JOIN *join)
{ {
result= 1; result= 1;
join->error= 1; join->error= 1;
table_list->is_schema_table_processed= TRUE; table_list->schema_table_state= executed_place;
break; break;
} }
table_list->is_schema_table_processed= TRUE; table_list->schema_table_state= executed_place;
} }
} }
thd->no_warnings_for_error= 0; thd->no_warnings_for_error= 0;
......
...@@ -3031,7 +3031,7 @@ void st_table_list::reinit_before_use(THD *thd) ...@@ -3031,7 +3031,7 @@ void st_table_list::reinit_before_use(THD *thd)
*/ */
table= 0; table= 0;
/* Reset is_schema_table_processed value(needed for I_S tables */ /* Reset is_schema_table_processed value(needed for I_S tables */
is_schema_table_processed= FALSE; schema_table_state= NOT_PROCESSED;
TABLE_LIST *embedded; /* The table at the current level of nesting. */ TABLE_LIST *embedded; /* The table at the current level of nesting. */
TABLE_LIST *embedding= this; /* The parent nested table reference. */ TABLE_LIST *embedding= this; /* The parent nested table reference. */
......
...@@ -287,6 +287,12 @@ struct st_table { ...@@ -287,6 +287,12 @@ struct st_table {
void reset_item_list(List<Item> *item_list) const; void reset_item_list(List<Item> *item_list) const;
}; };
enum enum_schema_table_state
{
NOT_PROCESSED= 0,
PROCESSED_BY_CREATE_SORT_INDEX,
PROCESSED_BY_JOIN_EXEC
};
typedef struct st_foreign_key_info typedef struct st_foreign_key_info
{ {
...@@ -529,7 +535,6 @@ typedef struct st_table_list ...@@ -529,7 +535,6 @@ typedef struct st_table_list
st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */ ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
st_select_lex *schema_select_lex; st_select_lex *schema_select_lex;
bool is_schema_table_processed;
/* /*
True when the view field translation table is used to convert True when the view field translation table is used to convert
schema table fields for backwards compatibility with SHOW command. schema table fields for backwards compatibility with SHOW command.
...@@ -638,6 +643,7 @@ typedef struct st_table_list ...@@ -638,6 +643,7 @@ typedef struct st_table_list
*/ */
bool prelocking_placeholder; bool prelocking_placeholder;
enum enum_schema_table_state schema_table_state;
void calc_md5(char *buffer); void calc_md5(char *buffer);
void set_underlying_merge(); void set_underlying_merge();
int view_check_option(THD *thd, bool ignore_failure); int view_check_option(THD *thd, bool ignore_failure);
......
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