List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:August 20 2010 4:00pm
Subject:bzr commit into mysql-5.5-bugfixing branch (alik:3120) Bug#27480
View as plain text  
#At file:///mnt/raid/alik/MySQL/bzr/00/bug27480/mysql-5.5-runtime-bug27480.2/ based on revid:alik@stripped

 3120 Alexander Nozdrin	2010-08-20
      Bug#27480 (Extend CREATE TEMPORARY TABLES privilege
      to allow temp table operations) -- prerequisite patch #4:
      
        - 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_and_process_temporary_table() to fully prepare
          temporary tables for use (similar to open_and_process_table());
      
        - introduce a new "command flag" (CF_OPEN_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_OPEN_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/handler_myisam.result
      mysql-test/r/merge.result
      mysql-test/r/sp.result
      mysql-test/r/temp_table.result
      mysql-test/t/handler_myisam.test
      mysql-test/t/merge.test
      mysql-test/t/sp.test
      mysql-test/t/temp_table.test
      sql/lock.cc
      sql/log_event_old.cc
      sql/sp_head.cc
      sql/sql_admin.cc
      sql/sql_base.cc
      sql/sql_base.h
      sql/sql_class.h
      sql/sql_delete.cc
      sql/sql_handler.cc
      sql/sql_insert.cc
      sql/sql_parse.cc
      sql/sql_prepare.cc
      sql/sql_show.cc
      sql/sql_table.cc
      sql/sql_truncate.cc
      sql/sql_update.cc
      sql/sql_view.cc
=== modified file 'mysql-test/r/handler_myisam.result'
--- a/mysql-test/r/handler_myisam.result	2010-07-05 11:59:34 +0000
+++ b/mysql-test/r/handler_myisam.result	2010-08-20 16:00:19 +0000
@@ -1847,4 +1847,70 @@ a	b
 4	40
 HANDLER t1 CLOSE;
 DROP TABLE t1;
+#
+# Bug#27480
+#
+CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1;
+# -- CREATE TABLE
+HANDLER t1 OPEN;
+CREATE TABLE t2 SELECT * FROM t1;
+HANDLER t1 READ FIRST;
+ERROR 42S02: Unknown table 't1' in HANDLER
+DROP TABLE t2;
+# -- 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
+# -- 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-08-18 09:35:41 +0000
+++ b/mysql-test/r/merge.result	2010-08-20 16:00:19 +0000
@@ -2674,10 +2674,7 @@ DROP TABLE tm1, t1, t2, t3, t4, t5;
 CREATE TEMPORARY TABLE t1 (c1 INT);
 ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists,t1);
 OPTIMIZE TABLE t1;
-Table	Op	Msg_type	Msg_text
-test.t1	optimize	Error	Table 'test.t_not_exists' doesn't exist
-test.t1	optimize	Error	Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
-test.t1	optimize	note	The storage engine for the table doesn't support optimize
+ERROR HY000: Can't reopen table: 't1'
 DROP TABLE t1;
 #
 # Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine

=== modified file 'mysql-test/r/sp.result'
--- a/mysql-test/r/sp.result	2010-07-30 15:28:36 +0000
+++ b/mysql-test/r/sp.result	2010-08-20 16:00:19 +0000
@@ -1105,7 +1105,7 @@ select * from v1|
 a
 3
 select * from v1, t1|
-ERROR HY000: Table 't1' was not locked with LOCK TABLES
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
 select f4()|
 ERROR HY000: Table 't2' was not locked with LOCK TABLES
 unlock tables|

=== modified file 'mysql-test/r/temp_table.result'
--- a/mysql-test/r/temp_table.result	2010-06-23 11:34:40 +0000
+++ b/mysql-test/r/temp_table.result	2010-08-20 16:00:19 +0000
@@ -223,3 +223,46 @@ CREATE TEMPORARY TABLE bug48067.t1 (c1 i
 DROP DATABASE bug48067;
 DROP TEMPORARY table bug48067.t1;
 End of 5.1 tests
+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

=== 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-08-20 16:00:19 +0000
@@ -97,4 +97,73 @@ HANDLER t1 CLOSE;
 DROP TABLE t1;
 
 
+--echo #
+--echo # Bug#27480
+--echo #
+
+CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1; 
+
+--echo # -- CREATE TABLE
+HANDLER t1 OPEN;
+CREATE TABLE t2 SELECT * FROM t1;
+--error ER_UNKNOWN_TABLE
+HANDLER t1 READ FIRST;
+
+DROP TABLE t2;
+
+--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 # -- 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-08-18 09:35:41 +0000
+++ b/mysql-test/t/merge.test	2010-08-20 16:00:19 +0000
@@ -2114,6 +2114,7 @@ DROP TABLE tm1, t1, t2, t3, t4, t5;
 --echo #
 CREATE TEMPORARY TABLE t1 (c1 INT);
 ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists,t1);
+--error ER_CANT_REOPEN_TABLE
 OPTIMIZE TABLE t1;
 DROP TABLE t1;
 

=== modified file 'mysql-test/t/sp.test'
--- a/mysql-test/t/sp.test	2010-07-30 15:28:36 +0000
+++ b/mysql-test/t/sp.test	2010-08-20 16:00:19 +0000
@@ -1325,7 +1325,7 @@ lock tables v2 read, mysql.proc read|
 select * from v2|
 select * from v1|
 # These should not work as we have too little instances of tables locked
---error ER_TABLE_NOT_LOCKED
+--error ER_VIEW_INVALID
 select * from v1, t1|
 --error ER_TABLE_NOT_LOCKED
 select f4()|

=== 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-08-20 16:00:19 +0000
@@ -251,3 +251,40 @@ DROP DATABASE bug48067;
 DROP TEMPORARY table bug48067.t1;
 
 --echo End of 5.1 tests
+
+# Check admin statements.
+
+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;

=== modified file 'sql/lock.cc'
--- a/sql/lock.cc	2010-08-12 13:50:23 +0000
+++ b/sql/lock.cc	2010-08-20 16:00:19 +0000
@@ -77,7 +77,7 @@
 #include "debug_sync.h"
 #include "unireg.h"                    // REQUIRED: for other includes
 #include "lock.h"
-#include "sql_base.h"                       // close_tables_for_reopen
+#include "sql_base.h"
 #include "sql_parse.h"                     // is_log_table_write_query
 #include "sql_acl.h"                       // SUPER_ACL
 #include <hash.h>

=== modified file 'sql/log_event_old.cc'
--- a/sql/log_event_old.cc	2010-07-15 13:47:50 +0000
+++ b/sql/log_event_old.cc	2010-08-20 16:00:19 +0000
@@ -7,7 +7,7 @@
 #include "log_event.h"
 #ifndef MYSQL_CLIENT
 #include "sql_cache.h"                       // QUERY_CACHE_FLAGS_SIZE
-#include "sql_base.h"                       // close_tables_for_reopen
+#include "sql_base.h"
 #include "key.h"                            // key_copy
 #include "lock.h"                           // mysql_unlock_tables
 #include "sql_parse.h"             // mysql_reset_thd_for_next_command

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2010-08-12 13:55:27 +0000
+++ b/sql/sp_head.cc	2010-08-20 16:00:19 +0000
@@ -2913,6 +2913,9 @@ sp_lex_keeper::reset_lex_and_exec_core(T
   reinit_stmt_before_use(thd, m_lex);
 
   if (open_tables)
+    res= open_and_process_temporary_table_seq(thd, m_lex->query_tables);
+
+  if (!res && open_tables)
     res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
 
   if (!res)
@@ -4129,6 +4132,11 @@ sp_head::add_used_tables_to_table_list(T
       table->prelocking_placeholder= 1;
       table->belong_to_view= belong_to_view;
       table->trg_event_map= stab->trg_event_map;
+
+      table->open_type=
+        find_temporary_table(thd, table->db, table->table_name) ?
+        OT_TEMPORARY_OR_BASE : OT_BASE_ONLY;
+
       /*
         Since we don't allow DDL on base tables in prelocked mode it
         is safe to infer the type of metadata lock from the type of

=== modified file 'sql/sql_admin.cc'
--- a/sql/sql_admin.cc	2010-08-18 11:29:04 +0000
+++ b/sql/sql_admin.cc	2010-08-20 16:00:19 +0000
@@ -272,8 +272,6 @@ static bool mysql_admin_table(THD* thd, 
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
     DBUG_RETURN(TRUE);
 
-  mysql_ha_rm_tables(thd, tables);
-
   for (table= tables; table; table= table->next_local)
   {
     char table_name[NAME_LEN*2+2];
@@ -385,6 +383,9 @@ static bool mysql_admin_table(THD* thd, 
         trans_rollback(thd);
         close_thread_tables(thd);
         thd->mdl_context.release_transactional_locks();
+        /* Re-open temporary tables after close_thread_tables(). */
+        if (open_and_process_temporary_table_seq(thd, tables))
+          goto err;
         DBUG_PRINT("admin", ("simple error, admin next table"));
         continue;
       case -1:           // error, message could be written to net
@@ -460,6 +461,9 @@ static bool mysql_admin_table(THD* thd, 
       close_thread_tables(thd);
       thd->mdl_context.release_transactional_locks();
       lex->reset_query_tables_list(FALSE);
+        /* Re-open temporary tables after close_thread_tables(). */
+      if (open_and_process_temporary_table_seq(thd, tables))
+        goto err;
       /*
         Restore Query_tables_list::sql_command value to make statement
         safe for re-execution.
@@ -528,6 +532,9 @@ static bool mysql_admin_table(THD* thd, 
         trans_rollback(thd);
         close_thread_tables(thd);
         thd->mdl_context.release_transactional_locks();
+        /* Re-open temporary tables after close_thread_tables(). */
+        if (open_and_process_temporary_table_seq(thd, tables))
+          goto err;
         tmp_disable_binlog(thd); // binlogging is done by caller if wanted
         result_code= mysql_recreate_table(thd, table);
         reenable_binlog(thd);
@@ -646,6 +653,9 @@ send_result_message:
       trans_commit(thd);
       close_thread_tables(thd);
       thd->mdl_context.release_transactional_locks();
+      /* Re-open temporary tables after close_thread_tables(). */
+      if (open_and_process_temporary_table_seq(thd, tables))
+        goto err;
       DEBUG_SYNC(thd, "ha_admin_try_alter");
       protocol->store(STRING_WITH_LEN("note"), system_charset_info);
       protocol->store(STRING_WITH_LEN(
@@ -672,8 +682,11 @@ send_result_message:
       trans_commit(thd);
       close_thread_tables(thd);
       thd->mdl_context.release_transactional_locks();
-      table->table= NULL;
-      if (!result_code) // recreation went ok
+      /* Re-open temporary tables after close_thread_tables(). */
+      if (open_and_process_temporary_table_seq(thd, tables))
+        goto err;
+      if (!result_code && // recreation went ok
+          !table->table)  // not a temporary table opened above
       {
         /* Clear the ticket released above. */
         table->mdl_request.ticket= NULL;
@@ -786,6 +799,9 @@ send_result_message:
     trans_commit_implicit(thd);
     close_thread_tables(thd);
     thd->mdl_context.release_transactional_locks();
+    /* Re-open temporary tables after close_thread_tables(). */
+    if (open_and_process_temporary_table_seq(thd, tables))
+      goto err;
 
     /*
       If it is CHECK TABLE v1, v2, v3, and v1, v2, v3 are views, we will run
@@ -815,8 +831,7 @@ 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);
 }
 

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-08-20 12:20:19 +0000
+++ b/sql/sql_base.cc	2010-08-20 16:00:19 +0000
@@ -2617,46 +2617,42 @@ tdc_wait_for_old_version(THD *thd, const
 }
 
 
-/*
-  Open a table.
+/**
+  Open a base 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
+  @param thd            Thread context.
+  @param table_list     Open first table in list.
+  @param action[in,out] 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.
-
-  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 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_TAKE_UPGRADABLE_MDL - Obtain upgradable
+                        metadata lock for tables on which we are going to
+                        take some kind of write table-level lock.
+
+  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.
+
+  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)
 {
@@ -2671,6 +2667,8 @@ bool open_table(THD *thd, TABLE_LIST *ta
   my_hash_value_type hash_value;
   DBUG_ENTER("open_table");
 
+  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);
@@ -2707,57 +2705,6 @@ bool open_table(THD *thd, TABLE_LIST *ta
       DBUG_RETURN(TRUE);
     }
   }
-  /*
-    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);
-  }
 
   /*
     The table is not temporary - if we're in pre-locked or LOCK TABLES
@@ -2859,7 +2806,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.
@@ -4362,6 +4309,26 @@ open_and_process_table(THD *thd, LEX *le
     error= TRUE;
     goto end;
   }
+
+  if (tables->table)
+  {
+    DBUG_ASSERT(is_temporary_table(tables->table));
+    DBUG_RETURN(FALSE);
+  }
+
+  if (tables->open_type == OT_TEMPORARY_ONLY)
+  {
+    /* We're in CREATE TEMPORARY TABLE statement. */
+
+    if (tables->open_strategy == TABLE_LIST::OPEN_NORMAL)
+    {
+      my_error(ER_NO_SUCH_TABLE, MYF(0), tables->db, tables->table_name);
+      DBUG_RETURN(TRUE);
+    }
+
+    DBUG_RETURN(FALSE);
+  }
+
   DBUG_PRINT("tcache", ("opening table: '%s'.'%s'  item: %p",
                         tables->db, tables->table_name, tables)); //psergey: invalid read of size 1 here
   (*counter)++;
@@ -4371,6 +4338,29 @@ open_and_process_table(THD *thd, LEX *le
 
   if (tables->prelocking_placeholder)
   {
+    if (thd->locked_tables_mode)
+    {
+      /*
+        No need to pre-open new tables from the prelocking list if we are in
+        "locked tables mode" (i.e. all needed tables should be already
+        opened and locked). The table will be tried to open as usual during
+        execution.
+      */
+      DBUG_RETURN(FALSE);
+    }
+
+    if (tables->open_type != OT_BASE_ONLY)
+    {
+      /*
+        TABLE_LIST::open_type is not OT_BASE_ONLY. That means there is a
+        temporary table for that TABLE_LIST instance (there might be also a
+        base table, but that's not important because temporary tables take
+        precedence over base ones). Thus, there is no reason to pre-open
+        base table. Proper table will be opened during execution.
+      */
+      DBUG_RETURN(FALSE);
+    }
+
     /*
       For the tables added by the pre-locking code, attempt to open
       the table but fail silently if the table does not exist.
@@ -4571,7 +4561,6 @@ lock_table_names(THD *thd,
   {
     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))))
@@ -4639,7 +4628,6 @@ open_tables_check_upgradable_mdl(THD *th
   {
     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))))
@@ -4844,6 +4832,10 @@ restart:
           if (ot_ctx.recover_from_failed_open(thd))
             goto err;
 
+          /* Re-open temporary tables after close_tables_for_reopen(). */
+          if (open_and_process_temporary_table_seq(thd, *start))
+            goto err;
+
           error= FALSE;
           goto restart;
         }
@@ -4890,6 +4882,10 @@ restart:
             if (ot_ctx.recover_from_failed_open(thd))
               goto err;
 
+            /* Re-open temporary tables after close_tables_for_reopen(). */
+            if (open_and_process_temporary_table_seq(thd, *start))
+              goto err;
+
             error= FALSE;
             goto restart;
           }
@@ -4920,6 +4916,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)
     {
@@ -5744,6 +5745,129 @@ void close_tables_for_reopen(THD *thd, T
 }
 
 
+/**
+  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.
+
+  open_temporary_table() should be considered as an internal function.
+  Usually, open_and_process_temporary_table() should be used instead to
+  open temporary table completely. The only case where
+  open_temporary_table() is used directly is implementation of INSERT INTO
+  statement (sql_insert.cc).
+
+  @return Error status.
+    @retval FALSE On success. If tmp_table is NULL, temporary table does
+                  not exist for the specified key; if tmp_table is not
+                  NULL, the temporary table was found.
+    @retval TRUE  On error. my_error() has been called.
+*/
+
+bool open_temporary_table(THD *thd, TABLE_LIST *tl, TABLE **tmp_table)
+{
+  DBUG_ENTER("open_temporary_table");
+  DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db, tl->table_name));
+
+  *tmp_table= NULL;
+
+  if (tl->open_type == OT_BASE_ONLY)
+  {
+    DBUG_PRINT("info", ("skip_temporary is set"));
+    DBUG_RETURN(FALSE);
+  }
+
+  char table_key[MAX_DBKEY_LENGTH];
+  uint table_key_length= create_table_def_key(thd, table_key, tl, 1);
+
+  TABLE *table= find_temporary_table(thd, table_key, table_key_length);
+
+  if (!table)
+    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;
+
+  set_table_attributes_after_opening(thd, tl, table);
+
+  DBUG_PRINT("info", ("Using temporary table"));
+  *tmp_table= table;
+
+  DBUG_RETURN(FALSE);
+}
+
+
+bool open_and_process_temporary_table_seq(THD *thd, TABLE_LIST *tl_seq)
+{
+  DBUG_ENTER("open_and_process_temporary_table_seq");
+
+  for (TABLE_LIST *tl= tl_seq; tl; tl= tl->next_global)
+  {
+    if (open_and_process_temporary_table(thd, tl))
+      DBUG_RETURN(TRUE);
+  }
+
+  DBUG_RETURN(FALSE);
+}
+
+
+/**
+  Open a temporary table specified by TABLE_LIST instance.
+
+  @return Error status.
+    @retval FALSE On success. Opened temporary table is returned in
+                  TABLE_LIST::table member. If TABLE_LIST::table is NULL,
+                  the specified temporary table does not exist.
+    @retval TRUE  On error. my_error() has been called.
+*/
+
+bool open_and_process_temporary_table(THD *thd, TABLE_LIST *tl)
+{
+  DBUG_ENTER("open_and_process_temporary_table");
+
+  if (tl->schema_table || tl->derived)
+    DBUG_RETURN(FALSE);
+
+  if (open_temporary_table(thd, tl, &tl->table))
+    DBUG_RETURN(TRUE);
+
+  if (!tl->table)
+    DBUG_RETURN(FALSE);
+
+  /* Check and update metadata version of a base table. */
+  if (check_and_update_table_version(thd, tl, tl->table->s))
+    DBUG_RETURN(TRUE);
+
+  /* Non-MERGE tables ignore this call. */
+  if (tl->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
+    DBUG_RETURN(TRUE);
+
+  DBUG_RETURN(FALSE);
+}
+
+
 /*
   Open a single table from disk without table caching and don't set it in
   open_list.

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	2010-08-20 12:20:19 +0000
+++ b/sql/sql_base.h	2010-08-20 16:00:19 +0000
@@ -94,7 +94,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
 /**
@@ -257,6 +257,9 @@ 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_and_process_temporary_table_seq(THD *thd, TABLE_LIST *tl_seq);
+bool open_and_process_temporary_table(THD *thd, TABLE_LIST *tl);
+bool open_temporary_table(THD *thd, TABLE_LIST *table_list, TABLE **tmp_table);
 bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
 
 /* Functions to work with system tables. */
@@ -530,6 +533,31 @@ private:
 
 
 /**
+  Indicate if a TABLE instance represents a temporary table.
+*/
+
+inline bool is_temporary_table(TABLE *table)
+{
+  /*
+    NOTE: 'table->s' might be NULL when 'table' is not.
+    For instance: SHOW TRIGGERS LIKE ...
+  */
+
+  return table->s && table->s->tmp_table != NO_TMP_TABLE;
+}
+
+
+/**
+  Indicate if a TABLE_LIST instance represents a temporary table.
+*/
+
+inline bool is_temporary_table(TABLE_LIST *tl)
+{
+  return tl->table ? is_temporary_table(tl->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-08-18 11:29:04 +0000
+++ b/sql/sql_class.h	2010-08-20 16:00:19 +0000
@@ -1007,6 +1007,12 @@ public:
     use the prelocked tables, instead of opening their own ones.
     Prelocked mode is turned off automatically once close_thread_tables()
     of the main statement is called.
+
+    "Locked tables mode" is ON if locked_tables_mode is not LTM_NONE.
+
+    If "Locked tables mode" is ON the server does not open/lock new tables,
+    it just looks for a table in the list of open tables. If the table is
+    not there, an error is thrown.
   */
   enum enum_locked_tables_mode locked_tables_mode;
   uint current_tablenr;
@@ -3498,6 +3504,19 @@ public:
 */
 #define CF_CAN_GENERATE_ROW_EVENTS (1U << 11)
 
+/**
+  Identifies statements which may deal with temporary tables, thus
+  temporary tables should be open before executing the sql command.
+*/
+#define CF_OPEN_TMP_TABLES      (1U << 12)
+
+/**
+  Identfies statements for which open handlers should be closed in the
+  beginning of the statement.
+*/
+#define CF_HA_CLOSE             (1U << 13)
+
+
 /* Bits in server_command_flags */
 
 /**

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	2010-07-28 11:17:19 +0000
+++ b/sql/sql_delete.cc	2010-08-20 16:00:19 +0000
@@ -30,7 +30,6 @@
 #include "sql_parse.h"            // mysql_init_select
 #include "sql_acl.h"              // *_ACL
 #include "filesort.h"             // filesort
-#include "sql_handler.h"          // mysql_ha_rm_tables
 #include "sql_select.h"
 #include "sp_head.h"
 #include "sql_trigger.h"

=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc	2010-08-12 13:50:23 +0000
+++ b/sql/sql_handler.cc	2010-08-20 16:00:19 +0000
@@ -290,7 +290,14 @@ bool mysql_ha_open(THD *thd, TABLE_LIST 
     open_ltable() or open_table() because we would like to be able
     to open a temporary table.
   */
-  error= open_tables(thd, &hash_tables, &counter, 0);
+
+  error= open_and_process_temporary_table(thd, hash_tables);
+
+  if (is_temporary_table(hash_tables))
+    hash_tables->table->grant= hash_tables->grant;
+
+  if (!error && !hash_tables->table)
+    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-08-18 11:55:37 +0000
+++ b/sql/sql_insert.cc	2010-08-20 16:00:19 +0000
@@ -3601,8 +3601,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, &table))
         {
           /*
             This shouldn't happen as creation of temporary table should make
@@ -3611,8 +3610,6 @@ static TABLE *create_table_from_items(TH
           */
           drop_temporary_table(thd, create_table);
         }
-        else
-          table= create_table->table;
       }
     }
     if (!table)                                   // open failed

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-08-20 09:04:33 +0000
+++ b/sql/sql_parse.cc	2010-08-20 16:00:19 +0000
@@ -26,7 +26,7 @@
                               // start_waiting_global_read_lock,
                               // 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
@@ -287,8 +287,6 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_CREATE_EVENT]=   CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_ALTER_EVENT]=    CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_DROP_EVENT]=     CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
-  sql_command_flags[SQLCOM_CREATE_TRIGGER]= CF_AUTO_COMMIT_TRANS;
-  sql_command_flags[SQLCOM_DROP_TRIGGER]=   CF_AUTO_COMMIT_TRANS;
 
   sql_command_flags[SQLCOM_UPDATE]=	    CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
@@ -346,7 +344,7 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_GRANTS]=      CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_CREATE_DB]=   CF_STATUS_COMMAND;
-  sql_command_flags[SQLCOM_SHOW_CREATE]=  CF_STATUS_COMMAND;
+  sql_command_flags[SQLCOM_SHOW_CREATE]=      CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]=  CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
@@ -419,6 +417,47 @@ 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;
+
+  // Temporary tables should be opened for the following commands:
+
+  sql_command_flags[SQLCOM_CREATE_TABLE]|=    CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CREATE_INDEX]|=    CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_ALTER_TABLE]|=     CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_TRUNCATE]|=        CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_LOAD]|=            CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_DROP_INDEX]|=      CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CREATE_VIEW]|=     CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_UPDATE]|=          CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_UPDATE_MULTI]|=    CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_INSERT]|=          CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_INSERT_SELECT]|=   CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_DELETE]|=          CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_DELETE_MULTI]|=    CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_REPLACE]|=         CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_REPLACE_SELECT]|=  CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_SELECT]|=          CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_SET_OPTION]|=      CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_DO]|=              CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CALL]|=            CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_ANALYZE]|=         CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CHECK]|=           CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_CHECKSUM]|=        CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_OPTIMIZE]|=        CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_REPAIR]|=          CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_PRELOAD_KEYS]|=    CF_OPEN_TMP_TABLES;
+  sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|=  CF_OPEN_TMP_TABLES;
+
+  // Open handlers should be closed for the following commands:
+
+  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_PRELOAD_KEYS]|=    CF_HA_CLOSE;
+  sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|=  CF_HA_CLOSE;
 }
 
 bool sqlcom_can_generate_row_events(const THD *thd)
@@ -2097,6 +2136,18 @@ mysql_execute_command(THD *thd)
     DEBUG_SYNC(thd,"before_execute_sql_command");
 #endif
 
+  if (sql_command_flags[lex->sql_command] & CF_HA_CLOSE)
+  {
+    for (TABLE_LIST *tl= all_tables; tl; tl= tl->next_global)
+      mysql_ha_rm_tables(thd, tl);
+  }
+
+  if (sql_command_flags[lex->sql_command] & CF_OPEN_TMP_TABLES)
+  {
+    if (open_and_process_temporary_table_seq(thd, all_tables))
+      goto error;
+  }
+
   switch (lex->sql_command) {
 
   case SQLCOM_SHOW_EVENTS:
@@ -2173,7 +2224,7 @@ mysql_execute_command(THD *thd)
     res= execute_sqlcom_select(thd, all_tables);
     break;
   }
-case SQLCOM_PREPARE:
+  case SQLCOM_PREPARE:
   {
     mysql_sql_stmt_prepare(thd);
     break;
@@ -2401,9 +2452,20 @@ case SQLCOM_PREPARE:
       goto end_with_restore_list;
     }
 
+    if (lex->create_info.merge_list.elements)
+    {
+      if (open_and_process_temporary_table_seq(
+            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;
 
+
     /* Might have been updated in create_table_precheck */
     create_info.alias= create_table->alias;
 
@@ -2455,9 +2517,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;
@@ -2615,6 +2674,7 @@ end_with_restore_list:
       goto error;
 
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
+
     if (check_one_table_access(thd, INDEX_ACL, all_tables))
       goto error; /* purecov: inspected */
     /*
@@ -2759,6 +2819,13 @@ end_with_restore_list:
       else
       {
         /*
+          Temporary tables should be opened for SHOW CREATE TABLE, but not
+          for SHOW CREATE VIEW.
+        */
+        if (open_and_process_temporary_table_seq(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.
@@ -3223,6 +3290,10 @@ end_with_restore_list:
     thd->mdl_context.release_transactional_locks();
     if (res)
       goto error;
+
+    if (open_and_process_temporary_table_seq(thd, all_tables))
+      goto error;
+
     if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
                            FALSE, UINT_MAX, FALSE))
       goto error;
@@ -4601,10 +4672,15 @@ bool check_single_table_access(THD *thd,
   else
     db_name= all_tables->db;
 
-  if (check_access(thd, privilege, db_name,
-                   &all_tables->grant.privilege,
-                   &all_tables->grant.m_internal,
-                   0, no_errors))
+  bool res= check_access(thd, privilege, db_name,
+                         &all_tables->grant.privilege,
+                         &all_tables->grant.m_internal,
+                         0, no_errors);
+
+  if (is_temporary_table(all_tables))
+    all_tables->table->grant= all_tables->grant;
+
+  if (res)
     goto deny;
 
   /* Show only 1 table for check_grant */
@@ -5021,16 +5097,19 @@ 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(),
-                     &tables->grant.privilege,
-                     &tables->grant.m_internal,
-                     0, no_errors))
+    bool res= check_access(thd, want_access, tables->get_db_name(),
+                           &tables->grant.privilege,
+                           &tables->grant.m_internal,
+                           0, no_errors);
+
+    if (is_temporary_table(tables))
+      tables->table->grant= tables->grant;
+
+    if (res)
       goto deny;
   }
   thd->security_ctx= backup_ctx;

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2010-08-18 09:35:41 +0000
+++ b/sql/sql_prepare.cc	2010-08-20 16:00: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 */
@@ -1714,6 +1715,15 @@ 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_and_process_temporary_table_seq(
+          thd, lex->create_info.merge_list.first))
+    {
+      DBUG_RETURN(TRUE);
+    }
+  }
+
   if (create_table_precheck(thd, tables, create_table))
     DBUG_RETURN(TRUE);
 
@@ -1777,6 +1787,12 @@ static bool mysql_test_create_view(Prepa
   if (create_view_precheck(thd, tables, view, lex->create_view_mode))
     goto err;
 
+  for (TABLE_LIST *tl= tables; tl; tl= tl->next_global)
+  {
+    if (is_temporary_table(tl))
+      tl->table->grant= tl->grant;
+  }
+
   if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
     goto err;
 
@@ -1963,6 +1979,21 @@ 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)
+  {
+    for (TABLE_LIST *tl= tables; tl; tl= tl->next_global)
+      mysql_ha_rm_tables(thd, tl);
+  }
+
+  // Open temporary tables that are known now. Temporary tables added by
+  // prelocking will be opened afterwards (after the switch below).
+
+  if (sql_command_flags[sql_command] & CF_OPEN_TMP_TABLES)
+  {
+    if (open_and_process_temporary_table_seq(thd, tables))
+      goto error;
+  }
+
   switch (sql_command) {
   case SQLCOM_REPLACE:
   case SQLCOM_INSERT:
@@ -2093,6 +2124,43 @@ static bool check_prepared_statement(Pre
     }
     break;
   }
+
+  // Open temporary tables added by prelocking.
+  if (sql_command_flags[sql_command] & CF_OPEN_TMP_TABLES)
+  {
+    List<TABLE_LIST> new_tl_arr;
+
+    for (TABLE_LIST *tl= lex->query_tables; tl; tl= tl->next_global)
+    {
+      if (tl->table)
+        continue;
+
+      if (open_and_process_temporary_table(thd, tl))
+        goto error;
+
+      new_tl_arr.push_back(tl);
+    }
+
+    // Ensure that HA_ATTACH_CHILDREN has been called for newly added (by
+    // prelocking) merge tables.
+    {
+      List_iterator_fast<TABLE_LIST> new_tl_arr_it(new_tl_arr);
+      TABLE_LIST *tl;
+      while ((tl= new_tl_arr_it++))
+      {
+        if (!tl->table ||
+            tl->table->file->ht->db_type != DB_TYPE_MRG_MYISAM)
+          continue;
+
+        /* MERGE tables need to access parent and child TABLE_LISTs. */
+        DBUG_ASSERT(tl->table->pos_in_table_list == tl);
+
+        if (tl->table->file->extra(HA_EXTRA_ATTACH_CHILDREN))
+          goto error;
+      }
+    }
+  }
+
   if (res == 0)
     DBUG_RETURN(stmt->is_sql_prepare() ?
                 FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush()));

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2010-08-18 11:29:04 +0000
+++ b/sql/sql_show.cc	2010-08-20 16:00:19 +0000
@@ -3008,11 +3008,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_and_process_temporary_table_seq(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");
@@ -3043,6 +3050,7 @@ fill_schema_show_cols_or_idxs(THD *thd, 
    thd->temporary_tables= 0;
    close_tables_for_reopen(thd, &show_table_list,
                            open_tables_state_backup->mdl_system_tables_svp);
+   error= open_and_process_temporary_table_seq(thd, show_table_list) || error;
    DBUG_RETURN(error);
 }
 
@@ -3658,6 +3666,8 @@ int get_all_tables(THD *thd, TABLE_LIST 
                                                &tmp_lex_string);
               close_tables_for_reopen(thd, &show_table_list,
                                       open_tables_state_backup.mdl_system_tables_svp);
+              if (open_and_process_temporary_table_seq(thd, show_table_list))
+                goto err;
             }
             DBUG_ASSERT(!lex->query_tables_own_last);
             if (res)

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-08-20 12:20:19 +0000
+++ b/sql/sql_table.cc	2010-08-20 16:00:19 +0000
@@ -5612,8 +5612,6 @@ 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. */
@@ -6229,14 +6227,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_and_process_temporary_table(thd, &tbl);
       new_table= tbl.table;
     }
     else
@@ -6925,11 +6921,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. */
@@ -6969,13 +6960,16 @@ bool mysql_checksum_table(THD *thd, TABL
   /* Open one table after the other to keep lock time as short as possible. */
   for (table= tables; table; table= table->next_local)
   {
+    TABLE *t= table->table;
     char table_name[NAME_LEN*2+2];
-    TABLE *t;
 
     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
+    if (!table->table)
+    {
+      t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0);
+      thd->clear_error();			// these errors shouldn't get client
+    }
 
     protocol->prepare_for_resend();
     protocol->store(table_name, system_charset_info);
@@ -7073,11 +7067,9 @@ 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 (open_and_process_temporary_table_seq(thd, tables))
+        goto err;
     }
     if (protocol->write())
       goto err;

=== modified file 'sql/sql_truncate.cc'
--- a/sql/sql_truncate.cc	2010-08-20 12:20:19 +0000
+++ b/sql/sql_truncate.cc	2010-08-20 16:00:19 +0000
@@ -23,7 +23,7 @@
 #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"
@@ -387,24 +387,26 @@ static bool open_and_lock_table_for_trun
 
 bool mysql_truncate_table(THD *thd, TABLE_LIST *table_ref)
 {
-  TABLE *table;
-  bool error= TRUE, binlog_stmt;
+  bool error= TRUE;
+  bool binlog_stmt= FALSE;
   MDL_ticket *mdl_ticket= NULL;
   DBUG_ENTER("mysql_truncate_table");
 
-  /* Remove tables from the HANDLER's hash. */
-  mysql_ha_rm_tables(thd, table_ref);
+  DBUG_ASSERT((!table_ref->table) ||
+              (table_ref->table && table_ref->table->s));
 
   /* 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);
@@ -416,11 +418,10 @@ bool mysql_truncate_table(THD *thd, TABL
         table and delete all rows. In such a manner this can in fact
         open several tables if it's a temporary MyISAMMRG table.
       */
-      if (open_and_lock_tables(thd, table_ref, FALSE,
-                               MYSQL_OPEN_TEMPORARY_ONLY))
+      if (open_and_lock_tables(thd, table_ref, FALSE, 0))
         DBUG_RETURN(TRUE);
 
-      error= delete_all_rows(thd, table_ref->table);
+      error= delete_all_rows(thd, tmp_table);
     }
 
     /*
@@ -500,7 +501,7 @@ bool Truncate_statement::execute(THD *th
   bool res= TRUE;
   DBUG_ENTER("Truncate_statement::execute");
 
-  if (check_one_table_access(thd, DROP_ACL, first_table))
+  if (check_table_access(thd, DROP_ACL, first_table, FALSE, 1, FALSE))
     goto error;
   /*
     Don't allow this within a transaction because we want to use

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2010-08-09 12:11:29 +0000
+++ b/sql/sql_update.cc	2010-08-20 16:00:19 +0000
@@ -24,7 +24,7 @@
 #include "unireg.h"                    // REQUIRED: for other includes
 #include "sql_update.h"
 #include "sql_cache.h"                          // query_cache_*
-#include "sql_base.h"                       // close_tables_for_reopen
+#include "sql_base.h"
 #include "sql_parse.h"                          // cleanup_items
 #include "sql_partition.h"                   // partition_key_modified
 #include "sql_select.h"

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2010-08-18 11:55:37 +0000
+++ b/sql/sql_view.cc	2010-08-20 16:00:19 +0000
@@ -442,6 +442,18 @@ bool mysql_create_view(THD *thd, TABLE_L
     goto err;
   }
 
+  for (TABLE_LIST *tl= lex->query_tables; tl; tl= tl->next_global)
+  {
+    if (tl->table)
+      continue;
+
+    if (open_and_process_temporary_table(thd, tl))
+    {
+      res= TRUE;
+      goto err;
+    }
+  }
+
   view= lex->unlink_first_table(&link_to_local);
 
   if (mode == VIEW_ALTER && fill_defined_view_parts(thd, view))


Attachment: [text/bzr-bundle] bzr/alik@sun.com-20100820160019-pw9ii5pd7k8hcmcg.bundle
Thread
bzr commit into mysql-5.5-bugfixing branch (alik:3120) Bug#27480Alexander Nozdrin20 Aug