mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
MDEV-17167 - InnoDB: Failing assertion: table->get_ref_count() == 0 upon
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.
This commit is contained in:
parent
b9a5ff3644
commit
bad2f1569d
6 changed files with 89 additions and 1 deletions
|
@ -548,3 +548,27 @@ DROP TABLE nonexisting_table, t1;
|
|||
ERROR 42S02: Unknown table 'temp_db.nonexisting_table'
|
||||
# Cleanup
|
||||
DROP DATABASE temp_db;
|
||||
USE test;
|
||||
#
|
||||
# MDEV-17167 - InnoDB: Failing assertion: table->get_ref_count() == 0
|
||||
# upon truncating a temporary table
|
||||
#
|
||||
CREATE TEMPORARY TABLE t1(a INT) ENGINE=InnoDB;
|
||||
SELECT * FROM t1 AS t1a1, t1 AS t2a2;
|
||||
a a
|
||||
TRUNCATE TABLE t1;
|
||||
LOCK TABLES t1 WRITE;
|
||||
TRUNCATE TABLE t1;
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
UNLOCK TABLES;
|
||||
LOCK TABLES t1 AS t1a1 WRITE, t1 AS t1a2 WRITE;
|
||||
TRUNCATE TABLE t1;
|
||||
SELECT * FROM t1 AS t1a1, t1 AS t1a2;
|
||||
a a
|
||||
UNLOCK TABLES;
|
||||
CREATE TABLE t2(a INT) ENGINE=InnoDB;
|
||||
LOCK TABLES t2 WRITE;
|
||||
TRUNCATE TABLE t1;
|
||||
UNLOCK TABLES;
|
||||
DROP TABLE t1, t2;
|
||||
|
|
|
@ -594,4 +594,30 @@ DROP TABLE nonexisting_table, t1;
|
|||
|
||||
--echo # Cleanup
|
||||
DROP DATABASE temp_db;
|
||||
USE test;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-17167 - InnoDB: Failing assertion: table->get_ref_count() == 0
|
||||
--echo # upon truncating a temporary table
|
||||
--echo #
|
||||
CREATE TEMPORARY TABLE t1(a INT) ENGINE=InnoDB;
|
||||
SELECT * FROM t1 AS t1a1, t1 AS t2a2;
|
||||
TRUNCATE TABLE t1;
|
||||
|
||||
LOCK TABLES t1 WRITE;
|
||||
TRUNCATE TABLE t1;
|
||||
SELECT * FROM t1;
|
||||
UNLOCK TABLES;
|
||||
|
||||
LOCK TABLES t1 AS t1a1 WRITE, t1 AS t1a2 WRITE;
|
||||
TRUNCATE TABLE t1;
|
||||
SELECT * FROM t1 AS t1a1, t1 AS t1a2;
|
||||
UNLOCK TABLES;
|
||||
|
||||
CREATE TABLE t2(a INT) ENGINE=InnoDB;
|
||||
LOCK TABLES t2 WRITE;
|
||||
TRUNCATE TABLE t1;
|
||||
UNLOCK TABLES;
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
|
|
@ -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? */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue