Bug #46941 crash with lower_case_table_names=2 and foreign key
data dictionary confusion On file systems with case insensitive file names, and lower_case_table_names set to '2', the server could crash due to a table definition cache inconsistency. This is the default setting on MacOSX, but may also be set and used on MS Windows. The bug is caused by using two different strategies for creating the hash key for the table definition cache, resulting in failure to look up an entry which is present in the cache, or failure to delete an existing entry. One strategy was to use the real table name (with case preserved), and the other to use a normalized table name (i.e a lower case version). This is manifested in two cases. One is during 'DROP DATABASE', where all known files are removed. The removal from the table definition cache is done via a generated list of TABLE_LIST with keys (wrongly) created using the case preserved name. The other is during CREATE TABLE, where the cache lookup is also (wrongly) based on the case preserved name. The fix was to use only the normalized table name when creating hash keys.
This commit is contained in:
parent
6da8a65bf0
commit
1c68d2efe7
7
mysql-test/r/lowercase_table4.result
Executable file
7
mysql-test/r/lowercase_table4.result
Executable file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# Bug#46941 crash with lower_case_table_names=2 and
|
||||
# foreign data dictionary confusion
|
||||
#
|
||||
CREATE DATABASE XY;
|
||||
USE XY;
|
||||
DROP DATABASE XY;
|
1
mysql-test/t/lowercase_table4-master.opt
Executable file
1
mysql-test/t/lowercase_table4-master.opt
Executable file
@ -0,0 +1 @@
|
||||
--lower-case-table-names=2
|
56
mysql-test/t/lowercase_table4.test
Executable file
56
mysql-test/t/lowercase_table4.test
Executable file
@ -0,0 +1,56 @@
|
||||
--source include/have_case_insensitive_file_system.inc
|
||||
--source include/have_innodb.inc
|
||||
|
||||
--echo #
|
||||
--echo # Bug#46941 crash with lower_case_table_names=2 and
|
||||
--echo # foreign data dictionary confusion
|
||||
--echo #
|
||||
|
||||
CREATE DATABASE XY;
|
||||
USE XY;
|
||||
|
||||
#
|
||||
# Logs are disabled, since the number of creates tables
|
||||
# and subsequent select statements may vary between
|
||||
# versions
|
||||
#
|
||||
--disable_query_log
|
||||
--disable_result_log
|
||||
|
||||
let $tcs = `SELECT @@table_open_cache + 1`;
|
||||
|
||||
let $i = $tcs;
|
||||
|
||||
while ($i)
|
||||
{
|
||||
eval CREATE TABLE XY.T_$i (a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, d INT,
|
||||
primary key(a, b), unique(b)) ENGINE=InnoDB;
|
||||
dec $i;
|
||||
}
|
||||
|
||||
eval ALTER TABLE XY.T_$tcs ADD INDEX I1 (c, b),
|
||||
ADD CONSTRAINT C1 FOREIGN KEY (c, b) REFERENCES XY.T_1 (a, b);
|
||||
|
||||
eval ALTER TABLE XY.T_$tcs ADD INDEX I2 (b),
|
||||
ADD CONSTRAINT C2 FOREIGN KEY (b) REFERENCES XY.T_1(a);
|
||||
|
||||
let $i = $tcs;
|
||||
while ($i)
|
||||
{
|
||||
eval SELECT * FROM XY.T_$i LIMIT 1;
|
||||
dec $i;
|
||||
}
|
||||
|
||||
DROP DATABASE XY;
|
||||
CREATE DATABASE XY;
|
||||
USE XY;
|
||||
eval CREATE TABLE XY.T_$tcs (a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, d INT,
|
||||
PRIMARY KEY(a, b), UNIQUE(b)) ENGINE=InnoDB;
|
||||
#
|
||||
# The bug causes this SELECT to err
|
||||
eval SELECT * FROM XY.T_$tcs LIMIT 1;
|
||||
|
||||
--enable_query_log
|
||||
--enable_result_log
|
||||
DROP DATABASE XY;
|
||||
|
@ -1197,6 +1197,12 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
|
||||
VOID(filename_to_tablename(file->name, table_list->table_name,
|
||||
MYSQL50_TABLE_NAME_PREFIX_LENGTH +
|
||||
strlen(file->name) + 1));
|
||||
|
||||
/* To be able to correctly look up the table in the table cache. */
|
||||
if (lower_case_table_names)
|
||||
table_list->table_name_length= my_casedn_str(files_charset_info,
|
||||
table_list->table_name);
|
||||
|
||||
table_list->alias= table_list->table_name; // If lower_case_table_names=2
|
||||
table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix);
|
||||
/* Link into list */
|
||||
|
@ -3896,7 +3896,7 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
Then she could create the table. This case is pretty obscure and
|
||||
therefore we don't introduce a new error message only for it.
|
||||
*/
|
||||
if (get_cached_table_share(db, alias))
|
||||
if (get_cached_table_share(db, table_name))
|
||||
{
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
|
||||
goto unlock_and_end;
|
||||
|
Loading…
x
Reference in New Issue
Block a user