diff options
author | Monty <monty@mariadb.org> | 2018-02-10 14:24:15 +0200 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2018-02-10 14:32:24 +0200 |
commit | 12d5307e95687e543f80aa3e8636a2ab8b96fe8d (patch) | |
tree | a319f422364e0e9ba03d18aac0d203611e1f11db | |
parent | 7beaa5e34e1fc4a3987351f41b0f0ed1329aeb25 (diff) | |
download | mariadb-git-12d5307e95687e543f80aa3e8636a2ab8b96fe8d.tar.gz |
MDEV-13508 ALTER TABLE that renames columns and CHECK constraints
Fixed by adding Item::rename_fields_processor
Signed-off-by: Monty <monty@mariadb.org>
-rw-r--r-- | mysql-test/r/alter_table.result | 33 | ||||
-rw-r--r-- | mysql-test/t/alter_table.test | 18 | ||||
-rw-r--r-- | sql/item.cc | 28 | ||||
-rw-r--r-- | sql/item.h | 8 | ||||
-rw-r--r-- | sql/sql_alter.h | 1 | ||||
-rw-r--r-- | sql/sql_list.cc | 18 | ||||
-rw-r--r-- | sql/sql_list.h | 5 | ||||
-rw-r--r-- | sql/sql_table.cc | 29 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 3 |
9 files changed, 133 insertions, 10 deletions
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index b8f51ee25ad..0845459f6b6 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -2276,5 +2276,38 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; # +# MDEV-13508 Check that rename of columns changes defaults, virtual +# columns and constraints +# +create table t1 (a int, b int, check(a>b)); +alter table t1 change column a b int, change column b a int; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + CONSTRAINT `CONSTRAINT_1` CHECK (`b` > `a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a int primary key, b int, c int default (a+b) check (a+b>0), +d int as (a+b), +key (b), +constraint test check (a+b > 1)); +alter table t1 change b new_b int not null, add column b char(1), add constraint new check (length(b) > 0); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `new_b` int(11) NOT NULL, + `c` int(11) DEFAULT (`a` + `new_b`) CHECK (`a` + `new_b` > 0), + `d` int(11) GENERATED ALWAYS AS (`a` + `new_b`) VIRTUAL, + `b` char(1) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`new_b`), + CONSTRAINT `test` CHECK (`a` + `new_b` > 1), + CONSTRAINT `new` CHECK (length(`b`) > 0) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +# # End of 10.2 tests # diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 79a01d5e0c4..63d24c0740d 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -1883,5 +1883,23 @@ show create table t1; drop table t1; --echo # +--echo # MDEV-13508 Check that rename of columns changes defaults, virtual +--echo # columns and constraints +--echo # + +create table t1 (a int, b int, check(a>b)); +alter table t1 change column a b int, change column b a int; +show create table t1; +drop table t1; + +create table t1 (a int primary key, b int, c int default (a+b) check (a+b>0), + d int as (a+b), + key (b), + constraint test check (a+b > 1)); +alter table t1 change b new_b int not null, add column b char(1), add constraint new check (length(b) > 0); +show create table t1; +drop table t1; + +--echo # --echo # End of 10.2 tests --echo # diff --git a/sql/item.cc b/sql/item.cc index a46c17a0dbb..03949c1ceef 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -885,6 +885,34 @@ bool Item_field::add_field_to_set_processor(void *arg) DBUG_RETURN(FALSE); } + +/** + Rename fields in an expression to new field name as speficied by ALTER TABLE +*/ + +bool Item_field::rename_fields_processor(void *arg) +{ + Item::func_processor_rename *rename= (Item::func_processor_rename*) arg; + List_iterator<Create_field> def_it(rename->fields); + Create_field *def; + + while ((def=def_it++)) + { + if (def->change && + (!db_name || !db_name[0] || + !my_strcasecmp(table_alias_charset, db_name, rename->db_name.str)) && + (!table_name || !table_name[0] || + !my_strcasecmp(table_alias_charset, table_name, rename->table_name.str)) && + !my_strcasecmp(system_charset_info, field_name, def->change)) + { + field_name= def->field_name; + break; + } + } + return 0; +} + + /** Check if an Item_field references some field from a list of fields. diff --git a/sql/item.h b/sql/item.h index 727185a1deb..325514d19aa 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1667,6 +1667,7 @@ public: */ virtual bool check_partition_func_processor(void *arg) { return 1;} virtual bool vcol_in_partition_func_processor(void *arg) { return 0; } + virtual bool rename_fields_processor(void *arg) { return 0; } /** Processor used to check acceptability of an item in the defining expression for a virtual column @@ -1680,6 +1681,12 @@ public: uint errors; /* Bits of possible errors */ const char *name; /* Not supported function */ }; + struct func_processor_rename + { + LEX_CSTRING db_name; + LEX_CSTRING table_name; + List<Create_field> fields; + }; virtual bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); @@ -2639,6 +2646,7 @@ public: bool update_table_bitmaps_processor(void *arg); bool switch_to_nullable_fields_processor(void *arg); bool update_vcol_processor(void *arg); + bool rename_fields_processor(void *arg); bool check_vcol_func_processor(void *arg) { context= 0; diff --git a/sql/sql_alter.h b/sql/sql_alter.h index 5668a0f52be..4c75bd4a509 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -123,6 +123,7 @@ public: static const uint ALTER_ADD_CHECK_CONSTRAINT = 1L << 27; static const uint ALTER_DROP_CHECK_CONSTRAINT = 1L << 28; + static const uint ALTER_RENAME_COLUMN = 1L << 29; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; diff --git a/sql/sql_list.cc b/sql/sql_list.cc index 2c1b3c47d55..c63c83f0645 100644 --- a/sql/sql_list.cc +++ b/sql/sql_list.cc @@ -38,21 +38,21 @@ void free_list(I_List <i_string> *list) } -base_list::base_list(const base_list &rhs, MEM_ROOT *mem_root) +bool base_list::copy(const base_list *rhs, MEM_ROOT *mem_root) { - if (rhs.elements) + bool error= 0; + if (rhs->elements) { /* It's okay to allocate an array of nodes at once: we never call a destructor for list_node objects anyway. */ - first= (list_node*) alloc_root(mem_root, - sizeof(list_node) * rhs.elements); - if (first) + if ((first= (list_node*) alloc_root(mem_root, + sizeof(list_node) * rhs->elements))) { - elements= rhs.elements; + elements= rhs->elements; list_node *dst= first; - list_node *src= rhs.first; + list_node *src= rhs->first; for (; dst < first + elements - 1; dst++, src= src->next) { dst->info= src->info; @@ -63,10 +63,12 @@ base_list::base_list(const base_list &rhs, MEM_ROOT *mem_root) dst->next= &end_of_list; /* Setup 'last' member */ last= &dst->next; - return; + return 0; } + error= 1; } elements= 0; first= &end_of_list; last= &first; + return error; } diff --git a/sql/sql_list.h b/sql/sql_list.h index 321041cf200..c27ed44cb9c 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -200,7 +200,8 @@ public: need to copy elements by value, you should employ list_copy_and_replace_each_value after creating a copy. */ - base_list(const base_list &rhs, MEM_ROOT *mem_root); + bool copy(const base_list *rhs, MEM_ROOT *mem_root); + base_list(const base_list &rhs, MEM_ROOT *mem_root) { copy(&rhs, mem_root); } inline base_list(bool error) { } inline bool push_back(void *info) { @@ -536,6 +537,8 @@ public: inline void disjoin(List<T> *list) { base_list::disjoin(list); } inline bool add_unique(T *a, bool (*eq)(T *a, T *b)) { return base_list::add_unique(a, (List_eq *)eq); } + inline bool copy(const List<T> *list, MEM_ROOT *root) + { return base_list::copy(list, root); } void delete_elements(void) { list_node *element,*next; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index da001674887..40e551852cd 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7558,6 +7558,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, List<Virtual_column_info> new_constraint_list; uint db_create_options= (table->s->db_create_options & ~(HA_OPTION_PACK_RECORD)); + Item::func_processor_rename column_rename_param; uint used_fields; KEY *key_info=table->key_info; bool rc= TRUE; @@ -7607,6 +7608,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, if (!(used_fields & HA_CREATE_USED_CONNECTION)) create_info->connect_string= table->s->connect_string; + column_rename_param.db_name.str= table->s->db.str; + column_rename_param.db_name.length= table->s->db.length; + column_rename_param.table_name.str= table->s->table_name.str; + column_rename_param.table_name.length= table->s->table_name.length; + if (column_rename_param.fields.copy(&alter_info->create_list, thd->mem_root)) + DBUG_RETURN(1); // OOM + restore_record(table, s->default_values); // Empty record for DEFAULT if ((create_info->fields_option_struct= (ha_field_option_struct**) @@ -7651,6 +7659,24 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, bitmap_set_bit(dropped_fields, field->field_index); continue; } + + /* + If we are doing a rename of a column, update all references in virtual + column expressions, constraints and defaults to use the new column name + */ + if (alter_info->flags & Alter_info::ALTER_RENAME_COLUMN) + { + if (field->vcol_info) + field->vcol_info->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + if (field->check_constraint) + field->check_constraint->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + if (field->default_value) + field->default_value->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + } + /* Check if field is changed */ def_it.rewind(); while ((def=def_it++)) @@ -8060,7 +8086,10 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } } if (!drop) + { + check->expr->walk(&Item::rename_fields_processor, 1, &column_rename_param); new_constraint_list.push_back(check, thd->mem_root); + } } } /* Add new constraints */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1fcc568af09..112cf9877b4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7606,7 +7606,8 @@ alter_list_item: | CHANGE opt_column opt_if_exists_table_element field_ident field_spec opt_place { - Lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN; + Lex->alter_info.flags|= (Alter_info::ALTER_CHANGE_COLUMN | + Alter_info::ALTER_RENAME_COLUMN); Lex->create_last_non_select_table= Lex->last_table(); $5->change= $4.str; $5->after= $6; |