List:Commits« Previous MessageNext Message »
From:Alexander Barkov Date:August 19 2010 10:28am
Subject:bzr commit into mysql-5.5-bugfixing branch (bar:3188) Bug#55912
View as plain text  
#At file:///home/bar/mysql-bzr/mysql-5.5-bugfixing.b55912/ based on revid:bar@stripped

 3188 Alexander Barkov	2010-08-19
      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.

    modified:
      mysql-test/r/ctype_utf32.result
      mysql-test/r/func_str.result
      mysql-test/t/ctype_utf32.test
      mysql-test/t/func_str.test
      sql/item_strfunc.cc
      sql/item_strfunc.h
=== modified file 'mysql-test/r/ctype_utf32.result'
--- a/mysql-test/r/ctype_utf32.result	2010-08-18 12:08:59 +0000
+++ b/mysql-test/r/ctype_utf32.result	2010-08-19 10:23:37 +0000
@@ -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
 #

=== modified file 'mysql-test/r/func_str.result'
--- a/mysql-test/r/func_str.result	2010-04-27 09:58:21 +0000
+++ b/mysql-test/r/func_str.result	2010-08-19 10:23:37 +0000
@@ -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
+#

=== modified file 'mysql-test/t/ctype_utf32.test'
--- a/mysql-test/t/ctype_utf32.test	2010-08-18 12:08:59 +0000
+++ b/mysql-test/t/ctype_utf32.test	2010-08-19 10:23:37 +0000
@@ -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 #

=== modified file 'mysql-test/t/func_str.test'
--- a/mysql-test/t/func_str.test	2010-04-02 15:17:43 +0000
+++ b/mysql-test/t/func_str.test	2010-08-19 10:23:37 +0000
@@ -1404,3 +1404,20 @@ SELECT format(123, 1, 'Non-existent-loca
 
 --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 #

=== modified file 'sql/item_strfunc.cc'
--- a/sql/item_strfunc.cc	2010-08-18 12:08:59 +0000
+++ b/sql/item_strfunc.cc	2010-08-19 10:23:37 +0000
@@ -2235,7 +2235,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())))
@@ -2251,11 +2251,10 @@ MY_LOCALE *Item_func_format::get_locale(
 
 void Item_func_format::fix_length_and_dec()
 {
-  uint char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen;
+  uint char_length= args[0]->max_char_length();
   uint max_sep_count= char_length/3 + (decimals ? 1 : 0) + /*sign*/1;
   collation.set(default_charset());
-  max_length= (char_length + max_sep_count + decimals) *
-    collation.collation->mbmaxlen;
+  fix_char_length(char_length + max_sep_count + decimals);
   if (arg_count == 3)
     locale= args[2]->basic_const_item() ? get_locale(args[2]) : NULL;
   else
@@ -2269,7 +2268,7 @@ void Item_func_format::fix_length_and_de
   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 */
@@ -2309,8 +2308,7 @@ String *Item_func_format::val_str(String
     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_latin1);
     if (isnan(nr))
       return str;
     str_length=str->length();
@@ -2360,6 +2358,14 @@ String *Item_func_format::val_str(String
     /* 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;
 }
 

=== modified file 'sql/item_strfunc.h'
--- a/sql/item_strfunc.h	2010-08-18 12:08:59 +0000
+++ b/sql/item_strfunc.h	2010-08-19 10:23:37 +0000
@@ -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);


Attachment: [text/bzr-bundle] bzr/bar@mysql.com-20100819102337-air5pmeet4t03631.bundle
Thread
bzr commit into mysql-5.5-bugfixing branch (bar:3188) Bug#55912Alexander Barkov19 Aug