diff --git a/mysql-test/suite/rds/r/bugfix_fk_error_bug77467.result b/mysql-test/suite/rds/r/bugfix_fk_error_bug77467.result new file mode 100644 index 0000000000000000000000000000000000000000..b7fee8b1ad514c19d9db74fca864f93be2d93b76 --- /dev/null +++ b/mysql-test/suite/rds/r/bugfix_fk_error_bug77467.result @@ -0,0 +1,69 @@ +include/master-slave.inc +[connection master] +CREATE TABLE user ( +id int(11) NOT NULL AUTO_INCREMENT, +name varchar(100) NOT NULL, +PRIMARY KEY (Id) +) ENGINE=InnoDB; +CREATE TABLE blog ( +id int(11) NOT NULL AUTO_INCREMENT, +title varchar(1024) NOT NULL, +content text NOT NULL, +PRIMARY KEY (Id) +) ENGINE=InnoDB; +CREATE TABLE reply ( +id int(11) NOT NULL AUTO_INCREMENT, +contents text NOT NULL, +userId int(11) NOT NULL, +blogId int(11) NOT NULL, +PRIMARY KEY (Id), +KEY userId (userId), +KEY blogId (blogId), +CONSTRAINT reply_ibfk_1 FOREIGN KEY (userId) +REFERENCES user (Id), +CONSTRAINT reply_ibfk_2 FOREIGN KEY (blogId) +REFERENCES blog (Id) +) ENGINE=InnoDB; +Alter table reply +change blogId topicId int(11) NOT NULL, +drop index userId, +drop foreign key reply_ibfk_2; +ERROR HY000: Error on rename of '#sql-temporary' to './test/reply' (errno: 150) +Alter table reply +drop foreign key key_no_exist; +ERROR HY000: Error on rename of './test/reply' to '#sql-temporary' (errno: 152) +#------------master +SHOW CREATE TABLE reply; +Table Create Table +reply CREATE TABLE `reply` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `contents` text NOT NULL, + `userId` int(11) NOT NULL, + `blogId` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `userId` (`userId`), + KEY `blogId` (`blogId`), + CONSTRAINT `reply_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`), + CONSTRAINT `reply_ibfk_2` FOREIGN KEY (`blogId`) REFERENCES `blog` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +#------------slave +SHOW CREATE TABLE reply; +Table Create Table +reply CREATE TABLE `reply` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `contents` text NOT NULL, + `userId` int(11) NOT NULL, + `blogId` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `userId` (`userId`), + KEY `blogId` (`blogId`), + CONSTRAINT `reply_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`), + CONSTRAINT `reply_ibfk_2` FOREIGN KEY (`blogId`) REFERENCES `blog` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +insert into user values (1, 'fungo'); +insert into reply values(1, 'bla bla bla', 1, 1); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`reply`, CONSTRAINT `reply_ibfk_2` FOREIGN KEY (`blogId`) REFERENCES `blog` (`id`)) +drop table reply; +drop table user; +drop table blog; +include/rpl_end.inc diff --git a/mysql-test/suite/rds/t/bugfix_fk_error_bug77467-master.opt b/mysql-test/suite/rds/t/bugfix_fk_error_bug77467-master.opt new file mode 100644 index 0000000000000000000000000000000000000000..a4375cfbf773c91120c50cef4c6d7b29d7b0254d --- /dev/null +++ b/mysql-test/suite/rds/t/bugfix_fk_error_bug77467-master.opt @@ -0,0 +1 @@ +--log-bin --binlog_format=ROW diff --git a/mysql-test/suite/rds/t/bugfix_fk_error_bug77467-slave.opt b/mysql-test/suite/rds/t/bugfix_fk_error_bug77467-slave.opt new file mode 100644 index 0000000000000000000000000000000000000000..a4375cfbf773c91120c50cef4c6d7b29d7b0254d --- /dev/null +++ b/mysql-test/suite/rds/t/bugfix_fk_error_bug77467-slave.opt @@ -0,0 +1 @@ +--log-bin --binlog_format=ROW diff --git a/mysql-test/suite/rds/t/bugfix_fk_error_bug77467.test b/mysql-test/suite/rds/t/bugfix_fk_error_bug77467.test new file mode 100644 index 0000000000000000000000000000000000000000..c12ffdfe049268234fe6857371aa0e7282b7ad9c --- /dev/null +++ b/mysql-test/suite/rds/t/bugfix_fk_error_bug77467.test @@ -0,0 +1,76 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +let $MYSQLD_DATADIR= `select @@datadir`; +# create three tables +CREATE TABLE user ( + id int(11) NOT NULL AUTO_INCREMENT, + name varchar(100) NOT NULL, + PRIMARY KEY (Id) +) ENGINE=InnoDB; + +CREATE TABLE blog ( + id int(11) NOT NULL AUTO_INCREMENT, + title varchar(1024) NOT NULL, + content text NOT NULL, + PRIMARY KEY (Id) +) ENGINE=InnoDB; + +CREATE TABLE reply ( + id int(11) NOT NULL AUTO_INCREMENT, + contents text NOT NULL, + userId int(11) NOT NULL, + blogId int(11) NOT NULL, + PRIMARY KEY (Id), + KEY userId (userId), + KEY blogId (blogId), + CONSTRAINT reply_ibfk_1 FOREIGN KEY (userId) + REFERENCES user (Id), + CONSTRAINT reply_ibfk_2 FOREIGN KEY (blogId) + REFERENCES blog (Id) +) ENGINE=InnoDB; + +# alter reply table, try to drop index. +# The evil begins... +# mysqltest first does replace_regex, then replace_result +--replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ +# Embedded server doesn't chdir to data directory +--replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ '' +--error ER_ERROR_ON_RENAME +Alter table reply + change blogId topicId int(11) NOT NULL, + drop index userId, + drop foreign key reply_ibfk_2; + +# for cover test +--replace_regex /'[^']*test\/#sql2-[0-9a-f-]*'/'#sql-temporary'/ +--replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ '' +--error ER_ERROR_ON_RENAME + +Alter table reply + drop foreign key key_no_exist; +--exec > $MYSQLTEST_VARDIR/log/mysqld.1.err + +# now, the structures of table `reply` are different on master and slave +--echo #------------master +SHOW CREATE TABLE reply; + +connection slave; +--echo #------------slave +SHOW CREATE TABLE reply; + +# slave SQL thread failed after bellow sql clause +#connection master; +insert into user values (1, 'fungo'); +--error ER_NO_REFERENCED_ROW_2 +insert into reply values(1, 'bla bla bla', 1, 1); + +connection master; +drop table reply; +drop table user; +drop table blog; + +--sync_slave_with_master + +--source include/rpl_end.inc + diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 32354feea01d1ca76ad614d4a5fa55a52f379b6c..b71b12bbb4e8932ae7d2d42b68711d6f13758b84 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -4069,8 +4069,9 @@ dict_foreign_parse_drop_constraints( dict_table_t* table, /*!< in: table */ ulint* n, /*!< out: number of constraints to drop */ - const char*** constraints_to_drop) /*!< out: id's of the + const char*** constraints_to_drop, /*!< out: id's of the constraints to drop */ + ibool need_check) { dict_foreign_t* foreign; ibool success; @@ -4138,40 +4139,42 @@ loop: (*constraints_to_drop)[*n] = id; (*n)++; - /* Look for the given constraint id */ + if (need_check) { + /* Look for the given constraint id */ - foreign = UT_LIST_GET_FIRST(table->foreign_list); + foreign = UT_LIST_GET_FIRST(table->foreign_list); - while (foreign != NULL) { - if (0 == strcmp(foreign->id, id) - || (strchr(foreign->id, '/') - && 0 == strcmp(id, - dict_remove_db_name(foreign->id)))) { - /* Found */ - break; - } + while (foreign != NULL) { + if (0 == strcmp(foreign->id, id) + || (strchr(foreign->id, '/') + && 0 == strcmp(id, + dict_remove_db_name(foreign->id)))) { + /* Found */ + break; + } - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } - if (foreign == NULL) { - mutex_enter(&dict_foreign_err_mutex); - rewind(ef); - ut_print_timestamp(ef); - fputs(" Error in dropping of a foreign key constraint" - " of table ", ef); - ut_print_name(ef, NULL, TRUE, table->name); - fputs(",\n" - "in SQL command\n", ef); - fputs(str, ef); - fputs("\nCannot find a constraint with the given id ", ef); - ut_print_name(ef, NULL, FALSE, id); - fputs(".\n", ef); - mutex_exit(&dict_foreign_err_mutex); + if (foreign == NULL) { + mutex_enter(&dict_foreign_err_mutex); + rewind(ef); + ut_print_timestamp(ef); + fputs(" Error in dropping of a foreign key constraint" + " of table ", ef); + ut_print_name(ef, NULL, TRUE, table->name); + fputs(",\n" + "in SQL command\n", ef); + fputs(str, ef); + fputs("\nCannot find a constraint with the given id ", ef); + ut_print_name(ef, NULL, FALSE, id); + fputs(".\n", ef); + mutex_exit(&dict_foreign_err_mutex); - mem_free(str); + mem_free(str); - return(DB_CANNOT_DROP_CONSTRAINT); + return(DB_CANNOT_DROP_CONSTRAINT); + } } goto loop; diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 5818619bb760ca0db741388d9c48daec06f79e2c..795131549bc5ea1484cd6701ee4b386b8679a230 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -417,8 +417,9 @@ dict_foreign_parse_drop_constraints( dict_table_t* table, /*!< in: table */ ulint* n, /*!< out: number of constraints to drop */ - const char*** constraints_to_drop); /*!< out: id's of the + const char*** constraints_to_drop, /*!< out: id's of the constraints to drop */ + ibool need_check); /**********************************************************************//** Returns a table object and optionally increment its MySQL open handle count. NOTE! This is a high-level function to be used mainly from outside the diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 060c79c2deab300e983e73ea22e4e50eacb3b243..554a0709f17e057658468843a0133c0e41ee297d 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -3954,13 +3954,41 @@ row_rename_table_for_mysql( heap = mem_heap_create(100); err = dict_foreign_parse_drop_constraints( - heap, trx, table, &n_constraints_to_drop, - &constraints_to_drop); + heap, trx, table, &n_constraints_to_drop, + &constraints_to_drop, TRUE); if (err != DB_SUCCESS) { goto funct_exit; } + } else if (old_is_tmp && !new_is_tmp) { + /* + two situation here + 1. origin table have rename to tmp_name like #sql2-xxx-xxx + old_name is #sql-xxx_xxx + new_name is origin name + 2. rollock with error + old_name is #sql2-xxx-xxx + new_name is origin name + */ + + /* old_name include "/#sql2" when rollback, but we shouldn't + drop constraints when rollback */ + char *p = strstr(old_name, "/#sql2"); + + if (p == NULL) + { + heap = mem_heap_create(100); + + err = dict_foreign_parse_drop_constraints( + heap, trx, table, &n_constraints_to_drop, + &constraints_to_drop, FALSE); + + if (err != DB_SUCCESS) { + + goto funct_exit;//no cover line + } + } } /* We use the private SQL parser of Innobase to generate the query @@ -3983,6 +4011,24 @@ row_rename_table_for_mysql( goto end; } else if (!new_is_tmp) { + if (n_constraints_to_drop > 0) { + /* Drop some constraints of tmp tables. */ + + ulint db_name_len = dict_get_db_name_len(new_name) + 1; + char* db_name = mem_heap_strdupl(heap, new_name, + db_name_len); + ulint i; + + for (i = 0; i < n_constraints_to_drop; i++) { + err = row_delete_constraint(constraints_to_drop[i], + db_name, heap, trx); + + if (err != DB_SUCCESS) { + break; //no cover line + } + } + } + /* Rename all constraints. */ info = pars_info_create(); @@ -4056,24 +4102,7 @@ row_rename_table_for_mysql( "END;\n" , FALSE, trx); - } else if (n_constraints_to_drop > 0) { - /* Drop some constraints of tmp tables. */ - - ulint db_name_len = dict_get_db_name_len(old_name) + 1; - char* db_name = mem_heap_strdupl(heap, old_name, - db_name_len); - ulint i; - - for (i = 0; i < n_constraints_to_drop; i++) { - err = row_delete_constraint(constraints_to_drop[i], - db_name, heap, trx); - - if (err != DB_SUCCESS) { - break; - } - } } - end: if (err != DB_SUCCESS) { if (err == DB_DUPLICATE_KEY) {