3687 Jorgen Loland 2011-02-21
Bug#11766642: crash in Item_field::register_field_in_read_map
with view
(Former 59793)
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. A neg_transformer()
is also implemented for Item_func_xor to improve performance
when negating XOR expressions. An XOR is negated by negating
one of the operands.
@ mysql-test/include/subquery_sj.inc
Add test for BUG#11766642
@ mysql-test/r/negation_elimination.result
Add tests for XOR
@ mysql-test/r/subquery_sj_none.result
Add test for BUG#11766642
@ mysql-test/t/negation_elimination.test
Add tests for XOR
@ sql/item_cmpfunc.cc
Refactor XOR item: it is now a pure Item_func, inheriting from Item_bool_func2 instead of Item_cond. Also added neg_transformer() function to improve performance when XOR is negated.
@ sql/item_cmpfunc.h
Refactor XOR item: it is now a pure Item_func, inheriting from Item_bool_func2 instead of Item_cond. Also added neg_transformer() function to improve performance when XOR is negated.
@ 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_sj.inc
mysql-test/r/negation_elimination.result
mysql-test/r/subquery_sj_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
3686 Vasil Dimov 2011-02-21 [merge]
Merge mysql-trunk-innodb -> mysql-trunk
modified:
storage/innobase/btr/btr0sea.c
storage/innobase/include/ha0ha.h
=== modified file 'mysql-test/include/subquery_sj.inc'
--- a/mysql-test/include/subquery_sj.inc 2011-01-27 11:38:22 +0000
+++ b/mysql-test/include/subquery_sj.inc 2011-02-21 10:36:31 +0000
@@ -3504,3 +3504,19 @@ deallocate prepare s;
DROP TABLE ot1, ot2, ot3, it1;
--echo # End of the test for bug#57623.
+
+--echo #
+--echo # Bug#11766642: 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-21 10:36:31 +0000
@@ -375,6 +375,121 @@ 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
+# Should have empty result
+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`)
+# End XOR
delete from t1 where a > 3;
select a, not(not(a)) from t1;
a not(not(a))
=== modified file 'mysql-test/r/subquery_sj_none.result'
--- a/mysql-test/r/subquery_sj_none.result 2011-02-14 11:21:26 +0000
+++ b/mysql-test/r/subquery_sj_none.result 2011-02-21 10:36:31 +0000
@@ -5538,4 +5538,17 @@ a a a
deallocate prepare s;
DROP TABLE ot1, ot2, ot3, it1;
# End of the test for bug#57623.
+#
+# Bug#11766642: 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-21 10:36:31 +0000
@@ -65,6 +65,35 @@ 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 # 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)));
+
+--echo # Should have empty result
+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 # End XOR
+
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));
=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc 2011-02-18 07:43:02 +0000
+++ b/sql/item_cmpfunc.cc 2011-02-21 10:36:31 +0000
@@ -5333,23 +5333,21 @@ 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<Item> li(list);
- Item *item;
- int result=0;
- null_value=0;
- while ((item=li++))
+ int result= 0;
+ null_value= false;
+ 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;
+ null_value= true;
return 0;
}
}
- return (longlong) result;
+ return result;
}
/**
@@ -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-21 10:36:31 +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<Item> *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-21 10:36:31 +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-16 17:13:30 +0000
+++ b/sql/sql_yacc.yy 2011-02-21 10:36:31 +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-18 11:39:05 +0000
+++ b/unittest/gunit/item-t.cc 2011-02-21 10:36:31 +0000
@@ -239,4 +239,50 @@ TEST_F(ItemTest, OutOfMemory)
#endif
}
+TEST_F(ItemTest, ItemFuncXor)
+{
+ const uint length= 1U;
+ Item_int *item_zero= new Item_int(0, length);
+ Item_int *item_one_a= new Item_int(1, length);
+
+ Item_func_xor *item_xor=
+ new Item_func_xor(item_zero, item_one_a);
+
+ EXPECT_FALSE(item_xor->fix_fields(m_thd, NULL));
+ EXPECT_EQ(1, item_xor->val_int());
+ EXPECT_EQ(1U, item_xor->decimal_precision());
+
+ Item_int *item_one_b= new Item_int(1, length);
+
+ Item_func_xor *item_xor_same=
+ new Item_func_xor(item_one_a, item_one_b);
+
+ EXPECT_FALSE(item_xor_same->fix_fields(m_thd, NULL));
+ EXPECT_EQ(0, item_xor_same->val_int());
+ EXPECT_FALSE(item_xor_same->val_bool());
+ EXPECT_FALSE(item_xor_same->is_null());
+
+ String print_buffer;
+ item_xor->print(&print_buffer, QT_ORDINARY);
+ EXPECT_STREQ("(0 xor 1)", print_buffer.c_ptr_safe());
+
+ 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_FALSE(neg_xor->is_null());
+
+ print_buffer= String();
+ neg_xor->print(&print_buffer, QT_ORDINARY);
+ EXPECT_STREQ("((not(0)) xor 1)", print_buffer.c_ptr_safe());
+
+ Item_func_xor *item_xor_null=
+ new Item_func_xor(item_zero, 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());
+}
+
}
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (jorgen.loland:3686 to 3687) Bug#11766642 | Jorgen Loland | 21 Feb |