#At file:///export/home/tmp/x/mysql-5.1-bugteam-46941/ based on revid:jon.hauglid@stripped
3536 Magne Mahre 2010-10-19
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.
@ sql/sql_db.cc
Normalize table name (i.e lower case it)
@ sql/sql_table.cc
table_name contains the normalized name
alias contains the real table name
added:
mysql-test/r/lowercase_table4.result
mysql-test/t/lowercase_table4-master.opt
mysql-test/t/lowercase_table4.test
modified:
sql/sql_db.cc
sql/sql_table.cc
=== added file 'mysql-test/r/lowercase_table4.result'
--- a/mysql-test/r/lowercase_table4.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/lowercase_table4.result 2010-10-19 10:27:09 +0000
@@ -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;
=== added file 'mysql-test/t/lowercase_table4-master.opt'
--- a/mysql-test/t/lowercase_table4-master.opt 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/lowercase_table4-master.opt 2010-10-19 10:27:09 +0000
@@ -0,0 +1 @@
+--lower-case-table-names=2
=== added file 'mysql-test/t/lowercase_table4.test'
--- a/mysql-test/t/lowercase_table4.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/lowercase_table4.test 2010-10-19 10:27:09 +0000
@@ -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;
+
=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc 2010-06-26 17:36:00 +0000
+++ b/sql/sql_db.cc 2010-10-19 10:27:09 +0000
@@ -1197,6 +1197,12 @@ static long mysql_rm_known_files(THD *th
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 */
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2010-09-21 14:37:18 +0000
+++ b/sql/sql_table.cc 2010-10-19 10:27:09 +0000
@@ -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;
Attachment: [text/bzr-bundle] bzr/magne.mahre@sun.com-20101019102709-3xcmv9xauuuxu80s.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-bugteam branch (magne.mahre:3536) Bug#46941 | Magne Mahre | 19 Oct |