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

str0 IN (str1, str2, ...) now works according to collation rules

parent 52a7f956
...@@ -296,6 +296,28 @@ select _latin1'B' between _latin1'a' and _latin2'b'; ...@@ -296,6 +296,28 @@ select _latin1'B' between _latin1'a' and _latin2'b';
ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE) for operation 'between' ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE) for operation 'between'
select _latin1'B' collate latin1_general_ci between _latin1'a' collate latin1_bin and _latin1'b'; select _latin1'B' collate latin1_general_ci between _latin1'a' collate latin1_bin and _latin1'b';
ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_bin,EXPLICIT), (latin1_swedish_ci,COERCIBLE) for operation 'between' ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_bin,EXPLICIT), (latin1_swedish_ci,COERCIBLE) for operation 'between'
select _latin1'B' in (_latin1'a',_latin1'b');
_latin1'B' in (_latin1'a',_latin1'b')
1
select _latin1'B' collate latin1_bin in (_latin1'a',_latin1'b');
_latin1'B' collate latin1_bin in (_latin1'a',_latin1'b')
0
select _latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b');
_latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b')
0
select _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin);
_latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin)
0
select _latin2'B' in (_latin1'a',_latin1'b');
ERROR HY000: Illegal mix of collations for operation ' IN '
select _latin1'B' in (_latin2'a',_latin1'b');
ERROR HY000: Illegal mix of collations for operation ' IN '
select _latin1'B' in (_latin1'a',_latin2'b');
ERROR HY000: Illegal mix of collations for operation ' IN '
select _latin1'B' COLLATE latin1_general_ci in (_latin1'a' COLLATE latin1_bin,_latin1'b');
ERROR HY000: Illegal mix of collations for operation ' IN '
select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE latin1_bin);
ERROR HY000: Illegal mix of collations for operation ' IN '
select collation(bin(130)), coercibility(bin(130)); select collation(bin(130)), coercibility(bin(130));
collation(bin(130)) coercibility(bin(130)) collation(bin(130)) coercibility(bin(130))
latin1_swedish_ci 3 latin1_swedish_ci 3
......
...@@ -175,6 +175,21 @@ select _latin1'B' between _latin1'a' and _latin2'b'; ...@@ -175,6 +175,21 @@ select _latin1'B' between _latin1'a' and _latin2'b';
--error 1268 --error 1268
select _latin1'B' collate latin1_general_ci between _latin1'a' collate latin1_bin and _latin1'b'; select _latin1'B' collate latin1_general_ci between _latin1'a' collate latin1_bin and _latin1'b';
select _latin1'B' in (_latin1'a',_latin1'b');
select _latin1'B' collate latin1_bin in (_latin1'a',_latin1'b');
select _latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b');
select _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin);
--error 1269
select _latin2'B' in (_latin1'a',_latin1'b');
--error 1269
select _latin1'B' in (_latin2'a',_latin1'b');
--error 1269
select _latin1'B' in (_latin1'a',_latin2'b');
--error 1269
select _latin1'B' COLLATE latin1_general_ci in (_latin1'a' COLLATE latin1_bin,_latin1'b');
--error 1269
select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE latin1_bin);
select collation(bin(130)), coercibility(bin(130)); select collation(bin(130)), coercibility(bin(130));
select collation(oct(130)), coercibility(oct(130)); select collation(oct(130)), coercibility(oct(130));
select collation(conv(130,16,10)), coercibility(conv(130,16,10)); select collation(conv(130,16,10)), coercibility(conv(130,16,10));
......
...@@ -1196,17 +1196,17 @@ void Item_func_coalesce::fix_length_and_dec() ...@@ -1196,17 +1196,17 @@ void Item_func_coalesce::fix_length_and_dec()
Classes and function for the IN operator Classes and function for the IN operator
****************************************************************************/ ****************************************************************************/
static int cmp_longlong(longlong *a,longlong *b) static int cmp_longlong(void *cmp_arg, longlong *a,longlong *b)
{ {
return *a < *b ? -1 : *a == *b ? 0 : 1; return *a < *b ? -1 : *a == *b ? 0 : 1;
} }
static int cmp_double(double *a,double *b) static int cmp_double(void *cmp_arg, double *a,double *b)
{ {
return *a < *b ? -1 : *a == *b ? 0 : 1; return *a < *b ? -1 : *a == *b ? 0 : 1;
} }
static int cmp_row(cmp_item_row* a, cmp_item_row* b) static int cmp_row(void *cmp_arg, cmp_item_row* a, cmp_item_row* b)
{ {
return a->compare(b); return a->compare(b);
} }
...@@ -1223,18 +1223,18 @@ int in_vector::find(Item *item) ...@@ -1223,18 +1223,18 @@ int in_vector::find(Item *item)
{ {
uint mid=(start+end+1)/2; uint mid=(start+end+1)/2;
int res; int res;
if ((res=(*compare)(base+mid*size,result)) == 0) if ((res=(*compare)(collation, base+mid*size, result)) == 0)
return 1; return 1;
if (res < 0) if (res < 0)
start=mid; start=mid;
else else
end=mid-1; end=mid-1;
} }
return (int) ((*compare)(base+start*size,result) == 0); return (int) ((*compare)(collation, base+start*size, result) == 0);
} }
in_string::in_string(uint elements,qsort_cmp cmp_func) in_string::in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs)
:in_vector(elements, sizeof(String), cmp_func), :in_vector(elements, sizeof(String), cmp_func, cs),
tmp(buff, sizeof(buff), &my_charset_bin) tmp(buff, sizeof(buff), &my_charset_bin)
{} {}
...@@ -1273,7 +1273,7 @@ in_row::in_row(uint elements, Item * item) ...@@ -1273,7 +1273,7 @@ in_row::in_row(uint elements, Item * item)
{ {
base= (char*) new cmp_item_row[count= elements]; base= (char*) new cmp_item_row[count= elements];
size= sizeof(cmp_item_row); size= sizeof(cmp_item_row);
compare= (qsort_cmp) cmp_row; compare= (qsort2_cmp) cmp_row;
tmp.store_value(item); tmp.store_value(item);
} }
...@@ -1298,7 +1298,7 @@ void in_row::set(uint pos, Item *item) ...@@ -1298,7 +1298,7 @@ void in_row::set(uint pos, Item *item)
} }
in_longlong::in_longlong(uint elements) in_longlong::in_longlong(uint elements)
:in_vector(elements,sizeof(longlong),(qsort_cmp) cmp_longlong) :in_vector(elements,sizeof(longlong),(qsort2_cmp) cmp_longlong, 0)
{} {}
void in_longlong::set(uint pos,Item *item) void in_longlong::set(uint pos,Item *item)
...@@ -1315,7 +1315,7 @@ byte *in_longlong::get_value(Item *item) ...@@ -1315,7 +1315,7 @@ byte *in_longlong::get_value(Item *item)
} }
in_double::in_double(uint elements) in_double::in_double(uint elements)
:in_vector(elements,sizeof(double),(qsort_cmp) cmp_double) :in_vector(elements,sizeof(double),(qsort2_cmp) cmp_double, 0)
{} {}
void in_double::set(uint pos,Item *item) void in_double::set(uint pos,Item *item)
...@@ -1462,17 +1462,8 @@ bool Item_func_in::nulls_in_row() ...@@ -1462,17 +1462,8 @@ bool Item_func_in::nulls_in_row()
return 0; return 0;
} }
static int srtcmp_in(const String *x,const String *y) static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
{ {
CHARSET_INFO *cs= x->charset();
return cs->coll->strnncollsp(cs,
(unsigned char *) x->ptr(),x->length(),
(unsigned char *) y->ptr(),y->length());
}
static int bincmp_in(const String *x,const String *y)
{
CHARSET_INFO *cs= &my_charset_bin;
return cs->coll->strnncollsp(cs, return cs->coll->strnncollsp(cs,
(unsigned char *) x->ptr(),x->length(), (unsigned char *) x->ptr(),x->length(),
(unsigned char *) y->ptr(),y->length()); (unsigned char *) y->ptr(),y->length());
...@@ -1488,10 +1479,18 @@ void Item_func_in::fix_length_and_dec() ...@@ -1488,10 +1479,18 @@ void Item_func_in::fix_length_and_dec()
{ {
switch (item->result_type()) { switch (item->result_type()) {
case STRING_RESULT: case STRING_RESULT:
if (item->binary()) uint i;
array=new in_string(arg_count,(qsort_cmp) srtcmp_in); cmp_collation.set(item->collation);
else for (i=0 ; i<arg_count; i++)
array=new in_string(arg_count,(qsort_cmp) bincmp_in); if (cmp_collation.aggregate(args[i]->collation))
break;
if (cmp_collation.derivation == DERIVATION_NONE)
{
my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),func_name());
return;
}
array=new in_string(arg_count,(qsort2_cmp) srtcmp_in,
cmp_collation.collation);
break; break;
case INT_RESULT: case INT_RESULT:
array= new in_longlong(arg_count); array= new in_longlong(arg_count);
......
...@@ -382,21 +382,23 @@ class in_vector :public Sql_alloc ...@@ -382,21 +382,23 @@ class in_vector :public Sql_alloc
protected: protected:
char *base; char *base;
uint size; uint size;
qsort_cmp compare; qsort2_cmp compare;
CHARSET_INFO *collation;
uint count; uint count;
public: public:
uint used_count; uint used_count;
in_vector() {} in_vector() {}
in_vector(uint elements,uint element_length,qsort_cmp cmp_func) in_vector(uint elements,uint element_length,qsort2_cmp cmp_func,
CHARSET_INFO *cmp_coll)
:base((char*) sql_calloc(elements*element_length)), :base((char*) sql_calloc(elements*element_length)),
size(element_length), compare(cmp_func), count(elements), size(element_length), compare(cmp_func), collation(cmp_coll),
used_count(elements) {} count(elements), used_count(elements) {}
virtual ~in_vector() {} virtual ~in_vector() {}
virtual void set(uint pos,Item *item)=0; virtual void set(uint pos,Item *item)=0;
virtual byte *get_value(Item *item)=0; virtual byte *get_value(Item *item)=0;
void sort() void sort()
{ {
qsort(base,used_count,size,compare); qsort2(base,used_count,size,compare,collation);
} }
int find(Item *item); int find(Item *item);
}; };
...@@ -406,7 +408,7 @@ class in_string :public in_vector ...@@ -406,7 +408,7 @@ class in_string :public in_vector
char buff[80]; char buff[80];
String tmp; String tmp;
public: public:
in_string(uint elements,qsort_cmp cmp_func); in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs);
~in_string(); ~in_string();
void set(uint pos,Item *item); void set(uint pos,Item *item);
byte *get_value(Item *item); byte *get_value(Item *item);
...@@ -605,6 +607,7 @@ class Item_func_in :public Item_int_func ...@@ -605,6 +607,7 @@ class Item_func_in :public Item_int_func
in_vector *array; in_vector *array;
cmp_item *in_item; cmp_item *in_item;
bool have_null; bool have_null;
DTCollation cmp_collation;
public: public:
Item_func_in(Item *a,List<Item> &list) Item_func_in(Item *a,List<Item> &list)
:Item_int_func(list), item(a), array(0), in_item(0), have_null(0) :Item_int_func(list), item(a), array(0), in_item(0), have_null(0)
......
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