diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 2865a019f4b..42b96956cef 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -278,6 +278,25 @@ 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 FIELD('b','A','B'); +FIELD('b','A','B') +2 +select FIELD('B','A','B'); +FIELD('B','A','B') +2 +select FIELD('b' COLLATE latin1_bin,'A','B'); +FIELD('b' COLLATE latin1_bin,'A','B') +0 +select FIELD('b','A' COLLATE latin1_bin,'B'); +FIELD('b','A' COLLATE latin1_bin,'B') +0 +select FIELD(_latin2'b','A','B'); +ERROR HY000: Illegal mix of collations for operation 'field' +select FIELD('b',_latin2'A','B'); +ERROR HY000: Illegal mix of collations for operation 'field' +select FIELD('b',_latin2'A','B',1); +FIELD('b',_latin2'A','B',1) +1 select POSITION(_latin1'B' IN _latin1'abcd'); POSITION(_latin1'B' IN _latin1'abcd') 2 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 7dc08dece55..79d2b082d01 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -152,6 +152,19 @@ 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'); +# +# Test FIELD() and collations +# +select FIELD('b','A','B'); +select FIELD('B','A','B'); +select FIELD('b' COLLATE latin1_bin,'A','B'); +select FIELD('b','A' COLLATE latin1_bin,'B'); +--error 1269 +select FIELD(_latin2'b','A','B'); +--error 1269 +select FIELD('b',_latin2'A','B'); +select FIELD('b',_latin2'A','B',1); + select POSITION(_latin1'B' IN _latin1'abcd'); select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin); diff --git a/sql/item_func.cc b/sql/item_func.cc index 41daa09521c..eba6a2cc8d1 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1118,19 +1118,65 @@ longlong Item_func_locate::val_int() longlong Item_func_field::val_int() { - String *field; - if (!(field=item->val_str(&value))) - return 0; // -1 if null ? - for (uint i=0 ; i < arg_count ; i++) + if (cmp_type == STRING_RESULT) { - String *tmp_value=args[i]->val_str(&tmp); - if (tmp_value && field->length() == tmp_value->length() && - !memcmp(field->ptr(),tmp_value->ptr(),tmp_value->length())) - return (longlong) (i+1); + String *field; + if (!(field=item->val_str(&value))) + return 0; // -1 if null ? + for (uint i=0 ; i < arg_count ; i++) + { + String *tmp_value=args[i]->val_str(&tmp); + if (tmp_value && field->length() == tmp_value->length() && + !sortcmp(field,tmp_value,cmp_collation.collation)) + return (longlong) (i+1); + } + } + else if (cmp_type == INT_RESULT) + { + longlong val= item->val_int(); + for (uint i=0; i < arg_count ; i++) + { + if (val == args[i]->val_int()) + return (longlong) (i+1); + } + } + else + { + double val= item->val(); + for (uint i=0; i < arg_count ; i++) + { + if (val == args[i]->val()) + return (longlong) (i+1); + } } return 0; } +void Item_func_field::fix_length_and_dec() +{ + maybe_null=0; max_length=3; + used_tables_cache|= item->used_tables(); + const_item_cache&= item->const_item(); + with_sum_func= with_sum_func || item->with_sum_func; + + cmp_type= item->result_type(); + for (uint i=0; i < arg_count ; i++) + cmp_type= item_cmp_type(cmp_type, args[i]->result_type()); + + if (cmp_type == STRING_RESULT) + { + cmp_collation.set(item->collation); + for (uint i=0 ; i < arg_count ; i++) + { + if (cmp_collation.aggregate(args[i]->collation)) + { + my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),func_name()); + return; + } + } + } +} + void Item_func_field::split_sum_func(Item **ref_pointer_array, List &fields) diff --git a/sql/item_func.h b/sql/item_func.h index 9ba5bea8b87..6a08d961bc3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -624,6 +624,8 @@ class Item_func_field :public Item_int_func { Item *item; String value,tmp; + Item_result cmp_type; + DTCollation cmp_collation; public: Item_func_field(Item *a,List &list) :Item_int_func(list),item(a) {} ~Item_func_field() { delete item; } @@ -641,13 +643,7 @@ public: const_item_cache&= item->const_item(); } const char *func_name() const { return "field"; } - void fix_length_and_dec() - { - maybe_null=0; max_length=3; - used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); - with_sum_func= with_sum_func || item->with_sum_func; - } + void fix_length_and_dec(); void set_outer_resolving() { item->set_outer_resolving();