From 4a1c66290dc81244f0f68c24666382fb2dae8f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 1 Mar 2019 10:16:56 +0200 Subject: [PATCH] MDEV-18775 Fix ALTER TABLE error handling for DROP INDEX On an error (such as when an index cannot be dropped due to FOREIGN KEY constraints), the field dict_index_t::to_be_dropped was only being cleared in debug builds, even though the field is available and being used also in non-debug builds. This was a regression that was introduced by myself originally in MySQL 5.7.6 and later merged to MariaDB 10.2.2, in https://github.com/mysql/mysql-server/commit/d39898de8e0de21f64ce94cd4ea698675edfb447 An error manifested itself in the MariaDB Server 10.4 non-debug build, involving instant ADD or DROP column. Because an earlier failed ALTER TABLE operation incorrectly left the dict_index_t::to_be_dropped flag set, the column pointers of the index fields would fail to be adjusted for instant ADD or DROP column (MDEV-15562). The instant ADD COLUMN in MariaDB Server 10.3 is unlikely to be affected by a similar scenario, because dict_table_t::instant_add_column() in 10.3 is applying the transformations to all indexes, not skipping to-be-dropped ones. --- mysql-test/suite/innodb/r/alter_table.result | 15 ++++++++++++++ mysql-test/suite/innodb/t/alter_table.test | 21 ++++++++++++++++++++ storage/innobase/handler/handler0alter.cc | 2 -- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/r/alter_table.result b/mysql-test/suite/innodb/r/alter_table.result index 2fb09e2fe5c..e47bfb90152 100644 --- a/mysql-test/suite/innodb/r/alter_table.result +++ b/mysql-test/suite/innodb/r/alter_table.result @@ -38,3 +38,18 @@ Warnings: Warning 1105 ORDER BY ignored as there is a user-defined clustered index in the table 't1' DROP TABLE t1; SET sql_mode=DEFAULT; +# +# MDEV-18775 Server crashes in dict_table_t::instant_column +# upon ADD COLUMN +# +CREATE TABLE tx (pk INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t1 (pk INT, a INT, PRIMARY KEY (pk), KEY (a), FOREIGN KEY (a) REFERENCES tx (pk)) ENGINE=InnoDB; +SET FOREIGN_KEY_CHECKS=OFF; +ALTER TABLE t1 DROP a; +ERROR HY000: Cannot drop column 'a': needed in a foreign key constraint 'test/t1_ibfk_1' +SET FOREIGN_KEY_CHECKS=ON; +ALTER TABLE t1 ADD b INT; +ALTER TABLE t1 DROP a; +ERROR HY000: Cannot drop index 'a': needed in a foreign key constraint +ALTER TABLE t1 ADD c INT; +DROP TABLE t1, tx; diff --git a/mysql-test/suite/innodb/t/alter_table.test b/mysql-test/suite/innodb/t/alter_table.test index ece24eb45c7..d0943e7d407 100644 --- a/mysql-test/suite/innodb/t/alter_table.test +++ b/mysql-test/suite/innodb/t/alter_table.test @@ -38,3 +38,24 @@ ALTER TABLE t1 ORDER BY a; DROP TABLE t1; SET sql_mode=DEFAULT; + +--echo # +--echo # MDEV-18775 Server crashes in dict_table_t::instant_column +--echo # upon ADD COLUMN +--echo # + +CREATE TABLE tx (pk INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t1 (pk INT, a INT, PRIMARY KEY (pk), KEY (a), FOREIGN KEY (a) REFERENCES tx (pk)) ENGINE=InnoDB; + +SET FOREIGN_KEY_CHECKS=OFF; + +--error ER_FK_COLUMN_CANNOT_DROP +ALTER TABLE t1 DROP a; + +SET FOREIGN_KEY_CHECKS=ON; + +ALTER TABLE t1 ADD b INT; +--error ER_DROP_INDEX_FK +ALTER TABLE t1 DROP a; +ALTER TABLE t1 ADD c INT; +DROP TABLE t1, tx; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 47cc31ce9dc..c04c69ba8e2 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -5142,14 +5142,12 @@ error_handled: ut_ad(!user_table->drop_aborted); err_exit: -#ifdef UNIV_DEBUG /* Clear the to_be_dropped flag in the data dictionary cache. */ for (ulint i = 0; i < ctx->num_to_drop_index; i++) { DBUG_ASSERT(ctx->drop_index[i]->is_committed()); DBUG_ASSERT(ctx->drop_index[i]->to_be_dropped); ctx->drop_index[i]->to_be_dropped = 0; } -#endif /* UNIV_DEBUG */ row_mysql_unlock_data_dictionary(ctx->trx);