MDEV-35962 CREATE INDEX fails to heal a FOREIGN KEY constraint

commit_cache_norebuild(): Replace any newly added indexes in
the attached foreign key constraints.
This commit is contained in:
Marko Mäkelä 2025-01-29 09:04:50 +02:00
parent 831f5bc66f
commit 3cfffb4de6
3 changed files with 85 additions and 6 deletions

View File

@ -164,9 +164,6 @@ DELETE FROM parent;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`a`) REFERENCES `parent` (`a`) ON DELETE CASCADE)
ALTER TABLE child ADD INDEX(a);
DELETE FROM parent;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`a`) REFERENCES `parent` (`a`) ON DELETE CASCADE)
ALTER TABLE child FORCE;
DELETE FROM parent;
DROP TABLE child,parent;
SELECT unique_constraint_name FROM information_schema.referential_constraints
WHERE table_name = 't2';
@ -1142,5 +1139,31 @@ DELETE FROM t2;
DELETE FROM t1;
DROP DATABASE `#mysql50##mysql50#d-b`;
USE test;
#
# MDEV-35962 CREATE INDEX fails to heal a FOREIGN KEY constraint
#
CREATE TABLE t2 (b INT, FOREIGN KEY (b) REFERENCES t1(a)) ENGINE=InnoDB;
ERROR HY000: Can't create table `test`.`t2` (errno: 150 "Foreign key constraint is incorrectly formed")
SET STATEMENT foreign_key_checks=0 FOR
CREATE TABLE t2 (b INT, FOREIGN KEY (b) REFERENCES t1(a)) ENGINE=InnoDB;
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
ERROR HY000: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed")
SET STATEMENT foreign_key_checks=0 FOR
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1);
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`a`))
ALTER TABLE t1 ADD KEY(a), ALGORITHM=NOCOPY;
INSERT INTO t2 VALUES (1);
DROP INDEX b ON t2;
ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
SET STATEMENT foreign_key_checks=0 FOR
DROP INDEX b ON t2;
DELETE FROM t2;
DELETE FROM t1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`a`))
ALTER TABLE t2 ADD KEY(b), ALGORITHM=NOCOPY;
DELETE FROM t1;
DROP TABLE t2, t1;
# End of 10.6 tests
SET GLOBAL innodb_stats_persistent = @save_stats_persistent;

View File

@ -142,9 +142,6 @@ INSERT INTO child SET a=1;
--error ER_ROW_IS_REFERENCED_2
DELETE FROM parent;
ALTER TABLE child ADD INDEX(a);
--error ER_ROW_IS_REFERENCED_2
DELETE FROM parent;
ALTER TABLE child FORCE;
DELETE FROM parent;
DROP TABLE child,parent;
@ -1205,6 +1202,34 @@ DELETE FROM t1;
DROP DATABASE `#mysql50##mysql50#d-b`;
USE test;
--echo #
--echo # MDEV-35962 CREATE INDEX fails to heal a FOREIGN KEY constraint
--echo #
--error ER_CANT_CREATE_TABLE
CREATE TABLE t2 (b INT, FOREIGN KEY (b) REFERENCES t1(a)) ENGINE=InnoDB;
SET STATEMENT foreign_key_checks=0 FOR
CREATE TABLE t2 (b INT, FOREIGN KEY (b) REFERENCES t1(a)) ENGINE=InnoDB;
--error ER_CANT_CREATE_TABLE
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
SET STATEMENT foreign_key_checks=0 FOR
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
--error ER_NO_REFERENCED_ROW_2
INSERT INTO t2 VALUES (1);
ALTER TABLE t1 ADD KEY(a), ALGORITHM=NOCOPY;
INSERT INTO t2 VALUES (1);
--error ER_DROP_INDEX_FK
DROP INDEX b ON t2;
SET STATEMENT foreign_key_checks=0 FOR
DROP INDEX b ON t2;
DELETE FROM t2;
--error ER_ROW_IS_REFERENCED_2
DELETE FROM t1;
ALTER TABLE t2 ADD KEY(b), ALGORITHM=NOCOPY;
DELETE FROM t1;
DROP TABLE t2, t1;
--echo # End of 10.6 tests
SET GLOBAL innodb_stats_persistent = @save_stats_persistent;

View File

@ -11036,6 +11036,37 @@ commit_cache_norebuild(
dict_index_remove_from_cache(index->table, index);
}
if (ctx->num_to_add_index) {
for (dict_foreign_t* foreign: ctx->new_table->foreign_set) {
if (foreign->foreign_table == ctx->new_table
&& !foreign->foreign_index) {
foreign->foreign_index =
dict_foreign_find_index(
foreign->foreign_table,
nullptr,
foreign->foreign_col_names,
foreign->n_fields, nullptr,
/*check_charsets=*/TRUE,
/*check_null=*/FALSE,
nullptr, nullptr, nullptr);
}
}
for (dict_foreign_t* foreign: ctx->new_table->referenced_set) {
if (foreign->referenced_table == ctx->new_table
&& !foreign->referenced_index) {
foreign->referenced_index =
dict_foreign_find_index(
foreign->referenced_table,
nullptr,
foreign->referenced_col_names,
foreign->n_fields, nullptr,
/*check_charsets=*/TRUE,
/*check_null=*/FALSE,
nullptr, nullptr, nullptr);
}
}
}
fts_clear_all(ctx->old_table);
if (!ctx->is_instant()) {