diff --git a/mysql-test/r/ctype_collate.result b/mysql-test/r/ctype_collate.result index a2ff8a606cb..07da8c8c75f 100644 --- a/mysql-test/r/ctype_collate.result +++ b/mysql-test/r/ctype_collate.result @@ -523,7 +523,7 @@ Variable_name Value client_collation latin1 SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; charset('a') collation('a') coercibility('a') 'a'='A' -latin1 latin1 2 1 +latin1 latin1 3 1 SET NAMES latin1 COLLATE latin1_bin; SHOW VARIABLES LIKE 'client_collation'; Variable_name Value @@ -538,35 +538,35 @@ Variable_name Value client_collation latin1_bin SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; charset('a') collation('a') coercibility('a') 'a'='A' -latin1 latin1_bin 2 0 +latin1 latin1_bin 3 0 SET NAMES koi8r; SHOW VARIABLES LIKE 'client_collation'; Variable_name Value client_collation koi8r SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; charset('a') collation('a') coercibility('a') 'a'='A' -latin1 latin1 2 1 +latin1 latin1 3 1 SET COLLATION koi8r_bin; SHOW VARIABLES LIKE 'client_collation'; Variable_name Value client_collation koi8r_bin SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; charset('a') collation('a') coercibility('a') 'a'='A' -latin1 latin1 2 1 +latin1 latin1 3 1 SET COLLATION DEFAULT; SHOW VARIABLES LIKE 'client_collation'; Variable_name Value client_collation koi8r SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; charset('a') collation('a') coercibility('a') 'a'='A' -latin1 latin1 2 1 +latin1 latin1 3 1 SET NAMES DEFAULT; SHOW VARIABLES LIKE 'client_collation'; Variable_name Value client_collation latin1 SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; charset('a') collation('a') coercibility('a') 'a'='A' -latin1 latin1 2 1 +latin1 latin1 3 1 SET NAMES latin1 COLLATE koi8r; COLLATION 'koi8r' is not valid for CHARACTER SET 'latin1' SET NAMES 'DEFAULT'; diff --git a/sql/item.cc b/sql/item.cc index 6dbe026515d..b28b390c4a0 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -172,6 +172,39 @@ CHARSET_INFO * Item::default_charset() const return current_thd->db_charset; } +bool Item::set_charset(CHARSET_INFO *cs1, enum coercion co1, + CHARSET_INFO *cs2, enum coercion co2) +{ + if (cs1 == &my_charset_bin || cs2 == &my_charset_bin) + { + set_charset(&my_charset_bin, COER_NOCOLL); + return 0; + } + + if (!my_charset_same(cs1,cs2)) + { + set_charset(&my_charset_bin, COER_NOCOLL); + return 0; + } + + if (co1 < co2) + { + set_charset(cs1, co1); + } + else if (co2 < co1) + { + set_charset(cs2, co2); + } + else // co2 == co1 + { + if (cs1 != cs2) + set_charset(&my_charset_bin, COER_NOCOLL); + else + set_charset(cs2, co2); + } + return 0; +} + Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name) { set_field(f); @@ -195,8 +228,7 @@ void Item_field::set_field(Field *field_par) table_name=field_par->table_name; field_name=field_par->field_name; unsigned_flag=test(field_par->flags & UNSIGNED_FLAG); - set_charset(field_par->charset()); - coercibility= COER_IMPLICIT; + set_charset(field_par->charset(), COER_IMPLICIT); } const char *Item_ident::full_name() const diff --git a/sql/item.h b/sql/item.h index 2bb22d47083..d9698e09ade 100644 --- a/sql/item.h +++ b/sql/item.h @@ -39,8 +39,8 @@ public: SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; - enum coercion { COER_NOCOLL=3, COER_COERCIBLE=2, - COER_IMPLICIT=1, COER_EXPLICIT=0 }; + enum coercion { COER_COERCIBLE=3, COER_IMPLICIT=2, + COER_NOCOLL=1, COER_EXPLICIT=0 }; String str_value; /* used to store value */ my_string name; /* Name from select */ @@ -113,6 +113,13 @@ public: CHARSET_INFO *default_charset() const; CHARSET_INFO *charset() const { return str_value.charset(); }; void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); } + void set_charset(CHARSET_INFO *cs, enum coercion coer) + { + str_value.set_charset(cs); + coercibility= coer; + } + bool set_charset(CHARSET_INFO *cs1, enum coercion co1, + CHARSET_INFO *cs2, enum coercion co2); virtual void set_outer_resolving() {} // Row emulation diff --git a/sql/item_func.cc b/sql/item_func.cc index 6bd61a4e1e2..b7ff6f17969 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -107,7 +107,6 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return 0; // Fatal error if flag is set! if (arg_count) { // Print purify happy - bool first_coll= 1; for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { if ((*arg)->fix_fields(thd, tables, arg) || @@ -116,38 +115,6 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) if ((*arg)->maybe_null) maybe_null=1; - if ((*arg)->result_type() == STRING_RESULT) - { - /* - Set return character set to first argument if we are returning a - string. - */ - if (first_coll) - { - set_charset((*arg)->charset()); - coercibility= (*args)->coercibility; - first_coll= 0; - } - else if ((*arg)->charset() == &my_charset_bin || - charset() == &my_charset_bin) - { - set_charset(&my_charset_bin); - coercibility= COER_NOCOLL; - } - else if ((*arg)->coercibility < coercibility) - { - if (!my_charset_same(charset(),(*arg)->charset())) - { - set_charset(&my_charset_bin); - coercibility= COER_NOCOLL; - } - else - { - coercibility= (*arg)->coercibility; - set_charset((*arg)->charset()); - } - } - } with_sum_func= with_sum_func || (*arg)->with_sum_func; used_tables_cache|=(*arg)->used_tables(); const_item_cache&= (*arg)->const_item(); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 320a4258a49..5151a25f257 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -321,9 +321,17 @@ null: void Item_func_concat::fix_length_and_dec() { + bool first_coll= 1; max_length=0; + + set_charset(args[0]->charset(),args[0]->coercibility); for (uint i=0 ; i < arg_count ; i++) + { max_length+=args[i]->max_length; + set_charset(charset(), coercibility, + args[i]->charset(), args[i]->coercibility); + } + if (max_length > MAX_BLOB_WIDTH) { max_length=MAX_BLOB_WIDTH; @@ -978,6 +986,7 @@ void Item_func_substr::fix_length_and_dec() { max_length=args[0]->max_length; + set_charset(args[0]->charset(), args[0]->coercibility); if (args[1]->const_item()) { int32 start=(int32) args[1]->val_int()-1; @@ -1791,6 +1800,7 @@ inline String* alloc_buffer(String *res,String *str,String *tmp_value, void Item_func_repeat::fix_length_and_dec() { + set_charset(args[0]->charset(), args[0]->coercibility); if (args[1]->const_item()) { max_length=(long) (args[0]->max_length * args[1]->val_int()); @@ -2028,8 +2038,7 @@ String *Item_func_conv_charset::val_str(String *str) void Item_func_conv_charset::fix_length_and_dec() { max_length = args[0]->max_length*conv_charset->mbmaxlen; - coercibility= COER_IMPLICIT; - set_charset(conv_charset); + set_charset(conv_charset, COER_IMPLICIT); } @@ -2171,9 +2180,7 @@ bool Item_func_set_collation::fix_fields(THD *thd,struct st_table_list *tables, set_collation->name,args[0]->charset()->csname); return 1; } - set_charset(set_collation); - - coercibility= COER_EXPLICIT; + set_charset(set_collation, COER_EXPLICIT); with_sum_func= with_sum_func || args[0]->with_sum_func; used_tables_cache=args[0]->used_tables(); const_item_cache=args[0]->const_item(); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 726008716c5..84653a8315c 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -151,7 +151,11 @@ class Item_str_conv :public Item_str_func { public: Item_str_conv(Item *item) :Item_str_func(item) {} - void fix_length_and_dec() { max_length = args[0]->max_length; } + void fix_length_and_dec() + { + set_charset(args[0]->charset(), args[0]->coercibility); + max_length = args[0]->max_length; + } };