1. 背景描述
MySQL从8.0开始支持rename column语法,方便用户在不改变列定义的前提下为列重新命名。以下是一个rename column的使用示例:
alter table t1 rename column col_a to col_b;
OceanBase过去的版本中,已在Oracle租户下支持了rename column语法,本次调整是在4.2.1以及往后的版本中,支持MySQL租户的rename column的语法,以兼容MySQL8.0。
2. 功能描述
rename column语法:
ALTER TABLE tbl_name [rename_action [, rename_action] ...];
rename_action: RENAME old_col_name To new_col_name;
rename column不改变列定义,仅修改列名。如果目标名称在表中已经存在,那么rename column执行会报错:
OceanBase(root@test)>create table t1 (a int, b int);
Query OK, 0 rows affected (0.100 sec)
OceanBase(root@test)>alter table t1 rename column a to b;
ERROR 1060 (42S21): Duplicate column name 'b'
不过也有例外,如果重命名的列出现了循环,可以正常执行。比如下面的是一个合法的alter示例:
OceanBase(root@test)>create table t1 (a int, b int);
Query OK, 0 rows affected (0.046 sec)
OceanBase(root@test)>alter table t1 rename column a to b, rename column b to a;
Query OK, 0 rows affected (0.076 sec)
OceanBase(root@test)>desc t1;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| b | int(11) | YES | | NULL | |
| a | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.003 sec)
如果重命名的列上建有索引,或者有外键约束,rename column可以正常执行,并且索引定义和外键约束会自动级联联修改,比如:
OceanBase(root@test)>create table t1 (a int, b int, index idx_a(a));
Query OK, 0 rows affected (0.057 sec)
OceanBase(root@test)>show index from t1;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| t1 | 1 | idx_a | 1 | a | A | NULL | NULL | NULL | YES | BTREE | available | | YES | NULL |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
1 row in set (0.014 sec)
OceanBase(root@test)>alter table t1 rename column a to c;
Query OK, 0 rows affected (0.058 sec)
OceanBase(root@test)>show index from t1;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| t1 | 1 | idx_a | 1 | c | A | NULL | NULL | NULL | YES | BTREE | available | | YES | NULL |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
OceanBase(root@test)>create table t1 (a int primary key);
Query OK, 0 rows affected (0.043 sec)
OceanBase(root@test)>create table t2(b int, foreign key (b) references t1(a));
Query OK, 0 rows affected (0.066 sec)
OceanBase(root@test)>show create table t2;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t2 | CREATE TABLE `t2` (
`b` int(11) DEFAULT NULL,
CONSTRAINT `t2_OBFK_1691379783330957` FOREIGN KEY (`b`) REFERENCES `test`.`t1`(`a`) ON UPDATE RESTRICT ON DELETE RESTRICT
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0 |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.019 sec)
OceanBase(root@test)>alter table t1 rename column a to b;
Query OK, 0 rows affected (0.053 sec)
OceanBase(root@test)>show create table t2;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t2 | CREATE TABLE `t2` (
`b` int(11) DEFAULT NULL,
CONSTRAINT `t2_OBFK_1691379783330957` FOREIGN KEY (`b`) REFERENCES `test`.`t1`(`b`) ON UPDATE RESTRICT ON DELETE RESTRICT
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0 |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.009 sec)
但是在以下场景,并不会自动级联修改:
- 重命名的列被生成列表达式引用,执行会报错,不支持修改。
- 重命名的列被分区表达式引用,执行报错,不支持修改。
- 重命名的列被check约束引用,执行报错,不支持修改。
- 重命名的列被视图引用,rename column执行成功,查询视图报错,需要用户手动修改视图定义。
- 重命名的列被存储过程引用,rename column执行成功,call procedure报错,需要用户手动修改。
OceanBase(root@test)>create table t1(a int, b int as (a + 1), c int, d int, constraint d_check check(d > 0)) partition by hash(c + 1) partitions 2;
Query OK, 0 rows affected (0.057 sec)
OceanBase(root@test)>alter table t1 rename column a to e;
ERROR 3108 (HY000): Column 'a' has a generated column dependency
OceanBase(root@test)>alter table t1 rename column c to e;
ERROR 3855 (HY000): Column 'c' has a partitioning function dependency and cannot be dropped or renamed.
OceanBase(root@test)>alter table t1 rename column d to e;
ERROR 3959 (HY000): Check constraint 'd_check' uses column 'd', hence column cannot be dropped or renamed.
OceanBase(root@test)>create table t1 (a int);
Query OK, 0 rows affected (0.043 sec)
OceanBase(root@test)>create view v1 as select a + 1 from t1;
Query OK, 0 rows affected (0.040 sec)
OceanBase(root@test)>create procedure p() select a + 1 from t1;
Query OK, 0 rows affected (0.036 sec)
OceanBase(root@test)>select * from v1;
Empty set (0.010 sec)
OceanBase(root@test)>call p();
Empty set (0.014 sec)
Query OK, 0 rows affected (0.014 sec)
OceanBase(root@test)>alter table t1 rename column a to b;
Query OK, 0 rows affected (0.053 sec)
OceanBase(root@test)>select * from v1;
ERROR 1356 (42S22): View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
OceanBase(root@test)>call p();
ERROR 1054 (42S22): Unknown column 'a' in 'field list'
3. 限制以及注意事项
第一:MySQL 8.0规定ADD PARTITION
, DROP PARTITION
, DISCARD PARTITION
, IMPORT PARTITION
, COALESCE PARTITION
, REORGANIZE PARTITION
, EXCHANGE PARTITION
, ANALYZE PARTITION
, CHECK PARTITION
和REPAIR PARTITION
操作不能和rename column语句一起使用,比如下面一个add partition的例子,执行会报语法错误:
mysql> create table t1 (a int, b int) partition by range(a) (partition p0 values less than (10));
Query OK, 0 rows affected (0.01 sec)
mysql> alter table t1 rename column b to c, add partition (partition p1 values less than (20));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'partition (partition p1 values less than (20))' at line 1
对于同一条alter stmt中同时包含alter_partition_action和alter_column_action的场景,OB当前的实现选择了执行报错(NOT SUPPORTED错误),比如上述SQL:
OceanBase(root@test)>create table t1 (a int, b int) partition by range(a) (partition p0 values less than (10));
Query OK, 0 rows affected (0.052 sec)
OceanBase(root@test)>alter table t1 rename column b to c, add partition (partition p1 values less than (20));
ERROR 1235 (0A000): specify alter_column_action and alter_partition_action in a single alter table stmt not supported
第二:MySQL 8.0支持在同一条alter stmt中指定drop column和rename column,如果rename的目标列名和drop的列名相同,rename column可以执行成功,比如:
mysql> create table t1(a int, b int);
Query OK, 0 rows affected (0.01 sec)
mysql> alter table t1 drop column a, rename column b to a;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
OB目前不支持上述两个alter_column_action在一次DDL中执行:
OceanBase(root@test)>create table t1 (a int, b int);
Query OK, 0 rows affected (0.047 sec)
OceanBase(root@test)>alter table t1 drop column a, rename column b to a;
ERROR 1060 (42S21): Duplicate column name 'a'
建议再drop column和rename column拆成两个DDL语句执行分别执行。