Skip to content

Commit

Permalink
Bug #17449901 TABLE DISAPPEARS WHEN ALTERING WITH
Browse files Browse the repository at this point in the history
			FOREIGN KEY CHECKS OFF

Analysis:
By removing the FK index with out removing the foreign key constraint,
we are moving the table into inconsistent state. FK index lookup happens
during load table process. So it fails to open the table when FK index
is missing.

Fix:
Don't allow to drop an index if it is needed for an FK constraint,
even if foreign_key_checks is disabled.

		Approved by Jimmy (rb-5274)
  • Loading branch information
Thirunarayanan committed May 5, 2014
1 parent 94af2a1 commit c1ed0ea
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 36 deletions.
8 changes: 4 additions & 4 deletions mysql-test/suite/innodb/r/innodb-alter.result
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,6 @@ ALTER TABLE t1c DROP INDEX C2, DROP INDEX C3;
ERROR HY000: Cannot drop index 'c2': needed in a foreign key constraint
ALTER TABLE t1c DROP INDEX C3;
ERROR HY000: Cannot drop index 'c3': needed in a foreign key constraint
SET foreign_key_checks=0;
ALTER TABLE t1c DROP INDEX C3;
SET foreign_key_checks=1;
SHOW CREATE TABLE t1c;
Table Create Table
t1c CREATE TABLE `t1c` (
Expand All @@ -325,6 +322,7 @@ t1c CREATE TABLE `t1c` (
`c3` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`),
KEY `c2` (`c2`),
KEY `c3` (`c3`),
CONSTRAINT `t1c2` FOREIGN KEY (`c2`) REFERENCES `t1` (`c3`),
CONSTRAINT `t1c3` FOREIGN KEY (`c3`) REFERENCES `t1p` (`c2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Expand Down Expand Up @@ -354,6 +352,7 @@ t1c CREATE TABLE `t1c` (
`c3` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`),
KEY `c2` (`c2`),
KEY `c3` (`c3`),
CONSTRAINT `t1c2` FOREIGN KEY (`c2`) REFERENCES `t1` (`c3`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SELECT i.NAME,i.POS,i.MTYPE,i.PRTYPE,i.LEN
Expand All @@ -379,7 +378,8 @@ t1c CREATE TABLE `t1c` (
`c1` int(11) NOT NULL,
`c2` int(11) DEFAULT NULL,
`c3` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`)
PRIMARY KEY (`c1`),
KEY `c3` (`c3`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SELECT i.NAME,i.POS,i.MTYPE,i.PRTYPE,i.LEN
FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS i
Expand Down
39 changes: 39 additions & 0 deletions mysql-test/suite/innodb/r/innodb-index-online-fk.result
Original file line number Diff line number Diff line change
Expand Up @@ -615,3 +615,42 @@ test/e d a 0
test/fw c a 0
DROP TABLE t2;
DROP TABLE t3;
# Bug #17449901 TABLE DISAPPEARS WHEN ALTERING
# WITH FOREIGN KEY CHECKS OFF
create table t1(f1 int,primary key(f1))engine=innodb;
create table t2(f2 int,f3 int,key t(f2,f3),foreign key(f2) references t1(f1))engine=innodb;
SET foreign_key_checks=0;
drop index t on t2;
ERROR HY000: Cannot drop index 't': needed in a foreign key constraint
drop table t2;
drop table t1;
create table t1(f1 int ,primary key(f1))engine=innodb;
create table t2(f2 int,f3 int, key t(f2),foreign key(f2) references t1(f1))engine=innodb;
SET foreign_key_checks = 0;
alter table t2 drop key t,algorithm=inplace;
ERROR HY000: Cannot drop index 't': needed in a foreign key constraint
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`f2` int(11) DEFAULT NULL,
`f3` int(11) DEFAULT NULL,
KEY `t` (`f2`),
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f2`) REFERENCES `t1` (`f1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t2;
drop table t1;
create table t1(f1 int ,primary key(f1))engine=innodb;
create table t2(f2 int,f3 int, key t(f2),key t1(f2,f3),
foreign key(f2) references t1(f1))engine=innodb;
SET foreign_key_checks = 0;
alter table t2 drop key t,algorithm=inplace;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`f2` int(11) DEFAULT NULL,
`f3` int(11) DEFAULT NULL,
KEY `t1` (`f2`,`f3`),
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f2`) REFERENCES `t1` (`f1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t2;
drop table t1;
4 changes: 2 additions & 2 deletions mysql-test/suite/innodb/r/innodb-index.result
Original file line number Diff line number Diff line change
Expand Up @@ -497,11 +497,11 @@ SET FOREIGN_KEY_CHECKS=0;
alter table t2 DROP COLUMN b, ALGORITHM=COPY;
ERROR HY000: Cannot drop column 'b': needed in a foreign key constraint 't2_ibfk_1'
alter table t2 DROP COLUMN b;
ERROR HY000: Cannot drop column 'b': needed in a foreign key constraint 'test/t2_ibfk_1'
ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
alter table t1 DROP COLUMN b, ALGORITHM=COPY;
ERROR HY000: Cannot drop column 'b': needed in a foreign key constraint 't2_ibfk_1' of table 'test.t2'
alter table t1 DROP COLUMN b;
ERROR HY000: Cannot drop column 'b': needed in a foreign key constraint 'test/t2_ibfk_1' of table '"test"."t2"'
ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
create unique index dc on t2 (d,c);
affected rows: 0
Expand Down
6 changes: 5 additions & 1 deletion mysql-test/suite/innodb/r/innodb-wl5980-alter.result
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ ALTER TABLE t1c DROP INDEX C3;
ERROR HY000: Cannot drop index 'c3': needed in a foreign key constraint
SET foreign_key_checks=0;
ALTER TABLE t1c DROP INDEX C3;
ERROR HY000: Cannot drop index 'c3': needed in a foreign key constraint
### files in MYSQL_DATA_DIR/test
sys_foreign.frm
sys_foreign.ibd
Expand All @@ -539,6 +540,7 @@ t1c CREATE TABLE `t1c` (
`c3` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`),
KEY `c2` (`c2`),
KEY `c3` (`c3`),
CONSTRAINT `t1c2` FOREIGN KEY (`c2`) REFERENCES `t1` (`c3`),
CONSTRAINT `t1c3` FOREIGN KEY (`c3`) REFERENCES `t1p` (`c2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir/'
Expand Down Expand Up @@ -585,6 +587,7 @@ t1c CREATE TABLE `t1c` (
`c3` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`),
KEY `c2` (`c2`),
KEY `c3` (`c3`),
CONSTRAINT `t1c2` FOREIGN KEY (`c2`) REFERENCES `t1` (`c3`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir/'
SELECT i.NAME,i.POS,i.MTYPE,i.PRTYPE,i.LEN
Expand Down Expand Up @@ -627,7 +630,8 @@ t1c CREATE TABLE `t1c` (
`c1` int(11) NOT NULL,
`c2` int(11) DEFAULT NULL,
`c3` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`)
PRIMARY KEY (`c1`),
KEY `c3` (`c3`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir/'
SELECT i.NAME,i.POS,i.MTYPE,i.PRTYPE,i.LEN
FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS i
Expand Down
4 changes: 0 additions & 4 deletions mysql-test/suite/innodb/t/innodb-alter.test
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,6 @@ ALTER TABLE t1c DROP INDEX C2, DROP INDEX C3;
--error ER_DROP_INDEX_FK
ALTER TABLE t1c DROP INDEX C3;

SET foreign_key_checks=0;
ALTER TABLE t1c DROP INDEX C3;
SET foreign_key_checks=1;

SHOW CREATE TABLE t1c;
-- source suite/innodb/include/innodb_dict.inc

Expand Down
31 changes: 31 additions & 0 deletions mysql-test/suite/innodb/t/innodb-index-online-fk.test
Original file line number Diff line number Diff line change
Expand Up @@ -484,3 +484,34 @@ SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
DROP TABLE t2;

DROP TABLE t3;

--echo # Bug #17449901 TABLE DISAPPEARS WHEN ALTERING
--echo # WITH FOREIGN KEY CHECKS OFF

# Drop index via inplace algorithm
create table t1(f1 int,primary key(f1))engine=innodb;
create table t2(f2 int,f3 int,key t(f2,f3),foreign key(f2) references t1(f1))engine=innodb;
SET foreign_key_checks=0;
--error ER_DROP_INDEX_FK
drop index t on t2;
drop table t2;
drop table t1;

# Drop index using alter statement via inplace
create table t1(f1 int ,primary key(f1))engine=innodb;
create table t2(f2 int,f3 int, key t(f2),foreign key(f2) references t1(f1))engine=innodb;
SET foreign_key_checks = 0;
--error ER_DROP_INDEX_FK
alter table t2 drop key t,algorithm=inplace;
show create table t2;
drop table t2;
drop table t1;

create table t1(f1 int ,primary key(f1))engine=innodb;
create table t2(f2 int,f3 int, key t(f2),key t1(f2,f3),
foreign key(f2) references t1(f1))engine=innodb;
SET foreign_key_checks = 0;
alter table t2 drop key t,algorithm=inplace;
show create table t2;
drop table t2;
drop table t1;
4 changes: 2 additions & 2 deletions mysql-test/suite/innodb/t/innodb-index.test
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,11 @@ set @@sql_mode = @old_sql_mode;
SET FOREIGN_KEY_CHECKS=0;
--error ER_FK_COLUMN_CANNOT_DROP
alter table t2 DROP COLUMN b, ALGORITHM=COPY;
--error ER_FK_COLUMN_CANNOT_DROP
--error ER_DROP_INDEX_FK
alter table t2 DROP COLUMN b;
--error ER_FK_COLUMN_CANNOT_DROP_CHILD
alter table t1 DROP COLUMN b, ALGORITHM=COPY;
--error ER_FK_COLUMN_CANNOT_DROP_CHILD
--error ER_DROP_INDEX_FK
alter table t1 DROP COLUMN b;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;

Expand Down
1 change: 1 addition & 0 deletions mysql-test/suite/innodb/t/innodb-wl5980-alter.test
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ ALTER TABLE t1c DROP INDEX C2, DROP INDEX C3;
ALTER TABLE t1c DROP INDEX C3;

SET foreign_key_checks=0;
--error ER_DROP_INDEX_FK
ALTER TABLE t1c DROP INDEX C3;

--echo ### files in MYSQL_DATA_DIR/test
Expand Down
44 changes: 21 additions & 23 deletions storage/innobase/handler/handler0alter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3911,36 +3911,34 @@ ha_innobase::prepare_inplace_alter_table(
}
}

if (prebuilt->trx->check_foreigns) {
for (uint i = 0; i < n_drop_index; i++) {
dict_index_t* index = drop_index[i];

if (innobase_check_foreign_key_index(
ha_alter_info, index,
indexed_table, col_names,
prebuilt->trx, drop_fk, n_drop_fk)) {
row_mysql_unlock_data_dictionary(
prebuilt->trx);
prebuilt->trx->error_info = index;
print_error(HA_ERR_DROP_INDEX_FK,
MYF(0));
goto err_exit;
}
}
for (uint i = 0; i < n_drop_index; i++) {
dict_index_t* index = drop_index[i];

/* If a primary index is dropped, need to check
any depending foreign constraints get affected */
if (drop_primary
&& innobase_check_foreign_key_index(
ha_alter_info, drop_primary,
if (innobase_check_foreign_key_index(
ha_alter_info, index,
indexed_table, col_names,
prebuilt->trx, drop_fk, n_drop_fk)) {
row_mysql_unlock_data_dictionary(prebuilt->trx);
print_error(HA_ERR_DROP_INDEX_FK, MYF(0));
row_mysql_unlock_data_dictionary(
prebuilt->trx);
prebuilt->trx->error_info = index;
print_error(HA_ERR_DROP_INDEX_FK,
MYF(0));
goto err_exit;
}
}

/* If a primary index is dropped, need to check
any depending foreign constraints get affected */
if (drop_primary
&& innobase_check_foreign_key_index(
ha_alter_info, drop_primary,
indexed_table, col_names,
prebuilt->trx, drop_fk, n_drop_fk)) {
row_mysql_unlock_data_dictionary(prebuilt->trx);
print_error(HA_ERR_DROP_INDEX_FK, MYF(0));
goto err_exit;
}

row_mysql_unlock_data_dictionary(prebuilt->trx);
} else {
drop_index = NULL;
Expand Down

0 comments on commit c1ed0ea

Please sign in to comment.