diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index 7d96a4acf3f..b6976e43bcb 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -2663,7 +2663,6 @@ COUNT(*) 1537 SET SESSION sort_buffer_size = DEFAULT; DROP TABLE t1; -End of 5.1 tests # # Test for bug #39932 "create table fails if column for FK is in different # case than in corr index". @@ -2685,6 +2684,23 @@ t2 CREATE TABLE `t2` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 drop table t2, t1; # +# Test for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE:: +# UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". +# +DROP TABLE IF EXISTS t1; +CREATE TEMPORARY TABLE t1 (c int) ENGINE = InnoDB; +INSERT INTO t1 VALUES (1); +LOCK TABLES t1 READ; +# Even though temporary table was locked for READ we +# still allow writes to it to be compatible with MyISAM. +# This is possible since due to fact that temporary tables +# are specific to connection and therefore locking for them +# is irrelevant. +UPDATE t1 SET c = 5; +UNLOCK TABLES; +DROP TEMPORARY TABLE t1; +End of 5.1 tests +# # Bug#44613 SELECT statement inside FUNCTION takes a shared lock # DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/innodb/t/innodb_mysql.test b/mysql-test/suite/innodb/t/innodb_mysql.test index acc843341eb..910b93b443b 100644 --- a/mysql-test/suite/innodb/t/innodb_mysql.test +++ b/mysql-test/suite/innodb/t/innodb_mysql.test @@ -830,8 +830,6 @@ SET SESSION sort_buffer_size = DEFAULT; DROP TABLE t1; ---echo End of 5.1 tests - --echo # --echo # Test for bug #39932 "create table fails if column for FK is in different @@ -851,6 +849,28 @@ show create table t2; drop table t2, t1; +--echo # +--echo # Test for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE:: +--echo # UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TEMPORARY TABLE t1 (c int) ENGINE = InnoDB; +INSERT INTO t1 VALUES (1); +LOCK TABLES t1 READ; +--echo # Even though temporary table was locked for READ we +--echo # still allow writes to it to be compatible with MyISAM. +--echo # This is possible since due to fact that temporary tables +--echo # are specific to connection and therefore locking for them +--echo # is irrelevant. +UPDATE t1 SET c = 5; +UNLOCK TABLES; +DROP TEMPORARY TABLE t1; + +--echo End of 5.1 tests + + --echo # --echo # Bug#44613 SELECT statement inside FUNCTION takes a shared lock --echo # diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4f5bce3e8af..44a9243d8f5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1748,6 +1748,67 @@ bool sp_process_definer(THD *thd) } +/** + Auxiliary call that opens and locks tables for LOCK TABLES statement + and initializes the list of locked tables. + + @param thd Thread context. + @param tables List of tables to be locked. + + @return FALSE in case of success, TRUE in case of error. +*/ + +static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables) +{ + Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; + uint counter; + TABLE_LIST *table; + + thd->in_lock_tables= 1; + + if (open_tables(thd, &tables, &counter, 0, &lock_tables_prelocking_strategy)) + goto err; + + /* + We allow to change temporary tables even if they were locked for read + by LOCK TABLES. To avoid a discrepancy between lock acquired at LOCK + TABLES time and by the statement which is later executed under LOCK TABLES + we ensure that for temporary tables we always request a write lock (such + discrepancy can cause problems for the storage engine). + We don't set TABLE_LIST::lock_type in this case as this might result in + extra warnings from THD::decide_logging_format() even though binary logging + is totally irrelevant for LOCK TABLES. + */ + for (table= tables; table; table= table->next_global) + if (!table->placeholder() && table->table->s->tmp_table) + table->table->reginfo.lock_type= TL_WRITE; + + if (lock_tables(thd, tables, counter, 0) || + thd->locked_tables_list.init_locked_tables(thd)) + goto err; + + thd->in_lock_tables= 0; + + return FALSE; + +err: + thd->in_lock_tables= 0; + + trans_rollback_stmt(thd); + /* + Need to end the current transaction, so the storage engine (InnoDB) + can free its locks if LOCK TABLES locked some tables before finding + that it can't lock a table in its list + */ + trans_commit_implicit(thd); + /* Close tables and release metadata locks. */ + close_thread_tables(thd); + DBUG_ASSERT(!thd->locked_tables_mode); + thd->mdl_context.release_transactional_locks(); + return TRUE; +} + + /** Execute command saved in thd and lex->sql_command. @@ -3093,31 +3154,11 @@ end_with_restore_list: goto error; thd->variables.option_bits|= OPTION_TABLE_LOCK; - thd->in_lock_tables=1; - { - Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; - - res= (open_and_lock_tables(thd, all_tables, FALSE, 0, - &lock_tables_prelocking_strategy) || - thd->locked_tables_list.init_locked_tables(thd)); - } - - thd->in_lock_tables= 0; + res= lock_tables_open_and_lock_tables(thd, all_tables); if (res) { - trans_rollback_stmt(thd); - /* - Need to end the current transaction, so the storage engine (InnoDB) - can free its locks if LOCK TABLES locked some tables before finding - that it can't lock a table in its list - */ - trans_commit_implicit(thd); - /* Close tables and release metadata locks. */ - close_thread_tables(thd); - DBUG_ASSERT(!thd->locked_tables_mode); - thd->mdl_context.release_transactional_locks(); thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); } else