summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Midenkov <midenok@gmail.com>2019-10-19 17:31:27 +0300
committerAleksey Midenkov <midenok@gmail.com>2019-10-19 17:31:27 +0300
commitabcce38a623d86bdd9e27cfd0b04ae9698cfef0b (patch)
treea4848966acdebb4142ce7a0362cf8263ec708aa9
parent65717be1a1e1a3b6e9154a5794c068230245714b (diff)
downloadmariadb-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.cc7
-rw-r--r--sql/sql_table.cc6
-rw-r--r--sql/table.cc45
-rw-r--r--sql/table.h1
-rw-r--r--storage/innobase/handler/ha_innodb.cc4
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);