mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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.
This commit is contained in:
@ -1278,3 +1278,40 @@ table_name
|
||||
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
|
||||
where table_schema = 'test' and column_name = 'f3');
|
||||
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.
|
||||
|
@ -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_table_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) \
|
||||
!my_strcasecmp(system_charset_info, information_schema_name.str, (X))
|
||||
|
||||
|
@ -1505,7 +1505,7 @@ JOIN::exec()
|
||||
|
||||
if ((curr_join->select_lex->options & OPTION_SCHEMA_TABLE) &&
|
||||
!thd->lex->describe &&
|
||||
get_schema_tables_result(curr_join))
|
||||
get_schema_tables_result(curr_join, PROCESSED_BY_JOIN_EXEC))
|
||||
{
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -12372,7 +12372,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
|
||||
/* Fill schema tables with data before filesort if it's necessary */
|
||||
if ((join->select_lex->options & OPTION_SCHEMA_TABLE) &&
|
||||
!thd->lex->describe &&
|
||||
get_schema_tables_result(join))
|
||||
get_schema_tables_result(join, PROCESSED_BY_CREATE_SORT_INDEX))
|
||||
goto err;
|
||||
|
||||
if (table->s->tmp_table)
|
||||
|
@ -3938,13 +3938,15 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
|
||||
SYNOPSIS
|
||||
get_schema_tables_result()
|
||||
join join which use schema tables
|
||||
executed_place place where I_S table processed
|
||||
|
||||
RETURN
|
||||
FALSE success
|
||||
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;
|
||||
THD *thd= join->thd;
|
||||
@ -3964,14 +3966,24 @@ bool get_schema_tables_result(JOIN *join)
|
||||
bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
|
||||
lex->current_select->master_unit()->item);
|
||||
/*
|
||||
The schema table is already processed and
|
||||
the statement is not a subselect.
|
||||
So we don't need to handle this table again.
|
||||
If schema table is already processed and
|
||||
the statement is not a subselect then
|
||||
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;
|
||||
|
||||
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_RESET_STATE);
|
||||
@ -3988,10 +4000,10 @@ bool get_schema_tables_result(JOIN *join)
|
||||
{
|
||||
result= 1;
|
||||
join->error= 1;
|
||||
table_list->is_schema_table_processed= TRUE;
|
||||
table_list->schema_table_state= executed_place;
|
||||
break;
|
||||
}
|
||||
table_list->is_schema_table_processed= TRUE;
|
||||
table_list->schema_table_state= executed_place;
|
||||
}
|
||||
}
|
||||
thd->no_warnings_for_error= 0;
|
||||
|
@ -3031,7 +3031,7 @@ void st_table_list::reinit_before_use(THD *thd)
|
||||
*/
|
||||
table= 0;
|
||||
/* 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 *embedding= this; /* The parent nested table reference. */
|
||||
|
@ -287,6 +287,12 @@ struct st_table {
|
||||
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
|
||||
{
|
||||
@ -529,7 +535,6 @@ typedef struct st_table_list
|
||||
st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
|
||||
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
|
||||
st_select_lex *schema_select_lex;
|
||||
bool is_schema_table_processed;
|
||||
/*
|
||||
True when the view field translation table is used to convert
|
||||
schema table fields for backwards compatibility with SHOW command.
|
||||
@ -638,6 +643,7 @@ typedef struct st_table_list
|
||||
*/
|
||||
bool prelocking_placeholder;
|
||||
|
||||
enum enum_schema_table_state schema_table_state;
|
||||
void calc_md5(char *buffer);
|
||||
void set_underlying_merge();
|
||||
int view_check_option(THD *thd, bool ignore_failure);
|
||||
|
Reference in New Issue
Block a user