• unknown's avatar
    A fix and a test case for Bug#24918 drop table and lock / inconsistent · 0936976e
    unknown authored
    between perm and temp tables. Review fixes.
    
    The original bug report complains that if we locked a temporary table
    with LOCK TABLES statement, we would not leave LOCK TABLES mode
    when this temporary table is dropped.
    
    Additionally, the bug was escalated when it was discovered than
    when a temporary transactional table that was previously
    locked with LOCK TABLES statement was dropped, futher actions with
    this table, such as UNLOCK TABLES, would lead to a crash.
    
    The problem originates from incomplete support of transactional temporary
    tables. When we added calls to handler::store_lock()/handler::external_lock()
    to operations that work with such tables, we only covered the normal
    server code flow and did not cover LOCK TABLES mode. 
    In LOCK TABLES mode, ::external_lock(LOCK) would sometimes be called without
    matching ::external_lock(UNLOCK), e.g. when a transactional temporary table
    was dropped. Additionally, this table would be left in the list of LOCKed 
    TABLES.
    
    The patch aims to address this inadequacy. Now, whenever an instance
    of 'handler' is destroyed, we assert that it was priorly
    external_lock(UNLOCK)-ed. All the places that violate this assert
    were fixed.
    
    This patch introduces no changes in behavior -- the discrepancy in
    behavior will be fixed when we start calling ::store_lock()/::external_lock()
    for all tables, regardless whether they are transactional or not, 
    temporary or not.
    
    
    mysql-test/r/innodb_mysql.result:
      Update test results (Bug#24918)
    mysql-test/t/innodb_mysql.test:
      Add a test case for Bug#24918
    sql/handler.h:
      Make handler::external_lock() a protected method. Backport from 5.1 its
      public wrapper handler::ha_external_lock().
      Assert that the handler is not closed if it is still locked.
    sql/lock.cc:
      In mysql_lock_tables only call lock_external() for the list of tables that
      we called store_lock() for. 
      E.g. get_lock_data() does not add non-transactional temporary tables to the
      lock list, so lock_external() should not be called for them.
      
      Use handler::ha_external_lock() instead of handler::external_lock().
      
      Add comments for mysql_lock_remove(), parameterize one strange
      side effect that it has. At least in one place where mysql_lock_remove
      is used, this side effect is not desired (DROP TABLE). The parameter
      will be dropped in 5.1, along with the side effect.
    sql/mysql_priv.h:
      Update declaration of mysql_lock_remove().
    sql/opt_range.cc:
      Deploy handler::ha_external_lock() instead of handler::external_lock()
    sql/sql_base.cc:
      When closing a temporary table, remove the table from the list of LOCKed 
      TABLES of this thread, in case it's there. 
      It's there if it is a transactional temporary table.
      Use a new declaration of mysql_lock_remove().
    sql/sql_class.h:
      Extend the comment for THD::temporary_tables.
    sql/sql_table.cc:
      Deploy handler::ha_external_lock() instead of handler::external_lock()
    0936976e
sql_base.cc 195 KB