From fc01b0995d92aea1ca2ed790df37362a290df689 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Sat, 2 Jun 2007 01:21:18 +0400 Subject: [PATCH] Bug#28427: Columns were renamed instead of moving by ALTER TABLE. To avoid unnecessary work the mysql_alter_table function takes the list of table fields and applies all changes to it (drops/moves/renames/etc). Then this function compares the new list and the old one. If the changes require only .frm to be modified then the actual data isn't copied. To detect changes all columns attributes but names are compared. When a column has been moved and has replaced another column with the same attributes except name the mysql_alter_table function wrongly decides that two fields has been just renamed. As a result the data from the moved column and from all columns after it is not copied. Now the mysql_alter_table function forces table data copying by setting the need_copy_table flag when it finds a moved column. The flag is set at the stage when the modified fields are created. --- mysql-test/r/alter_table.result | 14 ++++++++++++++ mysql-test/t/alter_table.test | 12 ++++++++++++ sql/sql_table.cc | 5 ++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 3fa12f2997a..c9e3655660b 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -1103,3 +1103,17 @@ Field Type Null Key Default Extra unsigned_int_field bigint(20) unsigned NO MUL char_field char(10) YES NULL DROP TABLE t2; +CREATE TABLE t1 (f1 INT, f2 INT, f3 INT); +INSERT INTO t1 VALUES (1, 2, NULL); +SELECT * FROM t1; +f1 f2 f3 +1 2 NULL +ALTER TABLE t1 MODIFY COLUMN f3 INT AFTER f1; +SELECT * FROM t1; +f1 f3 f2 +1 NULL 2 +ALTER TABLE t1 MODIFY COLUMN f3 INT AFTER f2; +SELECT * FROM t1; +f1 f2 f3 +1 2 NULL +DROP TABLE t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 70fd1dfa898..7c1c096534e 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -839,3 +839,15 @@ ALTER TABLE t2 MODIFY unsigned_int_field BIGINT UNSIGNED NOT NULL; DESCRIBE t2; DROP TABLE t2; + +# +# Bug#28427: Columns were renamed instead of moving by ALTER TABLE. +# +CREATE TABLE t1 (f1 INT, f2 INT, f3 INT); +INSERT INTO t1 VALUES (1, 2, NULL); +SELECT * FROM t1; +ALTER TABLE t1 MODIFY COLUMN f3 INT AFTER f1; +SELECT * FROM t1; +ALTER TABLE t1 MODIFY COLUMN f3 INT AFTER f2; +SELECT * FROM t1; +DROP TABLE t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 11d7d15c685..a77ed172478 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5932,6 +5932,7 @@ view_err: goto err; } find_it.after(def); // Put element after this + need_copy_table= ALTER_TABLE_DATA_CHANGED; } } if (alter_info->alter_list.elements) @@ -6170,12 +6171,14 @@ view_err: (uint*) thd->alloc(sizeof(uint) * prepared_key_list.elements))) goto err; /* Check how much the tables differ. */ - need_copy_table= compare_tables(table, &prepared_create_list, + bool res= compare_tables(table, &prepared_create_list, key_info_buffer, key_count, create_info, alter_info, order_num, index_drop_buffer, &index_drop_count, index_add_buffer, &index_add_count, varchar); + if (!need_copy_table) + need_copy_table= res; } /*