From 14263b222a9ab2f0769dcc5c6f2b0825dc7163b1 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 1 Mar 2011 15:09:37 +0300 Subject: Bug#11753363 (bug#44793) CHARACTER SETS: CASE CLAUSE, UCS2 OR UTF32, FAILURE Problem: in case of string CASE/WHEN arguments with different character sets, Item_func_case::find_item() called comparator cmp_items[x] on mixed character set Items, so a 8-bit value could be errouneously referenced to as being utf16/utf32 value, which led to crash on DBUG_ASSERT() because of wrong value length. This was wrong, as string comparator expects arguments in the same character set. Fix: modify Item_func_case's argument list after calling agg_arg_charsets_for_comparison() - put the Items in "agg" array back to "args", because some of the Items in the "agg" array might have been changed to character set converters: - to Item_func_conv_charset for non-constant items - to Item_string for constant items In other words, perform the same substitution which is done in all other operations string comparison or string result operations: Replace CASE latin1_item WHEN utf16_item THEN ... END to CASE CONVERT(latin1_item USING utf16) WHEN utf16_item THEN ... END Replace CASE utf16_item WHEN latin1_item THEN ... END to CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END @ mysql-test/r/ctype_utf16.result @ mysql-test/r/ctype_utf32.result @ mysql-test/t/ctype_utf16.test @ mysql-test/t/ctype_utf32.test Adding tests @ sql/item_cmpfunc.cc Put "agg" back to "args". @ sql/sql_string.cc Backporting a fix for String::set_or_copy_aligned() from 5.6, for better test coverage: "SELECT _utf16 0x61" should expand the string to 0x0061 rather than to 0x000061. This fix was made in 5.6 under terms of "WL#4616 Implement UTF16-LE". --- sql/sql_string.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql/sql_string.cc') diff --git a/sql/sql_string.cc b/sql/sql_string.cc index d19b876a82f..66f293a82c6 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -252,8 +252,8 @@ bool String::copy_aligned(const char *str,uint32 arg_length, uint32 offset, CHARSET_INFO *cs) { /* How many bytes are in incomplete character */ - offset= cs->mbmaxlen - offset; /* How many zeros we should prepend */ - DBUG_ASSERT(offset && offset != cs->mbmaxlen); + offset= cs->mbminlen - offset; /* How many zeros we should prepend */ + DBUG_ASSERT(offset && offset != cs->mbminlen); uint32 aligned_length= arg_length + offset; if (alloc(aligned_length)) -- cgit v1.2.1