From: Jorgen Loland Date: February 9 2011 1:25pm Subject: bzr commit into mysql-trunk branch (jorgen.loland:3625) Bug#59793 List-Archive: http://lists.mysql.com/commits/130863 X-Bug: 59793 Message-Id: <20110209132559.2658472C@atum21.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3727667291701055492==" --===============3727667291701055492== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/jl208045/mysql/mysql-trunk-59793/ based on revid:dmitry.shulga@stripped 3625 Jorgen Loland 2011-02-09 Bug#59793: crash in Item_field::register_field_in_read_map with view Prior to the refactoring in this patch, Item_cond_xor behaved partially as an Item_cond and partially as an Item_func. The reasoning behind this was that XOR is currently not optimized (thus should be Item_func instead of Item_cond), but it was planned optimize it in the future (thus, made Item_cond anyway to ease optimization later). Even though Item_cond inherits from Item_func, there are differences between these two. One difference is that the arguments are stored differently. Item_cond stores them in a list while Item_func store them in an args[]. BUG no 45221 was caused by Item_cond_xor storing arguments in the list while users of the objects would look for them in args[]. The fix back then was to store the arguments in both locations. In this bug, Item_cond_xor initially gets two Item_field arguments. These are stored in the list inherited from Item_cond and in args[] inherited from Item_func. During resolution, find_field_in_view() replaces the Item_fields stored in the list with Item_direct_view_refs, but args[] still points to the unresolved Item_fields. This shows that the fix for 45221 was incorrect. The refactoring performed in this patch removes the confusion by making the XOR item an Item_func period. @ mysql-test/include/subquery.inc Add test for BUG#59793 @ mysql-test/r/negation_elimination.result Add tests for negation of XOR @ mysql-test/r/subquery_nomat_nosj.result Add test for BUG#59793 @ mysql-test/r/subquery_none.result Add test for BUG#59793 @ mysql-test/t/negation_elimination.test Add tests for negation of XOR @ sql/item_cmpfunc.cc Refactor XOR item: it is now a pure Item_func, inheriting from Item_bool_func2 instead of Item_cond @ sql/item_cmpfunc.h Refactor XOR item: it is now a pure Item_func, inheriting from Item_bool_func2 instead of Item_cond @ sql/item_func.h Refactor XOR item: it is now a pure Item_func, inheriting from Item_bool_func2 instead of Item_cond @ sql/sql_yacc.yy Refactor XOR item: it is now a pure Item_func, inheriting from Item_bool_func2 instead of Item_cond @ unittest/gunit/item-t.cc Add unit test for Item_func_xor modified: mysql-test/include/subquery.inc mysql-test/r/negation_elimination.result mysql-test/r/subquery_nomat_nosj.result mysql-test/r/subquery_none.result mysql-test/t/negation_elimination.test sql/item_cmpfunc.cc sql/item_cmpfunc.h sql/item_func.h sql/sql_yacc.yy unittest/gunit/item-t.cc === modified file 'mysql-test/include/subquery.inc' --- a/mysql-test/include/subquery.inc 2011-02-02 09:04:55 +0000 +++ b/mysql-test/include/subquery.inc 2011-02-09 13:25:55 +0000 @@ -5286,3 +5286,19 @@ CREATE TABLE t(a VARCHAR(245) DEFAULT INSERT INTO t VALUES (''),(''),(''),(''),(''),(''),(''),(''),(''),(''),(''); SELECT * FROM (SELECT default(a) FROM t GROUP BY a) d; DROP TABLE t; + +--echo # +--echo # Bug#59793: crash in Item_field::register_field_in_read_map with view +--echo # + +CREATE TABLE t1(a INT); +CREATE VIEW v1 AS SELECT a FROM t1; + +INSERT INTO t1 VALUES (0),(1),(2); + +SELECT a FROM t1 WHERE a IN + (SELECT a XOR a FROM v1) +ORDER BY a; + +DROP TABLE t1; +DROP VIEW v1; === modified file 'mysql-test/r/negation_elimination.result' --- a/mysql-test/r/negation_elimination.result 2010-04-20 07:22:51 +0000 +++ b/mysql-test/r/negation_elimination.result 2011-02-09 13:25:55 +0000 @@ -375,6 +375,122 @@ a 13 14 15 + +# XOR (Note: XOR is negated by negating one of the operands) +# Should return 6,7 +SELECT * FROM t1 WHERE ((a > 5) XOR (a > 7)); +a +6 +7 +# Should return 0..5,8..19 +SELECT * FROM t1 WHERE ((NOT (a > 5)) XOR (a > 7)); +a +0 +1 +2 +3 +4 +5 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +SELECT * FROM t1 WHERE ((a > 5) XOR (NOT (a > 7))); +a +0 +1 +2 +3 +4 +5 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +SELECT * FROM t1 WHERE NOT ((a > 5) XOR (a > 7)); +a +0 +1 +2 +3 +4 +5 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +# Should return 6,7 +SELECT * FROM t1 WHERE NOT ((NOT (a > 5)) XOR (a > 7)); +a +6 +7 +SELECT * FROM t1 WHERE NOT ((a > 5) XOR (NOT (a > 7))); +a +6 +7 +# Should return 0..5,8..19 +SELECT * FROM t1 WHERE NOT (NOT (a > 5) XOR (NOT (a > 7))); +a +0 +1 +2 +3 +4 +5 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +SELECT * FROM t1 WHERE (NULL XOR (a > 7)); +a +SELECT * FROM t1 WHERE NOT (NULL XOR (a > 7)); +a +# Should be simplified to "...WHERE (a XOR a) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NOT ((NOT a) XOR (a)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL a 5 NULL 21 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` xor `test`.`t1`.`a`) +# Should be simplified to "...WHERE (a XOR a) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NOT (a XOR (NOT a)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL a 5 NULL 21 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` xor `test`.`t1`.`a`) +# XOR End + delete from t1 where a > 3; select a, not(not(a)) from t1; a not(not(a)) === modified file 'mysql-test/r/subquery_nomat_nosj.result' --- a/mysql-test/r/subquery_nomat_nosj.result 2011-02-02 09:04:55 +0000 +++ b/mysql-test/r/subquery_nomat_nosj.result 2011-02-09 13:25:55 +0000 @@ -6442,4 +6442,17 @@ SELECT * FROM (SELECT default(a) FROM t default(a) aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa DROP TABLE t; +# +# Bug#59793: crash in Item_field::register_field_in_read_map with view +# +CREATE TABLE t1(a INT); +CREATE VIEW v1 AS SELECT a FROM t1; +INSERT INTO t1 VALUES (0),(1),(2); +SELECT a FROM t1 WHERE a IN +(SELECT a XOR a FROM v1) +ORDER BY a; +a +0 +DROP TABLE t1; +DROP VIEW v1; set optimizer_switch=default; === modified file 'mysql-test/r/subquery_none.result' --- a/mysql-test/r/subquery_none.result 2011-02-02 09:04:55 +0000 +++ b/mysql-test/r/subquery_none.result 2011-02-09 13:25:55 +0000 @@ -6441,4 +6441,17 @@ SELECT * FROM (SELECT default(a) FROM t default(a) aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa DROP TABLE t; +# +# Bug#59793: crash in Item_field::register_field_in_read_map with view +# +CREATE TABLE t1(a INT); +CREATE VIEW v1 AS SELECT a FROM t1; +INSERT INTO t1 VALUES (0),(1),(2); +SELECT a FROM t1 WHERE a IN +(SELECT a XOR a FROM v1) +ORDER BY a; +a +0 +DROP TABLE t1; +DROP VIEW v1; set optimizer_switch=default; === modified file 'mysql-test/t/negation_elimination.test' --- a/mysql-test/t/negation_elimination.test 2005-07-28 00:22:47 +0000 +++ b/mysql-test/t/negation_elimination.test 2011-02-09 13:25:55 +0000 @@ -65,10 +65,40 @@ select * from t1 where not((a < 5 and a explain select * from t1 where ((a between 5 and 15) and (not(a like 10))); select * from t1 where ((a between 5 and 15) and (not(a like 10))); +--echo +--echo # XOR (Note: XOR is negated by negating one of the operands) + +--echo # Should return 6,7 +SELECT * FROM t1 WHERE ((a > 5) XOR (a > 7)); + +--echo # Should return 0..5,8..19 +SELECT * FROM t1 WHERE ((NOT (a > 5)) XOR (a > 7)); +SELECT * FROM t1 WHERE ((a > 5) XOR (NOT (a > 7))); +SELECT * FROM t1 WHERE NOT ((a > 5) XOR (a > 7)); + +--echo # Should return 6,7 +SELECT * FROM t1 WHERE NOT ((NOT (a > 5)) XOR (a > 7)); +SELECT * FROM t1 WHERE NOT ((a > 5) XOR (NOT (a > 7))); + +--echo # Should return 0..5,8..19 +SELECT * FROM t1 WHERE NOT (NOT (a > 5) XOR (NOT (a > 7))); + +SELECT * FROM t1 WHERE (NULL XOR (a > 7)); +SELECT * FROM t1 WHERE NOT (NULL XOR (a > 7)); + +--echo # Should be simplified to "...WHERE (a XOR a) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NOT ((NOT a) XOR (a)); + +--echo # Should be simplified to "...WHERE (a XOR a) +EXPLAIN EXTENDED SELECT * FROM t1 WHERE NOT (a XOR (NOT a)); + +--echo # XOR End +--echo + delete from t1 where a > 3; select a, not(not(a)) from t1; explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like "1"), not (a not in (1,2)), not(a != 2) from t1 where not(not(a)) having not(not(a)); drop table t1; -# End of 4.1 tests + === modified file 'sql/item_cmpfunc.cc' --- a/sql/item_cmpfunc.cc 2011-02-08 15:54:12 +0000 +++ b/sql/item_cmpfunc.cc 2011-02-09 13:25:55 +0000 @@ -5333,17 +5333,15 @@ bool Item_func_like::turboBM_matches(con very fast to use. */ -longlong Item_cond_xor::val_int() +longlong Item_func_xor::val_int() { DBUG_ASSERT(fixed == 1); - List_iterator li(list); - Item *item; - int result=0; + int result=0; null_value=0; - while ((item=li++)) + for (uint i= 0; i < arg_count; i++) { - result^= (item->val_int() != 0); - if (item->null_value) + result^= (args[i]->val_int() != 0); + if (args[i]->null_value) { null_value=1; return 0; @@ -5390,6 +5388,33 @@ Item *Item_bool_rowready_func2::neg_tran return item; } +/** + XOR can be negated by negating one of the operands: + + NOT (a XOR b) => (NOT a) XOR b + => a XOR (NOT b) + + @param thd Thread handle + @return New negated item +*/ +Item *Item_func_xor::neg_transformer(THD *thd) +{ + Item *neg_operand; + Item_func_xor *new_item; + if ((neg_operand= args[0]->neg_transformer(thd))) + // args[0] has neg_tranformer + new_item= new(thd->mem_root) Item_func_xor(neg_operand, args[1]); + else if ((neg_operand= args[1]->neg_transformer(thd))) + // args[1] has neg_tranformer + new_item= new(thd->mem_root) Item_func_xor(args[0], neg_operand); + else + { + neg_operand= new(thd->mem_root) Item_func_not(args[0]); + new_item= new(thd->mem_root) Item_func_xor(neg_operand, args[1]); + } + return new_item; +} + /** a IS NULL -> a IS NOT NULL. === modified file 'sql/item_cmpfunc.h' --- a/sql/item_cmpfunc.h 2010-12-29 00:38:59 +0000 +++ b/sql/item_cmpfunc.h 2011-02-09 13:25:55 +0000 @@ -1,7 +1,7 @@ #ifndef ITEM_CMPFUNC_INCLUDED #define ITEM_CMPFUNC_INCLUDED -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -411,6 +411,22 @@ public: bool subst_argument_checker(uchar **arg) { return TRUE; } }; +/** + XOR inherits from Item_bool_func2 because it is not optimized yet. + Later, when XOR is optimized, it needs to inherit from + Item_cond instead. See WL#5800. +*/ +class Item_func_xor :public Item_bool_func2 +{ +public: + Item_func_xor(Item *i1, Item *i2) :Item_bool_func2(i1, i2) {} + enum Functype functype() const { return XOR_FUNC; } + const char *func_name() const { return "xor"; } + longlong val_int(); + void top_level_item() {} + Item *neg_transformer(THD *thd); +}; + class Item_func_not :public Item_bool_func { public: @@ -1759,45 +1775,6 @@ inline bool is_cond_or(Item *item) return (cond_item->functype() == Item_func::COND_OR_FUNC); } -/* - XOR is Item_cond, not an Item_int_func because we could like to - optimize (a XOR b) later on. It's low prio, though -*/ - -class Item_cond_xor :public Item_cond -{ -public: - Item_cond_xor(Item *i1,Item *i2) :Item_cond(i1,i2) - { - /* - Items must be stored in args[] as well because this Item_cond is - treated as a FUNC_ITEM (see type()). I.e., users of it will get - it's children by calling arguments(), not argument_list(). This - is a temporary solution until XOR is optimized and treated like - a full Item_cond citizen. - */ - arg_count= 2; - args= tmp_arg; - args[0]= i1; - args[1]= i2; - } - enum Functype functype() const { return COND_XOR_FUNC; } - /* TODO: remove the next line when implementing XOR optimization */ - enum Type type() const { return FUNC_ITEM; } - longlong val_int(); - const char *func_name() const { return "xor"; } - void top_level_item() {} - /* Since child Items are stored in args[], Items cannot be added. - However, since Item_cond_xor is treated as a FUNC_ITEM (see - type()), the methods below should never be called. - */ - bool add(Item *item) { DBUG_ASSERT(FALSE); return FALSE; } - bool add_at_head(Item *item) { DBUG_ASSERT(FALSE); return FALSE; } - bool add_at_head(List *nlist) { DBUG_ASSERT(FALSE); return FALSE; } - void copy_andor_arguments(THD *thd, Item_cond *item) { DBUG_ASSERT(FALSE); } -}; - - /* Some useful inline functions */ inline Item *and_conds(Item *a, Item *b) === modified file 'sql/item_func.h' --- a/sql/item_func.h 2011-02-08 15:54:12 +0000 +++ b/sql/item_func.h 2011-02-09 13:25:55 +0000 @@ -46,7 +46,7 @@ public: enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, GE_FUNC,GT_FUNC,FT_FUNC, LIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC, - COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, + COND_AND_FUNC, COND_OR_FUNC, XOR_FUNC, BETWEEN, IN_FUNC, MULT_EQUAL_FUNC, INTERVAL_FUNC, ISNOTNULLTEST_FUNC, SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC, === modified file 'sql/sql_yacc.yy' --- a/sql/sql_yacc.yy 2011-02-03 10:13:06 +0000 +++ b/sql/sql_yacc.yy 2011-02-09 13:25:55 +0000 @@ -7620,7 +7620,7 @@ expr: | expr XOR expr %prec XOR { /* XOR is a proprietary extension */ - $$ = new (YYTHD->mem_root) Item_cond_xor($1, $3); + $$ = new (YYTHD->mem_root) Item_func_xor($1, $3); if ($$ == NULL) MYSQL_YYABORT; } === modified file 'unittest/gunit/item-t.cc' --- a/unittest/gunit/item-t.cc 2011-02-07 13:03:47 +0000 +++ b/unittest/gunit/item-t.cc 2011-02-09 13:25:55 +0000 @@ -183,4 +183,40 @@ TEST_F(ItemTest, ItemFuncDesDecrypt) EXPECT_LE(item_decrypt->max_length, length); } + +TEST_F(ItemTest, ItemFuncXor) +{ + const uint length= 1U; + Item_int *item_one= new Item_int(0, length); + Item_int *item_two= new Item_int(1, length); + + Item_func_xor *item_xor= + new Item_func_xor(item_one, item_two); + + EXPECT_FALSE(item_xor->fix_fields(m_thd, NULL)); + EXPECT_EQ(1, item_xor->val_int()); + + String print_buffer; + item_xor->print(&print_buffer, QT_ORDINARY); + EXPECT_STREQ("(0 xor 1)", print_buffer.c_ptr()); + + Item *neg_xor= item_xor->neg_transformer(m_thd); + EXPECT_FALSE(neg_xor->fix_fields(m_thd, NULL)); + EXPECT_EQ(0, neg_xor->val_int()); + EXPECT_DOUBLE_EQ(0.0, neg_xor->val_real()); + EXPECT_FALSE(neg_xor->val_bool()); + EXPECT_EQ(0, neg_xor->is_null()); + + print_buffer= String(); + neg_xor->print(&print_buffer, QT_ORDINARY); + EXPECT_STREQ("((not(0)) xor 1)", print_buffer.c_ptr()); + + Item_func_xor *item_xor_null= + new Item_func_xor(item_one, new Item_null()); + EXPECT_FALSE(item_xor_null->fix_fields(m_thd, NULL)); + + EXPECT_EQ(0, item_xor_null->val_int()); + EXPECT_TRUE(item_xor_null->is_null()); +} + } --===============3727667291701055492== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/jorgen.loland@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: jorgen.loland@stripped\ # j123yhwqymsn1vl4 # target_branch: file:///export/home/jl208045/mysql/mysql-trunk-59793/ # testament_sha1: d196defd2b23825d47047d39444a73ffcb2f36c4 # timestamp: 2011-02-09 14:25:59 +0100 # base_revision_id: dmitry.shulga@stripped\ # 62efv51tm3ugeowk # # Begin bundle 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 JFOFCQmz6c4A --===============3727667291701055492==--