Commit 12d5307e authored by Monty's avatar Monty

MDEV-13508 ALTER TABLE that renames columns and CHECK constraints

Fixed by adding Item::rename_fields_processor
Signed-off-by: default avatarMonty <monty@mariadb.org>
parent 7beaa5e3
...@@ -2276,5 +2276,38 @@ t1 CREATE TABLE `t1` ( ...@@ -2276,5 +2276,38 @@ t1 CREATE TABLE `t1` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; 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 # End of 10.2 tests
# #
...@@ -1882,6 +1882,24 @@ alter table t1 drop column a, drop index a; ...@@ -1882,6 +1882,24 @@ alter table t1 drop column a, drop index a;
show create table t1; show create table t1;
drop 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 #
--echo # End of 10.2 tests --echo # End of 10.2 tests
--echo # --echo #
...@@ -885,6 +885,34 @@ bool Item_field::add_field_to_set_processor(void *arg) ...@@ -885,6 +885,34 @@ bool Item_field::add_field_to_set_processor(void *arg)
DBUG_RETURN(FALSE); 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. Check if an Item_field references some field from a list of fields.
......
...@@ -1667,6 +1667,7 @@ class Item: public Value_source, ...@@ -1667,6 +1667,7 @@ class Item: public Value_source,
*/ */
virtual bool check_partition_func_processor(void *arg) { return 1;} virtual bool check_partition_func_processor(void *arg) { return 1;}
virtual bool vcol_in_partition_func_processor(void *arg) { return 0; } 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 /** Processor used to check acceptability of an item in the defining
expression for a virtual column expression for a virtual column
...@@ -1680,6 +1681,12 @@ class Item: public Value_source, ...@@ -1680,6 +1681,12 @@ class Item: public Value_source,
uint errors; /* Bits of possible errors */ uint errors; /* Bits of possible errors */
const char *name; /* Not supported function */ 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) virtual bool check_vcol_func_processor(void *arg)
{ {
return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE);
...@@ -2639,6 +2646,7 @@ class Item_field :public Item_ident ...@@ -2639,6 +2646,7 @@ class Item_field :public Item_ident
bool update_table_bitmaps_processor(void *arg); bool update_table_bitmaps_processor(void *arg);
bool switch_to_nullable_fields_processor(void *arg); bool switch_to_nullable_fields_processor(void *arg);
bool update_vcol_processor(void *arg); bool update_vcol_processor(void *arg);
bool rename_fields_processor(void *arg);
bool check_vcol_func_processor(void *arg) bool check_vcol_func_processor(void *arg)
{ {
context= 0; context= 0;
......
...@@ -123,6 +123,7 @@ class Alter_info ...@@ -123,6 +123,7 @@ class Alter_info
static const uint ALTER_ADD_CHECK_CONSTRAINT = 1L << 27; static const uint ALTER_ADD_CHECK_CONSTRAINT = 1L << 27;
static const uint ALTER_DROP_CHECK_CONSTRAINT = 1L << 28; 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 }; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
......
...@@ -38,21 +38,21 @@ void free_list(I_List <i_string> *list) ...@@ -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 It's okay to allocate an array of nodes at once: we never
call a destructor for list_node objects anyway. call a destructor for list_node objects anyway.
*/ */
first= (list_node*) alloc_root(mem_root, if ((first= (list_node*) alloc_root(mem_root,
sizeof(list_node) * rhs.elements); sizeof(list_node) * rhs->elements)))
if (first)
{ {
elements= rhs.elements; elements= rhs->elements;
list_node *dst= first; list_node *dst= first;
list_node *src= rhs.first; list_node *src= rhs->first;
for (; dst < first + elements - 1; dst++, src= src->next) for (; dst < first + elements - 1; dst++, src= src->next)
{ {
dst->info= src->info; dst->info= src->info;
...@@ -63,10 +63,12 @@ base_list::base_list(const base_list &rhs, MEM_ROOT *mem_root) ...@@ -63,10 +63,12 @@ base_list::base_list(const base_list &rhs, MEM_ROOT *mem_root)
dst->next= &end_of_list; dst->next= &end_of_list;
/* Setup 'last' member */ /* Setup 'last' member */
last= &dst->next; last= &dst->next;
return; return 0;
} }
error= 1;
} }
elements= 0; elements= 0;
first= &end_of_list; first= &end_of_list;
last= &first; last= &first;
return error;
} }
...@@ -200,7 +200,8 @@ class base_list :public Sql_alloc ...@@ -200,7 +200,8 @@ class base_list :public Sql_alloc
need to copy elements by value, you should employ need to copy elements by value, you should employ
list_copy_and_replace_each_value after creating a copy. 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 base_list(bool error) { }
inline bool push_back(void *info) inline bool push_back(void *info)
{ {
...@@ -536,6 +537,8 @@ template <class T> class List :public base_list ...@@ -536,6 +537,8 @@ template <class T> class List :public base_list
inline void disjoin(List<T> *list) { base_list::disjoin(list); } inline void disjoin(List<T> *list) { base_list::disjoin(list); }
inline bool add_unique(T *a, bool (*eq)(T *a, T *b)) inline bool add_unique(T *a, bool (*eq)(T *a, T *b))
{ return base_list::add_unique(a, (List_eq *)eq); } { 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) void delete_elements(void)
{ {
list_node *element,*next; list_node *element,*next;
......
...@@ -7558,6 +7558,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, ...@@ -7558,6 +7558,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
List<Virtual_column_info> new_constraint_list; List<Virtual_column_info> new_constraint_list;
uint db_create_options= (table->s->db_create_options uint db_create_options= (table->s->db_create_options
& ~(HA_OPTION_PACK_RECORD)); & ~(HA_OPTION_PACK_RECORD));
Item::func_processor_rename column_rename_param;
uint used_fields; uint used_fields;
KEY *key_info=table->key_info; KEY *key_info=table->key_info;
bool rc= TRUE; bool rc= TRUE;
...@@ -7607,6 +7608,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, ...@@ -7607,6 +7608,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (!(used_fields & HA_CREATE_USED_CONNECTION)) if (!(used_fields & HA_CREATE_USED_CONNECTION))
create_info->connect_string= table->s->connect_string; 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 restore_record(table, s->default_values); // Empty record for DEFAULT
if ((create_info->fields_option_struct= (ha_field_option_struct**) if ((create_info->fields_option_struct= (ha_field_option_struct**)
...@@ -7651,6 +7659,24 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, ...@@ -7651,6 +7659,24 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
bitmap_set_bit(dropped_fields, field->field_index); bitmap_set_bit(dropped_fields, field->field_index);
continue; 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 */ /* Check if field is changed */
def_it.rewind(); def_it.rewind();
while ((def=def_it++)) while ((def=def_it++))
...@@ -8060,7 +8086,10 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, ...@@ -8060,7 +8086,10 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
} }
} }
if (!drop) if (!drop)
{
check->expr->walk(&Item::rename_fields_processor, 1, &column_rename_param);
new_constraint_list.push_back(check, thd->mem_root); new_constraint_list.push_back(check, thd->mem_root);
}
} }
} }
/* Add new constraints */ /* Add new constraints */
......
...@@ -7606,7 +7606,8 @@ alter_list_item: ...@@ -7606,7 +7606,8 @@ alter_list_item:
| CHANGE opt_column opt_if_exists_table_element field_ident | CHANGE opt_column opt_if_exists_table_element field_ident
field_spec opt_place 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(); Lex->create_last_non_select_table= Lex->last_table();
$5->change= $4.str; $5->change= $4.str;
$5->after= $6; $5->after= $6;
......
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