Skip to content

Commit 327b271

Browse files
committed
MDEV-14410 - Assertion `table->pos_in_locked_tables == __null ||
table->pos_in_locked_tables->table == table' failed in mark_used_tables_as_free_for_reuse Assertion failure can be triggered by some DDL executed under LOCK TABLES that holds lock for DDL target table multiple times (either explicitly or implcitly). When closing all table instances for given table (e.g. when preparing for table removal during CREATE OR REPLACE), only one instance was removed from m_locked_tables list. Later we attempt to re-insert one of the instances in mysql_create_table()/ add_back_last_deleted_lock(), which wasn't actually removed. This leads to m_locks_tables corruption, specifically loss of all following elements. Then UNLOCK TABLE won't reset some table instances properly (specifically pos_in_locked_tables), since they're not present in m_locked_tables. Eventually such table instance gets released to table cache and then re-used by subsequent statement, which triggers this assertion failure.
1 parent b794434 commit 327b271

File tree

4 files changed

+39
-1
lines changed

4 files changed

+39
-1
lines changed

mysql-test/r/create_or_replace.result

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,3 +473,18 @@ ERROR HY000: Table 't1' was not locked with LOCK TABLES
473473
UNLOCK TABLES;
474474
DROP FUNCTION f1;
475475
DROP TABLE t1;
476+
#
477+
# MDEV-14410 - Assertion `table->pos_in_locked_tables == __null ||
478+
# table->pos_in_locked_tables->table == table' failed in
479+
# mark_used_tables_as_free_for_reuse
480+
#
481+
CREATE TABLE t1 (a INT);
482+
CREATE TABLE t2 (b INT);
483+
CREATE TABLE t3 (c INT);
484+
CREATE TRIGGER tr1 BEFORE INSERT ON t3 FOR EACH ROW INSERT INTO t1 VALUES ();
485+
CREATE TRIGGER tr2 BEFORE INSERT ON t2 FOR EACH ROW INSERT INTO t3 SELECT * FROM t1;
486+
LOCK TABLE t1 WRITE, t2 WRITE;
487+
CREATE OR REPLACE TABLE t1 (i INT);
488+
UNLOCK TABLES;
489+
INSERT INTO t2 VALUES (1);
490+
DROP TABLE t1, t2, t3;

mysql-test/t/create_or_replace.test

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,3 +423,24 @@ UNLOCK TABLES;
423423

424424
DROP FUNCTION f1;
425425
DROP TABLE t1;
426+
427+
428+
--echo #
429+
--echo # MDEV-14410 - Assertion `table->pos_in_locked_tables == __null ||
430+
--echo # table->pos_in_locked_tables->table == table' failed in
431+
--echo # mark_used_tables_as_free_for_reuse
432+
--echo #
433+
CREATE TABLE t1 (a INT);
434+
CREATE TABLE t2 (b INT);
435+
CREATE TABLE t3 (c INT);
436+
437+
CREATE TRIGGER tr1 BEFORE INSERT ON t3 FOR EACH ROW INSERT INTO t1 VALUES ();
438+
CREATE TRIGGER tr2 BEFORE INSERT ON t2 FOR EACH ROW INSERT INTO t3 SELECT * FROM t1;
439+
440+
LOCK TABLE t1 WRITE, t2 WRITE;
441+
CREATE OR REPLACE TABLE t1 (i INT);
442+
UNLOCK TABLES;
443+
INSERT INTO t2 VALUES (1);
444+
445+
# Cleanup
446+
DROP TABLE t1, t2, t3;

sql/sql_base.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,7 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
806806
uint key_length= share->table_cache_key.length;
807807
const char *db= key;
808808
const char *table_name= db + share->db.length + 1;
809+
bool remove_from_locked_tables= extra != HA_EXTRA_NOT_USED;
809810

810811
memcpy(key, share->table_cache_key.str, key_length);
811812

@@ -819,7 +820,7 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
819820
{
820821
thd->locked_tables_list.unlink_from_list(thd,
821822
table->pos_in_locked_tables,
822-
extra != HA_EXTRA_NOT_USED);
823+
remove_from_locked_tables);
823824
/* Inform handler that there is a drop table or a rename going on */
824825
if (extra != HA_EXTRA_NOT_USED && table->db_stat)
825826
{

sql/table_cache.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ bool tc_release_table(TABLE *table)
376376
{
377377
DBUG_ASSERT(table->in_use);
378378
DBUG_ASSERT(table->file);
379+
DBUG_ASSERT(!table->pos_in_locked_tables);
379380

380381
if (table->needs_reopen() || tc_records() > tc_size)
381382
{

0 commit comments

Comments
 (0)