mirror of
https://github.com/MariaDB/server.git
synced 2025-04-09 00:35:40 +02:00
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
This commit is contained in:
parent
8f92a70e21
commit
3709c7fc6d
7 changed files with 126 additions and 37 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue