diff --git a/mysql-test/suite/innodb/r/truncate.result b/mysql-test/suite/innodb/r/truncate.result index f389c351d70..f584ffadc05 100644 --- a/mysql-test/suite/innodb/r/truncate.result +++ b/mysql-test/suite/innodb/r/truncate.result @@ -27,3 +27,18 @@ SHOW TABLE STATUS; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary t1 InnoDB # Compressed # # # # # # 1 # # NULL latin1_swedish_ci NULL key_block_size=4 0 N DROP TABLE t1; +# +# MDEV-17859 Operating system errors in file operations +# after failed CREATE +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +call mtr.add_suppression("InnoDB: (Operating system )?[Ee]rror number"); +call mtr.add_suppression("InnoDB: Cannot create file '.*t1\\.ibd"); +FLUSH TABLES; +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +ERROR HY000: Tablespace for table '`test`.`t1`' exists. Please DISCARD the tablespace before IMPORT +SELECT * FROM t1; +a +1 +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/truncate.test b/mysql-test/suite/innodb/t/truncate.test index 16a3b06a8ae..5a80f7c49e3 100644 --- a/mysql-test/suite/innodb/t/truncate.test +++ b/mysql-test/suite/innodb/t/truncate.test @@ -36,3 +36,20 @@ TRUNCATE TABLE t1; --replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # SHOW TABLE STATUS; DROP TABLE t1; + +--echo # +--echo # MDEV-17859 Operating system errors in file operations +--echo # after failed CREATE +--echo # +let $MYSQLD_DATADIR= `select @@datadir`; +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +call mtr.add_suppression("InnoDB: (Operating system )?[Ee]rror number"); +call mtr.add_suppression("InnoDB: Cannot create file '.*t1\\.ibd"); +FLUSH TABLES; +--move_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/hidden.frm +--error ER_TABLESPACE_EXISTS +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +--move_file $MYSQLD_DATADIR/test/hidden.frm $MYSQLD_DATADIR/test/t1.frm +SELECT * FROM t1; +DROP TABLE t1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 9725375ebbb..7d555bfec51 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -10794,6 +10794,7 @@ create_table_info_t::create_table_def() DBUG_PRINT("enter", ("table_name: %s", m_table_name)); DBUG_ASSERT(m_trx->mysql_thd == m_thd); + DBUG_ASSERT(!m_drop_before_rollback); /* MySQL does the name length check. But we do additional check on the name length here */ @@ -11056,6 +11057,7 @@ err_col: table, m_trx, (fil_encryption_t)options->encryption, (uint32_t)options->encryption_key_id); + m_drop_before_rollback = (err == DB_SUCCESS); } DBUG_EXECUTE_IF("ib_crash_during_create_for_encryption", @@ -12282,6 +12284,9 @@ int create_table_info_t::create_table(bool create_fk) DBUG_RETURN(error); } + DBUG_ASSERT(m_drop_before_rollback + == !(m_flags2 & DICT_TF2_TEMPORARY)); + /* Create the keys */ if (m_form->s->keys == 0 || primary_key_no == -1) { @@ -12340,6 +12345,7 @@ int create_table_info_t::create_table(bool create_fk) my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), FTS_DOC_ID_INDEX_NAME); + m_drop_before_rollback = false; error = -1; DBUG_RETURN(error); case FTS_EXIST_DOC_ID_INDEX: @@ -12354,16 +12360,6 @@ int create_table_info_t::create_table(bool create_fk) error = convert_error_code_to_mysql(err, 0, NULL); if (error) { - /* Drop the being-created table before rollback, - so that rollback can possibly rename back a table - that could have been renamed before - the failed creation. */ - m_trx->error_state = DB_SUCCESS; - row_drop_table_for_mysql(m_table_name, m_trx, - SQLCOM_TRUNCATE); - trx_rollback_to_savepoint(m_trx, NULL); - - m_trx->error_state = DB_SUCCESS; DBUG_RETURN(error); } } @@ -12429,6 +12425,9 @@ int create_table_info_t::create_table(bool create_fk) error = convert_error_code_to_mysql(err, m_flags, NULL); if (error) { + /* row_table_add_foreign_constraints() dropped + the table */ + m_drop_before_rollback = false; DBUG_RETURN(error); } } @@ -12590,9 +12589,11 @@ ha_innobase::create( /* Drop the being-created table before rollback, so that rollback can possibly rename back a table that could have been renamed before the failed creation. */ - trx->error_state = DB_SUCCESS; - row_drop_table_for_mysql(info.table_name(), trx, - SQLCOM_TRUNCATE, true); + if (info.drop_before_rollback()) { + trx->error_state = DB_SUCCESS; + row_drop_table_for_mysql(info.table_name(), + trx, SQLCOM_TRUNCATE, true); + } trx_rollback_for_mysql(trx); row_mysql_unlock_data_dictionary(trx); if (own_trx) { diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 7bec858b5af..ed7d380db8b 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -656,7 +656,7 @@ public: m_trx(trx), m_form(form), m_create_info(create_info), - m_table_name(table_name), m_table(NULL), + m_table_name(table_name), m_table(NULL), m_drop_before_rollback(false), m_remote_path(remote_path), m_innodb_file_per_table(file_per_table) {} @@ -729,6 +729,9 @@ public: const char* table_name() const { return(m_table_name); } + /** @return whether the table needs to be dropped on rollback */ + bool drop_before_rollback() const { return m_drop_before_rollback; } + THD* thd() const { return(m_thd); } @@ -772,6 +775,8 @@ private: char* m_table_name; /** Table */ dict_table_t* m_table; + /** Whether the table needs to be dropped before rollback */ + bool m_drop_before_rollback; /** Remote path (DATA DIRECTORY) or zero length-string */ char* m_remote_path; diff --git a/storage/rocksdb/mysql-test/rocksdb/r/xa.result b/storage/rocksdb/mysql-test/rocksdb/r/xa.result new file mode 100644 index 00000000000..30cfe94e0b7 --- /dev/null +++ b/storage/rocksdb/mysql-test/rocksdb/r/xa.result @@ -0,0 +1,32 @@ +# +# MDEV-13155: XA recovery not supported for RocksDB (Just a testcase) +# +call mtr.add_suppression("Found .* prepared XA transactions"); +connect con1,localhost,root,,test; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a INT) ENGINE=RocksDB; +XA START 'xa1'; +INSERT INTO t1 (a) VALUES (1),(2); +XA END 'xa1'; +XA PREPARE 'xa1'; +connect con2,localhost,root,,test; +XA START 'xa2'; +INSERT INTO t1 (a) VALUES (3); +INSERT INTO t1 (a) VALUES (4); +XA END 'xa2'; +XA PREPARE 'xa2'; +connection default; +SELECT * FROM t1; +a +connect con3,localhost,root,,test; +XA RECOVER; +formatID gtrid_length bqual_length data +1 3 0 xa1 +1 3 0 xa2 +XA ROLLBACK 'xa1'; +XA COMMIT 'xa2'; +SELECT a FROM t1; +a +3 +4 +DROP TABLE t1; diff --git a/storage/rocksdb/mysql-test/rocksdb/t/xa-master.opt b/storage/rocksdb/mysql-test/rocksdb/t/xa-master.opt new file mode 100644 index 00000000000..70c120604f6 --- /dev/null +++ b/storage/rocksdb/mysql-test/rocksdb/t/xa-master.opt @@ -0,0 +1 @@ +--rocksdb_flush_log_at_trx_commit=1 diff --git a/storage/rocksdb/mysql-test/rocksdb/t/xa.test b/storage/rocksdb/mysql-test/rocksdb/t/xa.test new file mode 100644 index 00000000000..f8f381f0580 --- /dev/null +++ b/storage/rocksdb/mysql-test/rocksdb/t/xa.test @@ -0,0 +1,38 @@ +--echo # +--echo # MDEV-13155: XA recovery not supported for RocksDB (Just a testcase) +--echo # + +call mtr.add_suppression("Found .* prepared XA transactions"); + +--connect (con1,localhost,root,,test) +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a INT) ENGINE=RocksDB; + +XA START 'xa1'; +INSERT INTO t1 (a) VALUES (1),(2); +XA END 'xa1'; +XA PREPARE 'xa1'; + +--connect (con2,localhost,root,,test) +XA START 'xa2'; +INSERT INTO t1 (a) VALUES (3); +INSERT INTO t1 (a) VALUES (4); +XA END 'xa2'; +XA PREPARE 'xa2'; + +--connection default +SELECT * FROM t1; + +--let $shutdown_timeout= 0 +--source include/restart_mysqld.inc + +--connect (con3,localhost,root,,test) +--disable_abort_on_error +XA RECOVER; +XA ROLLBACK 'xa1'; +XA COMMIT 'xa2'; +SELECT a FROM t1; +DROP TABLE t1;