List:Commits« Previous MessageNext Message »
From:Andrei Elkin Date:April 27 2006 10:43pm
Subject:bk commit into 5.0 tree (aelkin:1.2153) BUG#19188
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of elkin. When elkin 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
  1.2153 06/04/27 23:42:22 aelkin@stripped +3 -0
  Bug#19188: incorrect temporary table name of DROP query in replication
  
  A pattern to generate binlog for DROPped temp table in close_temporary_tables
  was buggy: could not deal with a grave-accent-in-name table.
  
  The fix exploits `append_identifier()' for quoting and duplicating accents.

  sql/sql_base.cc
    1.332 06/04/27 23:42:12 aelkin@stripped +50 -25
    Utilizing `append_identifier()' magic to cope with strange names.

  mysql-test/t/rpl_temporary.test
    1.18 06/04/27 23:42:12 aelkin@stripped +1 -0
    added grave-quote named table

  mysql-test/r/rpl_temporary.result
    1.23 06/04/27 23:42:12 aelkin@stripped +1 -0
    results changed

# 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:	aelkin
# Host:	dsl-hkigw8-feb0de00-199.dhcp.inet.fi
# Root:	/net/nb/home/elkin/MySQL/FIXES/5.0-bug19188-temp_name

--- 1.331/sql/sql_base.cc	2006-04-21 10:35:31 +03:00
+++ 1.332/sql/sql_base.cc	2006-04-27 23:42:12 +03:00
@@ -621,15 +621,17 @@
   TABLE *next,
     *prev_table /* prev link is not maintained in TABLE's double-linked list */,
     *table;
-  char *query= (gptr) 0, *end;
-  uint query_buf_size, max_names_len; 
+  char *query= (gptr) 0;
+  // Better add "if exists", in case a RESET MASTER has been done
+  const char *stub= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
+  const uint stub_len= strlen(stub);
+  uint query_buf_size= stub_len, max_names_len;
+  uint was_quote_show= 1; /* to assume thd->options has OPTION_QUOTE_SHOW_CREATE */
   bool found_user_tables;
+  String s_query;
 
   if (!thd->temporary_tables)
     return;
-  
-  LINT_INIT(end);
-  query_buf_size= 50;   // Enough for DROP ... TABLE IF EXISTS
 
   /* 
      insertion sort of temp tables by pseudo_thread_id to build ordered list 
@@ -690,46 +692,67 @@
            tmpkeyval(thd, table) == tmpkeyval(thd, table->next);
          table=table->next)
     {
-      /*
-        We are going to add 4 ` around the db/table names, so 1 might not look
-        enough; indeed it is enough, because table->key_length is greater (by 8,
-        because of server_id and thread_id) than db||table.
-      */
-      tmp_names_len += table->next->s->key_length + 1;
+      /* Sufficient buf size calc, can't calc exact because of possible `s */
+      tmp_names_len += table->next->s->key_length 
+        /* Subtract server_id and thread_id as uints! */
+        - 8
+        /* max estimation on case ` in names */
+        + 2 * (strlen(table->s->db) + strlen(table->s->table_name))
+        /* grave quotes `db` `table` */
+        + 4 
+         /* . */
+        + 1
+         /* , */
+        + 1;
     }
     if (tmp_names_len > max_names_len) max_names_len= tmp_names_len;
   }
   
   /* allocate */
-  if (found_user_tables && mysql_bin_log.is_open() &&
-      (query = alloc_root(thd->mem_root, query_buf_size+= max_names_len)))
-    // Better add "if exists", in case a RESET MASTER has been done
-    end= strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ");
-
+  if (found_user_tables && mysql_bin_log.is_open())
+  {
+    query= alloc_root(thd->mem_root, query_buf_size+= max_names_len);
+    if (query != (gptr) 0)
+    {
+      memcpy(query, stub, stub_len);
+      s_query= String(query, query_buf_size, system_charset_info);
+    }
+    // we might be out of memory, but this is not fatal 
+  }
+  /* It should be slight overkill but always to quote db,table names */
+  if (!(was_quote_show= (thd->options & OPTION_QUOTE_SHOW_CREATE)))
+  {
+    thd->options |= OPTION_QUOTE_SHOW_CREATE;
+  }
   /* scan sorted tmps to generate sequence of DROP */
-  for (table=thd->temporary_tables; table; table= next)
+  for (table= thd->temporary_tables; table; table= next)
   {
-    if (query // we might be out of memory, but this is not fatal 
-        && table->s->table_name[0] != '#') 
+    if (query && table->s->table_name[0] != '#') 
     {
-      char *end_cur;
       /* Set pseudo_thread_id to be that of the processed table */
       thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
       /* Loop forward through all tables within the sublist of
          common pseudo_thread_id to create single DROP query */
-      for (end_cur= end;
+      for (s_query.length(stub_len);
            table && table->s->table_name[0] != '#' &&
              tmpkeyval(thd, table) == thd->variables.pseudo_thread_id;
            table= next)
       {
-        end_cur= strxmov(end_cur, "`", table->s->db, "`.`",
-                      table->s->table_name, "`,", NullS);
+        /*
+          We are going to add 4 ` around the db/table names and possible more
+          due to special characters in the names
+        */
+        append_identifier(thd, &s_query, table->s->db,
strlen(table->s->db));
+        s_query.q_append(".", 1);
+        append_identifier(thd, &s_query, table->s->table_name,
strlen(table->s->table_name));
+        s_query.q_append(",", 1);
         next= table->next;
         close_temporary(table, 1);
       }
       thd->clear_error();
-      /* The -1 is to remove last ',' */
-      Query_log_event qinfo(thd, query, (ulong)(end_cur - query) - 1, 0, FALSE);
+      Query_log_event qinfo(thd, s_query.ptr(),
+                            s_query.length() - 1 /* to remove trailing ',' */,
+                            0, FALSE);
       /*
         Imagine the thread had created a temp table, then was doing a SELECT, and
         the SELECT was killed. Then it's not clever to mark the statement above as
@@ -748,6 +771,8 @@
       close_temporary(table, 1);
     }
   }
+  if (!was_quote_show)
+    thd->options &= ~OPTION_QUOTE_SHOW_CREATE;
   thd->temporary_tables=0;
 }
 

--- 1.22/mysql-test/r/rpl_temporary.result	2006-04-21 10:35:31 +03:00
+++ 1.23/mysql-test/r/rpl_temporary.result	2006-04-27 23:42:12 +03:00
@@ -108,6 +108,7 @@
 create temporary table t102 (id int);
 set @session.pseudo_thread_id=200;
 create temporary table t201 (id int);
+create temporary table `t``201` (id int);
 create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int);
 set @con1_id=connection_id();
 kill @con1_id;

--- 1.17/mysql-test/t/rpl_temporary.test	2006-04-21 10:35:31 +03:00
+++ 1.18/mysql-test/t/rpl_temporary.test	2006-04-27 23:42:12 +03:00
@@ -168,6 +168,7 @@
 create temporary table t102 (id int);
 set @session.pseudo_thread_id=200;
 create temporary table t201 (id int);
+create temporary table `t``201` (id int);
 create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int);
 set @con1_id=connection_id();
 kill @con1_id;
Thread
bk commit into 5.0 tree (aelkin:1.2153) BUG#19188Andrei Elkin27 Apr