Commit b35801de authored by unknown's avatar unknown

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.


mysql-test/r/information_schema.result:
  test case
mysql-test/t/information_schema.test:
  test case
sql/mysql_priv.h:
  added new parameter 'executed_place' to function get_schema_tables_result()
sql/sql_select.cc:
  added new parameter 'executed_place' to function get_schema_tables_result()
sql/sql_show.cc:
  added more accurate check for cases when we need to refresh I_S table
sql/table.cc:
  added more accurate check for cases when we need to refresh I_S table
sql/table.h:
  added more accurate check for cases when we need to refresh I_S table
parent 68fbbbf1
......@@ -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);
......
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