Commit 3709c7fc authored by Alexander Barkov's avatar Alexander Barkov

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
parent 8f92a70e
......@@ -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
#
......@@ -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
#
......@@ -924,6 +924,14 @@ SELECT 'a','aa';
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 #
......@@ -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 #
......@@ -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;
......
......@@ -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);
......
......@@ -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();
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment