diff options
author | Alexander Barkov <bar@mariadb.org> | 2015-06-02 15:42:01 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2015-06-02 15:42:01 +0400 |
commit | 3709c7fc6d46c624c24523907eb2a0ad8a1e5062 (patch) | |
tree | 5a1d1d5c445e6d952be1633584a723696e94061e | |
parent | 8f92a70e214837f092b9e0c06b645654377f03d6 (diff) | |
download | mariadb-git-3709c7fc6d46c624c24523907eb2a0ad8a1e5062.tar.gz |
MDEV-8222 "string_field LIKE int_const" returns a wrong result in case of UCS2
MDEV-8257 Erroneous "Impossible where" when mixing decimal comparison and LIKE
-rw-r--r-- | mysql-test/r/ctype_ucs.result | 9 | ||||
-rw-r--r-- | mysql-test/r/func_like.result | 29 | ||||
-rw-r--r-- | mysql-test/t/ctype_ucs.test | 8 | ||||
-rw-r--r-- | mysql-test/t/func_like.test | 23 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 32 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 48 | ||||
-rw-r--r-- | sql/sql_select.cc | 14 |
7 files changed, 126 insertions, 37 deletions
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 740319a9dcd..5b4d1320f08 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -5542,5 +5542,14 @@ select collation(cast("a" as char(10) binary unicode)); collation(cast("a" as char(10) binary unicode)) ucs2_bin # +# MDEV-8222 "string_field LIKE int_const" returns a wrong result in case of UCS2 +# +CREATE TABLE t1 (a VARCHAR(10) CHARSET ucs2); +INSERT INTO t1 VALUES ('1'); +SELECT * FROM t1 WHERE a LIKE 1; +a +1 +DROP TABLE t1; +# # End of 10.1 tests # diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result index 8d72b818cf8..2fdcf1226b7 100644 --- a/mysql-test/r/func_like.result +++ b/mysql-test/r/func_like.result @@ -200,3 +200,32 @@ SELECT 'a' LIKE REPEAT('',0); SELECT 'a' LIKE EXTRACTVALUE('bar','qux'); 'a' LIKE EXTRACTVALUE('bar','qux') 0 +# +# End of 10.0 tests +# +# +# Start of 10.1 tests +# +# +# MDEV-8257 Erroneous "Impossible where" when mixing decimal comparison and LIKE +# +CREATE TABLE t1 (a DECIMAL(8,2)); +INSERT INTO t1 VALUES (10),(20); +SELECT * FROM t1 WHERE a=10.0; +a +10.00 +SELECT * FROM t1 WHERE a LIKE 10.00; +a +10.00 +SELECT * FROM t1 WHERE a=10.0 AND a LIKE 10.00; +a +10.00 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10.0 AND a LIKE 10.00; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 10.0) and (`test`.`t1`.`a` like 10.00)) +DROP TABLE t1; +# +# End of 10.1 tests +# diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 1dee393b90b..6e5b0850eca 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -925,5 +925,13 @@ select collation(cast("a" as char(10) unicode binary)); select collation(cast("a" as char(10) binary unicode)); --echo # +--echo # MDEV-8222 "string_field LIKE int_const" returns a wrong result in case of UCS2 +--echo # +CREATE TABLE t1 (a VARCHAR(10) CHARSET ucs2); +INSERT INTO t1 VALUES ('1'); +SELECT * FROM t1 WHERE a LIKE 1; +DROP TABLE t1; + +--echo # --echo # End of 10.1 tests --echo # diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test index bc64504c742..aab3c7fe43b 100644 --- a/mysql-test/t/func_like.test +++ b/mysql-test/t/func_like.test @@ -143,3 +143,26 @@ SELECT '' LIKE '1' ESCAPE COUNT(1); --echo # SELECT 'a' LIKE REPEAT('',0); SELECT 'a' LIKE EXTRACTVALUE('bar','qux'); + +--echo # +--echo # End of 10.0 tests +--echo # + +--echo # +--echo # Start of 10.1 tests +--echo # + +--echo # +--echo # MDEV-8257 Erroneous "Impossible where" when mixing decimal comparison and LIKE +--echo # +CREATE TABLE t1 (a DECIMAL(8,2)); +INSERT INTO t1 VALUES (10),(20); +SELECT * FROM t1 WHERE a=10.0; +SELECT * FROM t1 WHERE a LIKE 10.00; +SELECT * FROM t1 WHERE a=10.0 AND a LIKE 10.00; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=10.0 AND a LIKE 10.00; +DROP TABLE t1; + +--echo # +--echo # End of 10.1 tests +--echo # diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5bea5dac711..a1926756f13 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -503,15 +503,15 @@ bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp) args[0]->cmp_context= args[1]->cmp_context= item_cmp_type(args[0]->result_type(), args[1]->result_type()); - // Convert constants when compared to int/year field, unless this is LIKE - if (functype() != LIKE_FUNC) - convert_const_compared_to_int_field(thd); + // Convert constants when compared to int/year field + DBUG_ASSERT(functype() != LIKE_FUNC); + convert_const_compared_to_int_field(thd); return cmp->set_cmp_func(this, tmp_arg, tmp_arg + 1, true); } -void Item_bool_func2::fix_length_and_dec() +void Item_bool_rowready_func2::fix_length_and_dec() { max_length= 1; // Function returns 0 or 1 @@ -1881,7 +1881,7 @@ longlong Item_func_eq::val_int() void Item_func_equal::fix_length_and_dec() { - Item_bool_func2::fix_length_and_dec(); + Item_bool_rowready_func2::fix_length_and_dec(); maybe_null=null_value=0; } @@ -4784,13 +4784,13 @@ void Item_func_isnotnull::print(String *str, enum_query_type query_type) longlong Item_func_like::val_int() { DBUG_ASSERT(fixed == 1); - String* res = args[0]->val_str(&cmp.value1); + String* res= args[0]->val_str(&cmp_value1); if (args[0]->null_value) { null_value=1; return 0; } - String* res2 = args[1]->val_str(&cmp.value2); + String* res2= args[1]->val_str(&cmp_value2); if (args[1]->null_value) { null_value=1; @@ -4799,7 +4799,7 @@ longlong Item_func_like::val_int() null_value=0; if (canDoTurboBM) return turboBM_matches(res->ptr(), res->length()) ? 1 : 0; - return my_wildcmp(cmp.cmp_collation.collation, + return my_wildcmp(cmp_collation.collation, res->ptr(),res->ptr()+res->length(), res2->ptr(),res2->ptr()+res2->length(), escape,wild_one,wild_many) ? 0 : 1; @@ -4815,7 +4815,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const if (!args[1]->const_item() || args[1]->is_expensive()) return OPTIMIZE_NONE; - String* res2= args[1]->val_str((String *)&cmp.value2); + String* res2= args[1]->val_str((String *) &cmp_value2); if (!res2) return OPTIMIZE_NONE; @@ -4845,7 +4845,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) if (escape_item->const_item()) { /* If we are on execution stage */ - String *escape_str= escape_item->val_str(&cmp.value1); + String *escape_str= escape_item->val_str(&cmp_value1); if (escape_str) { const char *escape_str_ptr= escape_str->ptr(); @@ -4858,7 +4858,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) return TRUE; } - if (use_mb(cmp.cmp_collation.collation)) + if (use_mb(cmp_collation.collation)) { CHARSET_INFO *cs= escape_str->charset(); my_wc_t wc; @@ -4875,7 +4875,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) code instead of Unicode code as "escape" argument. Convert to "cs" if charset of escape differs. */ - CHARSET_INFO *cs= cmp.cmp_collation.collation; + CHARSET_INFO *cs= cmp_collation.collation; uint32 unused; if (escape_str->needs_conversion(escape_str->length(), escape_str->charset(), cs, &unused)) @@ -4901,7 +4901,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) if (args[1]->const_item() && !use_strnxfrm(collation.collation) && !args[1]->is_expensive()) { - String* res2 = args[1]->val_str(&cmp.value2); + String* res2= args[1]->val_str(&cmp_value2); if (!res2) return FALSE; // Null argument @@ -5182,7 +5182,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff) int f = 0; int g = plm1; int *const splm1 = suff + plm1; - CHARSET_INFO *cs= cmp.cmp_collation.collation; + CHARSET_INFO *cs= cmp_collation.collation; *splm1 = pattern_len; @@ -5282,7 +5282,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts() int *end = bmBc + alphabet_size; int j; const int plm1 = pattern_len - 1; - CHARSET_INFO *cs= cmp.cmp_collation.collation; + CHARSET_INFO *cs= cmp_collation.collation; for (i = bmBc; i < end; i++) *i = pattern_len; @@ -5314,7 +5314,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const int shift = pattern_len; int j = 0; int u = 0; - CHARSET_INFO *cs= cmp.cmp_collation.collation; + CHARSET_INFO *cs= cmp_collation.collation; const int plm1= pattern_len - 1; const int tlmpl= text_len - pattern_len; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 06a0c39dc7f..f2d0032600b 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -290,18 +290,10 @@ public: }; class Item_bool_func2 :public Item_bool_func -{ /* Bool with 2 string args */ -protected: - Arg_comparator cmp; - +{ /* Bool with 2 string args */ public: Item_bool_func2(Item *a,Item *b) - :Item_bool_func(a,b), cmp(tmp_arg, tmp_arg+1) { sargable= TRUE; } - void fix_length_and_dec(); - int set_cmp_func() - { - return cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE); - } + :Item_bool_func(a,b) { sargable= TRUE; } optimize_type select_optimize() const { return OPTIMIZE_OP; } virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; } bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; } @@ -312,14 +304,6 @@ public: } bool is_null() { return MY_TEST(args[0]->is_null() || args[1]->is_null()); } - CHARSET_INFO *compare_collation() const - { return cmp.cmp_collation.collation; } - Arg_comparator *get_comparator() { return &cmp; } - void cleanup() - { - Item_bool_func::cleanup(); - cmp.cleanup(); - } COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value, bool top_level); @@ -327,8 +311,11 @@ public: class Item_bool_rowready_func2 :public Item_bool_func2 { +protected: + Arg_comparator cmp; public: - Item_bool_rowready_func2(Item *a, Item *b) :Item_bool_func2(a, b) + Item_bool_rowready_func2(Item *a, Item *b) + :Item_bool_func2(a, b), cmp(tmp_arg, tmp_arg+1) { allowed_arg_cols= 0; // Fetch this value from first argument } @@ -338,6 +325,19 @@ public: { return (*arg != NULL); } + void fix_length_and_dec(); + int set_cmp_func() + { + return cmp.set_cmp_func(this, tmp_arg, tmp_arg + 1, true); + } + CHARSET_INFO *compare_collation() const + { return cmp.cmp_collation.collation; } + Arg_comparator *get_comparator() { return &cmp; } + void cleanup() + { + Item_bool_func2::cleanup(); + cmp.cleanup(); + } bool can_optimize_group_min_max(Item_field *min_max_arg_item, const Item *const_item) const { @@ -1490,6 +1490,8 @@ class Item_func_like :public Item_bool_func2 bool escape_used_in_parsing; bool use_sampling; + DTCollation cmp_collation; + String cmp_value1, cmp_value2; public: int escape; @@ -1500,6 +1502,8 @@ public: longlong val_int(); enum Functype functype() const { return LIKE_FUNC; } optimize_type select_optimize() const; + CHARSET_INFO *compare_collation() const + { return cmp_collation.collation; } cond_result eq_cmp_result() const { /** @@ -1539,6 +1543,12 @@ public: table_map usable_tables, SARGABLE_PARAM **sargables); const char *func_name() const { return "like"; } bool fix_fields(THD *thd, Item **ref); + void fix_length_and_dec() + { + max_length= 1; + args[0]->cmp_context= args[1]->cmp_context= STRING_RESULT; + agg_arg_charsets_for_comparison(cmp_collation, args, 2); + } void cleanup(); bool find_selective_predicates_list_processor(uchar *arg); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 87459a4441b..0372a06c469 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13884,7 +13884,16 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, if ((tmp2=new COND_CMP(and_father,func))) save_list->push_back(tmp2); } - func->set_cmp_func(); + /* + LIKE can be optimized for BINARY/VARBINARY/BLOB columns, e.g.: + + from: WHERE CONCAT(c1)='const1' AND CONCAT(c1) LIKE 'const2' + to: WHERE CONCAT(c1)='const1' AND 'const1' LIKE 'const2' + + So make sure to use set_cmp_func() only for non-LIKE operators. + */ + if (functype != Item_func::LIKE_FUNC) + ((Item_bool_rowready_func2*) func)->set_cmp_func(); } } else if (can_change_cond_ref_to_const(func, left_item, right_item, @@ -13907,7 +13916,8 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list, if ((tmp2=new COND_CMP(and_father,func))) save_list->push_back(tmp2); } - func->set_cmp_func(); + if (functype != Item_func::LIKE_FUNC) + ((Item_bool_rowready_func2*) func)->set_cmp_func(); } } } |