List:Commits« Previous MessageNext Message »
From:ingo Date:August 2 2006 1:23pm
Subject:bk commit into 5.1 tree (ingo:1.2247) BUG#18775
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of istruewing. When istruewing does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-08-02 15:23:08+02:00, ingo@stripped +14 -0
  Bug#18775 - Temporary table from alter table visible to other threads
  Continued implementation of WL#1324 (table name to filename encoding)
  
  The intermediate (not temporary) files of the new table
  during ALTER TABLE was visible for SHOW TABLES. These
  intermediate files are copies of the original table with
  the changes done by ALTER TABLE. After all the data is
  copied over from the original table, these files are renamed 
  to the original tables file names. So they are not temporary 
  files. They persist after ALTER TABLE, but just with another 
  name.
  
  In 5.0 the intermediate files are invisible for SHOW TABLES
  because all file names beginning with "#sql" were suppressed.
  
  This failed since 5.1.6 because even temporary table names were
  converted when making file names from them. The prefix became
  converted to "@0023sql". Converting the prefix during SHOW TABLES
  would suppress the listing of user tables that start with "#sql".
  
  The solution of the problem is to continue the implementation of
  the table name to file name conversion feature. One requirement
  is to suppress the conversion for temporary table names.
  
  This change is straightforward for real temporary tables as there
  is a function that creates temporary file names.
  
  But the generated path names are located in TMPDIR and have no
  relation to the internal table name. This cannot be used for
  ALTER TABLE. Its intermediate files need to be in the same
  directory as the old table files. And it is necessary to be
  able to deduce the same path from the same table name repeatedly.
  
  Consequently the intermediate table files must be handled like normal
  tables. Their internal names shall start with tmp_file_prefix
  (#sql) and they shall not be converted like normal table names.
  
  I added a flags parameter to all relevant functions that are
  called from ALTER TABLE. It is used to suppress the conversion
  for the intermediate table files.
  
  The outcome is that the suppression of #sql in SHOW TABLES
  works again. It does not suppress user tables as these are
  converted to @0023sql on file level.
  
  This patch does also fix ALTER TABLE ... RENAME, which could not 
  rename a table with non-ASCII characters in its name.
  
  It does also fix the problem that a user could create a table like
  `#sql-xxxx-yyyy`, where xxxx is mysqld's pid and yyyy is the thread
  ID of some other thread, which prevented this thread from running 
  ALTER TABLE.
  
  Some of the above problems are mentioned in Bug 1405, which can
  be closed with this patch.
  
  This patch does also contain some minor fixes for other forgotten
  conversions. Still known problems are reported as bugs 21370,
  21373, and 21387.

  mysql-test/r/alter_table.result@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +60 -0
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Added test results.

  mysql-test/r/backup.result@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +20 -0
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Added test results.

  mysql-test/r/repair.result@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +6 -0
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Added test results.

  mysql-test/t/alter_table.test@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +63 -0
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Added test cases.

  mysql-test/t/backup.test@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +19 -0
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Added test cases.

  mysql-test/t/repair.test@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +13 -0
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Added a test case.

  sql/ha_myisam.cc@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +8 -2
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Added missing table name mapping calls to backup() and restore().

  sql/ha_ndbcluster_binlog.h@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +1 -1
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Removed unnecessary check for wrong temp file prefix.

  sql/mysql_priv.h@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +10 -7
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Extended quick_rm_table(), mysql_rename_table(), and
    build_table_filename() by an flags argument, which can indicate
    temporary table names that should not be converted.
    Added symbolic flag values.

  sql/sql_base.cc@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +8 -3
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Fixed a comment.
    Added DBUG calls.

  sql/sql_show.cc@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +1 -4
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Reverted the former fix for this bug. tmp_file_prefix is now used
    verbatim in the comparison of file names.

  sql/sql_table.cc@stripped, 2006-08-02 15:23:04+02:00, ingo@stripped +201 -62
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Added a check for a tmp_file_prefix file name to
    filename_to_tablename(). These names are now accepted without
    conversion.
    Extended quick_rm_table(), mysql_rename_table(), and
    build_table_filename() by an flags argument, which can indicate
    temporary table names that should not be converted.
    Removed the table to file name conversion from
    build_tmptable_filename().
    Disabled REPAIR TABLE ... USE_FRM for temporary tables.
    Added the forgotten conversion to mysql_alter_table() for the case
    of ALTER TABLE ... RENAME.
    Added comments and DBUG calls.

  sql/table.cc@stripped, 2006-08-02 15:23:05+02:00, ingo@stripped +8 -3
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Replaced a literal ".frm" by reg_ext.
    Added DBUG calls.

  storage/innobase/row/row0mysql.c@stripped, 2006-08-02 15:23:05+02:00, ingo@stripped +2 -2
    Bug#18775 - Temporary table from alter table visible to other threads
    Continued implementation of WL#1324 (table name to filename encoding)
    Changed back the encoded temp file prefix to #sql.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	ingo
# Host:	chilla.local
# Root:	/home/mydev/mysql-5.1-bug18775

--- 1.184/sql/ha_myisam.cc	2006-08-02 15:23:16 +02:00
+++ 1.185/sql/ha_myisam.cc	2006-08-02 15:23:16 +02:00
@@ -464,11 +464,14 @@ int ha_myisam::restore(THD* thd, HA_CHEC
   HA_CHECK_OPT tmp_check_opt;
   char *backup_dir= thd->lex->backup_dir;
   char src_path[FN_REFLEN], dst_path[FN_REFLEN];
-  const char *table_name= table->s->table_name.str;
+  char table_name[FN_REFLEN];
   int error;
   const char* errmsg;
   DBUG_ENTER("restore");
 
+  VOID(tablename_to_filename(table->s->table_name.str, table_name,
+                             sizeof(table_name)));
+
   if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
 				      MI_NAME_DEXT))
     DBUG_RETURN(HA_ADMIN_INVALID);
@@ -504,10 +507,13 @@ int ha_myisam::backup(THD* thd, HA_CHECK
 {
   char *backup_dir= thd->lex->backup_dir;
   char src_path[FN_REFLEN], dst_path[FN_REFLEN];
-  const char *table_name= table->s->table_name.str;
+  char table_name[FN_REFLEN];
   int error;
   const char *errmsg;
   DBUG_ENTER("ha_myisam::backup");
+
+  VOID(tablename_to_filename(table->s->table_name.str, table_name,
+                             sizeof(table_name)));
 
   if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir,
 				      reg_ext))

--- 1.417/sql/mysql_priv.h	2006-08-02 15:23:16 +02:00
+++ 1.418/sql/mysql_priv.h	2006-08-02 15:23:16 +02:00
@@ -733,7 +733,7 @@ int mysql_rm_table_part2_with_lock(THD *
 				   bool if_exists, bool drop_temporary,
 				   bool log_query);
 bool quick_rm_table(handlerton *base,const char *db,
-                    const char *table_name);
+                    const char *table_name, uint flags= 0);
 void close_cached_table(THD *thd, TABLE *table);
 bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent);
 bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
@@ -880,11 +880,9 @@ bool mysql_recreate_table(THD *thd, TABL
 bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
                              HA_CREATE_INFO *create_info,
                              Table_ident *src_table);
-bool mysql_rename_table(handlerton *base,
-			const char *old_db,
-			const char * old_name,
-			const char *new_db,
-			const char * new_name);
+bool mysql_rename_table(handlerton *base, const char *old_db,
+                        const char * old_name, const char *new_db,
+                        const char * new_name, uint flags= 0);
 bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
 bool mysql_drop_index(THD *thd, TABLE_LIST *table_list,
                       ALTER_INFO *alter_info);
@@ -1827,7 +1825,12 @@ uint strconvert(CHARSET_INFO *from_cs, c
 uint filename_to_tablename(const char *from, char *to, uint to_length);
 uint tablename_to_filename(const char *from, char *to, uint to_length);
 uint build_table_filename(char *buff, size_t bufflen, const char *db,
-                          const char *table, const char *ext);
+                          const char *table, const char *ext, uint flags= 0);
+/* Flags for conversion functions. */
+#define FN_FROM_IS_TMP  (1 << 0)
+#define FN_TO_IS_TMP    (1 << 1)
+#define FN_IS_TMP       (FN_FROM_IS_TMP | FN_TO_IS_TMP)
+
 /* from hostname.cc */
 struct in_addr;
 my_string ip_to_hostname(struct in_addr *in,uint *errors);

--- 1.333/sql/sql_base.cc	2006-08-02 15:23:16 +02:00
+++ 1.334/sql/sql_base.cc	2006-08-02 15:23:16 +02:00
@@ -252,7 +252,7 @@ uint cached_table_definitions(void)
   Get TABLE_SHARE for a table.
 
   get_table_share()
-  thd			Table share
+  thd			Thread handle
   table_list		Table that should be opened
   key			Table cache key
   key_length		Length of key
@@ -1499,15 +1499,18 @@ TABLE *find_temporary_table(THD *thd, TA
   char	key[MAX_DBKEY_LENGTH];
   uint	key_length;
   TABLE *table;
+  DBUG_ENTER("find_temporary_table");
+  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)
   {
     if (table->s->table_cache_key.length == key_length &&
 	!memcmp(table->s->table_cache_key.str, key, key_length))
-      return table;
+      DBUG_RETURN(table);
   }
-  return 0;					// Not a temporary table
+  DBUG_RETURN(0);					// Not a temporary table
 }
 
 
@@ -3487,6 +3490,8 @@ TABLE *open_temporary_table(THD *thd, co
   uint key_length;
   TABLE_LIST table_list;
   DBUG_ENTER("open_temporary_table");
+  DBUG_PRINT("enter", ("table: '%s'.'%s'  path: '%s'",
+                       db, table_name, path));
 
   table_list.db=         (char*) db;
   table_list.table_name= (char*) table_name;

--- 1.354/sql/sql_show.cc	2006-08-02 15:23:16 +02:00
+++ 1.355/sql/sql_show.cc	2006-08-02 15:23:16 +02:00
@@ -463,7 +463,6 @@ mysql_find_files(THD *thd,List<char> *fi
   uint col_access=thd->col_access;
 #endif
   TABLE_LIST table_list;
-  char tbbuff[FN_REFLEN];
   DBUG_ENTER("mysql_find_files");
 
   if (wild && !wild[0])
@@ -480,8 +479,6 @@ mysql_find_files(THD *thd,List<char> *fi
     DBUG_RETURN(-1);
   }
 
-  VOID(tablename_to_filename(tmp_file_prefix, tbbuff, sizeof(tbbuff)));
-
   for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
   {
     char uname[NAME_LEN*3+1];                   /* Unencoded name */
@@ -519,7 +516,7 @@ mysql_find_files(THD *thd,List<char> *fi
     {
         // Return only .frm files which aren't temp files.
       if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),reg_ext) ||
-          is_prefix(file->name,tbbuff))
+          is_prefix(file->name, tmp_file_prefix))
         continue;
       *ext=0;
       VOID(filename_to_tablename(file->name, uname, sizeof(uname)));

--- 1.356/sql/sql_table.cc	2006-08-02 15:23:16 +02:00
+++ 1.357/sql/sql_table.cc	2006-08-02 15:23:16 +02:00
@@ -53,31 +53,77 @@ static int mysql_prepare_table(THD *thd,
 #define MYSQL50_TABLE_NAME_PREFIX         "#mysql50#"
 #define MYSQL50_TABLE_NAME_PREFIX_LENGTH  9
 
+
+/*
+  Translate a file name to a table name (WL #1324).
+
+  SYNOPSIS
+    filename_to_tablename()
+      from                      The file name in my_charset_filename.
+      to                OUT     The table name in system_charset_info.
+      to_length                 The size of the table name buffer.
+
+  RETURN
+    Table name length.
+*/
+
 uint filename_to_tablename(const char *from, char *to, uint to_length)
 {
-  uint errors, res= strconvert(&my_charset_filename, from,
-                               system_charset_info,  to, to_length, &errors);
-  if (errors) // Old 5.0 name
+  uint errors;
+  uint res;
+  DBUG_ENTER("filename_to_tablename");
+  DBUG_PRINT("enter", ("from '%s'", from));
+
+  if (!memcmp(from, tmp_file_prefix, tmp_file_prefix_length))
   {
-    res= strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX,  from, NullS) - to;
-    sql_print_error("Invalid (old?) table or database name '%s'", from);
-    /*
-      TODO: add a stored procedure for fix table and database names,
-      and mention its name in error log.
-    */
+    /* Temporary table name. */
+    res= (strnmov(to, from, to_length) - to);
   }
-  return res;
+  else
+  {
+    res= strconvert(&my_charset_filename, from,
+                    system_charset_info,  to, to_length, &errors);
+    if (errors) // Old 5.0 name
+    {
+      res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX,  from, NullS) -
+            to);
+      sql_print_error("Invalid (old?) table or database name '%s'", from);
+      /*
+        TODO: add a stored procedure for fix table and database names,
+        and mention its name in error log.
+      */
+    }
+  }
+
+  DBUG_PRINT("exit", ("to '%s'", to));
+  DBUG_RETURN(res);
 }
 
 
+/*
+  Translate a table name to a file name (WL #1324).
+
+  SYNOPSIS
+    tablename_to_filename()
+      from                      The table name in system_charset_info.
+      to                OUT     The file name in my_charset_filename.
+      to_length                 The size of the file name buffer.
+
+  RETURN
+    File name length.
+*/
+
 uint tablename_to_filename(const char *from, char *to, uint to_length)
 {
   uint errors, length;
+  DBUG_ENTER("tablename_to_filename");
+  DBUG_PRINT("enter", ("from '%s'", from));
+
   if (from[0] == '#' && !strncmp(from, MYSQL50_TABLE_NAME_PREFIX,
                                  MYSQL50_TABLE_NAME_PREFIX_LENGTH))
-    return (uint) (strmake(to, from+MYSQL50_TABLE_NAME_PREFIX_LENGTH,
-                           to_length-1) -
-                   (from + MYSQL50_TABLE_NAME_PREFIX_LENGTH));
+    DBUG_RETURN((uint) (strmake(to, from+MYSQL50_TABLE_NAME_PREFIX_LENGTH,
+                                to_length-1) -
+                        (from + MYSQL50_TABLE_NAME_PREFIX_LENGTH)));
   length= strconvert(system_charset_info, from,
                      &my_charset_filename, to, to_length, &errors);
   if (check_if_legal_tablename(to) &&
@@ -86,7 +132,8 @@ uint tablename_to_filename(const char *f
     memcpy(to + length, "@@@", 4);
     length+= 3;
   }
-  return length;
+  DBUG_PRINT("exit", ("to '%s'", to));
+  DBUG_RETURN(length);
 }
 
 
@@ -95,52 +142,87 @@ uint tablename_to_filename(const char *f
 
   SYNOPSIS
    build_table_filename()
-   buff			where to write result
-   bufflen              buff size
-   db                   database name, in system_charset_info
-   table                table name, in system_charset_info
-   ext                  file extension
+     buff                       Where to write result in my_charset_filename.
+     bufflen                    buff size
+     db                         Database name in system_charset_info.
+     table_name                 Table name in system_charset_info.
+     ext                        File extension.
+     flags                      FN_FROM_IS_TMP or FN_TO_IS_TMP or FN_IS_TMP
+                                table_name is temporary, do not change.
 
   NOTES
 
     Uses database and table name, and extension to create
     a file name in mysql_data_dir. Database and table
     names are converted from system_charset_info into "fscs".
+    Unless flags indicate a temporary table name.
+    'db' is always converted.
     'ext' is not converted.
 
-  RETURN
+    The conversion suppression is required for ALTER TABLE. This
+    statement creates intermediate tables. These are regular
+    (non-temporary) tables with a temporary name. Their path names must
+    be derivable from the table name. So we cannot use
+    build_tmptable_filename() for them.
 
+  RETURN
+    path length
 */
 
-
 uint build_table_filename(char *buff, size_t bufflen, const char *db,
-                          const char *table, const char *ext)
+                          const char *table_name, const char *ext, uint flags)
 {
   uint length;
   char dbbuff[FN_REFLEN];
   char tbbuff[FN_REFLEN];
-  VOID(tablename_to_filename(table, tbbuff, sizeof(tbbuff)));
+  DBUG_ENTER("build_table_filename");
+
+  if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP
+    strnmov(tbbuff, table_name, sizeof(tbbuff));
+  else
+    VOID(tablename_to_filename(table_name, tbbuff, sizeof(tbbuff)));
+
   VOID(tablename_to_filename(db, dbbuff, sizeof(dbbuff)));
-  strxnmov(buff, bufflen,
-           mysql_data_home, "/", dbbuff, "/", tbbuff, ext, NullS);
-  length= unpack_filename(buff, buff);
-  return length;
+  length= strxnmov(buff, bufflen, mysql_data_home, "/", dbbuff,
+                   "/", tbbuff, ext, NullS) - buff;
+  DBUG_PRINT("exit", ("buff: '%s'", buff));
+  DBUG_RETURN(length);
 }
 
 
+/*
+  Creates path to a file: mysql_tmpdir/#sql1234_12_1.ext
+
+  SYNOPSIS
+   build_tmptable_filename()
+     thd                        The thread handle.
+     buff                       Where to write result in my_charset_filename.
+     bufflen                    buff size
+
+  NOTES
+
+    Uses current_pid, thread_id, and tmp_table counter to create
+    a file name in mysql_tmpdir.
+
+  RETURN
+    path length
+*/
+
 uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen)
 {
   uint length;
-  char tbbuff[FN_REFLEN];
   char tmp_table_name[tmp_file_prefix_length+22+22+22+3];
+  DBUG_ENTER("build_tmptable_filename");
+
   my_snprintf(tmp_table_name, sizeof(tmp_table_name),
 	      "%s%lx_%lx_%x",
 	      tmp_file_prefix, current_pid,
 	      thd->thread_id, thd->tmp_table++);
-  VOID(tablename_to_filename(tmp_table_name, tbbuff, sizeof(tbbuff)));
-  strxnmov(buff, bufflen, mysql_tmpdir, "/", tbbuff, reg_ext, NullS);
+
+  strxnmov(buff, bufflen, mysql_tmpdir, "/", tmp_table_name, reg_ext, NullS);
   length= unpack_filename(buff, buff);
-  return length;
+  DBUG_PRINT("exit", ("buff: '%s'", buff));
+  DBUG_RETURN(length);
 }
 
 /*
@@ -1732,15 +1814,30 @@ int mysql_rm_table_part2(THD *thd, TABLE
 }
 
 
+/*
+  Quickly remove a table.
+
+  SYNOPSIS
+    quick_rm_table()
+      base                      The handlerton handle.
+      db                        The database name.
+      table_name                The table name.
+      flags                     flags for build_table_filename().
+
+  RETURN
+    0           OK
+    != 0        Error
+*/
+
 bool quick_rm_table(handlerton *base,const char *db,
-		   const char *table_name)
+                    const char *table_name, uint flags)
 {
   char path[FN_REFLEN];
   bool error= 0;
   DBUG_ENTER("quick_rm_table");
 
   uint path_length= build_table_filename(path, sizeof(path),
-                                         db, table_name, reg_ext);
+                                         db, table_name, reg_ext, flags);
   if (my_delete(path,MYF(0)))
     error= 1; /* purecov: inspected */
   path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
@@ -3074,6 +3171,8 @@ bool mysql_create_table_internal(THD *th
   handler	*file;
   bool		error= TRUE;
   DBUG_ENTER("mysql_create_table_internal");
+  DBUG_PRINT("enter", ("db: '%s'  table: '%s'  tmp: %d",
+                       db, table_name, internal_tmp_table));
 
   if (use_copy_create_info)
   {
@@ -3293,7 +3392,8 @@ bool mysql_create_table_internal(THD *th
       start++;
     }	  
 #endif
-    path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext);
+    path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext,
+                                      internal_tmp_table ? FN_IS_TMP : 0);
   }
 
   /* Check if table already exists */
@@ -3337,9 +3437,13 @@ bool mysql_create_table_internal(THD *th
   */
   if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
   {
+    char dbbuff[FN_REFLEN];
+    char tbbuff[FN_REFLEN];
     bool create_if_not_exists =
       create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
-    if (ha_table_exists_in_engine(thd, db, table_name))
+    VOID(tablename_to_filename(db, dbbuff, sizeof(dbbuff)));
+    VOID(tablename_to_filename(table_name, tbbuff, sizeof(tbbuff)));
+    if (ha_table_exists_in_engine(thd, dbbuff, tbbuff))
     {
       DBUG_PRINT("info", ("Table with same name already existed in handler"));
 
@@ -3491,12 +3595,30 @@ make_unique_key_name(const char *field_n
 ** Alter a table definition
 ****************************************************************************/
 
+
+/*
+  Rename a table.
+
+  SYNOPSIS
+    mysql_rename_table()
+      base                      The handlerton handle.
+      old_db                    The old database name.
+      old_name                  The old table name.
+      new_db                    The new database name.
+      new_name                  The new table name.
+      flags                     flags for build_table_filename().
+                                FN_FROM_IS_TMP old_name is temporary.
+                                FN_TO_IS_TMP   new_name is temporary.
+
+  RETURN
+    0           OK
+    != 0        Error
+*/
+
 bool
-mysql_rename_table(handlerton *base,
-		   const char *old_db,
-		   const char *old_name,
-		   const char *new_db,
-		   const char *new_name)
+mysql_rename_table(handlerton *base, const char *old_db,
+                   const char *old_name, const char *new_db,
+                   const char *new_name, uint flags)
 {
   THD *thd= current_thd;
   char from[FN_REFLEN], to[FN_REFLEN], lc_from[FN_REFLEN], lc_to[FN_REFLEN];
@@ -3505,12 +3627,16 @@ mysql_rename_table(handlerton *base,
   handler *file;
   int error=0;
   DBUG_ENTER("mysql_rename_table");
+  DBUG_PRINT("enter", ("old: '%s'.'%s'  new: '%s'.'%s'",
+                       old_db, old_name, new_db, new_name));
 
   file= (base == NULL ? 0 :
          get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base));
 
-  build_table_filename(from, sizeof(from), old_db, old_name, "");
-  build_table_filename(to, sizeof(to), new_db, new_name, "");
+  build_table_filename(from, sizeof(from), old_db, old_name, "",
+                       flags & FN_FROM_IS_TMP);
+  build_table_filename(to, sizeof(to), new_db, new_name, "",
+                       flags & FN_TO_IS_TMP);
 
   /*
     If lower_case_table_names == 2 (case-preserving but case-insensitive
@@ -3522,12 +3648,14 @@ mysql_rename_table(handlerton *base,
   {
     strmov(tmp_name, old_name);
     my_casedn_str(files_charset_info, tmp_name);
-    build_table_filename(lc_from, sizeof(lc_from), old_db, tmp_name, "");
+    build_table_filename(lc_from, sizeof(lc_from), old_db, tmp_name, "",
+                         flags & FN_FROM_IS_TMP);
     from_base= lc_from;
 
     strmov(tmp_name, new_name);
     my_casedn_str(files_charset_info, tmp_name);
-    build_table_filename(lc_to, sizeof(lc_to), new_db, tmp_name, "");
+    build_table_filename(lc_to, sizeof(lc_to), new_db, tmp_name, "",
+                         flags & FN_TO_IS_TMP);
     to_base= lc_to;
   }
 
@@ -3740,6 +3868,15 @@ static int prepare_for_repair(THD *thd, 
     table= &tmp_table;
     pthread_mutex_unlock(&LOCK_open);
   }
+  /*
+    REPAIR TABLE ... USE_FRM for temporary tables makes little sense.
+  */
+  if (table->s->tmp_table)
+  {
+    error= send_check_errmsg(thd, table_list, "repair",
+			     "Cannot repair temporary table from .frm file");
+    goto end;
+  }
 
   /*
     User gave us USE_FRM which means that the header in the index file is
@@ -5023,6 +5160,7 @@ bool mysql_alter_table(THD *thd,char *ne
   /* Check that we are not trying to rename to an existing table */
   if (new_name)
   {
+    DBUG_PRINT("info", ("new_db.new_name: '%s'.'%s'", new_db, new_name));
     strmov(new_name_buff,new_name);
     strmov(new_alias= new_alias_buff, new_name);
     if (lower_case_table_names)
@@ -5055,11 +5193,9 @@ bool mysql_alter_table(THD *thd,char *ne
       }
       else
       {
-	char dir_buff[FN_REFLEN];
-	strxnmov(dir_buff, sizeof(dir_buff)-1,
-                 mysql_real_data_home, new_db, NullS);
-	if (!access(fn_format(new_name_buff,new_name_buff,dir_buff,reg_ext,0),
-		    F_OK))
+        build_table_filename(new_name_buff, sizeof(new_name_buff),
+                             new_db, new_name_buff, reg_ext, 0);
+        if (!access(new_name_buff, F_OK))
 	{
 	  /* Table will be closed in do_command() */
 	  my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
@@ -5776,7 +5912,8 @@ bool mysql_alter_table(THD *thd,char *ne
     {
       char path[FN_REFLEN];
       /* table is a normal table: Create temporary table in same directory */
-      build_table_filename(path, sizeof(path), new_db, tmp_name, "");
+      build_table_filename(path, sizeof(path), new_db, tmp_name, "",
+                           FN_IS_TMP);
       new_table=open_temporary_table(thd, path, new_db, tmp_name,0);
     }
     if (!new_table)
@@ -5992,7 +6129,7 @@ bool mysql_alter_table(THD *thd,char *ne
   VOID(pthread_mutex_lock(&LOCK_open));
   if (error)
   {
-    VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+    VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
     VOID(pthread_mutex_unlock(&LOCK_open));
     goto err;
   }
@@ -6014,7 +6151,7 @@ bool mysql_alter_table(THD *thd,char *ne
     {
       error=1;
       my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
-      VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+      VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
       VOID(pthread_mutex_unlock(&LOCK_open));
       goto err;
     }
@@ -6042,22 +6179,24 @@ bool mysql_alter_table(THD *thd,char *ne
   error=0;
   if (!need_copy_table)
     new_db_type=old_db_type= NULL; // this type cannot happen in regular ALTER
-  if (mysql_rename_table(old_db_type,db,table_name,db,old_name))
+  if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
+                         FN_TO_IS_TMP))
   {
     error=1;
-    VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+    VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
   }
   else if (mysql_rename_table(new_db_type,new_db,tmp_name,new_db,
-			      new_alias) ||
+			      new_alias, FN_FROM_IS_TMP) ||
            (new_name != table_name || new_db != db) && // we also do rename
            Table_triggers_list::change_table_name(thd, db, table_name,
                                                   new_db, new_alias))
-       
-  {						// Try to get everything back
+  {
+    /* Try to get everything back. */
     error=1;
     VOID(quick_rm_table(new_db_type,new_db,new_alias));
-    VOID(quick_rm_table(new_db_type,new_db,tmp_name));
-    VOID(mysql_rename_table(old_db_type,db,old_name,db,alias));
+    VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
+    VOID(mysql_rename_table(old_db_type, db, old_name, db, alias,
+                            FN_FROM_IS_TMP));
   }
   if (error)
   {
@@ -6101,7 +6240,7 @@ bool mysql_alter_table(THD *thd,char *ne
       table->s->version= 0;              	// Force removal of table def
       close_cached_table(thd,table);
     }
-    VOID(quick_rm_table(old_db_type,db,old_name));
+    VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
   }
   else
   {
@@ -6118,7 +6257,7 @@ bool mysql_alter_table(THD *thd,char *ne
       /* end threads waiting on lock */
       mysql_lock_abort(thd,table, TRUE);
     }
-    VOID(quick_rm_table(old_db_type,db,old_name));
+    VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
     if (close_data_tables(thd,db,table_name) ||
 	reopen_tables(thd,1,0))
     {						// This shouldn't happen
@@ -6199,7 +6338,7 @@ end_temporary:
     close_temporary_table(thd, new_table, 1, 1);
   }
   else
-    VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+    VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
 
  err:
   DBUG_RETURN(TRUE);

--- 1.230/sql/table.cc	2006-08-02 15:23:16 +02:00
+++ 1.231/sql/table.cc	2006-08-02 15:23:16 +02:00
@@ -68,7 +68,7 @@ static byte *get_field_name(Field **buff
 char *fn_rext(char *name)
 {
   char *res= strrchr(name, '.');
-  if (res && !strcmp(res, ".frm"))
+  if (res && !strcmp(res, reg_ext))
     return res;
   return name + strlen(name);
 }
@@ -95,6 +95,9 @@ TABLE_SHARE *alloc_table_share(TABLE_LIS
   TABLE_SHARE *share;
   char path[FN_REFLEN];
   uint path_length;
+  DBUG_ENTER("alloc_table_share");
+  DBUG_PRINT("enter", ("table: '%s'.'%s'",
+                       table_list->db, table_list->table_name));
 
   path_length= build_table_filename(path, sizeof(path) - 1,
                                     table_list->db,
@@ -148,7 +151,7 @@ TABLE_SHARE *alloc_table_share(TABLE_LIS
     pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
     pthread_cond_init(&share->cond, NULL);
   }
-  return share;
+  DBUG_RETURN(share);
 }
 
 
@@ -179,6 +182,7 @@ void init_tmp_table_share(TABLE_SHARE *s
                           const char *path)
 {
   DBUG_ENTER("init_tmp_table_share");
+  DBUG_PRINT("enter", ("table: '%s'.'%s'", key, table_name));
 
   bzero((char*) share, sizeof(*share));
   init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
@@ -286,7 +290,8 @@ int open_table_def(THD *thd, TABLE_SHARE
   char	path[FN_REFLEN];
   MEM_ROOT **root_ptr, *old_root;
   DBUG_ENTER("open_table_def");
-  DBUG_PRINT("enter", ("name: '%s.%s'",share->db.str, share->table_name.str));
+  DBUG_PRINT("enter", ("table: '%s'.'%s'  path: '%s'", share->db.str,
+                       share->table_name.str, share->normalized_path.str));
 
   error= 1;
   error_given= 0;

--- 1.126/storage/innobase/row/row0mysql.c	2006-08-02 15:23:16 +02:00
+++ 1.127/storage/innobase/row/row0mysql.c	2006-08-02 15:23:16 +02:00
@@ -3414,8 +3414,8 @@ row_is_mysql_tmp_table_name(
 	const char*	name)	/* in: table name in the form
 				'database/tablename' */
 {
-	/* return(strstr(name, "/#sql") != NULL); */
-	return(strstr(name, "/@0023sql") != NULL);
+	return(strstr(name, "/#sql") != NULL);
+	/* return(strstr(name, "/@0023sql") != NULL); */
 }
 
 /********************************************************************

--- 1.64/mysql-test/r/alter_table.result	2006-08-02 15:23:16 +02:00
+++ 1.65/mysql-test/r/alter_table.result	2006-08-02 15:23:16 +02:00
@@ -657,3 +657,63 @@ SELECT * FROM t1;
 v	b
 abc	5
 DROP TABLE t1;
+DROP DATABASE IF EXISTS mysqltest;
+CREATE DATABASE mysqltest;
+use mysqltest;
+ERROR 42S01: Table 't1_blЭten' already exists
+ERROR 42S01: Table 'tt1_blЭten' already exists
+Table	Create Table
+  `c1` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+CREATE TABLE `#sql1` (c1 INT);
+CREATE TABLE `@0023sql2` (c1 INT);
+SHOW TABLES;
+Tables_in_mysqltest
+#sql1
+@0023sql2
+RENAME TABLE `#sql1`     TO `@0023sql1`;
+RENAME TABLE `@0023sql2` TO `#sql2`;
+SHOW TABLES;
+Tables_in_mysqltest
+#sql2
+@0023sql1
+ALTER TABLE `@0023sql1`  RENAME `#sql-1`;
+ALTER TABLE `#sql2`      RENAME `@0023sql-2`;
+SHOW TABLES;
+Tables_in_mysqltest
+#sql-1
+@0023sql-2
+INSERT INTO `#sql-1`     VALUES (1);
+INSERT INTO `@0023sql-2` VALUES (2);
+DROP TABLE `#sql-1`, `@0023sql-2`;
+CREATE TEMPORARY TABLE `#sql1` (c1 INT);
+CREATE TEMPORARY TABLE `@0023sql2` (c1 INT);
+SHOW TABLES;
+Tables_in_mysqltest
+ALTER TABLE `#sql1`      RENAME `@0023sql1`;
+ALTER TABLE `@0023sql2`  RENAME `#sql2`;
+SHOW TABLES;
+Tables_in_mysqltest
+INSERT INTO `#sql2`      VALUES (1);
+INSERT INTO `@0023sql1`  VALUES (2);
+SHOW CREATE TABLE `@0023sql1`;
+Table	Create Table
+@0023sql1	CREATE TEMPORARY TABLE `@0023sql1` (
+  `c1` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE `#sql2`, `@0023sql1`;
+use test;
+DROP DATABASE mysqltest;

--- 1.49/mysql-test/t/alter_table.test	2006-08-02 15:23:16 +02:00
+++ 1.50/mysql-test/t/alter_table.test	2006-08-02 15:23:16 +02:00
@@ -482,3 +482,66 @@ SELECT * FROM t1;
 ALTER TABLE t1 MODIFY COLUMN v VARCHAR(4);
 SELECT * FROM t1;
 DROP TABLE t1;
+
+# End of 5.0 tests
+
+#
+# Bug#18775 - Temporary table from alter table visible to other threads
+#
+# Use a special database to avoid name clashes with user tables.
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest;
+--enable_warnings
+CREATE DATABASE mysqltest;
+use mysqltest;
+#
+# Check if non-ASCII alphabetic characters work and duplicates are detected.
+--disable_warnings
+--enable_warnings
+--error ER_TABLE_EXISTS_ERROR
+#
+# Same for temporary tables though these names do not become file names.
+--error ER_TABLE_EXISTS_ERROR
+#
+# Check if special characters as in tmp_file_prefix work.
+CREATE TABLE `#sql1` (c1 INT);
+CREATE TABLE `@0023sql2` (c1 INT);
+SHOW TABLES;
+RENAME TABLE `#sql1`     TO `@0023sql1`;
+RENAME TABLE `@0023sql2` TO `#sql2`;
+SHOW TABLES;
+ALTER TABLE `@0023sql1`  RENAME `#sql-1`;
+ALTER TABLE `#sql2`      RENAME `@0023sql-2`;
+SHOW TABLES;
+INSERT INTO `#sql-1`     VALUES (1);
+INSERT INTO `@0023sql-2` VALUES (2);
+DROP TABLE `#sql-1`, `@0023sql-2`;
+#
+# Same for temporary tables though these names do not become file names.
+CREATE TEMPORARY TABLE `#sql1` (c1 INT);
+CREATE TEMPORARY TABLE `@0023sql2` (c1 INT);
+SHOW TABLES;
+ALTER TABLE `#sql1`      RENAME `@0023sql1`;
+ALTER TABLE `@0023sql2`  RENAME `#sql2`;
+SHOW TABLES;
+INSERT INTO `#sql2`      VALUES (1);
+INSERT INTO `@0023sql1`  VALUES (2);
+SHOW CREATE TABLE `@0023sql1`;
+DROP TABLE `#sql2`, `@0023sql1`;
+#
+# Cleanup
+use test;
+DROP DATABASE mysqltest;
+

--- 1.17/mysql-test/r/backup.result	2006-08-02 15:23:16 +02:00
+++ 1.18/mysql-test/r/backup.result	2006-08-02 15:23:16 +02:00
@@ -101,3 +101,23 @@ test.t5	backup	status	OK
 Warnings:
 Warning	1541	The syntax 'BACKUP TABLE' is deprecated and will be removed in MySQL 5.2. Please use MySQL Administrator (mysqldump, mysql) instead.
 drop table t5;
+Table	Op	Msg_type	Msg_text
+Warnings:
+Warning	1541	The syntax 'BACKUP TABLE' is deprecated and will be removed in MySQL 5.2. Please use MySQL Administrator (mysqldump, mysql) instead.
+Table	Op	Msg_type	Msg_text
+Warnings:
+Warning	1541	The syntax 'RESTORE TABLE' is deprecated and will be removed in MySQL 5.2. Please use MySQL Administrator (mysqldump, mysql) instead.
+c1
+1
+2
+3

--- 1.20/mysql-test/t/backup.test	2006-08-02 15:23:16 +02:00
+++ 1.21/mysql-test/t/backup.test	2006-08-02 15:23:16 +02:00
@@ -58,3 +58,22 @@ drop table t5;
 --system rm $MYSQLTEST_VARDIR/tmp/t?.*
 
 # End of 4.1 tests
+# End of 5.0 tests
+
+#
+# Bug#18775 - Temporary table from alter table visible to other threads
+#
+# Backup did not encode table names.
+--disable_warnings
+--enable_warnings
+#
+# Same for restore.
+

--- 1.18/mysql-test/r/repair.result	2006-08-02 15:23:16 +02:00
+++ 1.19/mysql-test/r/repair.result	2006-08-02 15:23:16 +02:00
@@ -41,3 +41,9 @@ Table	Op	Msg_type	Msg_text
 test.t1	repair	warning	Number of rows changed from 0 to 1
 test.t1	repair	status	OK
 drop table t1;
+DROP TABLE IF EXISTS tt1;
+CREATE TEMPORARY TABLE tt1 (c1 INT);
+REPAIR TABLE tt1 USE_FRM;
+Table	Op	Msg_type	Msg_text
+tt1	repair	error	Cannot repair temporary table from .frm file
+DROP TABLE tt1;

--- 1.15/mysql-test/t/repair.test	2006-08-02 15:23:16 +02:00
+++ 1.16/mysql-test/t/repair.test	2006-08-02 15:23:16 +02:00
@@ -35,3 +35,16 @@ repair table t1 use_frm;
 drop table t1;
 
 # End of 4.1 tests
+# End of 5.0 tests
+
+#
+# Bug#18775 - Temporary table from alter table visible to other threads
+#
+# REPAIR TABLE ... USE_FRM on temporary table crashed the table or server.
+--disable_warnings
+DROP TABLE IF EXISTS tt1;
+--enable_warnings
+CREATE TEMPORARY TABLE tt1 (c1 INT);
+REPAIR TABLE tt1 USE_FRM;
+DROP TABLE tt1;
+

--- 1.14/sql/ha_ndbcluster_binlog.h	2006-08-02 15:23:16 +02:00
+++ 1.15/sql/ha_ndbcluster_binlog.h	2006-08-02 15:23:16 +02:00
@@ -23,7 +23,7 @@ typedef NdbDictionary::Index  NDBINDEX;
 typedef NdbDictionary::Dictionary  NDBDICT;
 typedef NdbDictionary::Event  NDBEVENT;
 
-#define IS_TMP_PREFIX(A) (is_prefix(A, tmp_file_prefix) || is_prefix(A, "@0023sql"))
+#define IS_TMP_PREFIX(A) (is_prefix(A, tmp_file_prefix))
 
 extern ulong ndb_extra_logging;
 
Thread
bk commit into 5.1 tree (ingo:1.2247) BUG#18775ingo2 Aug