From aedc65fe10d1e5fd0a66da0aa5b1a23670ce5ef6 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 8 Jul 2025 14:01:50 +0300 Subject: [PATCH] MDEV-30364 Assertion MDL_EXCLUSIVE on DISCARD TABLESPACE in LOCK TABLE mode In locked_tables_mode when table is opened without MYSQL_OPEN_GET_NEW_TABLE flag it is taken from pre-opened and locked tables. In that case we upgrade its MDL ticket to MDL_EXCLUSIVE before the operation and downgrade after operation. --- mysql-test/main/debug_sync.result | 27 +++++++++++++++++++++ mysql-test/main/debug_sync.test | 40 +++++++++++++++++++++++++++++++ sql/sql_table.cc | 21 +++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/debug_sync.result b/mysql-test/main/debug_sync.result index 4c1711a6d6b..6bc2a5cbe24 100644 --- a/mysql-test/main/debug_sync.result +++ b/mysql-test/main/debug_sync.result @@ -320,3 +320,30 @@ SHOW VARIABLES LIKE 'DEBUG_SYNC'; Variable_name Value debug_sync ON - current signals: 's2,s7,s1,s5' SET DEBUG_SYNC= 'RESET'; +# +# MDEV-30364 Assertion MDL_EXCLUSIVE on DISCARD TABLESPACE in LOCK TABLE mode +# +create table t (c int) engine=innodb; +connect con1,localhost,root; +set debug_sync='get_schema_column WAIT_FOR go'; +select column_name from information_schema.columns +where table_schema='test' and table_name='t'; +connection default; +lock table t write; +alter table t discard tablespace; +connect con2,localhost,root; +disconnect con2; +connection default; +ERROR 70100: Query execution was interrupted +set debug_sync='now SIGNAL go'; +connection con1; +column_name +c +disconnect con1; +connection default; +unlock tables; +drop table t; +set debug_sync= 'reset'; +# +# End of 10.6 tests +# diff --git a/mysql-test/main/debug_sync.test b/mysql-test/main/debug_sync.test index 0c5bee3e220..1c8638832c1 100644 --- a/mysql-test/main/debug_sync.test +++ b/mysql-test/main/debug_sync.test @@ -18,6 +18,7 @@ # We need the Debug Sync Facility. # --source include/have_debug_sync.inc +--source include/have_innodb.inc # # We are checking privileges, which the embedded server cannot do. @@ -448,3 +449,42 @@ SHOW VARIABLES LIKE 'DEBUG_SYNC'; # SET DEBUG_SYNC= 'RESET'; +--echo # +--echo # MDEV-30364 Assertion MDL_EXCLUSIVE on DISCARD TABLESPACE in LOCK TABLE mode +--echo # +create table t (c int) engine=innodb; +--connect con1,localhost,root +set debug_sync='get_schema_column WAIT_FOR go'; +send select column_name from information_schema.columns +where table_schema='test' and table_name='t'; + +--connection default +let $wait_condition=select 1 from information_schema.processlist where state like 'debug sync point%'; +--source include/wait_condition.inc +let $connid=`select connection_id()`; +lock table t write; +send alter table t discard tablespace; + +--connect con2,localhost,root +--disable_query_log +--eval kill query $connid +--enable_query_log +--disconnect con2 + +--connection default +--error ER_QUERY_INTERRUPTED +reap; +set debug_sync='now SIGNAL go'; + +--connection con1 +reap; +--disconnect con1 + +--connection default +unlock tables; +drop table t; +set debug_sync= 'reset'; + +--echo # +--echo # End of 10.6 tests +--echo # diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 505926b67ce..7a3a25d3ce0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5946,6 +5946,8 @@ int mysql_discard_or_import_tablespace(THD *thd, { Alter_table_prelocking_strategy alter_prelocking_strategy; int error; + TABLE *table; + enum_mdl_type mdl_downgrade= MDL_NOT_INITIALIZED; DBUG_ENTER("mysql_discard_or_import_tablespace"); mysql_audit_alter_table(thd, table_list); @@ -5978,7 +5980,21 @@ int mysql_discard_or_import_tablespace(THD *thd, DBUG_RETURN(-1); } - error= table_list->table->file->ha_discard_or_import_tablespace(discard); + table= table_list->table; + DBUG_ASSERT(table->mdl_ticket || table->s->tmp_table); + if (table->mdl_ticket && table->mdl_ticket->get_type() < MDL_EXCLUSIVE) + { + DBUG_ASSERT(thd->locked_tables_mode); + mdl_downgrade= table->mdl_ticket->get_type(); + if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE, + thd->variables.lock_wait_timeout)) + { + error= 1; + goto err; + } + } + + error= table->file->ha_discard_or_import_tablespace(discard); THD_STAGE_INFO(thd, stage_end); @@ -6004,6 +6020,9 @@ int mysql_discard_or_import_tablespace(THD *thd, err: thd->tablespace_op=FALSE; + if (mdl_downgrade > MDL_NOT_INITIALIZED) + table->mdl_ticket->downgrade_lock(mdl_downgrade); + if (likely(error == 0)) { my_ok(thd);