mirror of
https://github.com/MariaDB/server.git
synced 2025-01-28 01:34:17 +01:00
MDEV-13508 ALTER TABLE that renames columns and CHECK constraints
Fixed by adding Item::rename_fields_processor Signed-off-by: Monty <monty@mariadb.org>
This commit is contained in:
parent
7beaa5e34e
commit
12d5307e95
9 changed files with 133 additions and 10 deletions
|
@ -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
|
||||
#
|
||||
|
|
|
@ -1882,6 +1882,24 @@ alter table t1 drop column a, drop index a;
|
|||
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 #
|
||||
|
|
28
sql/item.cc
28
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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue