diff options
author | Sergey Vojtovich <svoj@mariadb.org> | 2018-09-12 16:36:45 +0400 |
---|---|---|
committer | Sergey Vojtovich <svoj@mariadb.org> | 2018-10-02 13:42:44 +0400 |
commit | bad2f1569da57c4a81cc84ec2f4a79924df9c8d6 (patch) | |
tree | 9ec5b4596b163d275051f7de74736183a6c191c3 /sql | |
parent | b9a5ff364466d2d1495352dd6c932d877923a614 (diff) | |
download | mariadb-git-bad2f1569da57c4a81cc84ec2f4a79924df9c8d6.tar.gz |
MDEV-17167 - InnoDB: Failing assertion: table->get_ref_count() == 0 uponmariadb-10.3.10
truncating a temporary table
TRUNCATE expects only one TABLE instance (which is used by TRUNCATE
itself) to be open. However this requirement wasn't enforced after
"MDEV-5535: Cannot reopen temporary table".
Fixed by closing unused table instances before performing TRUNCATE.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_class.h | 1 | ||||
-rw-r--r-- | sql/sql_plist.h | 7 | ||||
-rw-r--r-- | sql/sql_truncate.cc | 2 | ||||
-rw-r--r-- | sql/temporary_tables.cc | 30 |
4 files changed, 39 insertions, 1 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h index 97c5bfa3c12..acd48b07900 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4628,6 +4628,7 @@ public: TMP_TABLE_SHARE* save_tmp_table_share(TABLE *table); void restore_tmp_table_share(TMP_TABLE_SHARE *share); + void close_unused_temporary_table_instances(const TABLE_LIST *tl); private: /* Whether a lock has been acquired? */ diff --git a/sql/sql_plist.h b/sql/sql_plist.h index bb9889cc534..4d279af7a0d 100644 --- a/sql/sql_plist.h +++ b/sql/sql_plist.h @@ -184,7 +184,12 @@ public: list= &a; current= a.m_first; } - /* Operator for it++ */ + /** + Operator for it++ + + @note since we save next element pointer, caller may remove current element. + Such modification doesn't invalidate iterator. + */ inline T* operator++(int) { T *result= current; diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 5a6417880b3..bab9bb5e9ac 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -401,6 +401,8 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) /* In RBR, the statement is not binlogged if the table is temporary. */ binlog_stmt= !thd->is_current_stmt_binlog_format_row(); + thd->close_unused_temporary_table_instances(table_ref); + error= handler_truncate(thd, table_ref, TRUE); /* diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index f23ec7a1acc..1c8af5eaf66 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -1540,3 +1540,33 @@ void THD::unlock_temporary_tables() DBUG_VOID_RETURN; } + +/** + Close unused TABLE instances for given temporary table. + + @param tl [IN] TABLE_LIST + + Initial use case was TRUNCATE, which expects only one instance (which is used + by TRUNCATE itself) to be open. Most probably some ALTER TABLE variants and + REPAIR may have similar expectations. +*/ + +void THD::close_unused_temporary_table_instances(const TABLE_LIST *tl) +{ + TMP_TABLE_SHARE *share= find_tmp_table_share(tl); + + if (share) + { + All_share_tables_list::Iterator tables_it(share->all_tmp_tables); + + while (TABLE *table= tables_it++) + { + if (table->query_id == 0) + { + /* Note: removing current list element doesn't invalidate iterator. */ + share->all_tmp_tables.remove(table); + free_temporary_table(table); + } + } + } +} |