List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:June 3 2010 9:01am
Subject:bzr commit into mysql-trunk-bugfixing branch (alik:3092) Bug#27480
View as plain text  
#At file:///mnt/raid/alik/MySQL/bzr/00/bug27480/mysql-trunk-bf-bug27480/ based on revid:alik@stripped

 3092 Alexander Nozdrin	2010-06-03
      Preliminary patch for Bug#27480 (Extend CREATE TEMPORARY TABLES
      privilege to allow temp table operations). All tests pass.

    added:
      mysql-test/r/create_notembedded.result
      mysql-test/t/create_notembedded.test
    modified:
      sql/lock.h
      sql/sql_acl.cc
      sql/sql_base.cc
      sql/sql_base.h
      sql/sql_class.h
      sql/sql_insert.cc
      sql/sql_parse.cc
=== added file 'mysql-test/r/create_notembedded.result'
--- a/mysql-test/r/create_notembedded.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/create_notembedded.result	2010-06-03 09:01:18 +0000
@@ -0,0 +1,102 @@
+DROP DATABASE IF EXISTS mysqltest2;
+CREATE DATABASE mysqltest2;
+GRANT CREATE, SELECT ON test.* TO mysqltest_u1@localhost;
+GRANT CREATE TEMPORARY TABLES ON mysqltest2.* TO mysqltest_u1@localhost;
+CREATE TEMPORARY TABLE tmp1(a INT);
+CREATE TEMPORARY TABLE tmp2(a INT);
+CREATE TABLE t1(a INT);
+ERROR 42000: CREATE command denied to user 'mysqltest_u1'@'localhost' for table 't1'
+CREATE TABLE test.t1(a INT);
+INSERT INTO tmp1 VALUES (11), (12), (13);
+INSERT INTO tmp2 VALUES (21), (22), (23);
+CREATE TEMPORARY TABLE tmp3(b INT);
+INSERT INTO tmp3 SELECT a FROM tmp1 UNION SELECT a FROM tmp2;
+SELECT * FROM tmp3;
+b
+11
+12
+13
+21
+22
+23
+SELECT * FROM tmp1;
+a
+11
+12
+13
+SELECT * FROM tmp1, tmp2;
+a	a
+11	21
+12	21
+13	21
+11	22
+12	22
+13	22
+11	23
+12	23
+13	23
+SELECT * FROM tmp1, t1, tmp2;
+ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 't1'
+SELECT * FROM tmp1, test.t1, tmp2;
+a	a	a
+UPDATE tmp1 SET a = a * 10;
+SELECT * FROM tmp1;
+a
+110
+120
+130
+UPDATE tmp2 SET a = a - 20 WHERE a >= 10;
+SELECT * FROM tmp2;
+a
+1
+2
+3
+UPDATE tmp1, tmp3
+SET a = a * 1, b = b * 1
+WHERE b < 100;
+SELECT * FROM tmp1;
+a
+110
+120
+130
+SELECT * FROM tmp3;
+b
+11
+12
+13
+21
+22
+23
+DELETE FROM tmp1;
+SELECT * FROM tmp1;
+a
+DELETE FROM tmp2 WHERE a > 2;
+SELECT * FROM tmp2;
+a
+1
+2
+DELETE FROM tmp2;
+INSERT INTO tmp1 VALUES (1), (2), (3);
+INSERT INTO tmp2 VALUES (2), (3), (4);
+SELECT * FROM tmp1;
+a
+1
+2
+3
+SELECT * FROM tmp2;
+a
+2
+3
+4
+DELETE a1, a2
+FROM tmp1 AS a1 INNER JOIN tmp2 AS a2
+WHERE a1.a = a2.a;
+SELECT * FROM tmp1;
+a
+1
+SELECT * FROM tmp2;
+a
+4
+DROP DATABASE mysqltest2;
+DROP TABLE t1;
+DROP USER mysqltest_u1@localhost;

=== added file 'mysql-test/t/create_notembedded.test'
--- a/mysql-test/t/create_notembedded.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/create_notembedded.test	2010-06-03 09:01:18 +0000
@@ -0,0 +1,92 @@
+# Grant tests not performed with embedded server
+-- source include/not_embedded.inc
+
+#
+# Bug#27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table
+# operations.
+#
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest2;
+--enable_warnings
+
+CREATE DATABASE mysqltest2;
+
+GRANT CREATE, SELECT ON test.* TO mysqltest_u1@localhost;
+GRANT CREATE TEMPORARY TABLES ON mysqltest2.* TO mysqltest_u1@localhost;
+
+--connect (con1, localhost, mysqltest_u1, , mysqltest2)
+
+CREATE TEMPORARY TABLE tmp1(a INT);
+CREATE TEMPORARY TABLE tmp2(a INT);
+
+--error ER_TABLEACCESS_DENIED_ERROR
+CREATE TABLE t1(a INT);
+
+CREATE TABLE test.t1(a INT);
+
+# Check INSERT INTO.
+
+INSERT INTO tmp1 VALUES (11), (12), (13);
+INSERT INTO tmp2 VALUES (21), (22), (23);
+
+CREATE TEMPORARY TABLE tmp3(b INT);
+INSERT INTO tmp3 SELECT a FROM tmp1 UNION SELECT a FROM tmp2;
+SELECT * FROM tmp3;
+
+# Check SELECT.
+
+SELECT * FROM tmp1;
+
+SELECT * FROM tmp1, tmp2;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM tmp1, t1, tmp2;
+
+SELECT * FROM tmp1, test.t1, tmp2;
+
+# Check UPDATE.
+
+UPDATE tmp1 SET a = a * 10;
+SELECT * FROM tmp1;
+
+UPDATE tmp2 SET a = a - 20 WHERE a >= 10;
+SELECT * FROM tmp2;
+
+UPDATE tmp1, tmp3
+SET a = a * 1, b = b * 1
+WHERE b < 100;
+
+SELECT * FROM tmp1;
+SELECT * FROM tmp3;
+
+# Check DELETE.
+
+DELETE FROM tmp1;
+SELECT * FROM tmp1;
+
+DELETE FROM tmp2 WHERE a > 2;
+SELECT * FROM tmp2;
+
+DELETE FROM tmp2;
+
+INSERT INTO tmp1 VALUES (1), (2), (3);
+INSERT INTO tmp2 VALUES (2), (3), (4);
+
+SELECT * FROM tmp1;
+SELECT * FROM tmp2;
+
+DELETE a1, a2
+FROM tmp1 AS a1 INNER JOIN tmp2 AS a2
+WHERE a1.a = a2.a;
+
+SELECT * FROM tmp1;
+SELECT * FROM tmp2;
+
+--connection default
+--disconnect con1
+
+DROP DATABASE mysqltest2;
+DROP TABLE t1;
+
+DROP USER mysqltest_u1@localhost;

=== modified file 'sql/lock.h'
--- a/sql/lock.h	2010-05-28 22:13:31 +0000
+++ b/sql/lock.h	2010-06-03 09:01:18 +0000
@@ -12,7 +12,7 @@ typedef struct st_mysql_lock MYSQL_LOCK;
 /* 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
 #define MYSQL_OPEN_TAKE_UPGRADABLE_MDL          0x0020

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2010-05-28 05:47:58 +0000
+++ b/sql/sql_acl.cc	2010-06-03 09:01:18 +0000
@@ -3988,6 +3988,19 @@ end:
   DBUG_RETURN(return_val);
 }
 
+static bool check_grant_for_temporary_table(THD *thd, TABLE_LIST *tl)
+{
+  TABLE *table= tl->table;
+
+  if (!table && tl->correspondent_table)
+    table= tl->correspondent_table->table;
+
+  return
+    !(table && table->s &&
+      table->s->tmp_table != NO_TMP_TABLE &&
+      !check_access(thd, CREATE_TMP_ACL, table->s->db.str, NULL, NULL, 0, TRUE));
+}
+
 
 /**
   @brief Check table level grants
@@ -4117,9 +4130,24 @@ bool check_grant(THD *thd, ulong want_ac
       }
       continue;
     }
-    if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
-                                         table->get_db_name(), sctx->priv_user,
-                                         table->get_table_name(), FALSE)))
+
+    grant_table= table_hash_search(sctx->host, sctx->ip,
+                                   table->get_db_name(), sctx->priv_user,
+                                   table->get_table_name(), FALSE);
+
+    if (grant_table)
+    {
+      table->grant.grant_table=grant_table;	// Remember for column test
+      table->grant.version=grant_version;
+      table->grant.privilege|= grant_table->privs;
+      table->grant.want_privilege= ((want_access & COL_ACLS)
+                                    & ~table->grant.privilege);
+    }
+
+    if (!check_grant_for_temporary_table(thd, table))
+      continue;
+
+    if (!grant_table)
     {
       want_access &= ~table->grant.privilege;
       goto err;					// No grants
@@ -4132,12 +4160,6 @@ bool check_grant(THD *thd, ulong want_ac
     if (any_combination_will_do)
       continue;
 
-    table->grant.grant_table=grant_table;	// Remember for column test
-    table->grant.version=grant_version;
-    table->grant.privilege|= grant_table->privs;
-    table->grant.want_privilege= ((want_access & COL_ACLS)
-				  & ~table->grant.privilege);
-
     if (!(~table->grant.privilege & want_access))
       continue;
 
@@ -4294,6 +4316,9 @@ bool check_column_grant_in_table_ref(THD
     table_name= table->s->table_name.str;
   }
 
+  if (!check_grant_for_temporary_table(thd, table_ref))
+    return FALSE;
+
   if (grant->want_privilege)
     return check_grant_column(thd, grant, db_name, table_name, name,
                               length, sctx);
@@ -4340,6 +4365,11 @@ bool check_grant_all_columns(THD *thd, u
   for (; !fields->end_of_fields(); fields->next())
   {
     const char *field_name= fields->name();
+    bool is_tmp_table= FALSE;
+    Field *field= fields->field();
+
+    if (field && field->table && field->table->s)
+      is_tmp_table= field->table->s->tmp_table != NO_TMP_TABLE;
 
     if (table_name != fields->get_table_name())
     {
@@ -4361,19 +4391,27 @@ bool check_grant_all_columns(THD *thd, u
         }
 
         grant_table= grant->grant_table;
-        DBUG_ASSERT (grant_table);
+        DBUG_ASSERT(grant_table || !grant_table && is_tmp_table);
       }
     }
 
     if (want_access)
     {
-      GRANT_COLUMN *grant_column= 
-        column_hash_search(grant_table, field_name,
-                           (uint) strlen(field_name));
-      if (grant_column)
-        using_column_privileges= TRUE;
-      if (!grant_column || (~grant_column->rights & want_access))
-        goto err;
+      if (is_tmp_table)
+      {
+        if (check_access(thd, CREATE_TMP_ACL, db_name, NULL, NULL, 0, TRUE))
+          goto err;
+      }
+      else
+      {
+        GRANT_COLUMN *grant_column=
+          column_hash_search(grant_table, field_name,
+            (uint) strlen(field_name));
+        if (grant_column)
+          using_column_privileges= TRUE;
+        if (!grant_column || (~grant_column->rights & want_access))
+          goto err;
+      }
     }
   }
   mysql_rwlock_unlock(&LOCK_grant);

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-06-01 13:49:31 +0000
+++ b/sql/sql_base.cc	2010-06-03 09:01:18 +0000
@@ -56,7 +56,6 @@
 #include <io.h>
 #endif
 
-
 /**
   This internal handler is used to trap internally
   errors that can occur when executing open table
@@ -1975,9 +1974,12 @@ TABLE *find_temporary_table(THD *thd, co
 {
   TABLE_LIST table_list;
 
+  DBUG_ENTER("find_temporary_table(db_name, table_name)");
+
   table_list.db= (char*) db;
   table_list.table_name= (char*) table_name;
-  return find_temporary_table(thd, &table_list);
+
+  DBUG_RETURN(find_temporary_table(thd, &table_list));
 }
 
 
@@ -1985,16 +1987,26 @@ TABLE *find_temporary_table(THD *thd, TA
 {
   char	key[MAX_DBKEY_LENGTH];
   uint	key_length;
-  TABLE *table;
-  DBUG_ENTER("find_temporary_table");
+
+  DBUG_ENTER("find_temporary_table(TABLE_LIST)");
   DBUG_PRINT("enter", ("table: '%s'.'%s'",
                        table_list->db, table_list->table_name));
 
   key_length= create_table_def_key(thd, key, table_list, 1);
-  for (table=thd->temporary_tables ; table ; table= table->next)
+  DBUG_RETURN(find_temporary_table(thd, key, key_length));
+}
+
+
+TABLE *find_temporary_table(THD *thd,
+                            const char *table_key,
+                            uint table_key_length)
+{
+
+  DBUG_ENTER("find_temporary_table(table_key)");
+  for (TABLE *table= thd->temporary_tables; table; table= table->next)
   {
-    if (table->s->table_cache_key.length == key_length &&
-	!memcmp(table->s->table_cache_key.str, key, key_length))
+    if (table->s->table_cache_key.length == table_key_length &&
+        !memcmp(table->s->table_cache_key.str, table_key, table_key_length))
     {
       DBUG_PRINT("info",
                  ("Found table. server_id: %u  pseudo_thread_id: %lu",
@@ -2003,7 +2015,7 @@ TABLE *find_temporary_table(THD *thd, TA
       DBUG_RETURN(table);
     }
   }
-  DBUG_RETURN(0);                               // Not a temporary table
+  DBUG_RETURN(NULL);  // Not a temporary table
 }
 
 
@@ -2057,6 +2069,7 @@ int drop_temporary_table(THD *thd, TABLE
   */
   mysql_lock_remove(thd, thd->lock, table);
   close_temporary_table(thd, table, 1, 1);
+  table_list->table= NULL;
   DBUG_RETURN(0);
 }
 
@@ -2158,6 +2171,48 @@ bool rename_temporary_table(THD* thd, TA
 }
 
 
+static void update_table_flags(THD *thd, TABLE_LIST *table_list, TABLE *table)
+{
+  DBUG_ASSERT(table->s->ref_count > 0 || table->s->tmp_table != NO_TMP_TABLE);
+
+  if (thd->lex->need_correct_ident())
+    table->alias_name_used= my_strcasecmp(table_alias_charset,
+                                          table->s->table_name.str,
+                                          table_list->alias);
+  /* Fix alias if table name changes */
+  if (strcmp(table->alias, table_list->alias))
+  {
+    uint length=(uint) strlen(table_list->alias)+1;
+    table->alias= (char*) my_realloc((char*) table->alias, length,
+                                     MYF(MY_WME));
+    memcpy((char*) table->alias, table_list->alias, length);
+  }
+  table->tablenr=thd->current_tablenr++;
+  table->used_fields=0;
+  table->const_table=0;
+  table->null_row= table->maybe_null= 0;
+  table->force_index= table->force_index_order= table->force_index_group= 0;
+  table->status=STATUS_NO_RECORD;
+  table->insert_values= 0;
+  table->fulltext_searched= 0;
+  table->file->ft_handler= 0;
+  table->reginfo.impossible_range= 0;
+  /* Catch wrong handling of the auto_increment_field_not_null. */
+  DBUG_ASSERT(!table->auto_increment_field_not_null);
+  table->auto_increment_field_not_null= FALSE;
+  if (table->timestamp_field)
+    table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
+  table->pos_in_table_list= table_list;
+  table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
+  table->clear_column_bitmaps();
+  table_list->table= table;
+  DBUG_ASSERT(table->key_read == 0);
+  /* Tables may be reused in a sub statement. */
+  if (table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN))
+    table->file->extra(HA_EXTRA_DETACH_CHILDREN);
+}
+
+
 /**
    Force all other threads to stop using the table by upgrading
    metadata lock on it and remove unused TABLE instances from cache.
@@ -2460,8 +2515,6 @@ open_table_get_mdl_lock(THD *thd, TABLE_
                           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.
@@ -2492,7 +2545,7 @@ open_table_get_mdl_lock(THD *thd, TABLE_
 bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
                 Open_table_context *ot_ctx, uint flags)
 {
-  reg1	TABLE *table;
+  TABLE *table;
   char	key[MAX_DBKEY_LENGTH];
   uint	key_length;
   char	*alias= table_list->alias;
@@ -2538,48 +2591,14 @@ 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 (open_temporary_table(thd, table_list, &table, flags))
+    DBUG_RETURN(TRUE);
+
+  if (table)
+    goto reset;
+
+  if (table_list->open_type == OT_TEMPORARY_ONLY)
   {
     if (table_list->open_strategy == TABLE_LIST::OPEN_NORMAL)
     {
@@ -2965,42 +2984,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
   table->reginfo.lock_type=TL_READ;		/* Assume read */
 
  reset:
-  DBUG_ASSERT(table->s->ref_count > 0 || table->s->tmp_table != NO_TMP_TABLE);
-
-  if (thd->lex->need_correct_ident())
-    table->alias_name_used= my_strcasecmp(table_alias_charset,
-                                          table->s->table_name.str, alias);
-  /* Fix alias if table name changes */
-  if (strcmp(table->alias, alias))
-  {
-    uint length=(uint) strlen(alias)+1;
-    table->alias= (char*) my_realloc((char*) table->alias, length,
-                                     MYF(MY_WME));
-    memcpy((char*) table->alias, alias, length);
-  }
-  table->tablenr=thd->current_tablenr++;
-  table->used_fields=0;
-  table->const_table=0;
-  table->null_row= table->maybe_null= 0;
-  table->force_index= table->force_index_order= table->force_index_group= 0;
-  table->status=STATUS_NO_RECORD;
-  table->insert_values= 0;
-  table->fulltext_searched= 0;
-  table->file->ft_handler= 0;
-  table->reginfo.impossible_range= 0;
-  /* Catch wrong handling of the auto_increment_field_not_null. */
-  DBUG_ASSERT(!table->auto_increment_field_not_null);
-  table->auto_increment_field_not_null= FALSE;
-  if (table->timestamp_field)
-    table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
-  table->pos_in_table_list= table_list;
-  table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
-  table->clear_column_bitmaps();
-  table_list->table= table;
-  DBUG_ASSERT(table->key_read == 0);
-  /* Tables may be reused in a sub statement. */
-  if (table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN))
-    table->file->extra(HA_EXTRA_DETACH_CHILDREN);
+  update_table_flags(thd, table_list, table);
   DBUG_RETURN(FALSE);
 
 err_unlock:
@@ -4198,6 +4182,21 @@ open_and_process_table(THD *thd, LEX *le
   bool safe_to_ignore_table= FALSE;
   DBUG_ENTER("open_and_process_table");
 
+  if ((tables->open_type == OT_BASE_ONLY ||
+      (flags & MYSQL_OPEN_SKIP_TEMPORARY)) &&
+      tables->table && tables->table->s->tmp_table != NO_TMP_TABLE)
+  {
+    tables->table->query_id= 0;
+    tables->table= NULL;
+    // XXX: what to do with THD::thread_specific_used?
+  }
+
+  if (tables->table &&
+      tables->table->s->tmp_table != NO_TMP_TABLE)
+  {
+    goto end;
+  }
+
   /*
     Ignore placeholders for derived tables. After derived tables
     processing, link to created temporary table will be put here.
@@ -4386,6 +4385,8 @@ open_and_process_table(THD *thd, LEX *le
   /* MERGE tables need to access parent and child TABLE_LISTs. */
   DBUG_ASSERT(tables->table->pos_in_table_list == tables);
   /* Non-MERGE tables ignore this call. */
+  DBUG_PRINT("info", ("calling HA_EXTRA_ADD_CHILDREN_LIST (%s)...",
+      (char *) tables->table_name));
   if (tables->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
   {
     error= TRUE;
@@ -4631,8 +4632,7 @@ restart:
       these two flags. At this point, that does not matter as they
       are not used together with MYSQL_OPEN_TAKE_UPGRADABLE_MDL.
     */
-    DBUG_ASSERT(!(flags & (MYSQL_OPEN_SKIP_TEMPORARY |
-                           MYSQL_OPEN_TEMPORARY_ONLY)));
+    DBUG_ASSERT(!(flags & MYSQL_OPEN_SKIP_TEMPORARY));
     if (thd->locked_tables_mode)
     {
       /*
@@ -5569,7 +5569,120 @@ void close_tables_for_reopen(THD *thd, T
 
 
 /*
-  Open a single table without table caching and don't set it in open_list
+  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.
+
+  @return FALSE if success, TRUE - otherwise.
+  @retval FALSE 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.
+
+*/
+static bool open_temporary_table(THD *thd,
+                                 const char *table_key,
+                                 uint table_key_length,
+                                 TABLE_LIST *table_list,
+                                 TABLE **tmp_table,
+                                 uint flags)
+{
+  DBUG_ENTER("open_temporary_table");
+  DBUG_PRINT("enter", ("table: '%s'.'%s'",
+                       table_list->db, table_list->table_name));
+
+  *tmp_table= NULL;
+
+  if (table_list->open_type == OT_BASE_ONLY ||
+      (flags & MYSQL_OPEN_SKIP_TEMPORARY))
+  {
+    DBUG_PRINT("info", ("skip_temporary is set"));
+    DBUG_RETURN(FALSE);
+  }
+
+  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;
+
+  update_table_flags(thd, table_list, table);
+
+  DBUG_PRINT("info", ("Using temporary table"));
+  *tmp_table= table;
+
+  DBUG_RETURN(FALSE);
+}
+
+
+bool open_temporary_table(THD *thd, TABLE_LIST *tl, TABLE **tmp_table,
+                          uint flags)
+{
+  /*
+    If TABLE_LIST::schema_table is set, TABLE_LIST::table_name may be
+    corrupted.
+
+    TABLE_LIST::db may be an empty string, and TABLE_LIST::table_name
+    is corrupted in this case.
+  */
+
+  if (tl->schema_table || !tl->db[0])
+    return FALSE;
+
+  char key[MAX_DBKEY_LENGTH];
+  uint key_length;
+
+  key_length= create_table_def_key(thd, key, tl, 1);
+
+  return open_temporary_table(thd, key, key_length, tl, tmp_table, flags);
+}
+
+
+bool open_and_process_temporary_table(THD *thd, TABLE_LIST *tl)
+{
+  DBUG_ENTER("open_and_process_temporary_table");
+
+  if (open_temporary_table(thd, tl, &tl->table, 0))
+    DBUG_RETURN(TRUE);
+
+  if (!tl->table)
+    DBUG_RETURN(FALSE);
+
+  /* Non-MERGE tables ignore this call. */
+  if (tl->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
+    DBUG_RETURN(TRUE);
+
+  /* Check and update metadata version of a base table. */
+  if (check_and_update_table_version(thd, tl, tl->table->s))
+    DBUG_RETURN(TRUE);
+
+  DBUG_RETURN(FALSE);
+}
+
+
+/*
+  Load a single temporary table from the disk without table caching and
+  don't set it in open_list.
 
   SYNPOSIS
     open_temporary_table()

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	2010-05-28 05:47:58 +0000
+++ b/sql/sql_base.h	2010-06-03 09:01:18 +0000
@@ -132,8 +132,13 @@ TABLE_LIST *find_table_in_list(TABLE_LIS
                                TABLE_LIST *TABLE_LIST::*link,
                                const char *db_name,
                                const char *table_name);
+
 TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name);
 TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list);
+TABLE *find_temporary_table(THD *thd,
+                            const char *table_key,
+                            uint table_key_length);
+
 void close_thread_tables(THD *thd);
 bool fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
                                           List<Item> &values,
@@ -231,6 +236,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(THD *thd, TABLE_LIST *tl);
+bool open_temporary_table(THD *thd, TABLE_LIST *table_list,
+                          TABLE **tmp_table, uint flags);
 void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table);
 void remove_db_from_cache(const char *db);
 void flush_tables();

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-06-01 23:25:08 +0000
+++ b/sql/sql_class.h	2010-06-03 09:01:18 +0000
@@ -3625,6 +3625,12 @@ 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)
+
 /* Bits in server_command_flags */
 
 /**

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2010-05-20 12:35:28 +0000
+++ b/sql/sql_insert.cc	2010-06-03 09:01:18 +0000
@@ -3628,8 +3628,7 @@ static TABLE *create_table_from_items(TH
       else
       {
         Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT);
-        if (open_table(thd, create_table, thd->mem_root, &ot_ctx_unused,
-                       MYSQL_OPEN_TEMPORARY_ONLY))
+        if (open_temporary_table(thd, create_table, &table, 0))
         {
           /*
             This shouldn't happen as creation of temporary table should make
@@ -3639,7 +3638,9 @@ static TABLE *create_table_from_items(TH
           drop_temporary_table(thd, create_table);
         }
         else
-          table= create_table->table;
+        {
+          create_table->table= table;
+        }
       }
     }
     if (!table)                                   // open failed

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-06-01 23:25:08 +0000
+++ b/sql/sql_parse.cc	2010-06-03 09:01:18 +0000
@@ -259,10 +259,11 @@ void init_update_queries(void)
   */
   sql_command_flags[SQLCOM_CREATE_TABLE]=   CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS | CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_CREATE_INDEX]=   CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_ALTER_TABLE]=    CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
-                                            CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
+                                            CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_TRUNCATE]=       CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
                                             CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_DROP_TABLE]=     CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
@@ -288,31 +289,41 @@ void init_update_queries(void)
 
   sql_command_flags[SQLCOM_UPDATE]=	    CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_UPDATE_MULTI]=   CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_INSERT]=	    CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_INSERT_SELECT]=  CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_DELETE]=         CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_DELETE_MULTI]=   CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_REPLACE]=        CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_SELECT]=         CF_REEXECUTION_FRAGILE |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
   sql_command_flags[SQLCOM_SET_OPTION]=     CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_DO]=             CF_REEXECUTION_FRAGILE |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPEN_TMP_TABLES;
 
   sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
   sql_command_flags[SQLCOM_SHOW_STATUS]=      CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
@@ -342,7 +353,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 | CF_OPEN_TMP_TABLES;
   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;
@@ -412,6 +423,8 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_FLUSH]=              CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_RESET]=              CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_CHECK]=              CF_AUTO_COMMIT_TRANS;
+
+  sql_command_flags[SQLCOM_LOCK_TABLES]=        CF_OPEN_TMP_TABLES;
 }
 
 bool sqlcom_can_generate_row_events(const THD *thd)
@@ -2228,6 +2241,15 @@ mysql_execute_command(THD *thd)
     DEBUG_SYNC(thd,"before_execute_sql_command");
 #endif
 
+  if (sql_command_flags[lex->sql_command] & CF_OPEN_TMP_TABLES)
+  {
+    for (TABLE_LIST *tl= all_tables; tl; tl= tl->next_global)
+    {
+      if (open_and_process_temporary_table(thd, tl))
+        goto error;
+    }
+  }
+
   switch (lex->sql_command) {
 
   case SQLCOM_SHOW_EVENTS:
@@ -2304,7 +2326,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;


Attachment: [text/bzr-bundle] bzr/alik@sun.com-20100603090118-u0fn8rh0n7ez33me.bundle
Thread
bzr commit into mysql-trunk-bugfixing branch (alik:3092) Bug#27480Alexander Nozdrin3 Jun