diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 352d5a987a2..fce37eef187 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -688,4 +688,24 @@ select * from t2; drop table t2; + +# +# Tests for bug #28415 "Some ALTER TABLE statements no longer work +# under LOCK TABLES" and some aspects of fast ALTER TABLE behaviour +# for transactional tables. +# +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +create table t1 (i int); +alter table t1 modify i int default 1; +alter table t1 modify i int default 2, rename t2; +lock table t2 write; +alter table t2 modify i int default 3; +unlock tables; +lock table t2 write; +alter table t2 modify i int default 4, rename t1; +unlock tables; +drop table t1; + --echo End of 5.1 tests diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index e51318af827..074efc30838 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -733,4 +733,15 @@ k a c 11 15 1 12 20 1 drop table t2; +drop table if exists t1, t2; +create table t1 (i int); +alter table t1 modify i int default 1; +alter table t1 modify i int default 2, rename t2; +lock table t2 write; +alter table t2 modify i int default 3; +unlock tables; +lock table t2 write; +alter table t2 modify i int default 4, rename t1; +unlock tables; +drop table t1; End of 5.1 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6f59e326814..23214c7c8a7 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6673,6 +6673,7 @@ view_err: } if (! need_copy_table) { + bool needs_unlink= FALSE; if (! table) { if (new_name != table_name || new_db != db) @@ -6683,11 +6684,41 @@ view_err: table_list->db= new_db; table_list->db_length= strlen(new_db); } - - VOID(pthread_mutex_unlock(&LOCK_open)); - if (! (table= open_ltable(thd, table_list, TL_WRITE_ALLOW_READ))) + else + { + /* + TODO: Creation of name-lock placeholder here is a temporary + work-around. Long term we should change close_cached_table() call + which we invoke before table renaming operation in such way that + it will leave placeholders for table in table cache/THD::open_tables + list. By doing this we will be able easily reopen and relock these + tables later and therefore behave under LOCK TABLES in the same way + on all platforms. + */ + char key[MAX_DBKEY_LENGTH]; + uint key_length; + key_length= create_table_def_key(thd, key, table_list, 0); + if (!(name_lock= table_cache_insert_placeholder(thd, key, + key_length))) + { + VOID(pthread_mutex_unlock(&LOCK_open)); + goto err; + } + name_lock->next= thd->open_tables; + thd->open_tables= name_lock; + } + table_list->table= name_lock; + if (reopen_name_locked_table(thd, table_list, FALSE)) + { + VOID(pthread_mutex_unlock(&LOCK_open)); goto err; - VOID(pthread_mutex_lock(&LOCK_open)); + } + table= table_list->table; + /* + We can't rely on later close_cached_table() calls to close + this instance of the table since it was not properly locked. + */ + needs_unlink= TRUE; } /* Tell the handler that a new frm file is in place. */ if (table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG, @@ -6696,6 +6727,11 @@ view_err: VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } + if (needs_unlink) + { + unlink_open_table(thd, table, FALSE); + table= name_lock= 0; + } } if (thd->lock || new_name != table_name || no_table_reopen) // True if WIN32