List:Commits« Previous MessageNext Message »
From:Ramil Kalimullin Date:February 26 2009 8:34am
Subject:bzr commit into mysql-5.0-bugteam branch (ramil:2765) Bug#19829
View as plain text  
#At file:///home/ram/mysql/b19829-5.0-bugteam/ based on revid:bernt.johnsen@stripped

 2765 Ramil Kalimullin	2009-02-26
      Fix for bug#19829:make test Failed in mysql_client_test
      *with --with-charset=utf8*
      
      Problem: wrong LONG TEXT field length is sent to a client 
      when multibyte server character set used.
      
      Fix: always limit field length sent to a client to 2^32,
      as we store it in 4 byte slot.
      
      Note: mysql_client_test changed accordingly.
     @ sql/protocol.cc
        Fix for bug#19829:make test Failed in mysql_client_test 
        *with --with-charset=utf8*
          - limit field length sent to client to UINT_MAX32 as 
            it may exceeds 32 bit slot for LONG TEXT fields if
            thd_charset->mbmaxlen > 1.
     @ tests/mysql_client_test.c
        Fix for bug#19829:make test Failed in mysql_client_test
        *with --with-charset=utf8*
          - checking field members have in mind that field length
            is limited to UINT_MAX32.

    modified:
      sql/protocol.cc
      tests/mysql_client_test.c
=== modified file 'sql/protocol.cc'
--- a/sql/protocol.cc	2007-12-01 12:09:16 +0000
+++ b/sql/protocol.cc	2009-02-26 08:34:15 +0000
@@ -616,7 +616,8 @@ bool Protocol::send_fields(List<Item> *l
       else
       {
         /* With conversion */
-        uint max_char_len;
+        ulonglong max_length;
+        uint32 field_length;
         int2store(pos, thd_charset->number);
         /*
           For TEXT/BLOB columns, field_length describes the maximum data
@@ -627,12 +628,21 @@ bool Protocol::send_fields(List<Item> *l
           char_count * mbmaxlen, where character count is taken from the
           definition of the column. In other words, the maximum number
           of characters here is limited by the column definition.
+
+          When one has a LONG TEXT column with a single-byte
+          character set, and the connection character set is multi-byte, the
+          client may get fields longer than UINT_MAX32, due to
+          <character set column> -> <character set connection> conversion.
+          In that case column max length does not fit into the 4 bytes
+          reserved for it in the protocol.
         */
-        max_char_len= (field.type >= (int) MYSQL_TYPE_TINY_BLOB &&
-                      field.type <= (int) MYSQL_TYPE_BLOB) ?
-                      field.length / item->collation.collation->mbminlen :
-                      field.length / item->collation.collation->mbmaxlen;
-        int4store(pos+2, max_char_len * thd_charset->mbmaxlen);
+        max_length= (field.type >= MYSQL_TYPE_TINY_BLOB &&
+                     field.type <= MYSQL_TYPE_BLOB) ?
+                     field.length / item->collation.collation->mbminlen :
+                     field.length / item->collation.collation->mbmaxlen;
+        max_length*= thd_charset->mbmaxlen;
+        field_length= (max_length > UINT_MAX32) ? UINT_MAX32 : max_length;
+        int4store(pos + 2, field_length);
       }
       pos[6]= field.type;
       int2store(pos+7,field.flags);

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2009-02-19 08:49:35 +0000
+++ b/tests/mysql_client_test.c	2009-02-26 08:34:15 +0000
@@ -714,6 +714,7 @@ static void do_verify_prepare_field(MYSQ
 {
   MYSQL_FIELD *field;
   CHARSET_INFO *cs;
+  ulonglong expected_field_length;
 
   if (!(field= mysql_fetch_field_direct(result, no)))
   {
@@ -722,6 +723,8 @@ static void do_verify_prepare_field(MYSQ
   }
   cs= get_charset(field->charsetnr, 0);
   DIE_UNLESS(cs);
+  if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32)
+    expected_field_length= UINT_MAX32;
   if (!opt_silent)
   {
     fprintf(stdout, "\n field[%d]:", no);
@@ -736,8 +739,8 @@ static void do_verify_prepare_field(MYSQ
       fprintf(stdout, "\n    org_table:`%s`\t(expected: `%s`)",
               field->org_table, org_table);
     fprintf(stdout, "\n    database :`%s`\t(expected: `%s`)", field->db, db);
-    fprintf(stdout, "\n    length   :`%lu`\t(expected: `%lu`)",
-            field->length, length * cs->mbmaxlen);
+    fprintf(stdout, "\n    length   :`%lu`\t(expected: `%llu`)",
+            field->length, expected_field_length);
     fprintf(stdout, "\n    maxlength:`%ld`", field->max_length);
     fprintf(stdout, "\n    charsetnr:`%d`", field->charsetnr);
     fprintf(stdout, "\n    default  :`%s`\t(expected: `%s`)",
@@ -773,11 +776,11 @@ static void do_verify_prepare_field(MYSQ
     as utf8. Field length is calculated as number of characters * maximum
     number of bytes a character can occupy.
   */
-  if (length && field->length != length * cs->mbmaxlen)
+  if (length && (field->length != expected_field_length))
   {
-    fprintf(stderr, "Expected field length: %d,  got length: %d\n",
-            (int) (length * cs->mbmaxlen), (int) field->length);
-    DIE_UNLESS(field->length == length * cs->mbmaxlen);
+    fprintf(stderr, "Expected field length: %llu,  got length: %lu\n",
+            expected_field_length, field->length);
+    DIE_UNLESS(field->length == expected_field_length);
   }
   if (def)
     DIE_UNLESS(strcmp(field->def, def) == 0);


Attachment: [text/bzr-bundle] bzr/ramil@mysql.com-20090226083415-tzt1kdka948cup24.bundle
Thread
bzr commit into mysql-5.0-bugteam branch (ramil:2765) Bug#19829Ramil Kalimullin26 Feb