List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:December 23 2010 4:18pm
Subject:bzr commit into mysql-trunk-bugfixing branch (alexander.nozdrin:3471)
Bug#27480
View as plain text  
#At file:///home/alik/MySQL/bzr/00/bug27480/mysql-trunk-bugfixing/ based on revid:tor.didriksen@stripped

 3471 Alexander Nozdrin	2010-12-23
      Prerequisite patch for Bug#27480 (Extend CREATE TEMPORARY TABLES privilege
      to allow temp table operations):
      
        - move opening of temporary tables out of open_table();
      
        - make open_table() to work with base tables and views only.
          It will be renamed to open_base_table_or_view()
          in a follow-up patch.
      
        - introduce open_temporary_table() to open temporary tables
          (similar to open_table());
      
        - introduce open_temporary_tables() to open temporary tables
          corresponding to table list elements;
      
        - introduce a new "command flag" (CF_PREOPEN_TMP_TABLES) to mark
          statements that work with temporary tables, thus temporary tables
          should be opened for those statements;
      
        - open temporary tables in a unified way in the beginning of
          the statements marked with CF_PREOPEN_TMP_TABLES flag;
      
        - introduce a new "command flag" (CF_HA_CLOSE) to mark statements
          for which open handlers (by HANDLER OPEN) should be closed;
      
        - close open handlers in a unified way in the beginning of
          the statements marked with CF_HA_CLOSE flag.

    modified:
      mysql-test/r/alter_table.result
      mysql-test/r/grant4.result
      mysql-test/r/handler_myisam.result
      mysql-test/r/merge.result
      mysql-test/r/temp_table.result
      mysql-test/suite/innodb/r/innodb_mysql.result
      mysql-test/suite/innodb/t/innodb_mysql.test
      mysql-test/suite/rpl/r/rpl_create_if_not_exists.result
      mysql-test/suite/rpl/t/rpl_create_if_not_exists.test
      mysql-test/t/alter_table.test
      mysql-test/t/grant4.test
      mysql-test/t/handler_myisam.test
      mysql-test/t/merge.test
      mysql-test/t/temp_table.test
      sql/log_event.cc
      sql/sp_head.cc
      sql/sql_admin.cc
      sql/sql_base.cc
      sql/sql_base.h
      sql/sql_class.h
      sql/sql_db.cc
      sql/sql_handler.cc
      sql/sql_insert.cc
      sql/sql_parse.cc
      sql/sql_partition_admin.cc
      sql/sql_prepare.cc
      sql/sql_rename.cc
      sql/sql_show.cc
      sql/sql_table.cc
      sql/sql_truncate.cc
      sql/sql_view.cc
      storage/myisammrg/ha_myisammrg.cc
=== modified file 'mysql-test/r/alter_table.result'
--- a/mysql-test/r/alter_table.result	2010-08-30 06:38:09 +0000
+++ b/mysql-test/r/alter_table.result	2010-12-23 16:18:19 +0000
@@ -1383,3 +1383,14 @@ ALTER TABLE t1 CHANGE a id INT;
 affected rows: 0
 info: Records: 0  Duplicates: 0  Warnings: 0
 DROP TABLE t1;
+#
+# Additional coverage for refactoring which is made as part
+# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+# to allow temp table operations".
+#
+# At some point the below test case failed on assertion.
+DROP TABLE IF EXISTS t1;
+CREATE TEMPORARY TABLE t1 (i int) ENGINE=MyISAM;
+ALTER TABLE t1 DISCARD TABLESPACE;
+ERROR HY000: Table storage engine for 't1' doesn't have this option
+DROP TABLE t1;

=== modified file 'mysql-test/r/grant4.result'
--- a/mysql-test/r/grant4.result	2010-02-20 10:07:32 +0000
+++ b/mysql-test/r/grant4.result	2010-12-23 16:18:19 +0000
@@ -121,3 +121,60 @@ View	Create View	character_set_client	co
 v3	CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t_select_priv`.`a` AS `a`,`t_select_priv`.`b` AS `b` from `t_select_priv`	latin1	latin1_swedish_ci
 drop database mysqltest_db1;
 drop user mysqltest_u1@localhost;
+#
+# Additional coverage for refactoring which is made as part
+# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+# to allow temp table operations".
+# 
+# Check that for statements like CHECK/REPAIR and OPTIMIZE TABLE
+# privileges for all tables involved are checked before processing
+# any tables. Doing otherwise, i.e. checking privileges for table
+# right before processing it might result in lost results for tables
+# which were processed by the time when table for which privileges
+# are insufficient are discovered.
+#
+call mtr.add_suppression("Got an error from thread_id=.*ha_myisam.cc:");
+call mtr.add_suppression("MySQL thread id .*, query id .* localhost.*mysqltest_u1 Checking table");
+drop database if exists mysqltest_db1;
+create database mysqltest_db1;
+# Create tables which we are going to CHECK/REPAIR.
+create table mysqltest_db1.t1 (a int, key(a)) engine=myisam;
+create table mysqltest_db1.t2 (b int);
+insert into mysqltest_db1.t1 values (1), (2);
+insert into mysqltest_db1.t2 values (1);
+# Create user which will try to do this.
+create user mysqltest_u1@localhost;
+grant insert, select on mysqltest_db1.t1 to mysqltest_u1@localhost;
+# Corrupt t1 by replacing t1.MYI with a corrupt + unclosed one created
+# by doing: 'create table t1 (a int key(a))'
+#           head -c1024 t1.MYI > corrupt_t1.MYI 
+flush table mysqltest_db1.t1;
+# Switching to connection 'con1'.
+check table mysqltest_db1.t1;
+Table	Op	Msg_type	Msg_text
+mysqltest_db1.t1	check	warning	1 client is using or hasn't closed the table properly
+mysqltest_db1.t1	check	error	Size of indexfile is: 1024        Should be: 2048
+mysqltest_db1.t1	check	warning	Size of datafile is: 14       Should be: 7
+mysqltest_db1.t1	check	error	Corrupt
+# The below statement should fail before repairing t1.
+# Otherwise info about such repair will be missing from its result-set.
+repair table mysqltest_db1.t1, mysqltest_db1.t2;
+ERROR 42000: SELECT, INSERT command denied to user 'mysqltest_u1'@'localhost' for table 't2'
+# The same is true for CHECK TABLE statement.
+check table mysqltest_db1.t1, mysqltest_db1.t2;
+ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 't2'
+check table mysqltest_db1.t1;
+Table	Op	Msg_type	Msg_text
+mysqltest_db1.t1	check	warning	Table is marked as crashed
+mysqltest_db1.t1	check	warning	1 client is using or hasn't closed the table properly
+mysqltest_db1.t1	check	error	Size of indexfile is: 1024        Should be: 2048
+mysqltest_db1.t1	check	warning	Size of datafile is: 14       Should be: 7
+mysqltest_db1.t1	check	error	Corrupt
+repair table mysqltest_db1.t1;
+Table	Op	Msg_type	Msg_text
+mysqltest_db1.t1	repair	warning	Number of rows changed from 1 to 2
+mysqltest_db1.t1	repair	status	OK
+# Clean-up.
+# Switching to connection 'default'.
+drop database mysqltest_db1;
+drop user mysqltest_u1@localhost;

=== modified file 'mysql-test/r/handler_myisam.result'
--- a/mysql-test/r/handler_myisam.result	2010-11-18 16:34:56 +0000
+++ b/mysql-test/r/handler_myisam.result	2010-12-23 16:18:19 +0000
@@ -1858,4 +1858,90 @@ a	b
 4	40
 HANDLER t1 CLOSE;
 DROP TABLE t1;
+#
+# Additional coverage for refactoring which is made as part
+# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+# to allow temp table operations".
+#
+# Check that DDL on temporary table properly closes HANDLER cursors
+# for this table belonging to the same connection.
+CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1;
+# -- CREATE TABLE
+HANDLER t1 OPEN;
+CREATE TEMPORARY TABLE IF NOT EXISTS t1 SELECT 1 AS f1;
+Warnings:
+Note	1050	Table 't1' already exists
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- REPAIR TABLE
+HANDLER t1 OPEN;
+REPAIR TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	repair	status	OK
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- ANALYZE TABLE
+HANDLER t1 OPEN;
+ANALYZE TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	analyze	status	OK
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- OPTIMIZE TABLE
+HANDLER t1 OPEN;
+OPTIMIZE TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	optimize	status	OK
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- CHECK TABLE
+HANDLER t1 OPEN;
+CHECK TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	check	status	OK
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- ALTER TABLE
+HANDLER t1 OPEN;
+ALTER TABLE t1 ADD COLUMN b INT;
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- CREATE INDEX
+HANDLER t1 OPEN;
+CREATE INDEX b ON t1 (b);
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- DROP INDEX
+HANDLER t1 OPEN;
+DROP INDEX b ON t1;
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- TRUNCATE TABLE
+HANDLER t1 OPEN;
+TRUNCATE TABLE t1;
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- DROP TABLE
+HANDLER t1 OPEN;
+DROP TABLE t1;
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+CREATE TEMPORARY TABLE t1(a INT, b INT, INDEX i(a));
+set global keycache1.key_cache_block_size=2048;
+set global keycache1.key_buffer_size=1*1024*1024;
+set global keycache1.key_buffer_size=1024*1024;
+# -- CACHE INDEX
+HANDLER t1 OPEN;
+CACHE INDEX t1 IN keycache1;
+Table	Op	Msg_type	Msg_text
+test.t1	assign_to_keycache	status	OK
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+# -- LOAD INDEX
+HANDLER t1 OPEN;
+LOAD INDEX INTO CACHE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	preload_keys	status	OK
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
 End of 5.1 tests

=== modified file 'mysql-test/r/merge.result'
--- a/mysql-test/r/merge.result	2010-12-06 13:12:51 +0000
+++ b/mysql-test/r/merge.result	2010-12-23 16:18:19 +0000
@@ -3676,4 +3676,78 @@ ALTER TABLE t1 engine=myisam;
 ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
 UNLOCK TABLES;
 DROP TABLE m1, t1;
+#
+# Additional coverage for refactoring which is made as part
+# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+# to allow temp table operations".
+# 
+# Check that prelocking works correctly for various variants of
+# merge tables.
+drop table if exists t1, t2, m1;
+drop function if exists f1;
+create table t1 (j int);
+insert into t1 values (1);
+create function f1() returns int return (select count(*) from m1);
+create temporary table t2 (a int) engine=myisam;
+insert into t2 values (1);
+create temporary table m1 (a int) engine=merge union=(t2);
+select f1() from t1;
+f1()
+1
+drop tables t2, m1;
+create table t2 (a int) engine=myisam;
+insert into t2 values (1);
+create table m1 (a int) engine=merge union=(t2);
+select f1() from t1;
+f1()
+1
+drop table m1;
+create temporary table m1 (a int) engine=merge union=(t2);
+select f1() from t1;
+f1()
+1
+drop tables t1, t2, m1;
+drop function f1;
+#
+# Check that REPAIR/CHECK and CHECKSUM statements work correctly
+# for various variants of merge tables.
+create table t1 (a int) engine=myisam;
+insert into t1 values (1);
+create table m1 (a int) engine=merge union=(t1);
+check table m1;
+Table	Op	Msg_type	Msg_text
+test.m1	check	status	OK
+repair table m1;
+Table	Op	Msg_type	Msg_text
+test.m1	repair	note	The storage engine for the table doesn't support repair
+checksum table m1;
+Table	Checksum
+test.m1	3459908756
+drop tables t1, m1;
+create temporary table t1 (a int) engine=myisam;
+insert into t1 values (1);
+create temporary table m1 (a int) engine=merge union=(t1);
+check table m1;
+Table	Op	Msg_type	Msg_text
+test.m1	check	status	OK
+repair table m1;
+Table	Op	Msg_type	Msg_text
+test.m1	repair	note	The storage engine for the table doesn't support repair
+checksum table m1;
+Table	Checksum
+test.m1	3459908756
+drop tables t1, m1;
+create table t1 (a int) engine=myisam;
+insert into t1 values (1);
+create temporary table m1 (a int) engine=merge union=(t1);
+check table m1;
+Table	Op	Msg_type	Msg_text
+test.m1	check	status	OK
+repair table m1;
+Table	Op	Msg_type	Msg_text
+test.m1	repair	note	The storage engine for the table doesn't support repair
+checksum table m1;
+Table	Checksum
+test.m1	3459908756
+drop tables t1, m1;
 End of 6.0 tests

=== modified file 'mysql-test/r/temp_table.result'
--- a/mysql-test/r/temp_table.result	2010-08-30 06:38:09 +0000
+++ b/mysql-test/r/temp_table.result	2010-12-23 16:18:19 +0000
@@ -223,3 +223,51 @@ CREATE TEMPORARY TABLE bug48067.t1 (c1 i
 DROP DATABASE bug48067;
 DROP TEMPORARY table bug48067.t1;
 End of 5.1 tests
+#
+# Test that admin statements work for temporary tables.
+#
+DROP TABLE IF EXISTS t1,t2;
+CREATE TEMPORARY TABLE t1(a INT);
+CREATE TEMPORARY TABLE t2(b INT);
+CREATE TEMPORARY TABLE t3(c INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+ANALYZE TABLE t1, t2, t3;
+Table	Op	Msg_type	Msg_text
+test.t1	analyze	status	OK
+test.t2	analyze	status	OK
+test.t3	analyze	status	OK
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+CHECK TABLE t1, t2, t3;
+Table	Op	Msg_type	Msg_text
+test.t1	check	status	OK
+test.t2	check	status	OK
+test.t3	check	status	OK
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+CHECKSUM TABLE t1, t2, t3;
+Table	Checksum
+test.t1	xxx
+test.t2	xxx
+test.t3	xxx
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+OPTIMIZE TABLE t1, t2, t3;
+Table	Op	Msg_type	Msg_text
+test.t1	optimize	status	OK
+test.t2	optimize	status	OK
+test.t3	optimize	status	OK
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+REPAIR TABLE t1, t2, t3;
+Table	Op	Msg_type	Msg_text
+test.t1	repair	status	OK
+test.t2	repair	status	OK
+test.t3	repair	status	OK
+DROP TABLES t1, t2, t3;

=== modified file 'mysql-test/suite/innodb/r/innodb_mysql.result'
--- a/mysql-test/suite/innodb/r/innodb_mysql.result	2010-12-20 13:24:37 +0000
+++ b/mysql-test/suite/innodb/r/innodb_mysql.result	2010-12-23 16:18:19 +0000
@@ -2830,4 +2830,17 @@ PACK_KEYS=0;
 CREATE INDEX a ON t1 (a);
 CREATE INDEX c on t1 (c);
 DROP TABLE t1;
+#
+# Additional coverage for refactoring which is made as part
+# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+# to allow temp table operations".
+#
+# Check that OPTIMIZE table works for temporary InnoDB tables.
+DROP TABLE IF EXISTS t1;
+CREATE TEMPORARY TABLE t1 (a INT) ENGINE=InnoDB;
+OPTIMIZE TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	optimize	note	Table does not support optimize, doing recreate + analyze instead
+test.t1	optimize	status	OK
+DROP TABLE t1;
 End of 6.0 tests

=== modified file 'mysql-test/suite/innodb/t/innodb_mysql.test'
--- a/mysql-test/suite/innodb/t/innodb_mysql.test	2010-12-20 12:43:48 +0000
+++ b/mysql-test/suite/innodb/t/innodb_mysql.test	2010-12-23 16:18:19 +0000
@@ -992,4 +992,19 @@ CREATE INDEX c on t1 (c);
 
 DROP TABLE t1;
 
+
+--echo #
+--echo # Additional coverage for refactoring which is made as part
+--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+--echo # to allow temp table operations".
+--echo #
+--echo # Check that OPTIMIZE table works for temporary InnoDB tables.
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+CREATE TEMPORARY TABLE t1 (a INT) ENGINE=InnoDB;
+OPTIMIZE TABLE t1;
+DROP TABLE t1;
+
+
 --echo End of 6.0 tests

=== modified file 'mysql-test/suite/rpl/r/rpl_create_if_not_exists.result'
--- a/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result	2010-12-19 17:22:30 +0000
+++ b/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result	2010-12-23 16:18:19 +0000
@@ -117,4 +117,18 @@ show binlog events from <binlog_start>;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
 DROP VIEW v1;
 DROP TABLE t1, t2;
+#
+# Test case which has failed on assertion after refactoring which was
+# made as part of fix for bug #27480 "Extend CREATE TEMPORARY TABLES
+# privilege to allow temp table operations".
+#
+CREATE TEMPORARY TABLE t1 (id int);
+CREATE TABLE IF NOT EXISTS t2 LIKE t1;
+# The below statement should succeed with warning and
+# should not crash due to failing assertion.
+CREATE TABLE IF NOT EXISTS t2 LIKE t1;
+Warnings:
+Note	1050	Table 't2' already exists
+# Clean-up.
+DROP TABLE t1, t2;
 include/rpl_end.inc

=== modified file 'mysql-test/suite/rpl/t/rpl_create_if_not_exists.test'
--- a/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test	2010-12-19 17:22:30 +0000
+++ b/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test	2010-12-23 16:18:19 +0000
@@ -173,4 +173,21 @@ DROP VIEW v1;
 
 DROP TABLE t1, t2;
 
+
+--echo #
+--echo # Test case which has failed on assertion after refactoring which was
+--echo # made as part of fix for bug #27480 "Extend CREATE TEMPORARY TABLES
+--echo # privilege to allow temp table operations".
+--echo #
+CREATE TEMPORARY TABLE t1 (id int);
+CREATE TABLE IF NOT EXISTS t2 LIKE t1;
+--echo # The below statement should succeed with warning and
+--echo # should not crash due to failing assertion.
+CREATE TABLE IF NOT EXISTS t2 LIKE t1;
+--echo # Clean-up.
+DROP TABLE t1, t2;
+sync_slave_with_master;
+connection master;
+
+
 --source include/rpl_end.inc

=== modified file 'mysql-test/t/alter_table.test'
--- a/mysql-test/t/alter_table.test	2010-07-26 09:22:38 +0000
+++ b/mysql-test/t/alter_table.test	2010-12-23 16:18:19 +0000
@@ -1144,3 +1144,18 @@ INSERT INTO t1 VALUES (1, 1), (2, 2);
 ALTER TABLE t1 CHANGE a id INT;
 --disable_info
 DROP TABLE t1;
+
+
+--echo #
+--echo # Additional coverage for refactoring which is made as part
+--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+--echo # to allow temp table operations".
+--echo #
+--echo # At some point the below test case failed on assertion.
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+CREATE TEMPORARY TABLE t1 (i int) ENGINE=MyISAM;
+--error ER_ILLEGAL_HA
+ALTER TABLE t1 DISCARD TABLESPACE;
+DROP TABLE t1;

=== modified file 'mysql-test/t/grant4.test'
--- a/mysql-test/t/grant4.test	2009-10-19 12:58:13 +0000
+++ b/mysql-test/t/grant4.test	2010-12-23 16:18:19 +0000
@@ -144,3 +144,62 @@ connection default;
 disconnect con1;
 drop database mysqltest_db1;
 drop user mysqltest_u1@localhost;
+
+
+--echo #
+--echo # Additional coverage for refactoring which is made as part
+--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+--echo # to allow temp table operations".
+--echo # 
+--echo # Check that for statements like CHECK/REPAIR and OPTIMIZE TABLE
+--echo # privileges for all tables involved are checked before processing
+--echo # any tables. Doing otherwise, i.e. checking privileges for table
+--echo # right before processing it might result in lost results for tables
+--echo # which were processed by the time when table for which privileges
+--echo # are insufficient are discovered.
+--echo #
+call mtr.add_suppression("Got an error from thread_id=.*ha_myisam.cc:");
+call mtr.add_suppression("MySQL thread id .*, query id .* localhost.*mysqltest_u1 Checking table");
+--disable_warnings
+drop database if exists mysqltest_db1;
+--enable_warnings
+let $MYSQLD_DATADIR = `SELECT @@datadir`;
+create database mysqltest_db1;
+--echo # Create tables which we are going to CHECK/REPAIR.
+create table mysqltest_db1.t1 (a int, key(a)) engine=myisam;
+create table mysqltest_db1.t2 (b int);
+insert into mysqltest_db1.t1 values (1), (2);
+insert into mysqltest_db1.t2 values (1);
+--echo # Create user which will try to do this.
+create user mysqltest_u1@localhost;
+grant insert, select on mysqltest_db1.t1 to mysqltest_u1@localhost;
+connect (con1,localhost,mysqltest_u1,,);
+connection default;
+
+--echo # Corrupt t1 by replacing t1.MYI with a corrupt + unclosed one created
+--echo # by doing: 'create table t1 (a int key(a))'
+--echo #           head -c1024 t1.MYI > corrupt_t1.MYI 
+flush table mysqltest_db1.t1;
+--remove_file $MYSQLD_DATADIR/mysqltest_db1/t1.MYI
+--copy_file std_data/corrupt_t1.MYI $MYSQLD_DATADIR/mysqltest_db1/t1.MYI
+
+--echo # Switching to connection 'con1'.
+connection con1;
+check table mysqltest_db1.t1;
+--echo # The below statement should fail before repairing t1.
+--echo # Otherwise info about such repair will be missing from its result-set.
+--error ER_TABLEACCESS_DENIED_ERROR
+repair table mysqltest_db1.t1, mysqltest_db1.t2;
+--echo # The same is true for CHECK TABLE statement.
+--error ER_TABLEACCESS_DENIED_ERROR
+check table mysqltest_db1.t1, mysqltest_db1.t2;
+check table mysqltest_db1.t1;
+repair table mysqltest_db1.t1;
+
+--echo # Clean-up.
+disconnect con1;
+--source include/wait_until_disconnected.inc
+--echo # Switching to connection 'default'.
+connection default;
+drop database mysqltest_db1;
+drop user mysqltest_u1@localhost;

=== modified file 'mysql-test/t/handler_myisam.test'
--- a/mysql-test/t/handler_myisam.test	2010-06-09 10:45:04 +0000
+++ b/mysql-test/t/handler_myisam.test	2010-12-23 16:18:19 +0000
@@ -97,4 +97,93 @@ HANDLER t1 CLOSE;
 DROP TABLE t1;
 
 
+--echo #
+--echo # Additional coverage for refactoring which is made as part
+--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+--echo # to allow temp table operations".
+--echo #
+--echo # Check that DDL on temporary table properly closes HANDLER cursors
+--echo # for this table belonging to the same connection.
+
+CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1; 
+
+--echo # -- CREATE TABLE
+HANDLER t1 OPEN;
+CREATE TEMPORARY TABLE IF NOT EXISTS t1 SELECT 1 AS f1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- REPAIR TABLE
+HANDLER t1 OPEN;
+REPAIR TABLE t1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- ANALYZE TABLE
+HANDLER t1 OPEN;
+ANALYZE TABLE t1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- OPTIMIZE TABLE
+HANDLER t1 OPEN;
+OPTIMIZE TABLE t1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- CHECK TABLE
+HANDLER t1 OPEN;
+CHECK TABLE t1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- ALTER TABLE
+HANDLER t1 OPEN;
+ALTER TABLE t1 ADD COLUMN b INT;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- CREATE INDEX
+HANDLER t1 OPEN;
+CREATE INDEX b ON t1 (b);
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- DROP INDEX
+HANDLER t1 OPEN;
+DROP INDEX b ON t1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- TRUNCATE TABLE
+HANDLER t1 OPEN;
+TRUNCATE TABLE t1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- DROP TABLE
+HANDLER t1 OPEN;
+DROP TABLE t1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+CREATE TEMPORARY TABLE t1(a INT, b INT, INDEX i(a));
+
+set global keycache1.key_cache_block_size=2048;
+set global keycache1.key_buffer_size=1*1024*1024;
+set global keycache1.key_buffer_size=1024*1024;
+
+--echo # -- CACHE INDEX
+HANDLER t1 OPEN;
+CACHE INDEX t1 IN keycache1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+--echo # -- LOAD INDEX
+HANDLER t1 OPEN;
+LOAD INDEX INTO CACHE t1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+
 --echo End of 5.1 tests

=== modified file 'mysql-test/t/merge.test'
--- a/mysql-test/t/merge.test	2010-10-26 09:10:59 +0000
+++ b/mysql-test/t/merge.test	2010-12-23 16:18:19 +0000
@@ -2798,6 +2798,60 @@ UNLOCK TABLES;
 DROP TABLE m1, t1;
 
 
+--echo #
+--echo # Additional coverage for refactoring which is made as part
+--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
+--echo # to allow temp table operations".
+--echo # 
+--echo # Check that prelocking works correctly for various variants of
+--echo # merge tables.
+--disable_warnings
+drop table if exists t1, t2, m1;
+drop function if exists f1;
+--enable_warnings
+create table t1 (j int);
+insert into t1 values (1);
+create function f1() returns int return (select count(*) from m1);
+create temporary table t2 (a int) engine=myisam;
+insert into t2 values (1);
+create temporary table m1 (a int) engine=merge union=(t2);
+select f1() from t1;
+drop tables t2, m1;
+create table t2 (a int) engine=myisam;
+insert into t2 values (1);
+create table m1 (a int) engine=merge union=(t2);
+select f1() from t1;
+drop table m1;
+create temporary table m1 (a int) engine=merge union=(t2);
+select f1() from t1;
+drop tables t1, t2, m1;
+drop function f1;
+--echo #
+--echo # Check that REPAIR/CHECK and CHECKSUM statements work correctly
+--echo # for various variants of merge tables.
+create table t1 (a int) engine=myisam;
+insert into t1 values (1);
+create table m1 (a int) engine=merge union=(t1);
+check table m1;
+repair table m1;
+checksum table m1;
+drop tables t1, m1;
+create temporary table t1 (a int) engine=myisam;
+insert into t1 values (1);
+create temporary table m1 (a int) engine=merge union=(t1);
+check table m1;
+repair table m1;
+checksum table m1;
+drop tables t1, m1;
+create table t1 (a int) engine=myisam;
+insert into t1 values (1);
+create temporary table m1 (a int) engine=merge union=(t1);
+check table m1;
+repair table m1;
+checksum table m1;
+drop tables t1, m1;
+
+
 --echo End of 6.0 tests
 
 --disable_result_log

=== modified file 'mysql-test/t/temp_table.test'
--- a/mysql-test/t/temp_table.test	2010-06-23 11:34:40 +0000
+++ b/mysql-test/t/temp_table.test	2010-12-23 16:18:19 +0000
@@ -251,3 +251,46 @@ DROP DATABASE bug48067;
 DROP TEMPORARY table bug48067.t1;
 
 --echo End of 5.1 tests
+
+--echo #
+--echo # Test that admin statements work for temporary tables.
+--echo #
+--disable_warnings
+DROP TABLE IF EXISTS t1,t2;
+--enable_warnings
+CREATE TEMPORARY TABLE t1(a INT);
+CREATE TEMPORARY TABLE t2(b INT);
+CREATE TEMPORARY TABLE t3(c INT);
+
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+
+ANALYZE TABLE t1, t2, t3;
+
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+
+CHECK TABLE t1, t2, t3;
+
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+
+--replace_column 2 xxx
+CHECKSUM TABLE t1, t2, t3;
+
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+
+OPTIMIZE TABLE t1, t2, t3;
+
+INSERT INTO t1 VALUES (1), (2), (3);
+INSERT INTO t2 VALUES (11), (12), (13);
+INSERT INTO t3 VALUES (101), (102), (103);
+
+REPAIR TABLE t1, t2, t3;
+
+DROP TABLES t1, t2, t3;

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2010-12-21 10:39:20 +0000
+++ b/sql/log_event.cc	2010-12-23 16:18:19 +0000
@@ -5321,7 +5321,8 @@ int Load_log_event::do_apply_event(NET* 
         update it inside mysql_load().
       */
       List<Item> tmp_list;
-      if (mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
+      if (open_temporary_tables(thd, &tables) ||
+          mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
                      handle_dup, ignore, net != 0))
         thd->is_slave_error= 1;
       if (thd->cuted_fields)

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2010-12-17 11:28:59 +0000
+++ b/sql/sp_head.cc	2010-12-23 16:18:19 +0000
@@ -3041,8 +3041,9 @@ int sp_instr::exec_open_and_lock_tables(
     Check whenever we have access to tables for this statement
     and open and lock them before executing instructions core function.
   */
-  if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)
-      || open_and_lock_tables(thd, tables, TRUE, 0))
+  if (open_temporary_tables(thd, tables) ||
+      check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE) ||
+      open_and_lock_tables(thd, tables, TRUE, 0))
     result= -1;
   else
     result= 0;

=== modified file 'sql/sql_admin.cc'
--- a/sql/sql_admin.cc	2010-11-18 16:34:56 +0000
+++ b/sql/sql_admin.cc	2010-12-23 16:18:19 +0000
@@ -17,7 +17,6 @@
 #include "keycaches.h"                       // get_key_cache
 #include "sql_base.h"                        // Open_table_context
 #include "lock.h"                            // MYSQL_OPEN_*
-#include "sql_handler.h"                     // mysql_ha_rm_tables
 #include "partition_element.h"               // PART_ADMIN
 #include "sql_partition.h"                   // set_part_state
 #include "transaction.h"                     // trans_rollback_stmt
@@ -88,8 +87,7 @@ static int prepare_for_repair(THD *thd, 
                                  MDL_EXCLUSIVE, MDL_TRANSACTION);
 
     if (lock_table_names(thd, table_list, table_list->next_global,
-                         thd->variables.lock_wait_timeout,
-                         MYSQL_OPEN_SKIP_TEMPORARY))
+                         thd->variables.lock_wait_timeout, 0))
       DBUG_RETURN(0);
     has_mdl_lock= TRUE;
 
@@ -292,7 +290,13 @@ static bool mysql_admin_table(THD* thd, 
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
-  mysql_ha_rm_tables(thd, tables);
+  /*
+    Close all temporary tables which were pre-open to simplify
+    privilege checking. Clear all references to closed tables.
+  */
+  close_thread_tables(thd);
+  for (table= tables; table; table= table->next_local)
+    table->table= NULL;
 
   for (table= tables; table; table= table->next_local)
   {
@@ -341,7 +345,11 @@ static bool mysql_admin_table(THD* thd, 
       if (view_operator_func == NULL)
         table->required_type=FRMTYPE_TABLE;
 
-      open_error= open_and_lock_tables(thd, table, TRUE, 0);
+      open_error= open_temporary_tables(thd, table);
+
+      if (! open_error)
+        open_error= open_and_lock_tables(thd, table, TRUE, 0);
+
       thd->no_warnings_for_error= 0;
       table->next_global= save_next_global;
       table->next_local= save_next_local;
@@ -556,10 +564,26 @@ static bool mysql_admin_table(THD* thd, 
            HA_ADMIN_NEEDS_ALTER))
       {
         DBUG_PRINT("admin", ("recreating table"));
+        /*
+          Temporary table are always created by current server so they never
+          require upgrade. So we don't need to pre-open them before calling
+          mysql_recreate_table().
+        */
+        DBUG_ASSERT(! table->table->s->tmp_table);
+
         trans_rollback_stmt(thd);
         trans_rollback(thd);
         close_thread_tables(thd);
         thd->mdl_context.release_transactional_locks();
+
+        /*
+          table_list->table has been closed and freed. Do not reference
+          uninitialized data. open_tables() could fail.
+        */
+        table->table= NULL;
+        /* Same applies to MDL ticket. */
+        table->mdl_request.ticket= NULL;
+
         tmp_disable_binlog(thd); // binlogging is done by caller if wanted
         result_code= mysql_recreate_table(thd, table);
         reenable_binlog(thd);
@@ -684,6 +708,15 @@ send_result_message:
       trans_commit(thd);
       close_thread_tables(thd);
       thd->mdl_context.release_transactional_locks();
+
+      /*
+         table_list->table has been closed and freed. Do not reference
+         uninitialized data. open_tables() could fail.
+       */
+      table->table= NULL;
+      /* Same applies to MDL ticket. */
+      table->mdl_request.ticket= NULL;
+
       DEBUG_SYNC(thd, "ha_admin_try_alter");
       protocol->store(STRING_WITH_LEN("note"), system_charset_info);
       protocol->store(STRING_WITH_LEN(
@@ -696,7 +729,9 @@ send_result_message:
                  *save_next_global= table->next_global;
       table->next_local= table->next_global= 0;
       tmp_disable_binlog(thd); // binlogging is done by caller if wanted
-      result_code= mysql_recreate_table(thd, table);
+      /* Don't forget to pre-open temporary tables. */
+      result_code= (open_temporary_tables(thd, table) ||
+                    mysql_recreate_table(thd, table));
       reenable_binlog(thd);
       /*
         mysql_recreate_table() can push OK or ERROR.
@@ -710,14 +745,15 @@ send_result_message:
       trans_commit(thd);
       close_thread_tables(thd);
       thd->mdl_context.release_transactional_locks();
+      /* Clear references to TABLE and MDL_ticket after releasing them. */
       table->table= NULL;
+      table->mdl_request.ticket= NULL;
       if (!result_code) // recreation went ok
       {
-        /* Clear the ticket released above. */
-        table->mdl_request.ticket= NULL;
         DEBUG_SYNC(thd, "ha_admin_open_ltable");
         table->mdl_request.set_type(MDL_SHARED_WRITE);
-        if ((table->table= open_ltable(thd, table, lock_type, 0)))
+        if (!open_temporary_tables(thd, table) &&
+            (table->table= open_n_lock_single_table(thd, table, lock_type, 0)))
         {
           result_code= table->table->file->ha_analyze(thd, check_opt);
           if (result_code == HA_ADMIN_ALREADY_DONE)
@@ -853,8 +889,6 @@ err:
   trans_rollback(thd);
   close_thread_tables(thd);			// Shouldn't be needed
   thd->mdl_context.release_transactional_locks();
-  if (table)
-    table->table=0;
   DBUG_RETURN(TRUE);
 }
 
@@ -890,8 +924,8 @@ bool mysql_assign_to_keycache(THD* thd, 
   mysql_mutex_unlock(&LOCK_global_system_variables);
   check_opt.key_cache= key_cache;
   DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt,
-				"assign_to_keycache", TL_READ_NO_INSERT, 0, 0,
-				0, 0, &handler::assign_to_keycache, 0));
+                                "assign_to_keycache", TL_READ_NO_INSERT, 0, 0,
+                                0, 0, &handler::assign_to_keycache, 0));
 }
 
 
@@ -917,8 +951,8 @@ bool mysql_preload_keys(THD* thd, TABLE_
     outdated information if parallel inserts into cache blocks happen.
   */
   DBUG_RETURN(mysql_admin_table(thd, tables, 0,
-				"preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0,
-				&handler::preload_keys, 0));
+                                "preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0,
+                                &handler::preload_keys, 0));
 }
 
 

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-12-16 10:09:53 +0000
+++ b/sql/sql_base.cc	2010-12-23 16:18:19 +0000
@@ -2557,46 +2557,41 @@ tdc_wait_for_old_version(THD *thd, const
 }
 
 
-/*
-  Open a table.
-
-  SYNOPSIS
-    open_table()
-    thd                 Thread context.
-    table_list          Open first table in list.
-    action       INOUT  Pointer to variable of enum_open_table_action type
-                        which will be set according to action which is
-                        required to remedy problem appeared during attempt
-                        to open table.
-    flags               Bitmap of flags to modify how open works:
-                          MYSQL_OPEN_IGNORE_FLUSH - Open table even if
-                          someone has done a flush or there is a pending
-                          exclusive metadata lock requests against it
-                          (i.e. request high priority metadata lock).
-                          No version number checking is done.
-                          MYSQL_OPEN_TEMPORARY_ONLY - Open only temporary
-                          table not the base table or view.
-                          MYSQL_OPEN_TAKE_UPGRADABLE_MDL - Obtain upgradable
-                          metadata lock for tables on which we are going to
-                          take some kind of write table-level lock.
-
-  IMPLEMENTATION
-    Uses a cache of open tables to find a table not in use.
-
-    If TABLE_LIST::open_strategy is set to OPEN_IF_EXISTS, the table is opened
-    only if it exists. If the open strategy is OPEN_STUB, the underlying table
-    is never opened. In both cases, metadata locks are always taken according
-    to the lock strategy.
+/**
+  Open a base table.
 
-  RETURN
-    TRUE  Open failed. "action" parameter may contain type of action
-          needed to remedy problem before retrying again.
-    FALSE Success. Members of TABLE_LIST structure are filled properly (e.g.
-          TABLE_LIST::table is set for real tables and TABLE_LIST::view is
-          set for views).
+  @param thd            Thread context.
+  @param table_list     Open first table in list.
+  @param mem_root       Temporary MEM_ROOT to be used for
+                        parsing .FRMs for views.
+  @param ot_ctx         Context with flags which modify how open works
+                        and which is used to recover from a failed
+                        open_table() attempt.
+                        Some examples of flags:
+                        MYSQL_OPEN_IGNORE_FLUSH - Open table even if
+                        someone has done a flush. No version number
+                        checking is done.
+                        MYSQL_OPEN_HAS_MDL_LOCK - instead of acquiring
+                        metadata locks rely on that caller already has
+                        appropriate ones.
+
+  Uses a cache of open tables to find a TABLE instance not in use.
+
+  If TABLE_LIST::open_strategy is set to OPEN_IF_EXISTS, the table is
+  opened only if it exists. If the open strategy is OPEN_STUB, the
+  underlying table is never opened. In both cases, metadata locks are
+  always taken according to the lock strategy.
+
+  The function used to open temporary tables, but now it opens base tables
+  only.
+
+  @retval TRUE  Open failed. "action" parameter may contain type of action
+                needed to remedy problem before retrying again.
+  @retval FALSE Success. Members of TABLE_LIST structure are filled properly
+                (e.g.  TABLE_LIST::table is set for real tables and
+                TABLE_LIST::view is set for views).
 */
 
-
 bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
                 Open_table_context *ot_ctx)
 {
@@ -2611,6 +2606,14 @@ bool open_table(THD *thd, TABLE_LIST *ta
   my_hash_value_type hash_value;
   DBUG_ENTER("open_table");
 
+  /*
+    The table must not be opened already. The table can be pre-opened for
+    some statements if it is a temporary table.
+
+    open_temporary_table() must be used to open temporary tables.
+  */
+  DBUG_ASSERT(!table_list->table);
+
   /* an open table operation needs a lot of the stack space */
   if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
     DBUG_RETURN(TRUE);
@@ -2618,66 +2621,13 @@ bool open_table(THD *thd, TABLE_LIST *ta
   if (thd->killed)
     DBUG_RETURN(TRUE);
 
-  key_length= (create_table_def_key(thd, key, table_list, 1) -
-               TMP_TABLE_KEY_EXTRA);
-
-  /*
-    Unless requested otherwise, try to resolve this table in the list
-    of temporary tables of this thread. In MySQL temporary tables
-    are always thread-local and "shadow" possible base tables with the
-    same name. This block implements the behaviour.
-    TODO: move this block into a separate function.
-  */
-  if (table_list->open_type != OT_BASE_ONLY &&
-      ! (flags & MYSQL_OPEN_SKIP_TEMPORARY))
-  {
-    for (table= thd->temporary_tables; table ; table=table->next)
-    {
-      if (table->s->table_cache_key.length == key_length +
-          TMP_TABLE_KEY_EXTRA &&
-	  !memcmp(table->s->table_cache_key.str, key,
-		  key_length + TMP_TABLE_KEY_EXTRA))
-      {
-        /*
-          We're trying to use the same temporary table twice in a query.
-          Right now we don't support this because a temporary table
-          is always represented by only one TABLE object in THD, and
-          it can not be cloned. Emit an error for an unsupported behaviour.
-        */
-	if (table->query_id)
-	{
-          DBUG_PRINT("error",
-                     ("query_id: %lu  server_id: %u  pseudo_thread_id: %lu",
-                      (ulong) table->query_id, (uint) thd->server_id,
-                      (ulong) thd->variables.pseudo_thread_id));
-	  my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
-	  DBUG_RETURN(TRUE);
-	}
-	table->query_id= thd->query_id;
-	thd->thread_specific_used= TRUE;
-        DBUG_PRINT("info",("Using temporary table"));
-        goto reset;
-      }
-    }
-  }
-
-  if (table_list->open_type == OT_TEMPORARY_ONLY ||
-      (flags & MYSQL_OPEN_TEMPORARY_ONLY))
-  {
-    if (table_list->open_strategy == TABLE_LIST::OPEN_NORMAL)
-    {
-      my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
-      DBUG_RETURN(TRUE);
-    }
-    else
-      DBUG_RETURN(FALSE);
-  }
+  key_length= create_table_def_key(thd, key, table_list, 0);
 
   /*
-    The table is not temporary - if we're in pre-locked or LOCK TABLES
-    mode, let's try to find the requested table in the list of pre-opened
-    and locked tables. If the table is not there, return an error - we can't
-    open not pre-opened tables in pre-locked/LOCK TABLES mode.
+    If we're in pre-locked or LOCK TABLES mode, let's try to find the
+    requested table in the list of pre-opened and locked tables. If the
+    table is not there, return an error - we can't open not pre-opened
+    tables in pre-locked/LOCK TABLES mode.
     TODO: move this block into a separate function.
   */
   if (thd->locked_tables_mode &&
@@ -2773,7 +2723,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
     }
     /*
       No table in the locked tables list. In case of explicit LOCK TABLES
-      this can happen if a user did not include the able into the list.
+      this can happen if a user did not include the table into the list.
       In case of pre-locked mode locked tables list is generated automatically,
       so we may only end up here if the table did not exist when
       locked tables list was created.
@@ -2785,10 +2735,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
     DBUG_RETURN(TRUE);
   }
 
-  /*
-    Non pre-locked/LOCK TABLES mode, and the table is not temporary.
-    This is the normal use case.
-  */
+  /* Non pre-locked/LOCK TABLES mode. This is the normal use case. */
 
   if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
   {
@@ -3997,8 +3944,7 @@ recover_from_failed_open(THD *thd)
     case OT_DISCOVER:
       {
         if ((result= lock_table_names(thd, m_failed_table, NULL,
-                                      get_timeout(),
-                                      MYSQL_OPEN_SKIP_TEMPORARY)))
+                                      get_timeout(), 0)))
           break;
 
         tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
@@ -4014,8 +3960,7 @@ recover_from_failed_open(THD *thd)
     case OT_REPAIR:
       {
         if ((result= lock_table_names(thd, m_failed_table, NULL,
-                                      get_timeout(),
-                                      MYSQL_OPEN_SKIP_TEMPORARY)))
+                                      get_timeout(), 0)))
           break;
 
         tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
@@ -4348,10 +4293,32 @@ open_and_process_table(THD *thd, LEX *le
                         tables->db, tables->table_name, tables)); //psergey: invalid read of size 1 here
   (*counter)++;
 
-  /* Not a placeholder: must be a base table or a view. Let us open it. */
-  DBUG_ASSERT(!tables->table);
+  /* Not a placeholder: must be a base/temporary table or a view. Let us open it. */
 
-  if (tables->prelocking_placeholder)
+  if (tables->table)
+  {
+    /*
+      If this TABLE_LIST object has an associated open TABLE object
+      (TABLE_LIST::table is not NULL), that TABLE object must be a pre-opened
+      temporary table.
+    */
+    DBUG_ASSERT(is_temporary_table(tables));
+  }
+  else if (tables->open_type == OT_TEMPORARY_ONLY)
+  {
+    /*
+      OT_TEMPORARY_ONLY means that we are in CREATE TEMPORARY TABLE statement.
+      Also such table list element can't correspond to prelocking placeholder
+      or to underlying table of merge table.
+      So existing temporary table should have been preopened by this moment
+      and we can simply continue without trying to open temporary or base
+      table.
+    */
+    DBUG_ASSERT(tables->open_strategy);
+    DBUG_ASSERT(!tables->prelocking_placeholder);
+    DBUG_ASSERT(!tables->parent_l);
+  }
+  else if (tables->prelocking_placeholder)
   {
     /*
       For the tables added by the pre-locking code, attempt to open
@@ -4361,12 +4328,53 @@ open_and_process_table(THD *thd, LEX *le
     */
     No_such_table_error_handler no_such_table_handler;
     thd->push_internal_handler(&no_such_table_handler);
-    error= open_table(thd, tables, new_frm_mem, ot_ctx);
+
+    /*
+      We're opening a table from the prelocking list.
+
+      Since this table list element might have been added after pre-opening
+      of temporary tables we have to try to open temporary table for it.
+
+      We can't simply skip this table list element and postpone opening of
+      temporary tabletill the execution of substatement for several reasons:
+      - Temporary table can be a MERGE table with base underlying tables,
+        so its underlying tables has to be properly open and locked at
+        prelocking stage.
+      - Temporary table can be a MERGE table and we might be in PREPARE
+        phase for a prepared statement. In this case it is important to call
+        HA_ATTACH_CHILDREN for all merge children.
+        This is necessary because merge children remember "TABLE_SHARE ref type"
+        and "TABLE_SHARE def version" in the HA_ATTACH_CHILDREN operation.
+        If HA_ATTACH_CHILDREN is not called, these attributes are not set.
+        Then, during the first EXECUTE, those attributes need to be updated.
+        That would cause statement re-preparing (because changing those
+        attributes during EXECUTE is caught by THD::m_reprepare_observer).
+        The problem is that since those attributes are not set in merge
+        children, another round of PREPARE will not help.
+    */
+    error= open_temporary_table(thd, tables);
+
+    if (!error && !tables->table)
+      error= open_table(thd, tables, new_frm_mem, ot_ctx);
+
     thd->pop_internal_handler();
     safe_to_ignore_table= no_such_table_handler.safely_trapped_errors();
   }
   else
-    error= open_table(thd, tables, new_frm_mem, ot_ctx);
+  {
+    if (tables->parent_l)
+    {
+      /*
+        Even if we are opening table not from the prelocking list we
+        still might need to look for a temporary table if this table
+        list element corresponds to underlying table of a merge table.
+      */
+      error= open_temporary_table(thd, tables);
+    }
+
+    if (!error && !tables->table)
+      error= open_table(thd, tables, new_frm_mem, ot_ctx);
+  }
 
   free_root(new_frm_mem, MYF(MY_KEEP_PREALLOC));
 
@@ -4454,6 +4462,7 @@ open_and_process_table(THD *thd, LEX *le
       goto end;
   }
 
+  /* Set appropriate TABLE::lock_type. */
   if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode)
   {
     if (tables->lock_type == TL_WRITE_DEFAULT)
@@ -4464,6 +4473,8 @@ open_and_process_table(THD *thd, LEX *le
     else
       tables->table->reginfo.lock_type= tables->lock_type;
   }
+
+  /* Copy grant information from TABLE_LIST instance to TABLE one. */
   tables->table->grant= tables->grant;
 
   /* Check and update metadata version of a base table. */
@@ -4551,18 +4562,17 @@ lock_table_names(THD *thd,
   for (table= tables_start; table && table != tables_end;
        table= table->next_global)
   {
-    if (table->mdl_request.type >= MDL_SHARED_NO_WRITE &&
-        !(table->open_type == OT_TEMPORARY_ONLY ||
-          (flags & MYSQL_OPEN_TEMPORARY_ONLY) ||
-          (table->open_type != OT_BASE_ONLY &&
-           ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
-           find_temporary_table(thd, table))))
+    if (table->mdl_request.type < MDL_SHARED_NO_WRITE ||
+        table->open_type == OT_TEMPORARY_ONLY ||
+        (table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table)))
     {
-      if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
-          schema_set.insert(table))
-        return TRUE;
-      mdl_requests.push_front(&table->mdl_request);
+      continue;
     }
+
+    if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) && schema_set.insert(table))
+      return TRUE;
+
+    mdl_requests.push_front(&table->mdl_request);
   }
 
   if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
@@ -4630,35 +4640,34 @@ open_tables_check_upgradable_mdl(THD *th
   for (table= tables_start; table && table != tables_end;
        table= table->next_global)
   {
-    if (table->mdl_request.type >= MDL_SHARED_NO_WRITE &&
-        !(table->open_type == OT_TEMPORARY_ONLY ||
-          (flags & MYSQL_OPEN_TEMPORARY_ONLY) ||
-          (table->open_type != OT_BASE_ONLY &&
-           ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
-           find_temporary_table(thd, table))))
-    {
-      /*
-        We don't need to do anything about the found TABLE instance as it
-        will be handled later in open_tables(), we only need to check that
-        an upgradable lock is already acquired. When we enter LOCK TABLES
-        mode, SNRW locks are acquired before all other locks. So if under
-        LOCK TABLES we find that there is TABLE instance with upgradeable
-        lock, all other instances of TABLE for the same table will have the
-        same ticket.
-
-        Note that this works OK even for CREATE TABLE statements which
-        request X type of metadata lock. This is because under LOCK TABLES
-        such statements don't create the table but only check if it exists
-        or, in most complex case, only insert into it.
-        Thus SNRW lock should be enough.
-
-        Note that find_table_for_mdl_upgrade() will report an error if
-        no suitable ticket is found.
-      */
-      if (!find_table_for_mdl_upgrade(thd->open_tables, table->db,
-                                      table->table_name, FALSE))
-        return TRUE;
+    if (table->mdl_request.type < MDL_SHARED_NO_WRITE ||
+        table->open_type == OT_TEMPORARY_ONLY ||
+        (table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table)))
+    {
+      continue;
     }
+
+    /*
+      We don't need to do anything about the found TABLE instance as it
+      will be handled later in open_tables(), we only need to check that
+      an upgradable lock is already acquired. When we enter LOCK TABLES
+      mode, SNRW locks are acquired before all other locks. So if under
+      LOCK TABLES we find that there is TABLE instance with upgradeable
+      lock, all other instances of TABLE for the same table will have the
+      same ticket.
+
+      Note that this works OK even for CREATE TABLE statements which
+      request X type of metadata lock. This is because under LOCK TABLES
+      such statements don't create the table but only check if it exists
+      or, in most complex case, only insert into it.
+      Thus SNRW lock should be enough.
+
+      Note that find_table_for_mdl_upgrade() will report an error if
+      no suitable ticket is found.
+    */
+    if (!find_table_for_mdl_upgrade(thd->open_tables, table->db,
+                                    table->table_name, FALSE))
+      return TRUE;
   }
 
   return FALSE;
@@ -4837,6 +4846,10 @@ restart:
           if (ot_ctx.recover_from_failed_open(thd))
             goto err;
 
+          /* Re-open temporary tables after close_tables_for_reopen(). */
+          if (open_temporary_tables(thd, *start))
+            goto err;
+
           error= FALSE;
           goto restart;
         }
@@ -4883,6 +4896,10 @@ restart:
             if (ot_ctx.recover_from_failed_open(thd))
               goto err;
 
+            /* Re-open temporary tables after close_tables_for_reopen(). */
+            if (open_temporary_tables(thd, *start))
+              goto err;
+
             error= FALSE;
             goto restart;
           }
@@ -4913,6 +4930,11 @@ restart:
   {
     TABLE *tbl= tables->table;
 
+    /*
+      NOTE: temporary merge tables should be processed here too, because
+      a temporary merge table can be based on non-temporary tables.
+    */
+
     /* Schema tables may not have a TABLE object here. */
     if (tbl && tbl->file->ht->db_type == DB_TYPE_MRG_MYISAM)
     {
@@ -5950,6 +5972,134 @@ static void update_field_dependencies(TH
 }
 
 
+/**
+  Find a temporary table specified by TABLE_LIST instance in the cache and
+  prepare its TABLE instance for use.
+
+  This function tries to resolve this table in the list of temporary tables
+  of this thread. Temporary tables are thread-local and "shadow" base
+  tables with the same name.
+
+  @note In most cases one should use open_temporary_tables() instead
+        of this call.
+
+  @note One should finalize process of opening temporary table for table
+        list element by calling open_and_process_table(). This function
+        is responsible for table version checking and handling of merge
+        tables.
+
+  @note We used to check global_read_lock before opening temporary tables.
+        However, that limitation was artificial and is removed now.
+
+  @return Error status.
+    @retval FALSE On success. If a temporary table exists for the given
+                  key, tl->table is set.
+    @retval TRUE  On error. my_error() has been called.
+*/
+
+bool open_temporary_table(THD *thd, TABLE_LIST *tl)
+{
+  DBUG_ENTER("open_temporary_table");
+  DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db, tl->table_name));
+
+  /*
+    Code in open_table() assumes that TABLE_LIST::table can
+    be non-zero only for pre-opened temporary tables.
+  */
+  DBUG_ASSERT(tl->table == NULL);
+
+  /*
+    This function should not be called for cases when derived or I_S
+    tables can be met since table list elements for such tables can
+    have invalid db or table name.
+    Instead open_temporary_tables() should be used.
+  */
+  DBUG_ASSERT(!tl->derived && !tl->schema_table);
+
+  if (tl->open_type == OT_BASE_ONLY)
+  {
+    DBUG_PRINT("info", ("skip_temporary is set"));
+    DBUG_RETURN(FALSE);
+  }
+
+  TABLE *table= find_temporary_table(thd, tl);
+
+  if (!table)
+  {
+    if (tl->open_type == OT_TEMPORARY_ONLY &&
+        tl->open_strategy == TABLE_LIST::OPEN_NORMAL)
+    {
+      my_error(ER_NO_SUCH_TABLE, MYF(0), tl->db, tl->table_name);
+      DBUG_RETURN(TRUE);
+    }
+    DBUG_RETURN(FALSE);
+  }
+
+  if (table->query_id)
+  {
+    /*
+      We're trying to use the same temporary table twice in a query.
+      Right now we don't support this because a temporary table is always
+      represented by only one TABLE object in THD, and it can not be
+      cloned. Emit an error for an unsupported behaviour.
+    */
+
+    DBUG_PRINT("error",
+               ("query_id: %lu  server_id: %u  pseudo_thread_id: %lu",
+                (ulong) table->query_id, (uint) thd->server_id,
+                (ulong) thd->variables.pseudo_thread_id));
+    my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
+    DBUG_RETURN(TRUE);
+  }
+
+  table->query_id= thd->query_id;
+  thd->thread_specific_used= TRUE;
+
+  tl->updatable= 1; // It is not derived table nor non-updatable VIEW.
+  tl->table= table;
+
+  table->init(thd, tl);
+
+  DBUG_PRINT("info", ("Using temporary table"));
+  DBUG_RETURN(FALSE);
+}
+
+
+/**
+  Pre-open temporary tables corresponding to table list elements.
+
+  @note One should finalize process of opening temporary tables
+        by calling open_tables(). This function is responsible
+        for table version checking and handling of merge tables.
+
+  @return Error status.
+    @retval FALSE On success. If a temporary tables exists for the
+                  given element, tl->table is set.
+    @retval TRUE  On error. my_error() has been called.
+*/
+
+bool open_temporary_tables(THD *thd, TABLE_LIST *tl_list)
+{
+  DBUG_ENTER("open_temporary_tables");
+
+  for (TABLE_LIST *tl= tl_list; tl; tl= tl->next_global)
+  {
+    if (tl->derived || tl->schema_table)
+    {
+      /*
+        Derived and I_S tables will be handled by a later call to open_tables().
+      */
+      continue;
+    }
+
+    if (open_temporary_table(thd, tl))
+      DBUG_RETURN(TRUE);
+  }
+
+  DBUG_RETURN(FALSE);
+}
+
+
 /*
   Find a field by name in a view that uses merge algorithm.
 

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	2010-11-23 22:37:59 +0000
+++ b/sql/sql_base.h	2010-12-23 16:18:19 +0000
@@ -93,7 +93,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST 
 /* mysql_lock_tables() and open_table() flags bits */
 #define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK      0x0001
 #define MYSQL_OPEN_IGNORE_FLUSH                 0x0002
-#define MYSQL_OPEN_TEMPORARY_ONLY               0x0004
+/* MYSQL_OPEN_TEMPORARY_ONLY (0x0004) is not used anymore. */
 #define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY      0x0008
 #define MYSQL_LOCK_LOG_TABLE                    0x0010
 /**
@@ -106,8 +106,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST 
   a new instance of the table.
 */
 #define MYSQL_OPEN_GET_NEW_TABLE                0x0040
-/** Don't look up the table in the list of temporary tables. */
-#define MYSQL_OPEN_SKIP_TEMPORARY               0x0080
+/* 0x0080 used to be MYSQL_OPEN_SKIP_TEMPORARY */
 /** Fail instead of waiting when conficting metadata lock is discovered. */
 #define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT         0x0100
 /** Open tables using MDL_SHARED lock instead of one specified in parser. */
@@ -139,7 +138,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST 
                             MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\
                             MYSQL_LOCK_IGNORE_TIMEOUT |\
                             MYSQL_OPEN_GET_NEW_TABLE |\
-                            MYSQL_OPEN_SKIP_TEMPORARY |\
                             MYSQL_OPEN_HAS_MDL_LOCK)
 
 bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
@@ -269,6 +267,8 @@ void close_temporary_table(THD *thd, TAB
 void close_temporary(TABLE *table, bool free_share, bool delete_table);
 bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
 			    const char *table_name);
+bool open_temporary_tables(THD *thd, TABLE_LIST *tl_list);
+bool open_temporary_table(THD *thd, TABLE_LIST *tl);
 bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
 
 /* Functions to work with system tables. */
@@ -572,6 +572,16 @@ private:
 
 
 /**
+  Check if a TABLE_LIST instance represents a pre-opened temporary table.
+*/
+
+inline bool is_temporary_table(TABLE_LIST *tl)
+{
+  return tl->table ? (tl->table->s->tmp_table != NO_TMP_TABLE) : FALSE;
+}
+
+
+/**
   This internal handler is used to trap ER_NO_SUCH_TABLE.
 */
 

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-12-20 10:28:06 +0000
+++ b/sql/sql_class.h	2010-12-23 16:18:19 +0000
@@ -3727,6 +3727,18 @@ public:
 #define CF_CAN_GENERATE_ROW_EVENTS (1U << 9)
 
 /**
+  Identifies statements which may deal with temporary tables and for which
+  temporary tables should be pre-opened to simplify privilege checks.
+*/
+#define CF_PREOPEN_TMP_TABLES   (1U << 10)
+
+/**
+  Identifies statements for which open handlers should be closed in the
+  beginning of the statement.
+*/
+#define CF_HA_CLOSE             (1U << 11)
+
+/**
   Identifies statements that can directly update a rpl info table.
 */
 #define CF_WRITE_RPL_INFO_COMMAND (1U << 12)

=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc	2010-12-10 12:52:55 +0000
+++ b/sql/sql_db.cc	2010-12-23 16:18:19 +0000
@@ -817,8 +817,7 @@ bool mysql_rm_db(THD *thd,char *db,bool 
   }
 
   /* Lock all tables and stored routines about to be dropped. */
-  if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
-                       MYSQL_OPEN_SKIP_TEMPORARY) ||
+  if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout, 0) ||
       lock_db_routines(thd, db))
     goto exit;
 

=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc	2010-11-18 16:34:56 +0000
+++ b/sql/sql_handler.cc	2010-12-23 16:18:19 +0000
@@ -288,11 +288,13 @@ bool mysql_ha_open(THD *thd, TABLE_LIST 
   DBUG_ASSERT(! hash_tables->table);
 
   /*
-    We use open_tables() here, rather than, say,
-    open_ltable() or open_table() because we would like to be able
-    to open a temporary table.
+    TODO/FIXME: In the upcoming patch we somehow should handle
+                situation with privilege check for temporary table.
   */
-  error= open_tables(thd, &hash_tables, &counter, 0);
+  error= open_temporary_tables(thd, hash_tables);
+
+  if (!error)
+    error= open_tables(thd, &hash_tables, &counter, 0);
 
   if (! error &&
       ! (hash_tables->table->file->ha_table_flags() & HA_CAN_SQL_HANDLER))

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2010-12-22 13:23:59 +0000
+++ b/sql/sql_insert.cc	2010-12-23 16:18:19 +0000
@@ -3785,8 +3785,7 @@ static TABLE *create_table_from_items(TH
       }
       else
       {
-        Open_table_context ot_ctx(thd, MYSQL_OPEN_TEMPORARY_ONLY);
-        if (open_table(thd, create_table, thd->mem_root, &ot_ctx))
+        if (open_temporary_table(thd, create_table))
         {
           /*
             This shouldn't happen as creation of temporary table should make
@@ -3796,7 +3795,9 @@ static TABLE *create_table_from_items(TH
           drop_temporary_table(thd, create_table, NULL);
         }
         else
+        {
           table= create_table->table;
+        }
       }
     }
     if (!table)                                   // open failed

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-12-17 11:28:59 +0000
+++ b/sql/sql_parse.cc	2010-12-23 16:18:19 +0000
@@ -23,7 +23,7 @@
                               // set_handler_table_locks,
                               // lock_global_read_lock,
                               // make_global_read_lock_block_commit
-#include "sql_base.h"         // find_temporary_tablesx
+#include "sql_base.h"         // find_temporary_table
 #include "sql_cache.h"        // QUERY_CACHE_FLAGS_SIZE, query_cache_*
 #include "sql_show.h"         // mysqld_list_*, mysqld_show_*,
                               // calc_sum_of_all_status
@@ -43,7 +43,6 @@
 #include "sql_table.h"        // mysql_create_like_table,
                               // mysql_create_table,
                               // mysql_alter_table,
-                              // mysql_recreate_table,
                               // mysql_backup_table,
                               // mysql_restore_table
 #include "sql_reload.h"       // reload_acl_and_cache
@@ -446,6 +445,60 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_CREATE_SERVER]=      CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_ALTER_SERVER]=       CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_DROP_SERVER]=        CF_AUTO_COMMIT_TRANS;
+
+  /*
+    The following statements can deal with temporary tables,
+    so temporary tables should be pre-opened for those statements to
+    simplify privilege checking.
+
+    There are other statements that deal with temporary tables and open
+    them, but which are not listed here. The thing is that the order of
+    pre-opening temporary tables for those statements is somewhat custom.
+  */
+  sql_command_flags[SQLCOM_CREATE_TABLE]|=    CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CREATE_INDEX]|=    CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_ALTER_TABLE]|=     CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_TRUNCATE]|=        CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_LOAD]|=            CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_DROP_INDEX]|=      CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CREATE_VIEW]|=     CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_UPDATE]|=          CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_UPDATE_MULTI]|=    CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_INSERT]|=          CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_INSERT_SELECT]|=   CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_DELETE]|=          CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_DELETE_MULTI]|=    CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_REPLACE]|=         CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_REPLACE_SELECT]|=  CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_SELECT]|=          CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_SET_OPTION]|=      CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_DO]|=              CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CALL]|=            CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CHECKSUM]|=        CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_ANALYZE]|=         CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CHECK]|=           CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_OPTIMIZE]|=        CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_REPAIR]|=          CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_PRELOAD_KEYS]|=    CF_PREOPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_PREOPEN_TMP_TABLES;
+
+  /*
+    DDL statements that should start with closing opened handlers.
+
+    We use this flag only for statements for which open HANDLERs
+    have to be closed before emporary tables are pre-opened.
+  */
+  sql_command_flags[SQLCOM_CREATE_TABLE]|=    CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_ALTER_TABLE]|=     CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_TRUNCATE]|=        CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_REPAIR]|=          CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_OPTIMIZE]|=        CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_ANALYZE]|=         CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_CHECK]|=           CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_CREATE_INDEX]|=    CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_DROP_INDEX]|=      CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_PRELOAD_KEYS]|=    CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|=  CF_HA_CLOSE;
 }
 
 bool sqlcom_can_generate_row_events(const THD *thd)
@@ -1203,6 +1256,9 @@ bool dispatch_command(enum enum_server_c
     thd->set_query(fields, query_length);
     general_log_print(thd, command, "%s %s", table_list.table_name, fields);
 
+    if (open_temporary_tables(thd, &table_list))
+      break;
+
     if (check_table_access(thd, SELECT_ACL, &table_list,
                            TRUE, UINT_MAX, FALSE))
       break;
@@ -2024,6 +2080,31 @@ mysql_execute_command(THD *thd)
     DEBUG_SYNC(thd,"before_execute_sql_command");
 #endif
 
+  /*
+    Close tables open by HANDLERs before executing DDL statement
+    which is going to affect those tables.
+
+    This should happen before temporary tables are pre-opened as
+    otherwise we will get errors about attempt to re-open tables
+    if table to be changed is open through HANDLER.
+
+    Note that even although this is done before any privilege
+    checks there is no security problem here as closing open
+    HANDLER doesn't require any privileges anyway.
+  */
+  if (sql_command_flags[lex->sql_command] & CF_HA_CLOSE)
+    mysql_ha_rm_tables(thd, all_tables);
+
+  /*
+    Pre-open temporary tables to simplify privilege checking
+    for statements which need this.
+  */
+  if (sql_command_flags[lex->sql_command] & CF_PREOPEN_TMP_TABLES)
+  {
+    if (open_temporary_tables(thd, all_tables))
+      goto error;
+  }
+
   switch (lex->sql_command) {
 
   case SQLCOM_SHOW_EVENTS:
@@ -2325,6 +2406,19 @@ case SQLCOM_PREPARE:
       goto end_with_restore_list;
     }
 
+    /*
+      Pre-open temporary tables from UNION clause to simplify privilege
+      checking for them.
+    */
+    if (lex->create_info.merge_list.elements)
+    {
+      if (open_temporary_tables(thd, lex->create_info.merge_list.first))
+      {
+        res= 1;
+        goto end_with_restore_list;
+      }
+    }
+
     if ((res= create_table_precheck(thd, select_tables, create_table)))
       goto end_with_restore_list;
 
@@ -2365,9 +2459,6 @@ case SQLCOM_PREPARE:
     }
 #endif
 
-    /* Close any open handlers for the table. */
-    mysql_ha_rm_tables(thd, create_table);
-
     if (select_lex->item_list.elements)		// With select
     {
       select_result *result;
@@ -2669,6 +2760,13 @@ end_with_restore_list:
       else
       {
         /*
+          Temporary tables should be opened for SHOW CREATE TABLE, but not
+          for SHOW CREATE VIEW.
+        */
+        if (open_temporary_tables(thd, all_tables))
+          goto error;
+
+        /*
           The fact that check_some_access() returned FALSE does not mean that
           access is granted. We need to check if first_table->grant.privilege
           contains any table-specific privilege.
@@ -3146,6 +3244,20 @@ end_with_restore_list:
     thd->mdl_context.release_transactional_locks();
     if (res)
       goto error;
+
+    /*
+      Here we have to pre-open temporary tables for LOCK TABLES.
+
+      CF_PREOPEN_TMP_TABLES is not set for this SQL statement simply
+      because LOCK TABLES calls close_thread_tables() as a first thing
+      (it's called from unlock_locked_tables() above). So even if
+      CF_PREOPEN_TMP_TABLES was set and the tables would be pre-opened
+      in a usual way, they would have been closed.
+    */
+
+    if (open_temporary_tables(thd, all_tables))
+      goto error;
+
     if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
                            FALSE, UINT_MAX, FALSE))
       goto error;
@@ -4880,6 +4992,12 @@ static bool check_show_access(THD *thd, 
 
     DBUG_ASSERT(dst_table);
 
+    /*
+      TODO/FIXME: In the upcoming patch we somehow should handle
+                  situation when table in question is a temporary
+                  table.
+    */
+
     if (check_access(thd, SELECT_ACL, dst_table->db,
                      &dst_table->grant.privilege,
                      &dst_table->grant.m_internal,
@@ -4978,10 +5096,10 @@ check_table_access(THD *thd, ulong requi
 
     DBUG_PRINT("info", ("derived: %d  view: %d", tables->derived != 0,
                         tables->view != 0));
-    if (tables->is_anonymous_derived_table() ||
-        (tables->table && tables->table->s &&
-         (int)tables->table->s->tmp_table))
+
+    if (tables->is_anonymous_derived_table())
       continue;
+
     thd->security_ctx= sctx;
 
     if (check_access(thd, want_access, tables->get_db_name(),

=== modified file 'sql/sql_partition_admin.cc'
--- a/sql/sql_partition_admin.cc	2010-12-03 10:05:56 +0000
+++ b/sql/sql_partition_admin.cc	2010-12-23 16:18:19 +0000
@@ -20,7 +20,6 @@
 #include "sql_cmd.h"                        // Sql_cmd
 #include "sql_alter.h"                      // Sql_cmd_alter_table
 #include "sql_partition.h"                  // struct partition_info, etc.
-#include "sql_handler.h"                    // mysql_ha_rm_tables
 #include "sql_base.h"                       // open_and_lock_tables, etc
 #include "debug_sync.h"                     // DEBUG_SYNC
 #include "sql_truncate.h"                   // mysql_truncate_table,
@@ -492,9 +491,6 @@ bool Sql_cmd_alter_table_exchange_partit
 
   partition_name= alter_info->partition_names.head();
 
-  /* Clear open tables from the threads table handler cache */
-  mysql_ha_rm_tables(thd, table_list);
-
   /* Don't allow to exchange with log table */
   swap_table_list= table_list->next_local;
   if (check_if_log_table(swap_table_list->db_length, swap_table_list->db,

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2010-12-17 11:28:59 +0000
+++ b/sql/sql_prepare.cc	2010-12-23 16:18:19 +0000
@@ -105,6 +105,7 @@ When one supplies long data for a placeh
 #include "sp_head.h"
 #include "sp.h"
 #include "sp_cache.h"
+#include "sql_handler.h"  // mysql_ha_rm_tables
 #include "probes_mysql.h"
 #ifdef EMBEDDED_LIBRARY
 /* include MYSQL_BIND headers */
@@ -1715,6 +1716,14 @@ static bool mysql_test_create_table(Prep
   TABLE_LIST *create_table= lex->query_tables;
   TABLE_LIST *tables= lex->create_last_non_select_table->next_global;
 
+  if (lex->create_info.merge_list.elements)
+  {
+    if (open_temporary_tables(thd, lex->create_info.merge_list.first))
+    {
+      DBUG_RETURN(TRUE);
+    }
+  }
+
   if (create_table_precheck(thd, tables, create_table))
     DBUG_RETURN(TRUE);
 
@@ -1964,6 +1973,19 @@ static bool check_prepared_statement(Pre
   if (tables)
     thd->warning_info->opt_clear_warning_info(thd->query_id);
 
+  if (sql_command_flags[sql_command] & CF_HA_CLOSE)
+    mysql_ha_rm_tables(thd, tables);
+
+  /*
+    Open temporary tables that are known now. Temporary tables added by
+    prelocking will be opened afterwards (during open_tables()).
+  */
+  if (sql_command_flags[sql_command] & CF_PREOPEN_TMP_TABLES)
+  {
+    if (open_temporary_tables(thd, tables))
+      goto error;
+  }
+
   switch (sql_command) {
   case SQLCOM_REPLACE:
   case SQLCOM_INSERT:

=== modified file 'sql/sql_rename.cc'
--- a/sql/sql_rename.cc	2010-11-18 16:34:56 +0000
+++ b/sql/sql_rename.cc	2010-12-23 16:18:19 +0000
@@ -139,8 +139,7 @@ bool mysql_rename_tables(THD *thd, TABLE
     }
   }
 
-  if (lock_table_names(thd, table_list, 0, thd->variables.lock_wait_timeout,
-                       MYSQL_OPEN_SKIP_TEMPORARY))
+  if (lock_table_names(thd, table_list, 0, thd->variables.lock_wait_timeout, 0))
     goto err;
 
   for (ren_table= table_list; ren_table; ren_table= ren_table->next_local)

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2010-12-21 15:27:40 +0000
+++ b/sql/sql_show.cc	2010-12-23 16:18:19 +0000
@@ -3028,11 +3028,18 @@ fill_schema_show_cols_or_idxs(THD *thd, 
     SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' 
   */
   lex->sql_command= SQLCOM_SHOW_FIELDS;
-  res= open_normal_and_derived_tables(thd, show_table_list,
-                                      (MYSQL_OPEN_IGNORE_FLUSH |
-                                       MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
-                                       (can_deadlock ?
-                                        MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
+
+  res= open_temporary_tables(thd, show_table_list);
+
+  if (!res)
+  {
+    res= open_normal_and_derived_tables(thd, show_table_list,
+                                        (MYSQL_OPEN_IGNORE_FLUSH |
+                                         MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
+                                         (can_deadlock ?
+                                          MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
+  }
+
   lex->sql_command= save_sql_command;
 
   DEBUG_SYNC(thd, "after_open_table_ignore_flush");

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-12-17 18:43:38 +0000
+++ b/sql/sql_table.cc	2010-12-23 16:18:19 +0000
@@ -2058,8 +2058,8 @@ bool mysql_rm_table(THD *thd,TABLE_LIST 
   {
     if (!thd->locked_tables_mode)
     {
-      if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
-                           MYSQL_OPEN_SKIP_TEMPORARY))
+      if (lock_table_names(thd, tables, NULL,
+                           thd->variables.lock_wait_timeout, 0))
         DBUG_RETURN(true);
       for (table= tables; table; table= table->next_local)
         tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
@@ -4810,6 +4810,7 @@ bool mysql_create_like_table(THD* thd, T
         String query(buf, sizeof(buf), system_charset_info);
         query.length(0);  // Have to zero it since constructor doesn't
         Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
+        bool new_table= FALSE; // Whether newly created table is open.
 
         /*
           The condition avoids a crash as described in BUG#48506. Other
@@ -4818,14 +4819,20 @@ bool mysql_create_like_table(THD* thd, T
         */
         if (!table->view)
         {
-          /*
-            Here we open the destination table, on which we already have
-            exclusive metadata lock. This is needed for store_create_info()
-            to work. The table will be closed by close_thread_table() at
-            the end of this branch.
-          */
-          if (open_table(thd, table, thd->mem_root, &ot_ctx))
-            goto err;
+          if (!table->table)
+          {
+            /*
+              In order for store_create_info() to work we need to open
+              destination table if it is not already open (i.e. if it
+              has not existed before). We don't need acquire metadata
+              lock in order to do this as we already hold exclusive
+              lock on this table. The table will be closed by
+              close_thread_table() at the end of this branch.
+            */
+            if (open_table(thd, table, thd->mem_root, &ot_ctx))
+              goto err;
+            new_table= TRUE;
+          }
 
           int result __attribute__((unused))=
             store_create_info(thd, table, &query,
@@ -4835,13 +4842,16 @@ bool mysql_create_like_table(THD* thd, T
           if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
             goto err;
 
-          DBUG_ASSERT(thd->open_tables == table->table);
-          /*
-            When opening the table, we ignored the locked tables
-            (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table without
-            risking to close some locked table.
-          */
-          close_thread_table(thd, &thd->open_tables);
+          if (new_table)
+          {
+            DBUG_ASSERT(thd->open_tables == table->table);
+            /*
+              When opening the table, we ignored the locked tables
+              (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table
+              without risking to close some locked table.
+            */
+            close_thread_table(thd, &thd->open_tables);
+          }
         }
       }
       else                                      // Case 1
@@ -4864,9 +4874,9 @@ err:
 static int
 mysql_discard_or_import_tablespace(THD *thd,
                                    TABLE_LIST *table_list,
-                                   enum tablespace_op_type tablespace_op)
+                                   Alter_info *alter_info)
 {
-  TABLE *table;
+  Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info);
   my_bool discard;
   int error;
   DBUG_ENTER("mysql_discard_or_import_tablespace");
@@ -4878,21 +4888,30 @@ mysql_discard_or_import_tablespace(THD *
 
   thd_proc_info(thd, "discard_or_import_tablespace");
 
-  discard= test(tablespace_op == DISCARD_TABLESPACE);
+  discard= test(alter_info->tablespace_op == DISCARD_TABLESPACE);
 
  /*
    We set this flag so that ha_innobase::open and ::external_lock() do
    not complain when we lock the table
  */
   thd->tablespace_op= TRUE;
+  /*
+    Adjust values of table-level and metadata which was set in parser
+    for the case general ALTER TABLE.
+  */
   table_list->mdl_request.set_type(MDL_SHARED_WRITE);
-  if (!(table=open_ltable(thd, table_list, TL_WRITE, 0)))
+  table_list->lock_type= TL_WRITE;
+  /* Do not open views. */
+  table_list->required_type= FRMTYPE_TABLE;
+
+  if (open_and_lock_tables(thd, table_list, FALSE, 0,
+                           &alter_prelocking_strategy))
   {
     thd->tablespace_op=FALSE;
     DBUG_RETURN(-1);
   }
 
-  error= table->file->ha_discard_or_import_tablespace(discard);
+  error= table_list->table->file->ha_discard_or_import_tablespace(discard);
 
   thd_proc_info(thd, "end");
 
@@ -4923,7 +4942,7 @@ err:
     DBUG_RETURN(0);
   }
 
-  table->file->print_error(error, MYF(0));
+  table_list->table->file->print_error(error, MYF(0));
 
   DBUG_RETURN(-1);
 }
@@ -5945,13 +5964,11 @@ bool mysql_alter_table(THD *thd,char *ne
   build_table_filename(reg_path, sizeof(reg_path) - 1, db, table_name, reg_ext, 0);
   build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
 
-  mysql_ha_rm_tables(thd, table_list);
-
   /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
   if (alter_info->tablespace_op != NO_TABLESPACE_OP)
     /* Conditionally writes to binlog. */
     DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
-						   alter_info->tablespace_op));
+                                                   alter_info));
 
   /*
     Code below can handle only base tables so ensure that we won't open a view.
@@ -6563,14 +6580,12 @@ bool mysql_alter_table(THD *thd,char *ne
   {
     if (table->s->tmp_table)
     {
-      Open_table_context ot_ctx(thd, (MYSQL_OPEN_IGNORE_FLUSH |
-                                      MYSQL_LOCK_IGNORE_TIMEOUT));
       TABLE_LIST tbl;
       bzero((void*) &tbl, sizeof(tbl));
       tbl.db= new_db;
       tbl.table_name= tbl.alias= tmp_name;
       /* Table is in thd->temporary_tables */
-      (void) open_table(thd, &tbl, thd->mem_root, &ot_ctx);
+      (void) open_temporary_table(thd, &tbl);
       new_table= tbl.table;
     }
     else
@@ -7286,13 +7301,6 @@ bool mysql_recreate_table(THD *thd, TABL
 
   DBUG_ENTER("mysql_recreate_table");
   DBUG_ASSERT(!table_list->next_global);
-  /*
-    table_list->table has been closed and freed. Do not reference
-    uninitialized data. open_tables() could fail.
-  */
-  table_list->table= NULL;
-  /* Same applies to MDL ticket. */
-  table_list->mdl_request.ticket= NULL;
   /* Set lock type which is appropriate for ALTER TABLE. */
   table_list->lock_type= TL_READ_NO_INSERT;
   /* Same applies to MDL request. */
@@ -7327,16 +7335,40 @@ bool mysql_checksum_table(THD *thd, TABL
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
+  /*
+    Close all temporary tables which were pre-open to simplify
+    privilege checking. Clear all references to closed tables.
+  */
+  close_thread_tables(thd);
+  for (table= tables; table; table= table->next_local)
+    table->table= NULL;
+
   /* Open one table after the other to keep lock time as short as possible. */
   for (table= tables; table; table= table->next_local)
   {
     char table_name[NAME_LEN*2+2];
     TABLE *t;
+    TABLE_LIST *save_next_global;
 
     strxmov(table_name, table->db ,".", table->table_name, NullS);
 
-    t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0);
-    thd->clear_error();			// these errors shouldn't get client
+    /* Remember old 'next' pointer and break the list.  */
+    save_next_global= table->next_global;
+    table->next_global= NULL;
+    table->lock_type= TL_READ;
+    /* Allow to open real tables only. */
+    table->required_type= FRMTYPE_TABLE;
+
+    if (open_temporary_tables(thd, table) ||
+        open_and_lock_tables(thd, table, FALSE, 0))
+    {
+      t= NULL;
+      thd->clear_error();     // these errors shouldn't get client
+    }
+    else
+      t= table->table;
+
+    table->next_global= save_next_global;
 
     protocol->prepare_for_resend();
     protocol->store(table_name, system_charset_info);
@@ -7434,11 +7466,6 @@ bool mysql_checksum_table(THD *thd, TABL
       if (! thd->in_sub_stmt)
         trans_rollback_stmt(thd);
       close_thread_tables(thd);
-      /*
-        Don't release metadata locks, this will be done at
-        statement end.
-      */
-      table->table=0;				// For query cache
     }
     if (protocol->write())
       goto err;

=== modified file 'sql/sql_truncate.cc'
--- a/sql/sql_truncate.cc	2010-11-18 13:50:08 +0000
+++ b/sql/sql_truncate.cc	2010-12-23 16:18:19 +0000
@@ -18,9 +18,8 @@
 #include "sql_class.h"   // THD
 #include "sql_base.h"    // open_and_lock_tables
 #include "sql_table.h"   // write_bin_log
-#include "sql_handler.h" // mysql_ha_rm_tables
 #include "datadict.h"    // dd_recreate_table()
-#include "lock.h"        // MYSQL_OPEN_TEMPORARY_ONLY
+#include "lock.h"        // MYSQL_OPEN_* flags
 #include "sql_acl.h"     // DROP_ACL
 #include "sql_parse.h"   // check_one_table_access()
 #include "sql_truncate.h"
@@ -194,9 +193,7 @@ int Sql_cmd_truncate_table::handler_trun
   */
 
   /* If it is a temporary table, no need to take locks. */
-  if (is_tmp_table)
-    flags= MYSQL_OPEN_TEMPORARY_ONLY;
-  else
+  if (!is_tmp_table)
   {
     /* We don't need to load triggers. */
     DBUG_ASSERT(table_ref->trg_event_map == 0);
@@ -211,7 +208,7 @@ int Sql_cmd_truncate_table::handler_trun
       the MDL lock taken above and otherwise there is no way to
       wait for FLUSH TABLES in deadlock-free fashion.
     */
-    flags= MYSQL_OPEN_IGNORE_FLUSH | MYSQL_OPEN_SKIP_TEMPORARY;
+    flags= MYSQL_OPEN_IGNORE_FLUSH;
     /*
       Even though we have an MDL lock on the table here, we don't
       pass MYSQL_OPEN_HAS_MDL_LOCK to open_and_lock_tables
@@ -340,8 +337,7 @@ bool Sql_cmd_truncate_table::lock_table(
     /* Acquire an exclusive lock. */
     DBUG_ASSERT(table_ref->next_global == NULL);
     if (lock_table_names(thd, table_ref, NULL,
-                         thd->variables.lock_wait_timeout,
-                         MYSQL_OPEN_SKIP_TEMPORARY))
+                         thd->variables.lock_wait_timeout, 0))
       DBUG_RETURN(TRUE);
 
     if (dd_check_storage_engine_flag(thd, table_ref->db, table_ref->table_name,
@@ -393,26 +389,27 @@ bool Sql_cmd_truncate_table::lock_table(
 bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
 {
   int error;
-  TABLE *table;
   bool binlog_stmt;
   DBUG_ENTER("Sql_cmd_truncate_table::truncate_table");
 
+  DBUG_ASSERT((!table_ref->table) ||
+              (table_ref->table && table_ref->table->s));
+
   /* Initialize, or reinitialize in case of reexecution (SP). */
   m_ticket_downgrade= NULL;
 
-  /* Remove table from the HANDLER's hash. */
-  mysql_ha_rm_tables(thd, table_ref);
-
   /* If it is a temporary table, no need to take locks. */
-  if ((table= find_temporary_table(thd, table_ref)))
+  if (is_temporary_table(table_ref))
   {
+    TABLE *tmp_table= table_ref->table;
+
     /* In RBR, the statement is not binlogged if the table is temporary. */
     binlog_stmt= !thd->is_current_stmt_binlog_format_row();
 
     /* Note that a temporary table cannot be partitioned. */
-    if (ha_check_storage_engine_flag(table->s->db_type(), HTON_CAN_RECREATE))
+    if (ha_check_storage_engine_flag(tmp_table->s->db_type(), HTON_CAN_RECREATE))
     {
-      if ((error= recreate_temporary_table(thd, table)))
+      if ((error= recreate_temporary_table(thd, tmp_table)))
         binlog_stmt= FALSE; /* No need to binlog failed truncate-by-recreate. */
 
       DBUG_ASSERT(! thd->transaction.stmt.modified_non_trans_table);

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2010-12-14 11:15:13 +0000
+++ b/sql/sql_view.cc	2010-12-23 16:18:19 +0000
@@ -1639,8 +1639,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIS
     DBUG_RETURN(TRUE);
   }
 
-  if (lock_table_names(thd, views, 0, thd->variables.lock_wait_timeout,
-                       MYSQL_OPEN_SKIP_TEMPORARY))
+  if (lock_table_names(thd, views, 0, thd->variables.lock_wait_timeout, 0))
     DBUG_RETURN(TRUE);
 
   for (view= views; view; view= view->next_local)

=== modified file 'storage/myisammrg/ha_myisammrg.cc'
--- a/storage/myisammrg/ha_myisammrg.cc	2010-10-20 19:02:59 +0000
+++ b/storage/myisammrg/ha_myisammrg.cc	2010-12-23 16:18:19 +0000
@@ -479,6 +479,11 @@ int ha_myisammrg::add_children_list(void
     child_l->set_table_ref_id(mrg_child_def->get_child_table_ref_type(),
                               mrg_child_def->get_child_def_version());
     /*
+      Copy parent's prelocking attribute to allow opening of child
+      temporary residing in the prelocking list.
+    */
+    child_l->prelocking_placeholder= parent_l->prelocking_placeholder;
+    /*
       For statements which acquire a SNW metadata lock on a parent table and
       then later try to upgrade it to an X lock (e.g. ALTER TABLE), SNW
       locks should be also taken on the children tables.


Attachment: [text/bzr-bundle] bzr/alexander.nozdrin@oracle.com-20101223161819-xwgz2rnc77g8b441.bundle
Thread
bzr commit into mysql-trunk-bugfixing branch (alexander.nozdrin:3471)Bug#27480Alexander Nozdrin23 Dec
  • Re: bzr commit into mysql-trunk-bugfixing branch(alexander.nozdrin:3471) Bug#27480Dmitry Lenev14 Jan