=== modified file 'mysql-test/suite/vcol/inc/vcol_non_stored_columns.inc' --- mysql-test/suite/vcol/inc/vcol_non_stored_columns.inc 2009-10-16 22:57:48 +0000 +++ mysql-test/suite/vcol/inc/vcol_non_stored_columns.inc 2014-05-29 12:20:08 +0000 @@ -160,3 +160,15 @@ select * from t1; show create table t1; drop table t1; +--echo # +--echo # MDEV-6103 - Adding/removing non-materialized virtual column triggers +--echo # table recreation +--echo # +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1); +enable_info; +ALTER TABLE t1 ADD COLUMN b INT AS (a + 1) VIRTUAL; +ALTER TABLE t1 DROP COLUMN b; +disable_info; +CHECK TABLE t1; +DROP TABLE t1; === modified file 'mysql-test/suite/vcol/r/vcol_non_stored_columns_innodb.result' --- mysql-test/suite/vcol/r/vcol_non_stored_columns_innodb.result 2010-12-31 09:39:14 +0000 +++ mysql-test/suite/vcol/r/vcol_non_stored_columns_innodb.result 2014-05-29 12:21:48 +0000 @@ -240,3 +240,19 @@ t1 CREATE TABLE `t1` ( `c` int(11) AS (week(b,1)) VIRTUAL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 drop table t1; +# +# MDEV-6103 - Adding/removing non-materialized virtual column triggers +# table recreation +# +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1); +ALTER TABLE t1 ADD COLUMN b INT AS (a + 1) VIRTUAL; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 DROP COLUMN b; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; === modified file 'sql/sql_table.cc' --- sql/sql_table.cc 2014-04-07 19:53:19 +0000 +++ sql/sql_table.cc 2014-05-29 12:13:31 +0000 @@ -5169,8 +5169,7 @@ mysql_compare_tables(TABLE *table, prior to 5.0 branch. See BUG#6236. */ - if (table->s->fields != alter_info->create_list.elements || - table->s->db_type() != create_info->db_type || + if (table->s->db_type() != create_info->db_type || table->s->tmp_table || create_info->used_fields & HA_CREATE_USED_ENGINE || create_info->used_fields & HA_CREATE_USED_CHARSET || @@ -5206,14 +5205,55 @@ mysql_compare_tables(TABLE *table, Go through fields and check if the original ones are compatible with new table. */ - for (i= 0, f_ptr= table->field, new_field= new_field_it++, - tmp_new_field= tmp_new_field_it++; - (field= *f_ptr); - i++, f_ptr++, new_field= new_field_it++, - tmp_new_field= tmp_new_field_it++) + for (i=0, f_ptr= table->field; (field= *f_ptr); f_ptr++) { - DBUG_ASSERT(i < table->s->fields); - create_info->fields_option_struct[i]= tmp_new_field->option_struct; + /* Skip virtual columns in old definition */ + if (field->vcol_info) + { + /* + Check if the altered column is computed and either + is stored or is used in the partitioning expression. + TODO: Mark such a column with an alter flag only if + the defining expression has changed. + */ + if (field->stored_in_db || field->vcol_info->is_in_partitioning_expr()) + { + DBUG_PRINT("info", ("Old virtual column '%s' is stored or used in " + "partitioning expression -> " + "ALTER_TABLE_DATA_CHANGED", field->field_name)); + DBUG_RETURN(0); + } + continue; + } + + /* Skip virtual columns in new definition */ + for (;;) + { + new_field= new_field_it++; + tmp_new_field= tmp_new_field_it++; + if (!tmp_new_field) + { + DBUG_PRINT("info", ("Column '%s' dropped -> " + "ALTER_TABLE_DATA_CHANGED", field->field_name)); + DBUG_RETURN(0); + } + create_info->fields_option_struct[i++]= tmp_new_field->option_struct; + + if (tmp_new_field->vcol_info) + { + if (tmp_new_field->stored_in_db || + tmp_new_field->vcol_info->is_in_partitioning_expr()) + { + DBUG_PRINT("info", ("New virtual column '%s' is stored or used in " + "partitioning expression -> " + "ALTER_TABLE_DATA_CHANGED", + tmp_new_field->field_name)); + DBUG_RETURN(0); + } + } + else + break; + } /* reset common markers of how field changed */ field->flags&= ~(FIELD_IS_RENAMED | FIELD_IN_ADD_INDEX); @@ -5231,19 +5271,6 @@ mysql_compare_tables(TABLE *table, DBUG_RETURN(0); } - /* - Check if the altered column is computed and either - is stored or is used in the partitioning expression. - TODO: Mark such a column with an alter flag only if - the defining expression has changed. - */ - if (field->vcol_info && - (field->stored_in_db || field->vcol_info->is_in_partitioning_expr())) - { - *need_copy_table= ALTER_TABLE_DATA_CHANGED; - DBUG_RETURN(0); - } - /* Don't pack rows in old tables if the user has requested this. */ if (create_info->row_type == ROW_TYPE_DYNAMIC || (tmp_new_field->flags & BLOB_FLAG) || @@ -5267,6 +5294,21 @@ mysql_compare_tables(TABLE *table, changes|= tmp; } + /* Make sure there are no new non-virtual columns */ + while ((tmp_new_field= tmp_new_field_it++)) + { + create_info->fields_option_struct[i++]= tmp_new_field->option_struct; + if (!tmp_new_field->vcol_info || tmp_new_field->stored_in_db || + tmp_new_field->vcol_info->is_in_partitioning_expr()) + { + DBUG_PRINT("info", ("New column '%s' is stored or used in " + "partitioning expression -> " + "ALTER_TABLE_DATA_CHANGED", + tmp_new_field->field_name)); + DBUG_RETURN(0); + } + } + /* Go through keys and check if the original ones are compatible with new table. @@ -5621,7 +5663,9 @@ mysql_prepare_alter_table(THD *thd, TABL when new version of the table has the same structure as the old one. */ - alter_info->change_level= ALTER_TABLE_DATA_CHANGED; + if (!field->vcol_info || field->stored_in_db || + field->vcol_info->is_in_partitioning_expr()) + alter_info->change_level= ALTER_TABLE_DATA_CHANGED; continue; } /* Check if field is changed */