diff --git a/mysql-test/main/case.result b/mysql-test/main/case.result index 1fd1ad86a8e..926ac000eb0 100644 --- a/mysql-test/main/case.result +++ b/mysql-test/main/case.result @@ -546,5 +546,32 @@ Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a' DROP TABLE t1; # +# MDEV-17411 Wrong WHERE optimization with simple CASE and searched CASE +# +CREATE TABLE t1 (a INT, b INT, KEY(a)); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +SELECT * FROM t1 WHERE CASE a WHEN b THEN 1 END=1; +a b +1 1 +2 2 +3 3 +SELECT * FROM t1 WHERE CASE WHEN a THEN b ELSE 1 END=3; +a b +3 3 +SELECT * FROM t1 WHERE +CASE a WHEN b THEN 1 END=1 AND +CASE WHEN a THEN b ELSE 1 END=3; +a b +3 3 +EXPLAIN EXTENDED +SELECT * FROM t1 WHERE +CASE a WHEN b THEN 1 END=1 AND +CASE WHEN a THEN b ELSE 1 END=3; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (case `test`.`t1`.`a` when `test`.`t1`.`b` then 1 end) = 1 and (case when `test`.`t1`.`a` then `test`.`t1`.`b` else 1 end) = 3 +DROP TABLE t1; +# # End of 10.3 test # diff --git a/mysql-test/main/case.test b/mysql-test/main/case.test index d7dac112b3b..78d5b3a5951 100644 --- a/mysql-test/main/case.test +++ b/mysql-test/main/case.test @@ -390,6 +390,28 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELS DROP TABLE t1; + +--echo # +--echo # MDEV-17411 Wrong WHERE optimization with simple CASE and searched CASE +--echo # + +CREATE TABLE t1 (a INT, b INT, KEY(a)); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +SELECT * FROM t1 WHERE CASE a WHEN b THEN 1 END=1; +SELECT * FROM t1 WHERE CASE WHEN a THEN b ELSE 1 END=3; + +SELECT * FROM t1 WHERE + CASE a WHEN b THEN 1 END=1 AND + CASE WHEN a THEN b ELSE 1 END=3; + +EXPLAIN EXTENDED +SELECT * FROM t1 WHERE + CASE a WHEN b THEN 1 END=1 AND + CASE WHEN a THEN b ELSE 1 END=3; + +DROP TABLE t1; + + --echo # --echo # End of 10.3 test --echo # diff --git a/sql/item.h b/sql/item.h index 6823d58a94c..d743cf6c19c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2211,6 +2211,15 @@ protected: } return true; } + bool eq(const Item_args *other, bool binary_cmp) const + { + for (uint i= 0; i < arg_count ; i++) + { + if (!args[i]->eq(other->args[i], binary_cmp)) + return false; + } + return true; + } public: Item_args(void) :args(NULL), arg_count(0) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 4a7a44b3399..92f1391c9f8 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1813,10 +1813,7 @@ bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const return 0; if (negated != ((Item_func_opt_neg *) item_func)->negated) return 0; - for (uint i=0; i < arg_count ; i++) - if (!args[i]->eq(item_func->arguments()[i], binary_cmp)) - return 0; - return 1; + return Item_args::eq(item_func, binary_cmp); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index b34bf1dde19..60b56090a23 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -2154,6 +2154,7 @@ public: DBUG_ASSERT(arg_count >= 2); reorder_args(0); } + enum Functype functype() const { return CASE_SEARCHED_FUNC; } void print(String *str, enum_query_type query_type); bool fix_length_and_dec(); Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) @@ -2206,6 +2207,7 @@ public: Predicant_to_list_comparator::cleanup(); DBUG_VOID_RETURN; } + enum Functype functype() const { return CASE_SIMPLE_FUNC; } void print(String *str, enum_query_type query_type); bool fix_length_and_dec(); Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond); diff --git a/sql/item_func.cc b/sql/item_func.cc index 3dcfe4fbce8..c5ac97f2905 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -647,10 +647,7 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const (func_type == Item_func::FUNC_SP && my_strcasecmp(system_charset_info, func_name(), item_func->func_name()))) return 0; - for (uint i=0; i < arg_count ; i++) - if (!args[i]->eq(item_func->args[i], binary_cmp)) - return 0; - return 1; + return Item_args::eq(item_func, binary_cmp); } diff --git a/sql/item_func.h b/sql/item_func.h index 1d19c7a43f1..fd789ffdc51 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -76,7 +76,10 @@ public: SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC, NEG_FUNC, GSYSVAR_FUNC, IN_OPTIMIZER_FUNC, DYNCOL_FUNC, - JSON_EXTRACT_FUNC }; + JSON_EXTRACT_FUNC, + CASE_SEARCHED_FUNC, // Used by ColumnStore/Spider + CASE_SIMPLE_FUNC // Used by ColumnStore/spider + }; enum Type type() const { return FUNC_ITEM; } virtual enum Functype functype() const { return UNKNOWN_FUNC; } Item_func(THD *thd): Item_func_or_sum(thd)