summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@mariadb.com>2021-10-19 11:06:32 +0200
committerVladislav Vaintroub <wlad@mariadb.com>2021-10-26 14:33:07 +0200
commit6211c35549338c07b766a3671dc0714140a26915 (patch)
tree610829c5fa983f6f6cb5f561f8d25a0f167260b7
parent81b8547697f16215be52f4cc2515bcad8c142eaa (diff)
downloadmariadb-git-6211c35549338c07b766a3671dc0714140a26915.tar.gz
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.
-rw-r--r--mysql-test/r/create_or_replace.result19
-rw-r--r--mysql-test/t/create_or_replace.test19
-rw-r--r--sql/sql_insert.cc14
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;
}