diff options
author | Aleksey Midenkov <midenok@gmail.com> | 2019-10-19 17:31:27 +0300 |
---|---|---|
committer | Aleksey Midenkov <midenok@gmail.com> | 2019-10-19 17:31:27 +0300 |
commit | abcce38a623d86bdd9e27cfd0b04ae9698cfef0b (patch) | |
tree | a4848966acdebb4142ce7a0362cf8263ec708aa9 | |
parent | 65717be1a1e1a3b6e9154a5794c068230245714b (diff) | |
download | mariadb-git-bb-10.5-midenok-MDEV-20480.tar.gz |
Close referenced shares on RENAME TABLEbb-10.5-midenok-MDEV-20480
-rw-r--r-- | sql/sql_rename.cc | 7 | ||||
-rw-r--r-- | sql/sql_table.cc | 6 | ||||
-rw-r--r-- | sql/table.cc | 45 | ||||
-rw-r--r-- | sql/table.h | 1 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 4 |
5 files changed, 63 insertions, 0 deletions
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index ada373546be..387a17fc2e0 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -286,6 +286,13 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db, if (ha_table_exists(thd, &ren_table->db, &old_alias, &hton) && hton) { DBUG_ASSERT(!thd->locked_tables_mode); + TDC_element *el= tdc_lock_share(thd, ren_table->db.str, ren_table->table_name.str); + if (el) + { + if (el->share->foreign_keys) + el->share->check_and_close_foreign_tables(thd, true); + tdc_unlock_share(el); + } tdc_remove_table(thd, TDC_RT_REMOVE_ALL, ren_table->db.str, ren_table->table_name.str, false); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index aac1ce57b67..883c4ab834d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9686,6 +9686,12 @@ do_continue:; } } + if (alter_info->flags & ALTER_DROP_FOREIGN_KEY && table->s->foreign_keys) + { + if (table->s->check_and_close_foreign_tables(thd, true)) + DBUG_RETURN(true); + } + if (handle_if_exists_options(thd, table, alter_info, &create_info->period_info) || fix_constraints_names(thd, &alter_info->check_constraint_list, diff --git a/sql/table.cc b/sql/table.cc index 8dc4cc5e9a0..50a07a4c035 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9282,6 +9282,51 @@ bool fk_modifies_child(enum_fk_option opt) return can_write[opt]; } +bool TABLE_SHARE::check_and_close_foreign_tables(THD* thd, bool force) +{ + DBUG_ASSERT(foreign_keys); + List_iterator_fast<FOREIGN_KEY_INFO> it(*foreign_keys); + List_iterator_fast<FOREIGN_KEY_INFO> ref_it; + while (FOREIGN_KEY_INFO *fk= it++) + { + if (!cmp(fk->referenced_db, &db) && !cmp(fk->referenced_table, &table_name)) + continue; + TDC_element *el= tdc_lock_share(thd, fk->referenced_db->str, fk->referenced_table->str); + if (!el) + continue; + if (!force && el->share->referenced_by_foreign_key()) + { + FOREIGN_KEY_INFO *ref; + ref_it.init(*el->share->referenced_keys); + while ((ref= ref_it++)) + { + if (!cmp(ref->foreign_db, &db) && !cmp(ref->foreign_table, &table_name)) + break; + } + if (!ref) + goto need_close; + tdc_unlock_share(el); + } + else + { +need_close: + MDL_request_list mdl_requests; + MDL_request target_mdl_request; + + target_mdl_request.init(MDL_key::TABLE, + el->share->db.str, el->share->table_name.str, + MDL_EXCLUSIVE, MDL_STATEMENT); + mdl_requests.push_front(&target_mdl_request); + tdc_unlock_share(el); + if (thd->mdl_context.acquire_locks(&mdl_requests, + thd->variables.lock_wait_timeout)) + return true; + close_all_tables_for_name(thd, el->share, HA_EXTRA_NOT_USED, NULL); + } + } + return false; +} + enum TR_table::enabled TR_table::use_transaction_registry= TR_table::MAYBE; TR_table::TR_table(THD* _thd, bool rw) : diff --git a/sql/table.h b/sql/table.h index d0a1b9ab5a1..609cfaf64ab 100644 --- a/sql/table.h +++ b/sql/table.h @@ -651,6 +651,7 @@ struct TABLE_SHARE { return referenced_keys && !referenced_keys->is_empty(); } + bool check_and_close_foreign_tables(THD *thd, bool force= false); Virtual_column_info **check_constraints; uint *blob_field; /* Index to blobs in Field arrray*/ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 4a976eae168..8c78b44d96f 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6270,6 +6270,10 @@ no_such_table: } } mysql_mutex_unlock(&table->s->LOCK_share); + if (table->s->foreign_keys + && table->s->check_and_close_foreign_tables(thd)) { + DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT); + } if (unlikely(err)) { set_my_errno(ENOMEM); DBUG_RETURN(HA_ERR_OUT_OF_MEM); |