3138 Jon Olav Hauglid 2010-09-16
Bug #56595 RENAME TABLE causes assert on OS X
The problem was that RENAME TABLE caused an assert if the system variable
lower_case_table_names was 2 (default on Mac OS X) and the old table name
was given in upper case. This caused lowercase_table2.test to fail.
The assert checks that an exclusive metadata lock is held by the connection
trying to do RENAME TABLE - specificially during updates of table triggers.
The assert was triggered since the check is case sensitive and the lock
was held on the normalized (lower case) version of the table name.
This patch fixes the problem by making sure a normalized version of the
table name is used for the metadata lock check, while using a non-normalized
version of the table name for the rename of trigger files. The same is done
for ALTER TABLE ... RENAME.
Regression testing for the bug itself is already covered by
lowercase_table2.test. Additional coverage added to lowercase_fs_off.test.
modified:
mysql-test/r/lowercase_fs_off.result
mysql-test/t/lowercase_fs_off.test
sql/sql_rename.cc
sql/sql_table.cc
sql/sql_trigger.cc
sql/sql_trigger.h
3137 Dmitry Lenev 2010-09-15
Fix for bug #56251 "Deadlock with INSERT DELAYED and MERGE
tables".
Attempting to issue an INSERT DELAYED statement for a MERGE
table might have caused a deadlock if it happened as part of
a transaction or under LOCK TABLES, and there was a concurrent
DDL or LOCK TABLES ... WRITE statement which tried to lock one
of its underlying tables.
The problem occurred when a delayed insert handler thread tried
to open a MERGE table and discovered that to do this it had also
to open all underlying tables and hence acquire metadata
locks on them. Since metadata locks on the underlying tables were
not pre-acquired by the connection thread executing INSERT DELAYED,
attempts to do so might lead to waiting. In this case the
connection thread had to wait for the delayed insert thread.
If the thread which was preventing the lock on the underlying table
from being acquired had to wait for the connection thread (due to
this or other metadata locks), a deadlock occurred.
This deadlock was not detected by the MDL deadlock detector since
waiting for the handler thread by the connection thread is not
represented in the wait-for graph.
This patch solves the problem by ensuring that the delayed
insert handler thread never tries to open underlying tables
of a MERGE table. Instead open_tables() is aborted right after
the parent table is opened and a ER_DELAYED_NOT_SUPPORTED
error is emitted (which is passed to the connection thread and
ultimately to the user).
@ mysql-test/r/merge.result
Added test for bug #56251 "Deadlock with INSERT DELAYED and
MERGE tables".
@ mysql-test/t/merge.test
Added test for bug #56251 "Deadlock with INSERT DELAYED and
MERGE tables".
@ sql/sql_base.cc
Changed open_n_lock_single_table() to take prelocking strategy
as an argument instead of always using DML_prelocking_strategy.
@ sql/sql_base.h
Changed open_n_lock_single_table() to take prelocking strategy
as an argument instead of always using DML_prelocking_strategy.
Added a version of this function which is compatible with old
signature.
@ sql/sql_insert.cc
When opening MERGE table in delayed insert thread stop and emit
ER_DELAYED_NOT_SUPPORTED right after opening main table and
before opening underlying tables. This ensures that we won't
try to acquire metadata lock on underlying tables which might
lead to a deadlock.
This is achieved by using special prelocking strategy which
abort open_tables() process as soon as we discover that we
have opened table with engine which doesn't support delayed
inserts.
modified:
mysql-test/r/merge.result
mysql-test/t/merge.test
sql/sql_base.cc
sql/sql_base.h
sql/sql_insert.cc
=== modified file 'mysql-test/r/lowercase_fs_off.result'
--- a/mysql-test/r/lowercase_fs_off.result 2009-11-06 14:20:27 +0000
+++ b/mysql-test/r/lowercase_fs_off.result 2010-09-16 09:11:13 +0000
@@ -55,3 +55,11 @@ DROP USER user_1@localhost;
DROP USER USER_1@localhost;
DROP DATABASE db1;
use test;
+#
+# Extra test coverage for Bug#56595 RENAME TABLE causes assert on OS X
+#
+CREATE TABLE t1(a INT);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a= 1;
+RENAME TABLE t1 TO T1;
+ALTER TABLE T1 RENAME t1;
+DROP TABLE t1;
=== modified file 'mysql-test/t/lowercase_fs_off.test'
--- a/mysql-test/t/lowercase_fs_off.test 2009-10-27 10:09:36 +0000
+++ b/mysql-test/t/lowercase_fs_off.test 2010-09-16 09:11:13 +0000
@@ -91,3 +91,14 @@ DROP DATABASE db1;
use test;
# End of 5.0 tests
+
+
+--echo #
+--echo # Extra test coverage for Bug#56595 RENAME TABLE causes assert on OS X
+--echo #
+
+CREATE TABLE t1(a INT);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a= 1;
+RENAME TABLE t1 TO T1;
+ALTER TABLE T1 RENAME t1;
+DROP TABLE t1;
=== modified file 'sql/sql_rename.cc'
--- a/sql/sql_rename.cc 2010-08-10 11:16:44 +0000
+++ b/sql/sql_rename.cc 2010-09-16 09:11:13 +0000
@@ -285,6 +285,7 @@ do_rename(THD *thd, TABLE_LIST *ren_tabl
{
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
old_alias,
+ ren_table->table_name,
new_db,
new_alias)))
{
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2010-09-03 07:42:51 +0000
+++ b/sql/sql_table.cc 2010-09-16 09:11:13 +0000
@@ -5918,7 +5918,8 @@ bool mysql_alter_table(THD *thd,char *ne
*fn_ext(new_name)=0;
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
error= -1;
- else if (Table_triggers_list::change_table_name(thd, db, table_name,
+ else if (Table_triggers_list::change_table_name(thd, db,
+ alias, table_name,
new_db, new_alias))
{
(void) mysql_rename_table(old_db_type, new_db, new_alias, db,
@@ -6555,7 +6556,7 @@ bool mysql_alter_table(THD *thd,char *ne
(need_copy_table != ALTER_TABLE_METADATA_ONLY ||
mysql_rename_table(save_old_db_type, db, table_name, new_db,
new_alias, NO_FRM_RENAME)) &&
- Table_triggers_list::change_table_name(thd, db, table_name,
+ Table_triggers_list::change_table_name(thd, db, alias, table_name,
new_db, new_alias)))
{
/* Try to get everything back. */
=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc 2010-08-31 09:52:56 +0000
+++ b/sql/sql_trigger.cc 2010-09-16 09:11:13 +0000
@@ -1874,6 +1874,7 @@ Table_triggers_list::change_table_name_i
@param[in,out] thd Thread context
@param[in] db Old database of subject table
+ @param[in] old_alias Old alias of subject table
@param[in] old_table Old name of subject table
@param[in] new_db New database for subject table
@param[in] new_table New name of subject table
@@ -1890,6 +1891,7 @@ Table_triggers_list::change_table_name_i
*/
bool Table_triggers_list::change_table_name(THD *thd, const char *db,
+ const char *old_alias,
const char *old_table,
const char *new_db,
const char *new_table)
@@ -1911,7 +1913,7 @@ bool Table_triggers_list::change_table_n
MDL_EXCLUSIVE));
DBUG_ASSERT(my_strcasecmp(table_alias_charset, db, new_db) ||
- my_strcasecmp(table_alias_charset, old_table, new_table));
+ my_strcasecmp(table_alias_charset, old_alias, new_table));
if (Table_triggers_list::check_n_load(thd, db, old_table, &table, TRUE))
{
@@ -1920,7 +1922,7 @@ bool Table_triggers_list::change_table_n
}
if (table.triggers)
{
- LEX_STRING old_table_name= { (char *) old_table, strlen(old_table) };
+ LEX_STRING old_table_name= { (char *) old_alias, strlen(old_alias) };
LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) };
/*
Since triggers should be in the same schema as their subject tables
=== modified file 'sql/sql_trigger.h'
--- a/sql/sql_trigger.h 2010-03-31 14:05:33 +0000
+++ b/sql/sql_trigger.h 2010-09-16 09:11:13 +0000
@@ -157,6 +157,7 @@ public:
TABLE *table, bool names_only);
static bool drop_all_triggers(THD *thd, char *db, char *table_name);
static bool change_table_name(THD *thd, const char *db,
+ const char *old_alias,
const char *old_table,
const char *new_db,
const char *new_table);
Attachment: [text/bzr-bundle] bzr/jon.hauglid@oracle.com-20100916091113-qe47clgild5b6mnn.bundle
| Thread |
|---|
| • bzr push into mysql-5.5-runtime branch (jon.hauglid:3137 to 3138) Bug#56595 | Jon Olav Hauglid | 16 Sep |