Commit 3f0cdbc4 authored by unknown's avatar unknown

Fix for bug #28415 "Some ALTER TABLE statements no longer work under LOCK

TABLES" and failures of alter_table.test on Windows which occured after
pushing fix for bugs #20662, #20903, #24508, #24738 (various problems
with CREATE TABLE SELECT).

ALTER TABLE statements which were handled using "fast" alter table
optimization were not properly working under LOCK TABLES if table
was transactional (for all table types under Windows).

Code implementing "fast" version of ALTER TABLE tried to open and
lock table using open_ltable() after renaming .FRM files (which
corresponds to renaming tables in normal case) in some cases
(for transactional tables or on Windows). This caused problems
under LOCK TABLES and conflicted with name-lock taken by 
ALTER TABLE RENAME on target tables.

This patch solves this issue by using reopen_name_locked_table()
instead of open_ltable().


mysql-test/include/mix1.inc:
  Added test for bug #28415 "Some ALTER TABLE statements no longer work
  under LOCK TABLES" and minimal coverage for fast ALTER TABLE behaviour
  for transactional tables.
mysql-test/r/innodb_mysql.result:
  Added test for bug #28415 "Some ALTER TABLE statements no longer work
  under LOCK TABLES" and minimal coverage for fast ALTER TABLE behaviour
  for transactional tables.
sql/sql_table.cc:
  mysql_alter_table():
    Fixed handling of transactional tables (and all tables on Windows)
    by "fast" ALTER TABLE.
    Code implementing "fast" version of ALTER TABLE tried to open and
    lock table using open_ltable() after renaming .FRM files (which
    corresponds to renaming tables in normal case) for such tables.
    This caused problems under LOCK TABLES and conflicted with name-lock
    taken by ALTER TABLE RENAME on target tables. We solve this issue by
    using reopen_name_locked_table() instead of open_ltable().
parent 5a7c51e0
...@@ -688,4 +688,24 @@ select * from t2; ...@@ -688,4 +688,24 @@ select * from t2;
drop table 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 --echo End of 5.1 tests
...@@ -733,4 +733,15 @@ k a c ...@@ -733,4 +733,15 @@ k a c
11 15 1 11 15 1
12 20 1 12 20 1
drop table t2; 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 End of 5.1 tests
...@@ -6673,6 +6673,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -6673,6 +6673,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
} }
if (! need_copy_table) if (! need_copy_table)
{ {
bool needs_unlink= FALSE;
if (! table) if (! table)
{ {
if (new_name != table_name || new_db != db) if (new_name != table_name || new_db != db)
...@@ -6683,11 +6684,41 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -6683,11 +6684,41 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
table_list->db= new_db; table_list->db= new_db;
table_list->db_length= strlen(new_db); table_list->db_length= strlen(new_db);
} }
else
VOID(pthread_mutex_unlock(&LOCK_open)); {
if (! (table= open_ltable(thd, table_list, TL_WRITE_ALLOW_READ))) /*
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; 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. */ /* Tell the handler that a new frm file is in place. */
if (table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG, if (table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG,
...@@ -6696,6 +6727,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -6696,6 +6727,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
VOID(pthread_mutex_unlock(&LOCK_open)); VOID(pthread_mutex_unlock(&LOCK_open));
goto err; 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 if (thd->lock || new_name != table_name || no_table_reopen) // True if WIN32
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment