summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <davi@moksha.local>2007-08-27 10:13:54 -0300
committerunknown <davi@moksha.local>2007-08-27 10:13:54 -0300
commit369a5f1cdcd569a02de4a12d64faebc33e9128f0 (patch)
tree1313fec2c43e8201aa5432ef88db4b13e2b4757e
parent33e123ead93b0122a67821e4b16ef70ef2b3d3af (diff)
downloadmariadb-git-369a5f1cdcd569a02de4a12d64faebc33e9128f0.tar.gz
Bug#25164 create table `a` as select * from `A` hangs
The problem from a user's perspective: user creates table A, and then tries to CREATE TABLE a SELECT from A - and this causes a deadlock error, a hang, or fails with a debug assert, but only if the storage engine is InnoDB. The origin of the problem: InnoDB uses case-insensitive collation (system_charset_info) when looking up the internal table share, thus returning the same share for 'a' and 'A'. Cause of the user-visible behavior: since the same share is returned to SQL locking subsystem, it assumes that the same table is first locked (within the same session) for WRITE, and then for READ, and returns a deadlock error. However, the code is wrong in not properly cleaning up upon an error, leaving external locks in place, which leads to assertion failures and hangs. Fix that has been implemented: the SQL layer should properly propagate the deadlock error, cleaning up and freeing all resources. Further work towards a more complete solution: InnoDB should not use case insensitive collation for table share hash if table names on disk honor the case. mysql-test/r/innodb-deadlock.result: Bug#25164 test case result mysql-test/t/innodb-deadlock.test: Bug#25164 test case. The CREATE TABLE may fail depending on the character set of the system and filesystem, but it should never hang. sql/lock.cc: Unlock the storage engine "external" table level locks, if the MySQL thr_lock locking subsystem detects a deadlock error.
-rw-r--r--mysql-test/r/innodb-deadlock.result11
-rw-r--r--mysql-test/t/innodb-deadlock.test27
-rw-r--r--sql/lock.cc2
3 files changed, 39 insertions, 1 deletions
diff --git a/mysql-test/r/innodb-deadlock.result b/mysql-test/r/innodb-deadlock.result
index 2ca82101fb4..b6a3373e8c6 100644
--- a/mysql-test/r/innodb-deadlock.result
+++ b/mysql-test/r/innodb-deadlock.result
@@ -94,3 +94,14 @@ id x
300 300
commit;
drop table t1, t2;
+End of 4.1 tests
+set storage_engine=innodb;
+drop table if exists a;
+drop table if exists A;
+create table A (c int);
+insert into A (c) values (0);
+create table a as select * from A;
+drop table A;
+drop table if exists a;
+set storage_engine=default;
+End of 5.0 tests.
diff --git a/mysql-test/t/innodb-deadlock.test b/mysql-test/t/innodb-deadlock.test
index 81acfba5c93..1a184f98771 100644
--- a/mysql-test/t/innodb-deadlock.test
+++ b/mysql-test/t/innodb-deadlock.test
@@ -112,4 +112,29 @@ commit;
drop table t1, t2;
-# End of 4.1 tests
+--echo End of 4.1 tests
+
+#
+# Bug#25164 create table `a` as select * from `A` hangs
+#
+
+set storage_engine=innodb;
+
+--disable_warnings
+drop table if exists a;
+drop table if exists A;
+--enable_warnings
+
+create table A (c int);
+insert into A (c) values (0);
+--error 0,ER_LOCK_DEADLOCK,ER_UPDATE_TABLE_USED
+create table a as select * from A;
+drop table A;
+
+--disable_warnings
+drop table if exists a;
+--enable_warnings
+
+set storage_engine=default;
+
+--echo End of 5.0 tests.
diff --git a/sql/lock.cc b/sql/lock.cc
index 0036d0aef77..cf06be5f95f 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -172,6 +172,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
thd->lock_id)];
if (rc > 1) /* a timeout or a deadlock */
{
+ if (sql_lock->table_count)
+ VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
my_error(rc, MYF(0));
my_free((gptr) sql_lock,MYF(0));
sql_lock= 0;