From 0e4b61369f1a787bd24bdb0250aa5062a028ff11 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 9 Jul 2019 17:03:02 +0530 Subject: MDEV-19630 ALTER TABLE ... ADD COLUMN damages foreign keys which are pointed to the table being altered Problem: ======== InnoDB failed to change the column name present in foreign key cache for instant add column. So it leads to column mismatch for the consecutive rename of column. Solution: ========= Evict the foreign key information from cache and load the foreign key information again for instant operation. --- .../suite/innodb/r/instant_alter_bugs.result | 26 ++++++++++++++++++++++ mysql-test/suite/innodb/t/instant_alter_bugs.test | 18 +++++++++++++++ storage/innobase/handler/handler0alter.cc | 12 ++++++---- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result index 14d88c64de8..080395b0120 100644 --- a/mysql-test/suite/innodb/r/instant_alter_bugs.result +++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result @@ -128,3 +128,29 @@ HANDLER h READ `PRIMARY` PREV WHERE 0; pk f1 f2 f3 f4 f5 f6 f7 f8 filler HANDLER h CLOSE; DROP TABLE t1; +CREATE TABLE t1(f1 int not null, primary key(f1))engine=innodb; +CREATE TABLE t2(f1 INT AUTO_INCREMENT NOT NULL, f2 INT NOT NULL, +status ENUM ('a', 'b', 'c'), INDEX idx1(f2), +PRIMARY KEY(f1), +FOREIGN KEY (f2) REFERENCES t1(f1))ENGINE=InnoDB; +ALTER TABLE t1 CHANGE f1 f1_id INT NOT NULL, ADD f3 VARCHAR(255) DEFAULT NULL; +ALTER TABLE t1 CHANGE f1_id f1 INT NOT NULL; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f3` varchar(255) DEFAULT NULL, + PRIMARY KEY (`f1`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `f1` int(11) NOT NULL AUTO_INCREMENT, + `f2` int(11) NOT NULL, + `status` enum('a','b','c') DEFAULT NULL, + PRIMARY KEY (`f1`), + KEY `idx1` (`f2`), + CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f2`) REFERENCES `t1` (`f1`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +ALTER TABLE t2 CHANGE status status VARCHAR(20) DEFAULT NULL; +DROP TABLE t2, t1; diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index 9cc0037703b..bab102ebd7f 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -134,5 +134,23 @@ HANDLER h READ `PRIMARY` PREV WHERE 0; # Cleanup HANDLER h CLOSE; DROP TABLE t1; + +# MDEV-19630 ALTER TABLE ... ADD COLUMN damages foreign keys which are pointed +# to the table being altered +CREATE TABLE t1(f1 int not null, primary key(f1))engine=innodb; +CREATE TABLE t2(f1 INT AUTO_INCREMENT NOT NULL, f2 INT NOT NULL, + status ENUM ('a', 'b', 'c'), INDEX idx1(f2), + PRIMARY KEY(f1), + FOREIGN KEY (f2) REFERENCES t1(f1))ENGINE=InnoDB; + +ALTER TABLE t1 CHANGE f1 f1_id INT NOT NULL, ADD f3 VARCHAR(255) DEFAULT NULL; +ALTER TABLE t1 CHANGE f1_id f1 INT NOT NULL; + +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; + +ALTER TABLE t2 CHANGE status status VARCHAR(20) DEFAULT NULL; +DROP TABLE t2, t1; + --let $datadir= `select @@datadir` --remove_file $datadir/test/load.data diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 571ec821999..bde0166db94 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -7448,7 +7448,8 @@ innobase_drop_foreign_try( @param[in] from old column name @param[in] to new column name @param[in] new_clustered whether the table has been rebuilt -@param[in] is_virtual whether it is a virtual column +@param[in] instant_table In case of instant table, reload the + foreign key information again. @retval true Failure @retval false Success */ static MY_ATTRIBUTE((nonnull, warn_unused_result)) @@ -7460,7 +7461,8 @@ innobase_rename_column_try( ulint nth_col, const char* from, const char* to, - bool new_clustered) + bool new_clustered, + bool instant_table) { pars_info_t* info; dberr_t error; @@ -7644,7 +7646,8 @@ rename_foreign: } } - if (new_clustered) { + /* Reload the foreign key info for instant table too. */ + if (new_clustered || instant_table) { std::for_each(fk_evict.begin(), fk_evict.end(), dict_foreign_remove_from_cache); } @@ -7699,7 +7702,8 @@ innobase_rename_columns_try( col_n, cf->field->field_name.str, cf->field_name.str, - ctx->need_rebuild())) { + ctx->need_rebuild(), + ctx->is_instant())) { return(true); } goto processed_field; -- cgit v1.2.1