From: Alexander Barkov Date: March 1 2011 12:10pm Subject: bzr push into mysql-5.5 branch (alexander.barkov:3359 to 3360) Bug#44793 Bug#11753363 List-Archive: http://lists.mysql.com/commits/132193 X-Bug: 44793,11753363 Message-Id: <201103011210.p21CAQHD009793@bar.myoffice.izhnet.ru> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3360 Alexander Barkov 2011-03-01 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". modified: mysql-test/r/ctype_utf16.result mysql-test/r/ctype_utf32.result mysql-test/t/ctype_utf16.test mysql-test/t/ctype_utf32.test sql/item_cmpfunc.cc sql/sql_string.cc 3359 Magne Mahre 2011-03-01 Bug#11765237 - 58179: CANNOT START MYSQLD WITH APP VERIFIER Bug#11763065 - 55730: KILL_SERVER() CALLS SETEVENT ON A NULL HANDLE, SMEM_EVENT_CONNECT_REQUEST Application Verifier is a Microsoft tool used for detecting certain classes of programming errors. In particular, MS Windows OS resource usage is monitored for wrong usage (handles, thread local storage, critical sections, ...) In MySQL 5.5.x, an error was introduced where an object on thread local storage was used before the TLS and the object was created. The fix has been to move the mysys initialization to an earlier stage in the boot process when built for Windows. For non-win builds, the init already happens early. Some un-tangling of calls to my_init(), my_basic_init() and my_thread_global_init() was done. There is no longer a need to do init in steps, so the full my_init() is called instead of my_init_basic(). In addition, Bug#11763065 was fixed. The event handle 'smem_event_connect_request' is only created if 'opt_enable_shared_memory' is set. When killing the server, an event was flagged on the handle unconditionally. Added a test, so it will only be flagged if created. @ include/my_pthread.h my_thread_basic_global_init is no longer necessary, and the my_thread_basic_global_reinit function is renamed to reflect that it now reinits mutexes and condvars originating from my_thread_global_init @ mysys/my_thr_init.c Reorganized code. modified: include/my_pthread.h include/my_sys.h mysys/my_init.c mysys/my_thr_init.c sql/mysqld.cc === modified file 'mysql-test/r/ctype_utf16.result' --- a/mysql-test/r/ctype_utf16.result 2010-11-24 14:52:57 +0000 +++ b/mysql-test/r/ctype_utf16.result 2011-03-01 12:09:37 +0000 @@ -30,13 +30,13 @@ binary 'a a' > 'a' binary 'a \0' > 'a' 1 1 1 select hex(_utf16 0x44); hex(_utf16 0x44) -00000044 +0044 select hex(_utf16 0x3344); hex(_utf16 0x3344) 3344 select hex(_utf16 0x113344); hex(_utf16 0x113344) -000000113344 +00113344 CREATE TABLE t1 (word VARCHAR(64), word2 CHAR(64)) CHARACTER SET utf16; INSERT INTO t1 VALUES (_koi8r 0xF2, _koi8r 0xF2), (X'2004',X'2004'); SELECT hex(word) FROM t1 ORDER BY word; @@ -434,10 +434,10 @@ aardvarz DROP TABLE t1; SELECT hex(cast(0xAA as char character set utf16)); hex(cast(0xAA as char character set utf16)) -000000AA +00AA SELECT hex(convert(0xAA using utf16)); hex(convert(0xAA using utf16)) -000000AA +00AA CREATE TABLE t1 (a char(10) character set utf16); INSERT INTO t1 VALUES (0x1),(0x11),(0x111),(0x1111),(0x11111); SELECT HEX(a) FROM t1; @@ -1102,5 +1102,20 @@ t2 CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1, t2; # +# Bug#11753363 (Bug#44793) Character sets: case clause, ucs2 or utf32, failure +# +SELECT CASE _latin1'a' WHEN _utf16'a' THEN 'A' END; +CASE _latin1'a' WHEN _utf16'a' THEN 'A' END +A +SELECT CASE _utf16'a' WHEN _latin1'a' THEN 'A' END; +CASE _utf16'a' WHEN _latin1'a' THEN 'A' END +A +CREATE TABLE t1 (s1 CHAR(5) CHARACTER SET utf16); +INSERT INTO t1 VALUES ('a'); +SELECT CASE s1 WHEN 'a' THEN 'b' ELSE 'c' END FROM t1; +CASE s1 WHEN 'a' THEN 'b' ELSE 'c' END +b +DROP TABLE t1; +# # End of 5.5 tests # === modified file 'mysql-test/r/ctype_utf32.result' --- a/mysql-test/r/ctype_utf32.result 2010-09-28 15:15:58 +0000 +++ b/mysql-test/r/ctype_utf32.result 2011-03-01 12:09:37 +0000 @@ -1152,5 +1152,20 @@ d f DROP TABLE t1; # +# Bug#11753363 (Bug#44793) Character sets: case clause, ucs2 or utf32, failure +# +SELECT CASE _latin1'a' WHEN _utf32'a' THEN 'A' END; +CASE _latin1'a' WHEN _utf32'a' THEN 'A' END +A +SELECT CASE _utf32'a' WHEN _latin1'a' THEN 'A' END; +CASE _utf32'a' WHEN _latin1'a' THEN 'A' END +A +CREATE TABLE t1 (s1 CHAR(5) CHARACTER SET utf32); +INSERT INTO t1 VALUES ('a'); +SELECT CASE s1 WHEN 'a' THEN 'b' ELSE 'c' END FROM t1; +CASE s1 WHEN 'a' THEN 'b' ELSE 'c' END +b +DROP TABLE t1; +# # End of 5.5 tests # === modified file 'mysql-test/t/ctype_utf16.test' --- a/mysql-test/t/ctype_utf16.test 2010-09-28 15:15:58 +0000 +++ b/mysql-test/t/ctype_utf16.test 2011-03-01 12:09:37 +0000 @@ -745,6 +745,15 @@ CREATE TABLE t2 AS SELECT CONCAT(s1) FRO SHOW CREATE TABLE t2; DROP TABLE t1, t2; +--echo # +--echo # Bug#11753363 (Bug#44793) Character sets: case clause, ucs2 or utf32, failure +--echo # +SELECT CASE _latin1'a' WHEN _utf16'a' THEN 'A' END; +SELECT CASE _utf16'a' WHEN _latin1'a' THEN 'A' END; +CREATE TABLE t1 (s1 CHAR(5) CHARACTER SET utf16); +INSERT INTO t1 VALUES ('a'); +SELECT CASE s1 WHEN 'a' THEN 'b' ELSE 'c' END FROM t1; +DROP TABLE t1; # ## TODO: add tests for all engines === modified file 'mysql-test/t/ctype_utf32.test' --- a/mysql-test/t/ctype_utf32.test 2010-09-28 15:15:58 +0000 +++ b/mysql-test/t/ctype_utf32.test 2011-03-01 12:09:37 +0000 @@ -831,5 +831,15 @@ SELECT * FROM t1 WHERE b BETWEEN 'a' AND DROP TABLE t1; --echo # +--echo # Bug#11753363 (Bug#44793) Character sets: case clause, ucs2 or utf32, failure +--echo # +SELECT CASE _latin1'a' WHEN _utf32'a' THEN 'A' END; +SELECT CASE _utf32'a' WHEN _latin1'a' THEN 'A' END; +CREATE TABLE t1 (s1 CHAR(5) CHARACTER SET utf32); +INSERT INTO t1 VALUES ('a'); +SELECT CASE s1 WHEN 'a' THEN 'b' ELSE 'c' END FROM t1; +DROP TABLE t1; + +--echo # --echo # End of 5.5 tests --echo # === modified file 'sql/item_cmpfunc.cc' --- a/sql/item_cmpfunc.cc 2011-02-18 07:32:40 +0000 +++ b/sql/item_cmpfunc.cc 2011-03-01 12:09:37 +0000 @@ -3054,20 +3054,59 @@ void Item_func_case::fix_length_and_dec( agg[0]= args[first_expr_num]; left_result_type= agg[0]->result_type(); + /* + As the first expression and WHEN expressions + are intermixed in args[] array THEN and ELSE items, + extract the first expression and all WHEN expressions into + a temporary array, to process them easier. + */ for (nagg= 0; nagg < ncases/2 ; nagg++) agg[nagg+1]= args[nagg*2]; nagg++; if (!(found_types= collect_cmp_types(agg, nagg))) return; + if (found_types & (1 << STRING_RESULT)) + { + /* + If we'll do string comparison, we also need to aggregate + character set and collation for first/WHEN items and + install converters for some of them to cmp_collation when necessary. + This is done because cmp_item compatators cannot compare + strings in two different character sets. + Some examples when we install converters: + + 1. Converter installed for the first expression: + + CASE latin1_item WHEN utf16_item THEN ... END + + is replaced to: + + CASE CONVERT(latin1_item USING utf16) WHEN utf16_item THEN ... END + + 2. Converter installed for the left WHEN item: + CASE utf16_item WHEN latin1_item THEN ... END + + is replaced to: + + CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END + */ + if (agg_arg_charsets_for_comparison(cmp_collation, agg, nagg)) + return; + /* + Now copy first expression and all WHEN expressions back to args[] + arrray, because some of the items might have been changed to converters + (e.g. Item_func_conv_charset, or Item_string for constants). + */ + args[first_expr_num]= agg[0]; + for (nagg= 0; nagg < ncases / 2; nagg++) + args[nagg * 2]= agg[nagg + 1]; + } for (i= 0; i <= (uint)DECIMAL_RESULT; i++) { if (found_types & (1 << i) && !cmp_items[i]) { DBUG_ASSERT((Item_result)i != ROW_RESULT); - if ((Item_result)i == STRING_RESULT && - agg_arg_charsets_for_comparison(cmp_collation, agg, nagg)) - return; if (!(cmp_items[i]= cmp_item::get_comparator((Item_result)i, cmp_collation.collation))) === modified file 'sql/sql_string.cc' --- a/sql/sql_string.cc 2011-01-13 08:07:21 +0000 +++ b/sql/sql_string.cc 2011-03-01 12:09:37 +0000 @@ -252,8 +252,8 @@ bool String::copy_aligned(const char *st 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)) No bundle (reason: useless for push emails).