summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2018-02-10 14:24:15 +0200
committerMonty <monty@mariadb.org>2018-02-10 14:32:24 +0200
commit12d5307e95687e543f80aa3e8636a2ab8b96fe8d (patch)
treea319f422364e0e9ba03d18aac0d203611e1f11db
parent7beaa5e34e1fc4a3987351f41b0f0ed1329aeb25 (diff)
downloadmariadb-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.result33
-rw-r--r--mysql-test/t/alter_table.test18
-rw-r--r--sql/item.cc28
-rw-r--r--sql/item.h8
-rw-r--r--sql/sql_alter.h1
-rw-r--r--sql/sql_list.cc18
-rw-r--r--sql/sql_list.h5
-rw-r--r--sql/sql_table.cc29
-rw-r--r--sql/sql_yacc.yy3
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;