diff --git a/mysql-test/r/create_or_replace.result b/mysql-test/r/create_or_replace.result index e6589807c2b..0403e1a0a35 100644 --- a/mysql-test/r/create_or_replace.result +++ b/mysql-test/r/create_or_replace.result @@ -427,4 +427,16 @@ THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME # MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2 drop table t1; unlock tables; +# +# MDEV-6560 +# Assertion `! is_set() ' failed in Diagnostics_area::set_ok_status +# +CREATE TABLE t1 (col_int_nokey INT) ENGINE=InnoDB; +CREATE OR REPLACE TEMPORARY TABLE tmp LIKE t1; +LOCK TABLE t1 WRITE; +CREATE OR REPLACE TABLE t1 LIKE tmp;; +KILL QUERY 3; +CREATE OR REPLACE TABLE t1 (a int);; +KILL QUERY 3; +drop table t1; DROP TABLE t2; diff --git a/mysql-test/suite/rpl/r/create_or_replace2.result b/mysql-test/suite/rpl/r/create_or_replace2.result new file mode 100644 index 00000000000..b96a0f8ae13 --- /dev/null +++ b/mysql-test/suite/rpl/r/create_or_replace2.result @@ -0,0 +1,31 @@ +include/master-slave.inc +[connection master] +# +# MDEV-6525 ; Problems with CREATE OR REPLACE under lock +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(a) FROM t1 ); +connect con1,localhost,root,,test; +CREATE TEMPORARY TABLE tmp (b INT) ENGINE=InnoDB; +LOCK TABLE t1 WRITE; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +CREATE OR REPLACE TABLE t1 LIKE tmp; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +connection default; +set session lock_wait_timeout=1; +SELECT f1(); +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +set session lock_wait_timeout=@@global.lock_wait_timeout; +SELECT f1(); +connection con1; +unlock tables; +connection default; +ERROR 42S22: Unknown column 'a' in 'field list' +disconnect con1; +drop function f1; +drop table t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace2.test b/mysql-test/suite/rpl/t/create_or_replace2.test new file mode 100644 index 00000000000..79c92a7ec5b --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace2.test @@ -0,0 +1,44 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_row_or_statement.inc +--source include/have_metadata_lock_info.inc +--source include/master-slave.inc +--enable_connect_log + +--echo # +--echo # MDEV-6525 ; Problems with CREATE OR REPLACE under lock +--echo # + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(a) FROM t1 ); + +--connect (con1,localhost,root,,test) + +CREATE TEMPORARY TABLE tmp (b INT) ENGINE=InnoDB; +LOCK TABLE t1 WRITE; + +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; + +CREATE OR REPLACE TABLE t1 LIKE tmp; +SHOW CREATE TABLE t1; + +--connection default +set session lock_wait_timeout=1; +--error 1205 +SELECT f1(); + +set session lock_wait_timeout=@@global.lock_wait_timeout; +--send SELECT f1() +--connection con1 +# This is here just in case, any timeout should be ok +--sleep 1 +unlock tables; +--connection default +--error 1054 +--reap +--disconnect con1 + +# Cleanup +drop function f1; +drop table t1; +--disable_connect_log +--source include/rpl_end.inc diff --git a/mysql-test/t/create_or_replace.test b/mysql-test/t/create_or_replace.test index 384768a87d5..c7b980f9107 100644 --- a/mysql-test/t/create_or_replace.test +++ b/mysql-test/t/create_or_replace.test @@ -332,6 +332,38 @@ select * from information_schema.metadata_lock_info; drop table t1; unlock tables; +--echo # +--echo # MDEV-6560 +--echo # Assertion `! is_set() ' failed in Diagnostics_area::set_ok_status +--echo # + +CREATE TABLE t1 (col_int_nokey INT) ENGINE=InnoDB; + +--let $con_id = `SELECT CONNECTION_ID()` +CREATE OR REPLACE TEMPORARY TABLE tmp LIKE t1; +LOCK TABLE t1 WRITE; + +--connect (con1,localhost,root,,test) + +--connection default +--send CREATE OR REPLACE TABLE t1 LIKE tmp; +--connection con1 +eval KILL QUERY $con_id; + +--connection default +--error 0,ER_QUERY_INTERRUPTED +--reap +--send CREATE OR REPLACE TABLE t1 (a int); + +--connection con1 +eval KILL QUERY $con_id; + +--connection default +--error 0,ER_QUERY_INTERRUPTED +--reap +--disconnect con1 +drop table t1; + # # Cleanup # diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index f1bc19e27eb..ca190104d79 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -412,6 +412,17 @@ fun:__libc_start_main } +# +# dl_init reports leaked memory in memalign on OpenSuse 12.3 + +{ + memory "loss" from _dl_init + Memcheck:Leak + fun:memalign + ... + fun:call_init + fun:_dl_init +} # # dlclose can allocate memory for error message, the memory will be diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 342a45247c5..5dd8a5b8abc 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2925,6 +2925,7 @@ Locked_tables_list::reopen_tables(THD *thd) size_t reopen_count= 0; MYSQL_LOCK *lock; MYSQL_LOCK *merged_lock; + DBUG_ENTER("Locked_tables_list::reopen_tables"); for (TABLE_LIST *table_list= m_locked_tables; table_list; table_list= table_list->next_global) @@ -2936,7 +2937,7 @@ Locked_tables_list::reopen_tables(THD *thd) if (open_table(thd, table_list, thd->mem_root, &ot_ctx)) { unlink_all_closed_tables(thd, 0, reopen_count); - return TRUE; + DBUG_RETURN(TRUE); } table_list->table->pos_in_locked_tables= table_list; /* See also the comment on lock type in init_locked_tables(). */ @@ -2968,11 +2969,11 @@ Locked_tables_list::reopen_tables(THD *thd) unlink_all_closed_tables(thd, lock, reopen_count); if (! thd->killed) my_error(ER_LOCK_DEADLOCK, MYF(0)); - return TRUE; + DBUG_RETURN(TRUE); } thd->lock= merged_lock; } - return FALSE; + DBUG_RETURN(FALSE); } /** diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a4aeb24a326..b429772613e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4453,9 +4453,18 @@ extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd) return binlog_filter->db_ok(thd->db); } +/* + This is similar to sqlcom_can_generate_row_events, with the expection + that we only return 1 if we are going to generate row events in a + transaction. + CREATE OR REPLACE is always safe to do as this will run in it's own + transaction. +*/ + extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd) { - return sqlcom_can_generate_row_events(thd); + return (sqlcom_can_generate_row_events(thd) && thd->lex->sql_command != + SQLCOM_CREATE_TABLE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5f2f1141a04..e410be4cba6 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5029,7 +5029,10 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, */ thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables); if (thd->locked_tables_list.reopen_tables(thd)) + { thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + result= 1; + } else { TABLE *table= pos_in_locked_tables->table; @@ -5292,6 +5295,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, if (res) { + /* is_error() may be 0 if table existed and we generated a warning */ res= thd->is_error(); goto err; } @@ -5374,7 +5378,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, */ thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables); if (thd->locked_tables_list.reopen_tables(thd)) + { thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + res= 1; // We got an error + } else { /*