From ba875e939619baefb08936863a889830f595e426 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Fri, 30 Sep 2022 23:58:08 +0300 Subject: [PATCH] MDEV-29664 Assertion `!n_mysql_tables_in_use' failed in innobase_close_connection When ha_end_bulk_insert() fails F_UNLCK was done twice: in select_insert::prepare_eof() and in select_create::abort_result_set(). Now we avoid making F_UNLCK in prepare_eof() if error is non-zero. --- ...or_replace2.result => create_replace_debug.result} | 10 ++++++++++ ...ate_or_replace2.test => create_replace_debug.test} | 11 +++++++++++ sql/handler.cc | 5 +++++ sql/sql_insert.cc | 5 ++++- storage/innobase/handler/ha_innodb.cc | 1 + 5 files changed, 31 insertions(+), 1 deletion(-) rename mysql-test/main/{create_or_replace2.result => create_replace_debug.result} (90%) rename mysql-test/main/{create_or_replace2.test => create_replace_debug.test} (88%) diff --git a/mysql-test/main/create_or_replace2.result b/mysql-test/main/create_replace_debug.result similarity index 90% rename from mysql-test/main/create_or_replace2.result rename to mysql-test/main/create_replace_debug.result index 248d5dbc3f5..3a3ef21bdec 100644 --- a/mysql-test/main/create_or_replace2.result +++ b/mysql-test/main/create_replace_debug.result @@ -91,3 +91,13 @@ ERROR HY000: Table 't2' was not locked with LOCK TABLES unlock tables; drop tables t1; set @@debug_dbug= @saved_debug_dbug; +# +# MDEV-29664 Assertion `!n_mysql_tables_in_use' failed in innobase_close_connection +# +create table t1 (x int); +set @old_dbug= @@debug_dbug; +set @@debug_dbug= '+d,ha_end_bulk_insert_fail'; +create or replace table t2 (y int) engine innodb select * from t1; +ERROR HY000: Out of memory. +set @@debug_dbug= @old_dbug; +drop table t1; diff --git a/mysql-test/main/create_or_replace2.test b/mysql-test/main/create_replace_debug.test similarity index 88% rename from mysql-test/main/create_or_replace2.test rename to mysql-test/main/create_replace_debug.test index bd82d13f1d1..86e68c47743 100644 --- a/mysql-test/main/create_or_replace2.test +++ b/mysql-test/main/create_replace_debug.test @@ -86,3 +86,14 @@ unlock tables; drop tables t1; set @@debug_dbug= @saved_debug_dbug; + +--echo # +--echo # MDEV-29664 Assertion `!n_mysql_tables_in_use' failed in innobase_close_connection +--echo # +create table t1 (x int); +set @old_dbug= @@debug_dbug; +set @@debug_dbug= '+d,ha_end_bulk_insert_fail'; +--error ER_OUT_OF_RESOURCES +create or replace table t2 (y int) engine innodb select * from t1; +set @@debug_dbug= @old_dbug; +drop table t1; diff --git a/sql/handler.cc b/sql/handler.cc index 4d7c2eb228f..477f1b7f8c2 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5030,6 +5030,11 @@ int handler::ha_end_bulk_insert() DBUG_ENTER("handler::ha_end_bulk_insert"); DBUG_EXECUTE_IF("crash_end_bulk_insert", { extra(HA_EXTRA_FLUSH) ; DBUG_SUICIDE();}); + if (DBUG_IF("ha_end_bulk_insert_fail")) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + } estimation_rows_to_insert= 0; DBUG_RETURN(end_bulk_insert()); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index e2ec0507cdd..c850bdbe34f 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -4285,7 +4285,7 @@ bool select_insert::prepare_eof() table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); - if (atomic_replace) + if (atomic_replace && !error) { DBUG_ASSERT(table->s->tmp_table); @@ -5490,7 +5490,10 @@ void select_create::abort_result_set() if (atomic_replace) { + ulonglong save_options_bits= thd->variables.option_bits; + thd->variables.option_bits|= OPTION_NOT_AUTOCOMMIT; (void) table->file->ha_external_lock(thd, F_UNLCK); + thd->variables.option_bits= save_options_bits; (void) thd->drop_temporary_table(table, NULL, true); } else diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index b0a70a5cb6c..9cc9ed04385 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -16172,6 +16172,7 @@ ha_innobase::external_lock( /* MySQL is releasing a table lock */ + ut_ad(trx->n_mysql_tables_in_use); trx->n_mysql_tables_in_use--; m_mysql_has_locked = false;