mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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: Adding test case. Fixing old result. mysql-test/t/ctype_utf8.test: Adding test case. sql/item_timefunc.cc: 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 commit is contained in:
@ -124,12 +124,34 @@ create table t1 select date_format("2004-01-19 10:10:10", "%Y-%m-%d");
|
|||||||
show create table t1;
|
show create table t1;
|
||||||
Table Create Table
|
Table Create Table
|
||||||
t1 CREATE TABLE `t1` (
|
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
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
select * from t1;
|
select * from t1;
|
||||||
date_format("2004-01-19 10:10:10", "%Y-%m-%d")
|
date_format("2004-01-19 10:10:10", "%Y-%m-%d")
|
||||||
2004-01-19
|
2004-01-19
|
||||||
drop table t1;
|
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;
|
set names koi8r;
|
||||||
create table t1 (s1 char(1) character set utf8);
|
create table t1 (s1 char(1) character set utf8);
|
||||||
insert into t1 values (_koi8r'<27><>');
|
insert into t1 values (_koi8r'<27><>');
|
||||||
|
@ -93,6 +93,26 @@ show create table t1;
|
|||||||
select * from t1;
|
select * from t1;
|
||||||
drop table 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
|
# Bug #2366 Wrong utf8 behaviour when data is truncated
|
||||||
#
|
#
|
||||||
|
@ -595,16 +595,10 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
|
|||||||
uint weekday;
|
uint weekday;
|
||||||
ulong length;
|
ulong length;
|
||||||
const char *ptr, *end;
|
const char *ptr, *end;
|
||||||
MY_LOCALE *locale;
|
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
char buf[128];
|
MY_LOCALE *locale= thd->variables.lc_time_names;
|
||||||
String tmp(buf, sizeof(buf), thd->variables.character_set_results);
|
|
||||||
uint errors= 0;
|
|
||||||
|
|
||||||
tmp.length(0);
|
|
||||||
str->length(0);
|
str->length(0);
|
||||||
str->set_charset(&my_charset_bin);
|
|
||||||
locale = thd->variables.lc_time_names;
|
|
||||||
|
|
||||||
if (l_time->neg)
|
if (l_time->neg)
|
||||||
str->append("-", 1);
|
str->append("-", 1);
|
||||||
@ -618,41 +612,37 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
|
|||||||
{
|
{
|
||||||
switch (*++ptr) {
|
switch (*++ptr) {
|
||||||
case 'M':
|
case 'M':
|
||||||
if (!l_time->month)
|
if (!l_time->month)
|
||||||
return 1;
|
return 1;
|
||||||
tmp.copy(locale->month_names->type_names[l_time->month-1],
|
str->append(locale->month_names->type_names[l_time->month-1],
|
||||||
strlen(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);
|
system_charset_info);
|
||||||
str->append(tmp.ptr(), tmp.length());
|
break;
|
||||||
break;
|
|
||||||
case 'b':
|
case 'b':
|
||||||
if (!l_time->month)
|
if (!l_time->month)
|
||||||
return 1;
|
return 1;
|
||||||
tmp.copy(locale->ab_month_names->type_names[l_time->month-1],
|
str->append(locale->ab_month_names->type_names[l_time->month-1],
|
||||||
strlen(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);
|
system_charset_info);
|
||||||
str->append(tmp.ptr(), tmp.length());
|
break;
|
||||||
break;
|
|
||||||
case 'W':
|
case 'W':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
|
weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
|
||||||
l_time->day),0);
|
l_time->day),0);
|
||||||
tmp.copy(locale->day_names->type_names[weekday],
|
str->append(locale->day_names->type_names[weekday],
|
||||||
strlen(locale->day_names->type_names[weekday]),
|
strlen(locale->day_names->type_names[weekday]),
|
||||||
system_charset_info, tmp.charset(), &errors);
|
system_charset_info);
|
||||||
str->append(tmp.ptr(), tmp.length());
|
break;
|
||||||
break;
|
|
||||||
case 'a':
|
case 'a':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
|
weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
|
||||||
l_time->day),0);
|
l_time->day),0);
|
||||||
tmp.copy(locale->ab_day_names->type_names[weekday],
|
str->append(locale->ab_day_names->type_names[weekday],
|
||||||
strlen(locale->ab_day_names->type_names[weekday]),
|
strlen(locale->ab_day_names->type_names[weekday]),
|
||||||
system_charset_info, tmp.charset(), &errors);
|
system_charset_info);
|
||||||
str->append(tmp.ptr(), tmp.length());
|
break;
|
||||||
break;
|
|
||||||
case 'D':
|
case 'D':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
@ -1638,8 +1628,9 @@ longlong Item_func_sec_to_time::val_int()
|
|||||||
|
|
||||||
void Item_func_date_format::fix_length_and_dec()
|
void Item_func_date_format::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
|
THD* thd= current_thd;
|
||||||
decimals=0;
|
decimals=0;
|
||||||
collation.set(&my_charset_bin);
|
collation.set(thd->variables.collation_connection);
|
||||||
if (args[1]->type() == STRING_ITEM)
|
if (args[1]->type() == STRING_ITEM)
|
||||||
{ // Optimize the normal case
|
{ // Optimize the normal case
|
||||||
fixed_length=1;
|
fixed_length=1;
|
||||||
@ -1653,17 +1644,14 @@ void Item_func_date_format::fix_length_and_dec()
|
|||||||
args[1]->collation.set(
|
args[1]->collation.set(
|
||||||
get_charset_by_csname(args[1]->collation.collation->csname,
|
get_charset_by_csname(args[1]->collation.collation->csname,
|
||||||
MY_CS_BINSORT,MYF(0)), DERIVATION_COERCIBLE);
|
MY_CS_BINSORT,MYF(0)), DERIVATION_COERCIBLE);
|
||||||
/*
|
max_length= format_length(((Item_string*) args[1])->const_string()) *
|
||||||
The result is a binary string (no reason to use collation->mbmaxlen
|
collation.collation->mbmaxlen;
|
||||||
This is becasue make_date_time() only returns binary strings
|
|
||||||
*/
|
|
||||||
max_length= format_length(((Item_string*) args[1])->const_string());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fixed_length=0;
|
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);
|
set_if_smaller(max_length,MAX_BLOB_WIDTH);
|
||||||
}
|
}
|
||||||
maybe_null=1; // If wrong date
|
maybe_null=1; // If wrong date
|
||||||
@ -1783,6 +1771,7 @@ String *Item_func_date_format::val_str(String *str)
|
|||||||
date_time_format.format.length= format->length();
|
date_time_format.format.length= format->length();
|
||||||
|
|
||||||
/* Create the result string */
|
/* Create the result string */
|
||||||
|
str->set_charset(collation.collation);
|
||||||
if (!make_date_time(&date_time_format, &l_time,
|
if (!make_date_time(&date_time_format, &l_time,
|
||||||
is_time_format ? MYSQL_TIMESTAMP_TIME :
|
is_time_format ? MYSQL_TIMESTAMP_TIME :
|
||||||
MYSQL_TIMESTAMP_DATE,
|
MYSQL_TIMESTAMP_DATE,
|
||||||
|
Reference in New Issue
Block a user