Commit 07f94cb7 authored by bar@bar.mysql.r18.ru's avatar bar@bar.mysql.r18.ru

Row comparison now does compare field collations, e.g.

  ROW('a','b','c) = ROW('A' collate latin1_bin,'b','c') returns 0
When a number is compared to a string, character sets and 
collations are not aggregated. e.g. this returned error in 4.1.0:

SELECT 1=_latin2'1';
because character sets was aggregated, and 1 was considered as
a string of latin1 charset during this aggregation.
parent 6a9a3ec0
drop table if exists t1; drop table if exists t1;
set names latin1;
select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo'; select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo';
hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo
hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo
...@@ -249,6 +250,34 @@ INSERT INTO t1 VALUES (1, 'a545f661efdd1fb66fdee3aab79945bf'); ...@@ -249,6 +250,34 @@ INSERT INTO t1 VALUES (1, 'a545f661efdd1fb66fdee3aab79945bf');
SELECT 1 FROM t1 WHERE tmp=AES_DECRYPT(tmp,"password"); SELECT 1 FROM t1 WHERE tmp=AES_DECRYPT(tmp,"password");
1 1
DROP TABLE t1; DROP TABLE t1;
select 1=_latin1'1';
1=_latin1'1'
1
select _latin1'1'=1;
_latin1'1'=1
1
select _latin2'1'=1;
_latin2'1'=1
1
select 1=_latin2'1';
1=_latin2'1'
1
select _latin1'1'=_latin2'1';
ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation '='
select row('a','b','c') = row('a','b','c');
row('a','b','c') = row('a','b','c')
1
select row('A','b','c') = row('a','b','c');
row('A','b','c') = row('a','b','c')
1
select row('A' COLLATE latin1_bin,'b','c') = row('a','b','c');
row('A' COLLATE latin1_bin,'b','c') = row('a','b','c')
0
select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c');
row('A','b','c') = row('a' COLLATE latin1_bin,'b','c')
0
select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c');
ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '='
select POSITION(_latin1'B' IN _latin1'abcd'); select POSITION(_latin1'B' IN _latin1'abcd');
POSITION(_latin1'B' IN _latin1'abcd') POSITION(_latin1'B' IN _latin1'abcd')
2 2
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
drop table if exists t1; drop table if exists t1;
--enable_warnings --enable_warnings
set names latin1;
select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo'; select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo';
select 'hello' 'monty'; select 'hello' 'monty';
select length('\n\t\r\b\0\_\%\\'); select length('\n\t\r\b\0\_\%\\');
...@@ -136,6 +138,21 @@ DROP TABLE t1; ...@@ -136,6 +138,21 @@ DROP TABLE t1;
# #
# Test collation and coercibility # Test collation and coercibility
# #
select 1=_latin1'1';
select _latin1'1'=1;
select _latin2'1'=1;
select 1=_latin2'1';
--error 1265
select _latin1'1'=_latin2'1';
select row('a','b','c') = row('a','b','c');
select row('A','b','c') = row('a','b','c');
select row('A' COLLATE latin1_bin,'b','c') = row('a','b','c');
select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c');
--error 1265
select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c');
select POSITION(_latin1'B' IN _latin1'abcd'); select POSITION(_latin1'B' IN _latin1'abcd');
select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin); select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin);
select POSITION(_latin1'B' COLLATE latin1_bin IN _latin1'abcd'); select POSITION(_latin1'B' COLLATE latin1_bin IN _latin1'abcd');
......
...@@ -109,15 +109,6 @@ static bool convert_constant_item(Field *field, Item **item) ...@@ -109,15 +109,6 @@ static bool convert_constant_item(Field *field, Item **item)
} }
bool Item_bool_func2::fix_fields(THD *thd, struct st_table_list *tables,
Item ** ref)
{
if (Item_int_func::fix_fields(thd, tables, ref))
return 1;
return 0;
}
void Item_bool_func2::fix_length_and_dec() void Item_bool_func2::fix_length_and_dec()
{ {
max_length= 1; // Function returns 0 or 1 max_length= 1; // Function returns 0 or 1
...@@ -191,8 +182,6 @@ void Item_bool_func2::fix_length_and_dec() ...@@ -191,8 +182,6 @@ void Item_bool_func2::fix_length_and_dec()
{ {
cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
INT_RESULT); // Works for all types. INT_RESULT); // Works for all types.
cmp_collation.set(&my_charset_bin,
DERIVATION_NONE); // For test in fix_fields
return; return;
} }
} }
...@@ -206,23 +195,11 @@ void Item_bool_func2::fix_length_and_dec() ...@@ -206,23 +195,11 @@ void Item_bool_func2::fix_length_and_dec()
{ {
cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
INT_RESULT); // Works for all types. INT_RESULT); // Works for all types.
cmp_collation.set(&my_charset_bin,
DERIVATION_NONE); // For test in fix_fields
return; return;
} }
} }
} }
set_cmp_func(); set_cmp_func();
/*
We must set cmp_charset here as we may be called from for an automatic
generated item, like in natural join
*/
if (cmp_collation.set(args[0]->collation, args[1]->collation))
{
/* set_cmp_charset() failed */
my_coll_agg_error(args[0]->collation, args[1]->collation, func_name());
return;
}
} }
...@@ -252,6 +229,18 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) ...@@ -252,6 +229,18 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
} }
} }
else if (type == STRING_RESULT)
{
/*
We must set cmp_charset here as we may be called from for an automatic
generated item, like in natural join
*/
if (cmp_collation.set((*a)->collation, (*b)->collation))
{
my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name());
return 1;
}
}
return 0; return 0;
} }
...@@ -264,7 +253,7 @@ int Arg_comparator::compare_string() ...@@ -264,7 +253,7 @@ int Arg_comparator::compare_string()
if ((res2= (*b)->val_str(&owner->tmp_value2))) if ((res2= (*b)->val_str(&owner->tmp_value2)))
{ {
owner->null_value= 0; owner->null_value= 0;
return sortcmp(res1,res2,owner->cmp_collation.collation); return sortcmp(res1,res2,cmp_collation.collation);
} }
} }
owner->null_value= 1; owner->null_value= 1;
...@@ -278,7 +267,7 @@ int Arg_comparator::compare_e_string() ...@@ -278,7 +267,7 @@ int Arg_comparator::compare_e_string()
res2= (*b)->val_str(&owner->tmp_value2); res2= (*b)->val_str(&owner->tmp_value2);
if (!res1 || !res2) if (!res1 || !res2)
return test(res1 == res2); return test(res1 == res2);
return test(sortcmp(res1, res2, owner->cmp_collation.collation) == 0); return test(sortcmp(res1, res2, cmp_collation.collation) == 0);
} }
...@@ -502,7 +491,7 @@ longlong Item_func_strcmp::val_int() ...@@ -502,7 +491,7 @@ longlong Item_func_strcmp::val_int()
null_value=1; null_value=1;
return 0; return 0;
} }
int value= sortcmp(a,b,cmp_collation.collation); int value= sortcmp(a,b,cmp.cmp_collation.collation);
null_value=0; null_value=0;
return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1); return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1);
} }
...@@ -1893,7 +1882,7 @@ longlong Item_func_like::val_int() ...@@ -1893,7 +1882,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_collation.collation, return my_wildcmp(cmp.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;
...@@ -2103,7 +2092,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff) ...@@ -2103,7 +2092,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff)
*splm1 = pattern_len; *splm1 = pattern_len;
if (cmp_collation.collation == &my_charset_bin) if (cmp.cmp_collation.collation == &my_charset_bin)
{ {
int i; int i;
for (i = pattern_len - 2; i >= 0; i--) for (i = pattern_len - 2; i >= 0; i--)
...@@ -2206,7 +2195,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts() ...@@ -2206,7 +2195,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts()
for (i = bmBc; i < end; i++) for (i = bmBc; i < end; i++)
*i = pattern_len; *i = pattern_len;
if (cmp_collation.collation == &my_charset_bin) if (cmp.cmp_collation.collation == &my_charset_bin)
{ {
for (j = 0; j < plm1; j++) for (j = 0; j < plm1; j++)
bmBc[(uint) (uchar) pattern[j]] = plm1 - j; bmBc[(uint) (uchar) pattern[j]] = plm1 - j;
...@@ -2237,7 +2226,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const ...@@ -2237,7 +2226,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
const int tlmpl= text_len - pattern_len; const int tlmpl= text_len - pattern_len;
/* Searching */ /* Searching */
if (cmp_collation.collation == &my_charset_bin) if (cmp.cmp_collation.collation == &my_charset_bin)
{ {
while (j <= tlmpl) while (j <= tlmpl)
{ {
......
...@@ -35,6 +35,8 @@ class Arg_comparator: public Sql_alloc ...@@ -35,6 +35,8 @@ class Arg_comparator: public Sql_alloc
Arg_comparator *comparators; // used only for compare_row() Arg_comparator *comparators; // used only for compare_row()
public: public:
DTCollation cmp_collation;
Arg_comparator() {}; Arg_comparator() {};
Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {};
...@@ -112,13 +114,10 @@ class Item_bool_func2 :public Item_int_func ...@@ -112,13 +114,10 @@ class Item_bool_func2 :public Item_int_func
protected: protected:
Arg_comparator cmp; Arg_comparator cmp;
String tmp_value1,tmp_value2; String tmp_value1,tmp_value2;
DTCollation cmp_collation;
public: public:
Item_bool_func2(Item *a,Item *b): Item_bool_func2(Item *a,Item *b):
Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {}
{ cmp_collation.set(0,DERIVATION_NONE);}
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref);
void fix_length_and_dec(); void fix_length_and_dec();
void set_cmp_func() void 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