List:Commits« Previous MessageNext Message »
From:Dmitry Lenev Date:December 22 2010 3:23pm
Subject:bzr commit into mysql-trunk-bugfixing branch (Dmitry.Lenev:3402) Bug#27480
View as plain text  
#At file:///home/dlenev/src/bzr/mysql-trunk-bugfixing-bug27480/ based on revid:dmitry.lenev@stripped

 3402 Dmitry Lenev	2010-12-22
      Prerequisite patch for Bug#27480 (Extend CREATE TEMPORARY
      TABLES privilege to allow temp table operations).
      
      Review fixes in progress. Final (almost) batch of fixes.

    modified:
      mysql-test/r/alter_table.result
      mysql-test/r/handler_myisam.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/handler_myisam.test
      mysql-test/t/temp_table.test
      sql/log_event.cc
      sql/sql_admin.cc
      sql/sql_base.cc
      sql/sql_base.h
      sql/sql_class.h
      sql/sql_handler.cc
      sql/sql_parse.cc
      sql/sql_partition_admin.cc
      sql/sql_show.cc
      sql/sql_table.cc
      sql/sql_truncate.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-22 15:23:28 +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/handler_myisam.result'
--- a/mysql-test/r/handler_myisam.result	2010-11-29 14:13:07 +0000
+++ b/mysql-test/r/handler_myisam.result	2010-12-22 15:23:28 +0000
@@ -1859,15 +1859,20 @@ a	b
 HANDLER t1 CLOSE;
 DROP TABLE t1;
 #
-# Bug#27480
+# 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 TABLE t2 SELECT * FROM t1;
+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
-DROP TABLE t2;
 # -- REPAIR TABLE
 HANDLER t1 OPEN;
 REPAIR TABLE t1;
@@ -1901,6 +1906,21 @@ 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;

=== modified file 'mysql-test/r/temp_table.result'
--- a/mysql-test/r/temp_table.result	2010-11-29 14:13:07 +0000
+++ b/mysql-test/r/temp_table.result	2010-12-22 15:23:28 +0000
@@ -223,6 +223,10 @@ 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);
@@ -266,3 +270,4 @@ 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-11-26 13:46:21 +0000
+++ b/mysql-test/suite/innodb/r/innodb_mysql.result	2010-12-22 15:23:28 +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-11-23 11:04:47 +0000
+++ b/mysql-test/suite/innodb/t/innodb_mysql.test	2010-12-22 15:23:28 +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-08-30 08:40:42 +0000
+++ b/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result	2010-12-22 15:23:28 +0000
@@ -126,3 +126,17 @@ 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;

=== 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-08-30 08:40:42 +0000
+++ b/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test	2010-12-22 15:23:28 +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/master-slave-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-22 15:23:28 +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/handler_myisam.test'
--- a/mysql-test/t/handler_myisam.test	2010-11-29 14:13:07 +0000
+++ b/mysql-test/t/handler_myisam.test	2010-12-22 15:23:28 +0000
@@ -98,19 +98,21 @@ DROP TABLE t1;
 
 
 --echo #
---echo # Bug#27480
+--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 TABLE t2 SELECT * FROM t1;
+CREATE TEMPORARY TABLE IF NOT EXISTS t1 SELECT 1 AS f1;
 --error ER_UNKNOWN_TABLE
 HANDLER t1 READ FIRST;
 
-DROP TABLE t2;
-
 --echo # -- REPAIR TABLE
 HANDLER t1 OPEN;
 REPAIR TABLE t1;
@@ -141,6 +143,24 @@ 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;

=== modified file 'mysql-test/t/temp_table.test'
--- a/mysql-test/t/temp_table.test	2010-11-29 14:13:07 +0000
+++ b/mysql-test/t/temp_table.test	2010-12-22 15:23:28 +0000
@@ -252,8 +252,12 @@ DROP TEMPORARY table bug48067.t1;
 
 --echo End of 5.1 tests
 
-# Check admin statements.
-
+--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);
@@ -288,3 +292,5 @@ 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-11-29 16:55:45 +0000
+++ b/sql/log_event.cc	2010-12-22 15:23:28 +0000
@@ -5302,7 +5302,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_table_list(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/sql_admin.cc'
--- a/sql/sql_admin.cc	2010-12-14 09:15:37 +0000
+++ b/sql/sql_admin.cc	2010-12-22 15:23:28 +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
@@ -565,6 +564,13 @@ 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);
@@ -723,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_table_list(thd, table) ||
+                    mysql_recreate_table(thd, table));
       reenable_binlog(thd);
       /*
         mysql_recreate_table() can push OK or ERROR.
@@ -737,14 +745,15 @@ send_result_message:
       trans_commit(thd);
       close_thread_tables(thd);
       thd->mdl_context.release_transactional_locks();
-      if (!result_code && // recreation went ok
-          !table->table)  // not a temporary table opened above
+      /* 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_table_list(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)

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-12-14 15:31:57 +0000
+++ b/sql/sql_base.cc	2010-12-22 15:23:28 +0000
@@ -2621,8 +2621,7 @@ 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);
+  key_length= create_table_def_key(thd, key, table_list, 0);
 
   /*
     If we're in pre-locked or LOCK TABLES mode, let's try to find the
@@ -4303,7 +4302,7 @@ open_and_process_table(THD *thd, LEX *le
       (TABLE_LIST::table is not NULL), that TABLE object must be a pre-opened
       temporary table.
     */
-    DBUG_ASSERT(is_temporary_table(tables->table));
+    DBUG_ASSERT(is_temporary_table(tables));
   }
   else if (tables->open_type == OT_TEMPORARY_ONLY)
   {
@@ -5973,6 +5972,9 @@ static void update_field_dependencies(TH
   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
@@ -5998,16 +6000,21 @@ bool open_temporary_table(THD *thd, TABL
   */
   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_table_list() 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);
   }
 
-  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);
+  TABLE *table= find_temporary_table(thd, tl);
 
   if (!table)
   {
@@ -6050,12 +6057,33 @@ bool open_temporary_table(THD *thd, TABL
 }
 
 
+/**
+  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_table_list(THD *thd, TABLE_LIST *tl_list)
 {
   DBUG_ENTER("open_temporary_table_list");
 
   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);
   }

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	2010-12-14 09:15:37 +0000
+++ b/sql/sql_base.h	2010-12-22 15:23:28 +0000
@@ -572,27 +572,12 @@ private:
 
 
 /**
-  Indicate if a TABLE instance represents a temporary table.
-*/
-
-inline bool is_temporary_table(TABLE *table)
-{
-  /*
-    NOTE: 'table->s' might be NULL for specially constructed TABLE_LIST
-    instances, like for SHOW TRIGGERS LIKE ...
-  */
-
-  return table->s && table->s->tmp_table != NO_TMP_TABLE;
-}
-
-
-/**
-  Indicate if a TABLE_LIST instance represents a temporary table.
+  Check if a TABLE_LIST instance represents a pre-opened temporary table.
 */
 
 inline bool is_temporary_table(TABLE_LIST *tl)
 {
-  return tl->table ? is_temporary_table(tl->table) : FALSE;
+  return tl->table ? (tl->table->s->tmp_table != NO_TMP_TABLE) : FALSE;
 }
 
 

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-12-06 10:36:38 +0000
+++ b/sql/sql_class.h	2010-12-22 15:23:28 +0000
@@ -3703,7 +3703,7 @@ public:
 #define CF_PREOPEN_TMP_TABLES   (1U << 10)
 
 /**
-  Identfies statements for which open handlers should be closed in the
+  Identifies statements for which open handlers should be closed in the
   beginning of the statement.
 */
 #define CF_HA_CLOSE             (1U << 11)

=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc	2010-12-14 09:15:37 +0000
+++ b/sql/sql_handler.cc	2010-12-22 15:23:28 +0000
@@ -287,7 +287,11 @@ bool mysql_ha_open(THD *thd, TABLE_LIST 
   */
   DBUG_ASSERT(! hash_tables->table);
 
-  error= open_temporary_table(thd, hash_tables);
+  /*
+    TODO/FIXME: In the upcoming patch we somehow should handle
+                situation with privilege check for temporary table.
+  */
+  error= open_temporary_table_list(thd, hash_tables);
 
   if (!error)
     error= open_tables(thd, &hash_tables, &counter, 0);

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-12-14 09:15:37 +0000
+++ b/sql/sql_parse.cc	2010-12-22 15:23:28 +0000
@@ -369,7 +369,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;
@@ -455,7 +455,6 @@ void init_update_queries(void)
     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;
@@ -484,9 +483,11 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_PREOPEN_TMP_TABLES;
 
   /*
-    DDL statements should start with closing opened handlers.
-  */
+    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;
@@ -1252,7 +1253,7 @@ 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_table(thd, &table_list))
+    if (open_temporary_table_list(thd, &table_list))
       break;
 
     if (check_table_access(thd, SELECT_ACL, &table_list,
@@ -2072,9 +2073,25 @@ 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_table_list(thd, all_tables))
@@ -2382,6 +2399,10 @@ 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_table_list(
@@ -3218,12 +3239,10 @@ end_with_restore_list:
       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() firstly (it's called
-      from release_transactional_locks() above).
-
-      close_thread_tables() closes all open tables, so even if
-      CF_PREOPEN_TMP_TABLES was set and the tables would be pre-opened in a
-      usual way, they would be closed by close_thread_tables().
+      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_table_list(thd, all_tables))
@@ -4630,6 +4649,7 @@ bool check_single_table_access(THD *thd,
                    &all_tables->grant.m_internal,
                    0, no_errors))
     goto deny;
+
   /* Show only 1 table for check_grant */
   if (!(all_tables->belong_to_view &&
         (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
@@ -4953,6 +4973,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,

=== modified file 'sql/sql_partition_admin.cc'
--- a/sql/sql_partition_admin.cc	2010-11-16 00:55:42 +0000
+++ b/sql/sql_partition_admin.cc	2010-12-22 15:23:28 +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_show.cc'
--- a/sql/sql_show.cc	2010-12-14 09:15:37 +0000
+++ b/sql/sql_show.cc	2010-12-22 15:23:28 +0000
@@ -3635,8 +3635,6 @@ int get_all_tables(THD *thd, TABLE_LIST 
             show_table_list->i_s_requested_object=
               schema_table->i_s_requested_object;
             DEBUG_SYNC(thd, "before_open_in_get_all_tables");
-            if (open_temporary_table_list(thd, show_table_list))
-              goto err;
             res= open_normal_and_derived_tables(thd, show_table_list,
                    (MYSQL_OPEN_IGNORE_FLUSH |
                     MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-12-14 09:15:37 +0000
+++ b/sql/sql_table.cc	2010-12-22 15:23:28 +0000
@@ -4800,6 +4800,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
@@ -4808,14 +4809,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,
@@ -4825,13 +4832,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
@@ -4854,9 +4864,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");
@@ -4868,21 +4878,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");
 
@@ -4913,7 +4932,7 @@ err:
     DBUG_RETURN(0);
   }
 
-  table->file->print_error(error, MYF(0));
+  table_list->table->file->print_error(error, MYF(0));
 
   DBUG_RETURN(-1);
 }
@@ -5939,7 +5958,7 @@ bool mysql_alter_table(THD *thd,char *ne
   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.
@@ -7328,7 +7347,7 @@ bool mysql_checksum_table(THD *thd, TABL
     /* Allow to open real tables only. */
     table->required_type= FRMTYPE_TABLE;
 
-    if (open_temporary_table(thd, table) ||
+    if (open_temporary_table_list(thd, table) ||
         open_and_lock_tables(thd, table, FALSE, 0))
     {
       t= NULL;

=== modified file 'sql/sql_truncate.cc'
--- a/sql/sql_truncate.cc	2010-11-29 14:13:07 +0000
+++ b/sql/sql_truncate.cc	2010-12-22 15:23:28 +0000
@@ -18,7 +18,6 @@
 #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_* flags
 #include "sql_acl.h"     // DROP_ACL


Attachment: [text/bzr-bundle] bzr/dmitry.lenev@oracle.com-20101222152328-7ksatp253uwpeamw.bundle
Thread
bzr commit into mysql-trunk-bugfixing branch (Dmitry.Lenev:3402) Bug#27480Dmitry Lenev22 Dec