Skip to content

Commit f97dfa8

Browse files
committed
Bug #19471516 SERVER CRASHES WHEN EXECUTING ALTER TABLE ADD FOREIGN KEY
Problem: We maintain two rb trees in each dict_table_t. The foreign_rbt must be in sync with foreign_list. The referenced_rbt must be in sync with referenced_list. There is one function which checks this consistency and it failed, resulting in an assert failure. The root cause of the problem was identified that the search order was lost in the referenced_rbt. This is because while renaming the table, we didn't not refresh this referenced_rbt. Solution: When a foreign key is renamed, we must delete and re-insert into both foreign_rbt and referenced_rbt. rb#6412 approved by Jimmy.
1 parent 97beafc commit f97dfa8

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#
2+
# Bug #19471516 SERVER CRASHES WHEN EXECUTING ALTER TABLE
3+
# ADD FOREIGN KEY
4+
#
5+
CREATE TABLE `department` (`department_id` INT, `department_people_fk` INT,
6+
PRIMARY KEY (`department_id`)) engine=innodb;
7+
CREATE TABLE `title` (`title_id` INT, `title_manager_fk` INT,
8+
`title_reporter_fk` INT, PRIMARY KEY (`title_id`));
9+
CREATE TABLE `people` (`people_id` INT, PRIMARY KEY (`people_id`));
10+
ALTER TABLE `department` ADD FOREIGN KEY (`department_people_fk`) REFERENCES
11+
`people` (`people_id`);
12+
ALTER TABLE `title` ADD FOREIGN KEY (`title_manager_fk`) REFERENCES `people`
13+
(`people_id`);
14+
ALTER TABLE `title` ADD FOREIGN KEY (`title_reporter_fk`) REFERENCES `people`
15+
(`people_id`);
16+
drop table title, department, people;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--source include/have_innodb.inc
2+
--source include/have_debug.inc
3+
4+
--echo #
5+
--echo # Bug #19471516 SERVER CRASHES WHEN EXECUTING ALTER TABLE
6+
--echo # ADD FOREIGN KEY
7+
--echo #
8+
9+
CREATE TABLE `department` (`department_id` INT, `department_people_fk` INT,
10+
PRIMARY KEY (`department_id`)) engine=innodb;
11+
12+
CREATE TABLE `title` (`title_id` INT, `title_manager_fk` INT,
13+
`title_reporter_fk` INT, PRIMARY KEY (`title_id`));
14+
15+
CREATE TABLE `people` (`people_id` INT, PRIMARY KEY (`people_id`));
16+
17+
ALTER TABLE `department` ADD FOREIGN KEY (`department_people_fk`) REFERENCES
18+
`people` (`people_id`);
19+
20+
ALTER TABLE `title` ADD FOREIGN KEY (`title_manager_fk`) REFERENCES `people`
21+
(`people_id`);
22+
23+
ALTER TABLE `title` ADD FOREIGN KEY (`title_reporter_fk`) REFERENCES `people`
24+
(`people_id`);
25+
26+
drop table title, department, people;

storage/innobase/dict/dict0dict.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,11 @@ dict_table_rename_in_cache(
11231123
/* The id will be changed. So remove old one */
11241124
rbt_delete(foreign->foreign_table->foreign_rbt, foreign->id);
11251125

1126+
if (foreign->referenced_table) {
1127+
rbt_delete(foreign->referenced_table->referenced_rbt,
1128+
foreign->id);
1129+
}
1130+
11261131
if (ut_strlen(foreign->foreign_table_name)
11271132
< ut_strlen(table->name)) {
11281133
/* Allocate a longer name buffer;
@@ -1273,6 +1278,11 @@ dict_table_rename_in_cache(
12731278
rbt_insert(foreign->foreign_table->foreign_rbt,
12741279
foreign->id, &foreign);
12751280

1281+
if (foreign->referenced_table) {
1282+
rbt_insert(foreign->referenced_table->referenced_rbt,
1283+
foreign->id, &foreign);
1284+
}
1285+
12761286
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
12771287
}
12781288

0 commit comments

Comments
 (0)