#At file:///home/ram/mysql/b19829-usual-5.0-bugteam/ based on revid:azundris@stripped
2728 Ramil Kalimullin 2009-01-12
Fix for bug#19829:make test Failed in mysql_client_test
*with --with-charset=utf8*
Problem: wrong LONG BLOB 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.
modified:
sql/protocol.cc
tests/mysql_client_test.c
per-file messages:
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 BLOB 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 file 'sql/protocol.cc'
--- a/sql/protocol.cc 2007-12-01 12:09:16 +0000
+++ b/sql/protocol.cc 2009-01-12 11:06:21 +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,17 @@ 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.
+
+ Note: the length is limited to UINT_MAX32 as we use 4 bytes
+ to store it.
*/
- 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 2008-12-11 10:37:18 +0000
+++ b/tests/mysql_client_test.c 2009-01-12 11:06:21 +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);