From: bar Date: November 8 2006 11:37am Subject: bk commit into 4.1 tree (bar:1.2545) BUG#22646 List-Archive: http://lists.mysql.com/commits/15014 X-Bug: 22646 Message-Id: <200611081137.kA8BbxLF034946@bar.intranet.mysql.r18.ru> 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); insert into t1 values (_koi8r''); --- 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;