diff --git a/mysql-test/r/ctype_utf32.result b/mysql-test/r/ctype_utf32.result index f7a22fcfc3f..79e714eab47 100644 --- a/mysql-test/r/ctype_utf32.result +++ b/mysql-test/r/ctype_utf32.result @@ -1100,5 +1100,19 @@ my_col 00 DROP TABLE t1; # +# Bug#55912 FORMAT with locale set fails for numbers < 1000 +# +SET collation_connection=utf32_general_ci; +CREATE TABLE t1 AS SELECT format(123,2,'no_NO'); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `format(123,2,'no_NO')` varchar(37) CHARACTER SET utf32 NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +format(123,2,'no_NO') +123,00 +DROP TABLE t1; +# # End of 5.5 tests # diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 7539cf43dd9..f01d46a9f41 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2734,3 +2734,28 @@ format(123, 1, 'Non-existent-locale') Warnings: Warning 1649 Unknown locale: 'Non-existent-locale' End of 5.4 tests +# +# Start of 5.5 tests +# +# +# Bug#55912 FORMAT with locale set fails for numbers < 1000 +# +SELECT FORMAT(123.33, 2, 'no_NO'), FORMAT(1123.33, 2, 'no_NO'); +FORMAT(123.33, 2, 'no_NO') FORMAT(1123.33, 2, 'no_NO') +123,33 1.123,33 +SELECT FORMAT(12333e-2, 2, 'no_NO'), FORMAT(112333e-2, 2, 'no_NO'); +FORMAT(12333e-2, 2, 'no_NO') FORMAT(112333e-2, 2, 'no_NO') +123,33 1.123,33 +CREATE TABLE t1 AS SELECT format(123,2,'no_NO'); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `format(123,2,'no_NO')` varchar(37) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +format(123,2,'no_NO') +123,00 +DROP TABLE t1; +# +# End of 5.5 tests +# diff --git a/mysql-test/t/ctype_utf32.test b/mysql-test/t/ctype_utf32.test index 51a28627daa..668b3b033bd 100644 --- a/mysql-test/t/ctype_utf32.test +++ b/mysql-test/t/ctype_utf32.test @@ -809,6 +809,15 @@ CREATE TABLE t1 AS SELECT HEX(0x00) AS my_col; SELECT * FROM t1; DROP TABLE t1; +--echo # +--echo # Bug#55912 FORMAT with locale set fails for numbers < 1000 +--echo # +SET collation_connection=utf32_general_ci; +CREATE TABLE t1 AS SELECT format(123,2,'no_NO'); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + --echo # --echo # End of 5.5 tests --echo # diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 10d35b16315..7b7bffd0bbc 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1404,3 +1404,20 @@ SELECT format(123, 1, 'Non-existent-locale'); --echo End of 5.4 tests +--echo # +--echo # Start of 5.5 tests +--echo # + +--echo # +--echo # Bug#55912 FORMAT with locale set fails for numbers < 1000 +--echo # +SELECT FORMAT(123.33, 2, 'no_NO'), FORMAT(1123.33, 2, 'no_NO'); +SELECT FORMAT(12333e-2, 2, 'no_NO'), FORMAT(112333e-2, 2, 'no_NO'); +CREATE TABLE t1 AS SELECT format(123,2,'no_NO'); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +--echo # +--echo # End of 5.5 tests +--echo # diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 1a772950303..6d3514bf356 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2217,7 +2217,7 @@ const int FORMAT_MAX_DECIMALS= 30; MY_LOCALE *Item_func_format::get_locale(Item *item) { DBUG_ASSERT(arg_count == 3); - String tmp, *locale_name= args[2]->val_str(&tmp); + String tmp, *locale_name= args[2]->val_str_ascii(&tmp); MY_LOCALE *lc; if (!locale_name || !(lc= my_locale_by_name(locale_name->c_ptr_safe()))) @@ -2250,7 +2250,7 @@ void Item_func_format::fix_length_and_dec() are stored in more than one byte */ -String *Item_func_format::val_str(String *str) +String *Item_func_format::val_str_ascii(String *str) { uint32 str_length; /* Number of decimal digits */ @@ -2290,8 +2290,7 @@ String *Item_func_format::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ nr= my_double_round(nr, (longlong) dec, FALSE, FALSE); - /* Here default_charset() is right as this is not an automatic conversion */ - str->set_real(nr, dec, default_charset()); + str->set_real(nr, dec, &my_charset_numeric); if (isnan(nr)) return str; str_length=str->length(); @@ -2341,6 +2340,14 @@ String *Item_func_format::val_str(String *str) /* Put the rest of the integer part without grouping */ str->copy(dst, buf + sizeof(buf) - dst, &my_charset_latin1); } + else if (dec_length && lc->decimal_point != '.') + { + /* + For short values without thousands (<1000) + replace decimal point to localized value. + */ + ((char*) str->ptr())[str_length - dec_length]= lc->decimal_point; + } return str; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 4461373f7b3..5dcef2e671f 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -539,17 +539,17 @@ public: }; -class Item_func_format :public Item_str_func +class Item_func_format :public Item_str_ascii_func { String tmp_str; MY_LOCALE *locale; public: - Item_func_format(Item *org, Item *dec): Item_str_func(org, dec) {} + Item_func_format(Item *org, Item *dec): Item_str_ascii_func(org, dec) {} Item_func_format(Item *org, Item *dec, Item *lang): - Item_str_func(org, dec, lang) {} + Item_str_ascii_func(org, dec, lang) {} MY_LOCALE *get_locale(Item *item); - String *val_str(String *); + String *val_str_ascii(String *); void fix_length_and_dec(); const char *func_name() const { return "format"; } virtual void print(String *str, enum_query_type query_type);