List:Commits« Previous MessageNext Message »
From:bar Date:November 8 2006 11:37am
Subject:bk commit into 4.1 tree (bar:1.2545) BUG#22646
View as plain text  
Below is the list of changes that have just been committed into a local
4.1 repository of bar. When bar 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-11-08 15:37:54+04:00, bar@stripped +3 -0
  Bug#22646 LC_TIME_NAMES: Assignment to non-UTF8 target fails
  Problem: After introducing of LC_TIME_NAMES variable,  the 
  function date_format() can return international non-ascii
  characters in month and weekday names. Thus, it cannot return
  a binary string anymore, because inserting a result of date_format()
  into a column with non-utf8 character set produces garbage.
  Fix: date_format() now returns a character string, using
  "collation_connection" to detect character set and collation
  for the returned value. This allows to insert
  results of date_format() properly into columns with
  various character sets.

  mysql-test/r/ctype_utf8.result@stripped, 2006-11-08 15:37:51+04:00, bar@stripped +23 -1
    Adding test case.
    Fixing old result.

  mysql-test/t/ctype_utf8.test@stripped, 2006-11-08 15:37:51+04:00, bar@stripped +20 -0
    Adding test case.

  sql/item_timefunc.cc@stripped, 2006-11-08 15:37:51+04:00, bar@stripped +36 -47
    DATE_FORMAT() now returns a character string
    instead of binary string:
    - make_date_time() now converts localte data from UTF8 to 
    the character set of "str" argument, instead of copying as is.
    - fix_dec_and_length() now uses "collation_connection"
    instead of "binary" for the result, it also now
    multiplies to mbmaxlen when calculating max_length

# 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:	bar
# Host:	bar.intranet.mysql.r18.ru
# Root:	/usr/home/bar/mysql-4.1.b22646

--- 1.110/sql/item_timefunc.cc	2006-11-08 15:38:00 +04:00
+++ 1.111/sql/item_timefunc.cc	2006-11-08 15:38:00 +04:00
@@ -595,16 +595,10 @@ bool make_date_time(DATE_TIME_FORMAT *fo
   uint weekday;
   ulong length;
   const char *ptr, *end;
-  MY_LOCALE *locale;
   THD *thd= current_thd;
-  char buf[128];
-  String tmp(buf, sizeof(buf), thd->variables.character_set_results);
-  uint errors= 0;
+  MY_LOCALE *locale= thd->variables.lc_time_names;
 
-  tmp.length(0);
   str->length(0);
-  str->set_charset(&my_charset_bin);
-  locale = thd->variables.lc_time_names;
 
   if (l_time->neg)
     str->append("-", 1);
@@ -618,41 +612,37 @@ bool make_date_time(DATE_TIME_FORMAT *fo
     {
       switch (*++ptr) {
       case 'M':
-	if (!l_time->month)
-	  return 1;
-	tmp.copy(locale->month_names->type_names[l_time->month-1],
-		   strlen(locale->month_names->type_names[l_time->month-1]),
-		   system_charset_info, tmp.charset(), &errors);
-	str->append(tmp.ptr(), tmp.length());
-	break;
+        if (!l_time->month)
+          return 1;
+        str->append(locale->month_names->type_names[l_time->month-1],
+                    strlen(locale->month_names->type_names[l_time->month-1]),
+                    system_charset_info);
+        break;
       case 'b':
-	if (!l_time->month)
-	  return 1;
-	tmp.copy(locale->ab_month_names->type_names[l_time->month-1],
-		 strlen(locale->ab_month_names->type_names[l_time->month-1]),
-		 system_charset_info, tmp.charset(), &errors);
-	str->append(tmp.ptr(), tmp.length());
-	break;
+        if (!l_time->month)
+          return 1;
+        str->append(locale->ab_month_names->type_names[l_time->month-1],
+                    strlen(locale->ab_month_names->type_names[l_time->month-1]),
+                    system_charset_info);
+        break;
       case 'W':
-	if (type == MYSQL_TIMESTAMP_TIME)
-	  return 1;
-	weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
-					 l_time->day),0);
-	tmp.copy(locale->day_names->type_names[weekday],
-		 strlen(locale->day_names->type_names[weekday]),
-		 system_charset_info, tmp.charset(), &errors);
-	str->append(tmp.ptr(), tmp.length());
-	break;
+        if (type == MYSQL_TIMESTAMP_TIME)
+          return 1;
+        weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
+                              l_time->day),0);
+        str->append(locale->day_names->type_names[weekday],
+                    strlen(locale->day_names->type_names[weekday]),
+                    system_charset_info);
+        break;
       case 'a':
-	if (type == MYSQL_TIMESTAMP_TIME)
-	  return 1;
-	weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
-					l_time->day),0);
-	tmp.copy(locale->ab_day_names->type_names[weekday],
-		 strlen(locale->ab_day_names->type_names[weekday]),
-		 system_charset_info, tmp.charset(), &errors);
-	str->append(tmp.ptr(), tmp.length());
-	break;
+        if (type == MYSQL_TIMESTAMP_TIME)
+          return 1;
+        weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
+                             l_time->day),0);
+        str->append(locale->ab_day_names->type_names[weekday],
+                    strlen(locale->ab_day_names->type_names[weekday]),
+                    system_charset_info);
+        break;
       case 'D':
 	if (type == MYSQL_TIMESTAMP_TIME)
 	  return 1;
@@ -1638,8 +1628,9 @@ longlong Item_func_sec_to_time::val_int(
 
 void Item_func_date_format::fix_length_and_dec()
 {
+  THD* thd= current_thd;
   decimals=0;
-  collation.set(&my_charset_bin);
+  collation.set(thd->variables.collation_connection);
   if (args[1]->type() == STRING_ITEM)
   {						// Optimize the normal case
     fixed_length=1;
@@ -1653,17 +1644,14 @@ void Item_func_date_format::fix_length_a
     args[1]->collation.set(
         get_charset_by_csname(args[1]->collation.collation->csname,
                               MY_CS_BINSORT,MYF(0)), DERIVATION_COERCIBLE);
-    /*
-      The result is a binary string (no reason to use collation->mbmaxlen
-      This is becasue make_date_time() only returns binary strings
-    */
-    max_length= format_length(((Item_string*) args[1])->const_string());
+    max_length= format_length(((Item_string*) args[1])->const_string()) *
+                collation.collation->mbmaxlen;
   }
   else
   {
     fixed_length=0;
-    /* The result is a binary string (no reason to use collation->mbmaxlen */
-    max_length=min(args[1]->max_length,MAX_BLOB_WIDTH) * 10;
+    max_length= min(args[1]->max_length,MAX_BLOB_WIDTH) * 10 * 
+                collation.collation->mbmaxlen;
     set_if_smaller(max_length,MAX_BLOB_WIDTH);
   }
   maybe_null=1;					// If wrong date
@@ -1783,6 +1771,7 @@ String *Item_func_date_format::val_str(S
   date_time_format.format.length= format->length(); 
 
   /* Create the result string */
+  str->set_charset(collation.collation);
   if (!make_date_time(&date_time_format, &l_time,
                       is_time_format ? MYSQL_TIMESTAMP_TIME :
                                        MYSQL_TIMESTAMP_DATE,

--- 1.74/mysql-test/r/ctype_utf8.result	2006-11-08 15:38:00 +04:00
+++ 1.75/mysql-test/r/ctype_utf8.result	2006-11-08 15:38:00 +04:00
@@ -124,12 +124,34 @@ create table t1 select date_format("2004
 show create table t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
-  `date_format("2004-01-19 10:10:10", "%Y-%m-%d")` binary(10) default NULL
+  `date_format("2004-01-19 10:10:10", "%Y-%m-%d")` char(10) character set utf8 default NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 select * from t1;
 date_format("2004-01-19 10:10:10", "%Y-%m-%d")
 2004-01-19
 drop table t1;
+set names utf8;
+set LC_TIME_NAMES='fr_FR';
+create table t1 (s1 char(20) character set latin1);
+insert into t1 values (date_format('2004-02-02','%M'));
+select hex(s1) from t1;
+hex(s1)
+66E97672696572
+drop table t1;
+create table t1 (s1 char(20) character set koi8r);
+set LC_TIME_NAMES='ru_RU';
+insert into t1 values (date_format('2004-02-02','%M'));
+insert into t1 values (date_format('2004-02-02','%b'));
+insert into t1 values (date_format('2004-02-02','%W'));
+insert into t1 values (date_format('2004-02-02','%a'));
+select hex(s1), s1 from t1;
+hex(s1)	s1
+E6C5D7D2C1CCD1	Февраля
+E6C5D7	Фев
+F0CFCEC5C4C5CCD8CEC9CB	Понедельник
+F0CEC4	Пнд
+drop table t1;
+set LC_TIME_NAMES='en_US';
 set names koi8r;
 create table t1 (s1 char(1) character set utf8);

--- 1.76/mysql-test/t/ctype_utf8.test	2006-11-08 15:38:00 +04:00
+++ 1.77/mysql-test/t/ctype_utf8.test	2006-11-08 15:38:00 +04:00
@@ -94,6 +94,26 @@ select * from t1;
 drop table t1;
 
 #
+# Bug#22646 LC_TIME_NAMES: Assignment to non-UTF8 target fails
+#
+set names utf8;
+set LC_TIME_NAMES='fr_FR';
+create table t1 (s1 char(20) character set latin1);
+insert into t1 values (date_format('2004-02-02','%M'));
+select hex(s1) from t1;
+drop table t1;
+create table t1 (s1 char(20) character set koi8r);
+set LC_TIME_NAMES='ru_RU';
+insert into t1 values (date_format('2004-02-02','%M'));
+insert into t1 values (date_format('2004-02-02','%b'));
+insert into t1 values (date_format('2004-02-02','%W'));
+insert into t1 values (date_format('2004-02-02','%a'));
+select hex(s1), s1 from t1;
+drop table t1;
+set LC_TIME_NAMES='en_US';
+
+
+#
 # Bug #2366  	Wrong utf8 behaviour when data is truncated
 #
 set names koi8r;
Thread
bk commit into 4.1 tree (bar:1.2545) BUG#22646bar8 Nov