Skip to content

Commit 0240b63

Browse files
author
Dmitry Lenev
committed
Bug #28772251 "SWAPPING COLUMN BY ALTER TABLE RENAME COLUMN BREAKS STORED GENERATED COLUMN".
Stored generated column values and indexes on virtual generated columns were not correctly updated after columns on which these generated columns depended were swapped using ALTER TABLE ... RENAME COLUMN or ALTER TABLE ... CHANGE COLUMN. This problem was caused by the fact that renaming of columns on which generated columns were dependent was not prohibited as it was planned initially (we only detected the problem if generation expression became invalid). Nor the fact that base columns were swapped and generated expression needs re-evaluation as result was detected. This fix solves the problem by disallowing renaming of base columns for generated columns, generated defaults and functional indexes. However, such renaming is allowed if generated column/default or functional index is removed by the same ALTER TABLE. We also allow such renaming if dependent expression in question is updated within the same ALTER TABLE. This allows to support existing/documented user scenarios in which generation expression was updated to follow base column renames. Restriction on dropping columns on which generated columns, defaults or functional indexes depend was relaxed in similar way. Code which evaluates flags for in-place/instant ALTER TABLE SE API was adjusted to detect situations in which generated column expressions stays the same but has changed its values due to base column swapping or replacement (through drop/add). To support the above changes handling of Alter_info::drop_list list by SQL-layer code has been changed. We no longer delete elements which correspond to columns and keys from it. As consequence InnoDB SE code has been adjusted to take this change into account. To support the latter new members for number of added and dropped virtual columns were added to Alter_inplace_info class. New error message and code was added to report about dependent functional indexes for columns being renamed/dropped. Existing error message about dependent default expressions was adjusted to make it possible to use in cases when base columns are renamed. Reviewed-by: Sivert Sorumgaard <sivert.sorumgaard@oracle.com> Reviewed-by: Bin Su <bin.x.su@oracle.com>
1 parent fc0351e commit 0240b63

15 files changed

+1184
-205
lines changed

mysql-test/r/alter_table.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3487,9 +3487,9 @@ t_gen CREATE TABLE `t_gen` (
34873487
`b` double GENERATED ALWAYS AS (sqrt(`c`)) VIRTUAL
34883488
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
34893489
ALTER TABLE t_gen CHANGE COLUMN c a INT;
3490-
ERROR 42S22: Unknown column 'c' in 'generated column function'
3490+
ERROR HY000: Column 'c' has a generated column dependency.
34913491
ALTER TABLE t_gen RENAME COLUMN c TO a;
3492-
ERROR 42S22: Unknown column 'c' in 'generated column function'
3492+
ERROR HY000: Column 'c' has a generated column dependency.
34933493
DROP TABLE t_gen;
34943494
CREATE TABLE foo (col1 INT);
34953495
INSERT INTO foo VALUES (1), (2);

mysql-test/r/default_as_expr.result

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ ERROR HY000: DEFAULT function cannot be used with default value expressions
240240
SELECT DEFAULT(c) from t3;
241241
ERROR HY000: DEFAULT function cannot be used with default value expressions
242242
ALTER TABLE t3 DROP COLUMN d;
243-
ERROR HY000: Column 'd' of table 't3' has a default value expression dependency and cannot be dropped.
243+
ERROR HY000: Column 'd' of table 't3' has a default value expression dependency and cannot be dropped or renamed.
244244
DROP TABLE t3;
245245
#
246246
# Test UTF8
@@ -934,14 +934,12 @@ DROP TABLE t2;
934934
# BUG#28040739 - WL#9418: INCORRECT ERROR THROWN WITH RENAME COLUMN
935935
#
936936
CREATE TABLE t1 ( i INT, j INT DEFAULT( i * i) ) ;
937-
# "Unknown column 'i' in 'default value expression'"
938937
ALTER TABLE t1 RENAME COLUMN i to i1 ;
939-
ERROR 42S22: Unknown column 'i' in 'default value expression'
938+
ERROR HY000: Column 'i' of table 't1' has a default value expression dependency and cannot be dropped or renamed.
940939
DROP TABLE t1;
941940
CREATE TABLE t1 ( i INT, j INT DEFAULT (i * i) ) ;
942-
# "Unknown column 'i' in 'default value expression'"
943941
ALTER TABLE t1 CHANGE COLUMN i i1 DOUBLE DEFAULT ( 4 * 4 ) ;
944-
ERROR 42S22: Unknown column 'i' in 'default value expression'
942+
ERROR HY000: Column 'i' of table 't1' has a default value expression dependency and cannot be dropped or renamed.
945943
DROP TABLE t1;
946944
create table t1 (i int, j double DEFAULT (i * i) ) ;
947945
# "Unknown column 'z' in 'default value expression'"

mysql-test/r/functional_index.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,9 +684,9 @@ ERROR HY000: Cannot create a functional index on an expression that returns a BL
684684
# column that is a part of a functional index.
685685
CREATE TABLE t1 (col1 INT, col2 INT, col3 INT, INDEX idx ((col1 + col2 + col3)));
686686
ALTER TABLE t1 DROP COLUMN col2;
687-
ERROR HY000: Cannot drop column 'col2' because it is used by a functional index. In order to drop the column, you must remove the functional index.
687+
ERROR HY000: Column 'col2' has a functional index dependency and cannot be dropped or renamed.
688688
ALTER TABLE t1 DROP COLUMN col3;
689-
ERROR HY000: Cannot drop column 'col3' because it is used by a functional index. In order to drop the column, you must remove the functional index.
689+
ERROR HY000: Column 'col3' has a functional index dependency and cannot be dropped or renamed.
690690
ALTER TABLE t1 DROP INDEX idx;
691691
ALTER TABLE t1 DROP COLUMN col3;
692692
DROP TABLE t1;

mysql-test/suite/gcol/r/gcol_bugfixes.result

Lines changed: 488 additions & 0 deletions
Large diffs are not rendered by default.

mysql-test/suite/gcol/t/gcol_bugfixes.test

Lines changed: 438 additions & 0 deletions
Large diffs are not rendered by default.

mysql-test/t/alter_table.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2765,9 +2765,9 @@ SHOW CREATE TABLE t_gen;
27652765
ALTER TABLE t_gen RENAME COLUMN a TO c, CHANGE COLUMN b b DOUBLE GENERATED ALWAYS AS (SQRT(c));
27662766
SELECT * FROM t_gen;
27672767
SHOW CREATE TABLE t_gen;
2768-
--error ER_BAD_FIELD_ERROR
2768+
--error ER_DEPENDENT_BY_GENERATED_COLUMN
27692769
ALTER TABLE t_gen CHANGE COLUMN c a INT;
2770-
--error ER_BAD_FIELD_ERROR
2770+
--error ER_DEPENDENT_BY_GENERATED_COLUMN
27712771
ALTER TABLE t_gen RENAME COLUMN c TO a;
27722772
DROP TABLE t_gen;
27732773

mysql-test/t/default_as_expr.test

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -839,14 +839,12 @@ DROP TABLE t2;
839839
--echo # BUG#28040739 - WL#9418: INCORRECT ERROR THROWN WITH RENAME COLUMN
840840
--echo #
841841
CREATE TABLE t1 ( i INT, j INT DEFAULT( i * i) ) ;
842-
--echo # "Unknown column 'i' in 'default value expression'"
843-
--error 1054
842+
--error ER_DEPENDENT_BY_DEFAULT_GENERATED_VALUE
844843
ALTER TABLE t1 RENAME COLUMN i to i1 ;
845844
DROP TABLE t1;
846845

847846
CREATE TABLE t1 ( i INT, j INT DEFAULT (i * i) ) ;
848-
--echo # "Unknown column 'i' in 'default value expression'"
849-
--error 1054
847+
--error ER_DEPENDENT_BY_DEFAULT_GENERATED_VALUE
850848
ALTER TABLE t1 CHANGE COLUMN i i1 DOUBLE DEFAULT ( 4 * 4 ) ;
851849
DROP TABLE t1;
852850

@@ -898,4 +896,4 @@ CREATE TABLE t1 (a datetime, b varchar(10) DEFAULT (localtimestamp()));
898896
--error ER_DATA_TOO_LONG
899897
INSERT INTO t1(a) VALUES (now());
900898
SELECT * FROM t1;
901-
DROP TABLE t1;
899+
DROP TABLE t1;

mysql-test/t/functional_index.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,9 @@ CREATE TABLE t1 (
395395
--echo # See that we get a reasonable error message when trying to remove a
396396
--echo # column that is a part of a functional index.
397397
CREATE TABLE t1 (col1 INT, col2 INT, col3 INT, INDEX idx ((col1 + col2 + col3)));
398-
--error ER_CANNOT_DROP_COLUMN_FUNCTIONAL_INDEX
398+
--error ER_DEPENDENT_BY_FUNCTIONAL_INDEX
399399
ALTER TABLE t1 DROP COLUMN col2;
400-
--error ER_CANNOT_DROP_COLUMN_FUNCTIONAL_INDEX
400+
--error ER_DEPENDENT_BY_FUNCTIONAL_INDEX
401401
ALTER TABLE t1 DROP COLUMN col3;
402402
ALTER TABLE t1 DROP INDEX idx;
403403
ALTER TABLE t1 DROP COLUMN col3;

share/errmsg-utf8.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8629,7 +8629,7 @@ ER_GENERATED_COLUMN_VARIABLES
86298629
eng "Expression of generated column '%s' cannot refer user or system variables."
86308630

86318631
ER_DEPENDENT_BY_DEFAULT_GENERATED_VALUE
8632-
eng "Column '%s' of table '%s' has a default value expression dependency and cannot be dropped."
8632+
eng "Column '%s' of table '%s' has a default value expression dependency and cannot be dropped or renamed."
86338633

86348634
ER_DEFAULT_VAL_GENERATED_NON_PRIOR
86358635
eng "Default value expression of column '%s' cannot refer to a column defined after it if that column is a generated column or has an expression as default value."
@@ -8844,6 +8844,9 @@ ER_UNSUPPORTED_USE_OF_GRANT_AS
88448844
ER_UKNOWN_AUTH_ID_OR_ACCESS_DENIED_FOR_GRANT_AS
88458845
eng "Either some of the authorization IDs in the AS clause are invalid or the current user lacks privileges to execute the statement."
88468846

8847+
ER_DEPENDENT_BY_FUNCTIONAL_INDEX
8848+
eng "Column '%s' has a functional index dependency and cannot be dropped or renamed."
8849+
88478850
#
88488851
# End of 8.0 error messages.
88498852
#

sql/handler.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2958,6 +2958,12 @@ class Alter_inplace_info {
29582958
KEY_PAIR *index_rename_buffer;
29592959
KEY_PAIR *index_altered_visibility_buffer;
29602960

2961+
/** Number of virtual columns to be added. */
2962+
uint virtual_column_add_count;
2963+
2964+
/** number of virtual columns to be dropped. */
2965+
uint virtual_column_drop_count;
2966+
29612967
/**
29622968
Context information to allow handlers to keep context between in-place
29632969
alter API calls.
@@ -3033,6 +3039,8 @@ class Alter_inplace_info {
30333039
index_rename_count(0),
30343040
index_altered_visibility_count(0),
30353041
index_rename_buffer(NULL),
3042+
virtual_column_add_count(0),
3043+
virtual_column_drop_count(0),
30363044
handler_ctx(NULL),
30373045
group_commit_ctx(NULL),
30383046
handler_flags(0),

sql/sql_alter.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,7 @@ class Alter_info {
365365
};
366366

367367
/**
368-
Columns and keys to be dropped.
369-
After mysql_prepare_alter_table() it contains only foreign keys and
370-
virtual generated columns to be dropped. This information is necessary
371-
for the storage engine to do in-place alter.
368+
Columns, keys and constraints to be dropped.
372369
*/
373370
Mem_root_array<const Alter_drop *> drop_list;
374371
// Columns for ALTER_COLUMN_CHANGE_DEFAULT.

0 commit comments

Comments
 (0)