summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mysql.com>2010-08-20 15:14:11 +0400
committerAlexander Barkov <bar@mysql.com>2010-08-20 15:14:11 +0400
commit84ee0a9fa40f13eaeec66ce2c9d3b8dcf2b9c67d (patch)
tree898cfdb055d0628299db2ec24858e41d693242ee
parent02863b41804352f1371407ccdc9e1cb51b9e20e3 (diff)
downloadmariadb-git-84ee0a9fa40f13eaeec66ce2c9d3b8dcf2b9c67d.tar.gz
Bug#55912 FORMAT with locale set fails for numbers < 1000
Problems: - dot character was always printed as decimal point instead of localized decimal point for short numbers without thousands - Item_func_format::val_str always returned values in ASCII format, regargless of @@character_set_connection, which in case of utf32 led to crash in debug build, or to incorrect values in release build. Fix: - Adding a piece of code to replace dot character to localized decimal point in short numbers. - Changing parent class for Item_func_format to Item_str_ascii_func, because its val_str() implementation is heavily ASCII oriented.
-rw-r--r--mysql-test/r/ctype_utf32.result14
-rw-r--r--mysql-test/r/func_str.result25
-rw-r--r--mysql-test/t/ctype_utf32.test9
-rw-r--r--mysql-test/t/func_str.test17
-rw-r--r--sql/item_strfunc.cc15
-rw-r--r--sql/item_strfunc.h8
6 files changed, 80 insertions, 8 deletions
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
@@ -810,5 +810,14 @@ 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);