From b8d576d087abbaf8075adb8936d505d0afd872f2 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 17:15:38 +0200 Subject: [PATCH] row0ins.c: Fix bug: if we dropped a table where an INSERT was waiting for a lock to check a FOREIGN KEY constraint, then an assertion would fail in lock_reset_all_on_table(), since that operation assumes no waiting locks on the table or its records row0mysql.c: Fix bug: InnoDB failed to drop a table in the background drop queue if the table was referenced by a foreign key constraint --- innobase/row/row0ins.c | 26 ++++++++++++++++++++++++++ innobase/row/row0mysql.c | 16 +++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index b9f860903cb..60dbf059673 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -1373,8 +1373,34 @@ row_ins_check_foreign_constraints( row_mysql_freeze_data_dictionary(trx); } + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + (foreign->referenced_table + ->n_foreign_key_checks_running)++; + + mutex_exit(&(dict_sys->mutex)); + } + + /* NOTE that if the thread ends up waiting for a lock + we will release dict_operation_lock temporarily! + But the counter on the table protects the referenced + table from being dropped while the check is running. */ + err = row_ins_check_foreign_constraint(TRUE, foreign, table, entry, thr); + + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + ut_a(foreign->referenced_table + ->n_foreign_key_checks_running > 0); + (foreign->referenced_table + ->n_foreign_key_checks_running)--; + + mutex_exit(&(dict_sys->mutex)); + } + if (got_s_lock) { row_mysql_unfreeze_data_dictionary(trx); } diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 2e8f7121d2c..ad5efc160c8 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1761,6 +1761,12 @@ row_drop_table_for_mysql_in_background( trx = trx_allocate_for_background(); + /* If the original transaction was dropping a table referenced by + foreign keys, we must set the following to be able to drop the + table: */ + + trx->check_foreigns = FALSE; + /* fputs("InnoDB: Error: Dropping table ", stderr); ut_print_name(stderr, name); fputs(" in background drop list\n", stderr); */ @@ -1834,16 +1840,16 @@ loop: goto already_dropped; } - - if (table->n_mysql_handles_opened > 0 - || table->n_foreign_key_checks_running > 0) { + + if (DB_SUCCESS != row_drop_table_for_mysql_in_background( + drop->table_name)) { + /* If the DROP fails for some table, we return, and let the + main thread retry later */ return(n_tables + n_tables_dropped); } n_tables_dropped++; - - row_drop_table_for_mysql_in_background(drop->table_name); already_dropped: mutex_enter(&kernel_mutex);