From 6211c35549338c07b766a3671dc0714140a26915 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 19 Oct 2021 11:06:32 +0200 Subject: MDEV-23391 Crash/assertion CREATE OR REPLACE TABLE AS SELECT under LOCK TABLE Happens with Innodb engine. Move unlock_locked_table() past drop_open_table(), and rollback current statement, so that we can actually unlock the table. Anything else results in assertions, in drop, or unlock, or in close_table. --- mysql-test/r/create_or_replace.result | 19 +++++++++++++++++++ mysql-test/t/create_or_replace.test | 19 +++++++++++++++++++ sql/sql_insert.cc | 14 ++++++++------ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/create_or_replace.result b/mysql-test/r/create_or_replace.result index 54bec5c3f9d..5684843c01c 100644 --- a/mysql-test/r/create_or_replace.result +++ b/mysql-test/r/create_or_replace.result @@ -313,6 +313,25 @@ create table t1 (i int); drop table t1; drop database mysqltest2; # +# MDEV-23391 Server crash in close_thread_table or assertion, upon CREATE OR REPLACE TABLE under lock +# +create table t1 (i int); +lock table t1 write; +select * from information_schema.metadata_lock_info; +THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME +# MDL_INTENTION_EXCLUSIVE NULL Global read lock +# MDL_INTENTION_EXCLUSIVE NULL Schema metadata lock test +# MDL_SHARED_NO_READ_WRITE NULL Table metadata lock test t1 +create or replace table t1 (a char(1)) engine=Innodb select 'foo' as a; +ERROR 22001: Data too long for column 'a' at row 1 +show tables; +Tables_in_test +t2 +select * from information_schema.metadata_lock_info; +THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME +create table t1 (i int); +drop table t1; +# # Testing CREATE .. LIKE # create or replace table t1 like t2; diff --git a/mysql-test/t/create_or_replace.test b/mysql-test/t/create_or_replace.test index 4b167663742..ba32f4b7603 100644 --- a/mysql-test/t/create_or_replace.test +++ b/mysql-test/t/create_or_replace.test @@ -251,6 +251,25 @@ create table t1 (i int); drop table t1; drop database mysqltest2; + +--echo # +--echo # MDEV-23391 Server crash in close_thread_table or assertion, upon CREATE OR REPLACE TABLE under lock +--echo # +create table t1 (i int); +lock table t1 write; +--replace_column 1 # +--sorted_result +select * from information_schema.metadata_lock_info; +--error ER_DATA_TOO_LONG +create or replace table t1 (a char(1)) engine=Innodb select 'foo' as a; +show tables; +--replace_column 1 # +--sorted_result +select * from information_schema.metadata_lock_info; +create table t1 (i int); +drop table t1; + + --echo # --echo # Testing CREATE .. LIKE --echo # diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 718682f767e..13dbbaed539 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -4708,12 +4708,6 @@ void select_create::abort_result_set() /* possible error of writing binary log is ignored deliberately */ (void) thd->binlog_flush_pending_rows_event(TRUE, TRUE); - if (create_info->table_was_deleted) - { - /* Unlock locked table that was dropped by CREATE */ - thd->locked_tables_list.unlock_locked_table(thd, - create_info->mdl_ticket); - } if (table) { bool tmp_table= table->s->tmp_table; @@ -4751,5 +4745,13 @@ void select_create::abort_result_set() tmp_table); } } + + if (create_info->table_was_deleted) + { + /* Unlock locked table that was dropped by CREATE. */ + (void) trans_rollback_stmt(thd); + thd->locked_tables_list.unlock_locked_table(thd, create_info->mdl_ticket); + } + DBUG_VOID_RETURN; } -- cgit v1.2.1