Skip to content

Commit

Permalink
Merge following commit from 5.5:
Browse files Browse the repository at this point in the history
commit ef92aaf
Author: Jan Lindström <jan.lindstrom@mariadb.com>
Date:   Wed Jun 22 22:37:28 2016 +0300

    MDEV-10083: Orphan ibd file when playing with foreign keys

    Analysis: row_drop_table_for_mysql did not allow dropping
    referenced table even in case when actual creating of the
    referenced table was not successfull if foreign_key_checks=1.

    Fix: Allow dropping referenced table even if foreign_key_checks=1
    if actual table create returned error.
  • Loading branch information
Jan Lindström committed Jun 23, 2016
1 parent e167806 commit 26de906
Show file tree
Hide file tree
Showing 16 changed files with 272 additions and 42 deletions.
89 changes: 89 additions & 0 deletions mysql-test/suite/innodb/r/innodb-fkcheck.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
set global innodb_file_per_table = 1;
drop table if exists b;
drop database if exists bug_fk;
create database bug_fk;
use bug_fk;
CREATE TABLE b (
b int unsigned NOT NULL,
d1 datetime NOT NULL,
PRIMARY KEY (b,d1)
) ENGINE=InnoDB;
CREATE TABLE c (
b int unsigned NOT NULL,
d1 datetime NOT NULL,
d2 datetime NOT NULL,
PRIMARY KEY (b,d1),
CONSTRAINT b_fk FOREIGN KEY (b) REFERENCES b (b)
) ENGINE=InnoDB;
show warnings;
Level Code Message
set foreign_key_checks = 0;
DROP TABLE IF EXISTS b;
show create table c;
Table Create Table
c CREATE TABLE `c` (
`b` int(10) unsigned NOT NULL,
`d1` datetime NOT NULL,
`d2` datetime NOT NULL,
PRIMARY KEY (`b`,`d1`),
CONSTRAINT `b_fk` FOREIGN KEY (`b`) REFERENCES `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE b (
b bigint unsigned NOT NULL,
d1 date NOT NULL,
PRIMARY KEY (b,d1)
) ENGINE=InnoDB;
ERROR HY000: Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed")
show warnings;
Level Code Message
Error 1005 Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed")
Warning 1215 Cannot add foreign key constraint
DROP TABLE IF EXISTS d;
Warnings:
Note 1051 Unknown table 'bug_fk.d'
CREATE TABLE d (
b bigint unsigned NOT NULL,
d1 date NOT NULL,
PRIMARY KEY (b,d1),
CONSTRAINT bd_fk FOREIGN KEY (b) REFERENCES b (b)
) ENGINE=InnoDB;
show warnings;
Level Code Message
set foreign_key_checks = 1;
show create table c;
Table Create Table
c CREATE TABLE `c` (
`b` int(10) unsigned NOT NULL,
`d1` datetime NOT NULL,
`d2` datetime NOT NULL,
PRIMARY KEY (`b`,`d1`),
CONSTRAINT `b_fk` FOREIGN KEY (`b`) REFERENCES `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
show create table d;
Table Create Table
d CREATE TABLE `d` (
`b` bigint(20) unsigned NOT NULL,
`d1` date NOT NULL,
PRIMARY KEY (`b`,`d1`),
CONSTRAINT `bd_fk` FOREIGN KEY (`b`) REFERENCES `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE b (
b bigint unsigned NOT NULL,
d1 date NOT NULL,
PRIMARY KEY (b,d1)
) ENGINE=InnoDB;
ERROR HY000: Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed")
show warnings;
Level Code Message
Error 1005 Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed")
Warning 1215 Cannot add foreign key constraint
set foreign_key_checks=0;
drop table c;
drop table d;
create table b(id int) engine=innodb;
show warnings;
Level Code Message
b.frm
b.ibd
drop table if exists b;
drop database if exists bug_fk;
115 changes: 115 additions & 0 deletions mysql-test/suite/innodb/t/innodb-fkcheck.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
--source include/have_innodb.inc

#
# MDEV-10083: Orphan ibd file when playing with foreign keys
#
--disable_query_log
SET @start_global_fpt = @@global.innodb_file_per_table;
SET @start_global_fkc = @@global.foreign_key_checks;
--enable_query_log

set global innodb_file_per_table = 1;

--disable_warnings
drop table if exists b;
drop database if exists bug_fk;
--enable_warnings

let $MYSQLD_DATADIR = `select @@datadir`;

create database bug_fk;
use bug_fk;

CREATE TABLE b (
b int unsigned NOT NULL,
d1 datetime NOT NULL,
PRIMARY KEY (b,d1)
) ENGINE=InnoDB;

CREATE TABLE c (
b int unsigned NOT NULL,
d1 datetime NOT NULL,
d2 datetime NOT NULL,
PRIMARY KEY (b,d1),
CONSTRAINT b_fk FOREIGN KEY (b) REFERENCES b (b)
) ENGINE=InnoDB;

show warnings;

set foreign_key_checks = 0;

DROP TABLE IF EXISTS b;

show create table c;

#
# Note that column b has different type in parent table
#
--error 1005
CREATE TABLE b (
b bigint unsigned NOT NULL,
d1 date NOT NULL,
PRIMARY KEY (b,d1)
) ENGINE=InnoDB;

show warnings;

DROP TABLE IF EXISTS d;

CREATE TABLE d (
b bigint unsigned NOT NULL,
d1 date NOT NULL,
PRIMARY KEY (b,d1),
CONSTRAINT bd_fk FOREIGN KEY (b) REFERENCES b (b)
) ENGINE=InnoDB;

show warnings;

set foreign_key_checks = 1;

show create table c;
show create table d;

#
# Table c column b used on foreign key has different type
# compared referenced column b in table b, but this
# create still produced b.ibd file. This is because
# we row_drop_table_for_mysql was called and referenced
# table is not allowed to be dropped even in case
# when actual create is not successfull.
#
--error 1005
CREATE TABLE b (
b bigint unsigned NOT NULL,
d1 date NOT NULL,
PRIMARY KEY (b,d1)
) ENGINE=InnoDB;

show warnings;

--list_files $MYSQLD_DATADIR/bug_fk b*

set foreign_key_checks=0;

drop table c;
drop table d;

--list_files $MYSQLD_DATADIR/bug_fk b*

create table b(id int) engine=innodb;
show warnings;

--list_files $MYSQLD_DATADIR/bug_fk b*

#
# Cleanup
#
--disable_query_log
SET @@global.innodb_file_per_table = @start_global_fpt;
SET @@global.foreign_key_checks = @start_global_fkc;
--enable_query_log

--disable_warnings
drop table if exists b;
drop database if exists bug_fk;
--enable_warnings
16 changes: 8 additions & 8 deletions storage/innobase/dict/dict0crea.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1365,15 +1365,15 @@ dict_create_or_check_foreign_constraint_tables(void)
ib_logf(IB_LOG_LEVEL_WARN,
"Dropping incompletely created "
"SYS_FOREIGN table.");
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE);
}

if (sys_foreign_cols_err == DB_CORRUPTION) {
ib_logf(IB_LOG_LEVEL_WARN,
"Dropping incompletely created "
"SYS_FOREIGN_COLS table.");

row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE);
}

ib_logf(IB_LOG_LEVEL_WARN,
Expand Down Expand Up @@ -1427,8 +1427,8 @@ dict_create_or_check_foreign_constraint_tables(void)
ut_ad(err == DB_OUT_OF_FILE_SPACE
|| err == DB_TOO_MANY_CONCURRENT_TRXS);

row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE);
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE);

if (err == DB_OUT_OF_FILE_SPACE) {
err = DB_MUST_GET_MORE_FILE_SPACE;
Expand Down Expand Up @@ -1853,15 +1853,15 @@ dict_create_or_check_sys_tablespace(void)
ib_logf(IB_LOG_LEVEL_WARN,
"Dropping incompletely created "
"SYS_TABLESPACES table.");
row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE);
row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE, TRUE);
}

if (sys_datafiles_err == DB_CORRUPTION) {
ib_logf(IB_LOG_LEVEL_WARN,
"Dropping incompletely created "
"SYS_DATAFILES table.");

row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE);
row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE, TRUE);
}

ib_logf(IB_LOG_LEVEL_INFO,
Expand Down Expand Up @@ -1897,8 +1897,8 @@ dict_create_or_check_sys_tablespace(void)
ut_a(err == DB_OUT_OF_FILE_SPACE
|| err == DB_TOO_MANY_CONCURRENT_TRXS);

row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE);
row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE);
row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE, TRUE);
row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE, TRUE);

if (err == DB_OUT_OF_FILE_SPACE) {
err = DB_MUST_GET_MORE_FILE_SPACE;
Expand Down
4 changes: 2 additions & 2 deletions storage/innobase/fts/fts0fts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1918,7 +1918,7 @@ fts_create_common_tables(

trx_rollback_to_savepoint(trx, NULL);

row_drop_table_for_mysql(table->name, trx, FALSE);
row_drop_table_for_mysql(table->name, trx, FALSE, TRUE);

trx->error_state = DB_SUCCESS;
}
Expand Down Expand Up @@ -2070,7 +2070,7 @@ fts_create_index_tables_low(

trx_rollback_to_savepoint(trx, NULL);

row_drop_table_for_mysql(table_name, trx, FALSE);
row_drop_table_for_mysql(table_name, trx, FALSE, TRUE);

trx->error_state = DB_SUCCESS;
}
Expand Down
6 changes: 4 additions & 2 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10686,7 +10686,8 @@ ha_innobase::delete_table(

/* Drop the table in InnoDB */
err = row_drop_table_for_mysql(
norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB);
norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB,
FALSE);


if (err == DB_TABLE_NOT_FOUND
Expand Down Expand Up @@ -10717,7 +10718,8 @@ ha_innobase::delete_table(
#endif
err = row_drop_table_for_mysql(
par_case_name, trx,
thd_sql_command(thd) == SQLCOM_DROP_DB);
thd_sql_command(thd) == SQLCOM_DROP_DB,
FALSE);
}
}

Expand Down
3 changes: 3 additions & 0 deletions storage/innobase/include/row0mysql.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,9 @@ row_drop_table_for_mysql(
const char* name, /*!< in: table name */
trx_t* trx, /*!< in: dictionary transaction handle */
bool drop_db,/*!< in: true=dropping whole database */
ibool create_failed,/*!<in: TRUE=create table failed
because e.g. foreign key column
type mismatch. */
bool nonatomic = true)
/*!< in: whether it is permitted
to release and reacquire dict_operation_lock */
Expand Down
2 changes: 1 addition & 1 deletion storage/innobase/row/row0merge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3636,7 +3636,7 @@ row_merge_drop_table(
/* There must be no open transactions on the table. */
ut_a(table->n_ref_count == 0);

return(row_drop_table_for_mysql(table->name, trx, false, false));
return(row_drop_table_for_mysql(table->name, trx, false, false, false));
}

/*********************************************************************//**
Expand Down
22 changes: 15 additions & 7 deletions storage/innobase/row/row0mysql.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2391,7 +2391,7 @@ row_create_table_for_mysql(

dict_table_close(table, TRUE, FALSE);

row_drop_table_for_mysql(table->name, trx, FALSE);
row_drop_table_for_mysql(table->name, trx, FALSE, TRUE);

if (commit) {
trx_commit_for_mysql(trx);
Expand Down Expand Up @@ -2551,7 +2551,7 @@ row_create_index_for_mysql(

trx_rollback_to_savepoint(trx, NULL);

row_drop_table_for_mysql(table_name, trx, FALSE);
row_drop_table_for_mysql(table_name, trx, FALSE, TRUE);

trx_commit_for_mysql(trx);

Expand Down Expand Up @@ -2628,7 +2628,7 @@ row_table_add_foreign_constraints(

trx_rollback_to_savepoint(trx, NULL);

row_drop_table_for_mysql(name, trx, FALSE);
row_drop_table_for_mysql(name, trx, FALSE, TRUE);

trx_commit_for_mysql(trx);

Expand Down Expand Up @@ -2669,7 +2669,7 @@ row_drop_table_for_mysql_in_background(

/* Try to drop the table in InnoDB */

error = row_drop_table_for_mysql(name, trx, FALSE);
error = row_drop_table_for_mysql(name, trx, FALSE, FALSE);

/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
Expand Down Expand Up @@ -3767,6 +3767,9 @@ row_drop_table_for_mysql(
const char* name, /*!< in: table name */
trx_t* trx, /*!< in: transaction handle */
bool drop_db,/*!< in: true=dropping whole database */
ibool create_failed,/*!<in: TRUE=create table failed
because e.g. foreign key column
type mismatch. */
bool nonatomic)
/*!< in: whether it is permitted
to release and reacquire dict_operation_lock */
Expand Down Expand Up @@ -3957,7 +3960,12 @@ row_drop_table_for_mysql(
name,
foreign->foreign_table_name_lookup);

if (foreign->foreign_table != table && !ref_ok) {
/* We should allow dropping a referenced table if creating
that referenced table has failed for some reason. For example
if referenced table is created but it column types that are
referenced do not match. */
if (foreign->foreign_table != table &&
!create_failed && !ref_ok) {

FILE* ef = dict_foreign_err_file;

Expand Down Expand Up @@ -4497,7 +4505,7 @@ row_mysql_drop_temp_tables(void)
table = dict_load_table(table_name, TRUE, DICT_ERR_IGNORE_NONE);

if (table) {
row_drop_table_for_mysql(table_name, trx, FALSE);
row_drop_table_for_mysql(table_name, trx, FALSE, FALSE);
trx_commit_for_mysql(trx);
}

Expand Down Expand Up @@ -4666,7 +4674,7 @@ row_drop_database_for_mysql(
goto loop;
}

err = row_drop_table_for_mysql(table_name, trx, TRUE);
err = row_drop_table_for_mysql(table_name, trx, TRUE, FALSE);
trx_commit_for_mysql(trx);

if (err != DB_SUCCESS) {
Expand Down
Loading

0 comments on commit 26de906

Please sign in to comment.