mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03: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:
@ -5542,5 +5542,14 @@ select collation(cast("a" as char(10) binary unicode));
|
|||||||
collation(cast("a" as char(10) binary unicode))
|
collation(cast("a" as char(10) binary unicode))
|
||||||
ucs2_bin
|
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
|
# End of 10.1 tests
|
||||||
#
|
#
|
||||||
|
@ -200,3 +200,32 @@ SELECT 'a' LIKE REPEAT('',0);
|
|||||||
SELECT 'a' LIKE EXTRACTVALUE('bar','qux');
|
SELECT 'a' LIKE EXTRACTVALUE('bar','qux');
|
||||||
'a' LIKE EXTRACTVALUE('bar','qux')
|
'a' LIKE EXTRACTVALUE('bar','qux')
|
||||||
0
|
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) unicode binary));
|
||||||
select collation(cast("a" as char(10) binary unicode));
|
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 #
|
||||||
--echo # End of 10.1 tests
|
--echo # End of 10.1 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -143,3 +143,26 @@ SELECT '' LIKE '1' ESCAPE COUNT(1);
|
|||||||
--echo #
|
--echo #
|
||||||
SELECT 'a' LIKE REPEAT('',0);
|
SELECT 'a' LIKE REPEAT('',0);
|
||||||
SELECT 'a' LIKE EXTRACTVALUE('bar','qux');
|
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=
|
args[0]->cmp_context= args[1]->cmp_context=
|
||||||
item_cmp_type(args[0]->result_type(), args[1]->result_type());
|
item_cmp_type(args[0]->result_type(), args[1]->result_type());
|
||||||
|
|
||||||
// Convert constants when compared to int/year field, unless this is LIKE
|
// Convert constants when compared to int/year field
|
||||||
if (functype() != LIKE_FUNC)
|
DBUG_ASSERT(functype() != LIKE_FUNC);
|
||||||
convert_const_compared_to_int_field(thd);
|
convert_const_compared_to_int_field(thd);
|
||||||
|
|
||||||
return cmp->set_cmp_func(this, tmp_arg, tmp_arg + 1, true);
|
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
|
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()
|
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;
|
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()
|
longlong Item_func_like::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
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)
|
if (args[0]->null_value)
|
||||||
{
|
{
|
||||||
null_value=1;
|
null_value=1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
String* res2 = args[1]->val_str(&cmp.value2);
|
String* res2= args[1]->val_str(&cmp_value2);
|
||||||
if (args[1]->null_value)
|
if (args[1]->null_value)
|
||||||
{
|
{
|
||||||
null_value=1;
|
null_value=1;
|
||||||
@ -4799,7 +4799,7 @@ longlong Item_func_like::val_int()
|
|||||||
null_value=0;
|
null_value=0;
|
||||||
if (canDoTurboBM)
|
if (canDoTurboBM)
|
||||||
return turboBM_matches(res->ptr(), res->length()) ? 1 : 0;
|
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(),
|
res->ptr(),res->ptr()+res->length(),
|
||||||
res2->ptr(),res2->ptr()+res2->length(),
|
res2->ptr(),res2->ptr()+res2->length(),
|
||||||
escape,wild_one,wild_many) ? 0 : 1;
|
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())
|
if (!args[1]->const_item() || args[1]->is_expensive())
|
||||||
return OPTIMIZE_NONE;
|
return OPTIMIZE_NONE;
|
||||||
|
|
||||||
String* res2= args[1]->val_str((String *)&cmp.value2);
|
String* res2= args[1]->val_str((String *) &cmp_value2);
|
||||||
if (!res2)
|
if (!res2)
|
||||||
return OPTIMIZE_NONE;
|
return OPTIMIZE_NONE;
|
||||||
|
|
||||||
@ -4845,7 +4845,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
|
|||||||
if (escape_item->const_item())
|
if (escape_item->const_item())
|
||||||
{
|
{
|
||||||
/* If we are on execution stage */
|
/* 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)
|
if (escape_str)
|
||||||
{
|
{
|
||||||
const char *escape_str_ptr= escape_str->ptr();
|
const char *escape_str_ptr= escape_str->ptr();
|
||||||
@ -4858,7 +4858,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_mb(cmp.cmp_collation.collation))
|
if (use_mb(cmp_collation.collation))
|
||||||
{
|
{
|
||||||
CHARSET_INFO *cs= escape_str->charset();
|
CHARSET_INFO *cs= escape_str->charset();
|
||||||
my_wc_t wc;
|
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.
|
code instead of Unicode code as "escape" argument.
|
||||||
Convert to "cs" if charset of escape differs.
|
Convert to "cs" if charset of escape differs.
|
||||||
*/
|
*/
|
||||||
CHARSET_INFO *cs= cmp.cmp_collation.collation;
|
CHARSET_INFO *cs= cmp_collation.collation;
|
||||||
uint32 unused;
|
uint32 unused;
|
||||||
if (escape_str->needs_conversion(escape_str->length(),
|
if (escape_str->needs_conversion(escape_str->length(),
|
||||||
escape_str->charset(), cs, &unused))
|
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) &&
|
if (args[1]->const_item() && !use_strnxfrm(collation.collation) &&
|
||||||
!args[1]->is_expensive())
|
!args[1]->is_expensive())
|
||||||
{
|
{
|
||||||
String* res2 = args[1]->val_str(&cmp.value2);
|
String* res2= args[1]->val_str(&cmp_value2);
|
||||||
if (!res2)
|
if (!res2)
|
||||||
return FALSE; // Null argument
|
return FALSE; // Null argument
|
||||||
|
|
||||||
@ -5182,7 +5182,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff)
|
|||||||
int f = 0;
|
int f = 0;
|
||||||
int g = plm1;
|
int g = plm1;
|
||||||
int *const splm1 = suff + plm1;
|
int *const splm1 = suff + plm1;
|
||||||
CHARSET_INFO *cs= cmp.cmp_collation.collation;
|
CHARSET_INFO *cs= cmp_collation.collation;
|
||||||
|
|
||||||
*splm1 = pattern_len;
|
*splm1 = pattern_len;
|
||||||
|
|
||||||
@ -5282,7 +5282,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts()
|
|||||||
int *end = bmBc + alphabet_size;
|
int *end = bmBc + alphabet_size;
|
||||||
int j;
|
int j;
|
||||||
const int plm1 = pattern_len - 1;
|
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++)
|
for (i = bmBc; i < end; i++)
|
||||||
*i = pattern_len;
|
*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 shift = pattern_len;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
int u = 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 plm1= pattern_len - 1;
|
||||||
const int tlmpl= text_len - pattern_len;
|
const int tlmpl= text_len - pattern_len;
|
||||||
|
@ -290,18 +290,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Item_bool_func2 :public Item_bool_func
|
class Item_bool_func2 :public Item_bool_func
|
||||||
{ /* Bool with 2 string args */
|
{ /* Bool with 2 string args */
|
||||||
protected:
|
|
||||||
Arg_comparator cmp;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Item_bool_func2(Item *a,Item *b)
|
Item_bool_func2(Item *a,Item *b)
|
||||||
:Item_bool_func(a,b), cmp(tmp_arg, tmp_arg+1) { sargable= TRUE; }
|
:Item_bool_func(a,b) { sargable= TRUE; }
|
||||||
void fix_length_and_dec();
|
|
||||||
int set_cmp_func()
|
|
||||||
{
|
|
||||||
return cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE);
|
|
||||||
}
|
|
||||||
optimize_type select_optimize() const { return OPTIMIZE_OP; }
|
optimize_type select_optimize() const { return OPTIMIZE_OP; }
|
||||||
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
|
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
|
||||||
bool have_rev_func() const { return rev_functype() != 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()); }
|
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,
|
COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
|
||||||
bool top_level);
|
bool top_level);
|
||||||
|
|
||||||
@ -327,8 +311,11 @@ public:
|
|||||||
|
|
||||||
class Item_bool_rowready_func2 :public Item_bool_func2
|
class Item_bool_rowready_func2 :public Item_bool_func2
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
Arg_comparator cmp;
|
||||||
public:
|
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
|
allowed_arg_cols= 0; // Fetch this value from first argument
|
||||||
}
|
}
|
||||||
@ -338,6 +325,19 @@ public:
|
|||||||
{
|
{
|
||||||
return (*arg != NULL);
|
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,
|
bool can_optimize_group_min_max(Item_field *min_max_arg_item,
|
||||||
const Item *const_item) const
|
const Item *const_item) const
|
||||||
{
|
{
|
||||||
@ -1490,6 +1490,8 @@ class Item_func_like :public Item_bool_func2
|
|||||||
bool escape_used_in_parsing;
|
bool escape_used_in_parsing;
|
||||||
bool use_sampling;
|
bool use_sampling;
|
||||||
|
|
||||||
|
DTCollation cmp_collation;
|
||||||
|
String cmp_value1, cmp_value2;
|
||||||
public:
|
public:
|
||||||
int escape;
|
int escape;
|
||||||
|
|
||||||
@ -1500,6 +1502,8 @@ public:
|
|||||||
longlong val_int();
|
longlong val_int();
|
||||||
enum Functype functype() const { return LIKE_FUNC; }
|
enum Functype functype() const { return LIKE_FUNC; }
|
||||||
optimize_type select_optimize() const;
|
optimize_type select_optimize() const;
|
||||||
|
CHARSET_INFO *compare_collation() const
|
||||||
|
{ return cmp_collation.collation; }
|
||||||
cond_result eq_cmp_result() const
|
cond_result eq_cmp_result() const
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -1539,6 +1543,12 @@ public:
|
|||||||
table_map usable_tables, SARGABLE_PARAM **sargables);
|
table_map usable_tables, SARGABLE_PARAM **sargables);
|
||||||
const char *func_name() const { return "like"; }
|
const char *func_name() const { return "like"; }
|
||||||
bool fix_fields(THD *thd, Item **ref);
|
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();
|
void cleanup();
|
||||||
|
|
||||||
bool find_selective_predicates_list_processor(uchar *arg);
|
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)))
|
if ((tmp2=new COND_CMP(and_father,func)))
|
||||||
save_list->push_back(tmp2);
|
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,
|
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)))
|
if ((tmp2=new COND_CMP(and_father,func)))
|
||||||
save_list->push_back(tmp2);
|
save_list->push_back(tmp2);
|
||||||
}
|
}
|
||||||
func->set_cmp_func();
|
if (functype != Item_func::LIKE_FUNC)
|
||||||
|
((Item_bool_rowready_func2*) func)->set_cmp_func();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user