diff --git a/sql/item.cc b/sql/item.cc index 4c7b30b041018dd95c73b177847eb82b16d85ddb..950f27c5d69d953305b78431162d036f2e52a3a4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -183,44 +183,61 @@ CHARSET_INFO * Item::default_charset() const return current_thd->variables.collation_connection; } -bool Item::set_charset(CHARSET_INFO *cs1, Derivation co1, - CHARSET_INFO *cs2, Derivation co2) +bool DTCollation::aggregate(DTCollation &dt) { - if (cs1 == &my_charset_bin || cs2 == &my_charset_bin) + if (collation == &my_charset_bin || dt.collation == &my_charset_bin) { - set_charset(&my_charset_bin, DERIVATION_NONE); + collation= &my_charset_bin; + derivation= derivation > dt.derivation ? derivation : dt.derivation; return 0; } - - if (!my_charset_same(cs1,cs2)) - return 1; - - if (co1 < co2) + + if (!my_charset_same(collation, dt.collation)) { - set_charset(cs1, co1); + /* + We do allow to use binary strings (like BLOBS) + together with character strings. + Binaries have more precedance + */ + if ((derivation <= dt.derivation) && (collation == &my_charset_bin)) + { + // Do nothing + } + else if ((dt.derivation <= derivation) && (dt.collation==&my_charset_bin)) + { + set(dt); + } + else + { + set(0, DERIVATION_NONE); + return 1; + } } - else if (co2 < co1) + else if (derivation < dt.derivation) { - set_charset(cs2, co2); + // Do nothing } - else // co2 == co1 + else if (dt.derivation < derivation) { - if (cs1 != cs2) + set(dt); + } + else + { + if (collation == dt.collation) { - if (co1 == DERIVATION_EXPLICIT) - { - return 1; - } - else + // Do nothing + } + else + { + if (derivation == DERIVATION_EXPLICIT) { - CHARSET_INFO *bin= get_charset_by_csname(cs1->csname, MY_CS_BINSORT,MYF(0)); - if (!bin) - return 1; - set_charset(bin, DERIVATION_NONE); + set(0, DERIVATION_NONE); + return 1; } + CHARSET_INFO *bin= get_charset_by_csname(collation->csname, + MY_CS_BINSORT,MYF(0)); + set(bin, DERIVATION_NONE); } - else - set_charset(cs2, co2); } return 0; } diff --git a/sql/item.h b/sql/item.h index ce79e70e5d696a280200734a0dbc57172f063c01..e80648b89deb78e55068275b62f0a4a175e9dd2d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -52,10 +52,10 @@ public: collation= collation_arg; derivation= derivation_arg; } - void set(DTCollation *dt) + void set(DTCollation &dt) { - collation= dt->collation; - derivation= dt->derivation; + collation= dt.collation; + derivation= dt.derivation; } void set(CHARSET_INFO *collation_arg, Derivation derivation_arg) { @@ -66,7 +66,9 @@ public: { collation= collation_arg; } void set(Derivation derivation_arg) { derivation= derivation_arg; } - bool aggregate(DTCollation *dt); + bool aggregate(DTCollation &dt); + bool set(DTCollation &dt1, DTCollation &dt2) + { set(dt1); return aggregate(dt2); } const char *derivation_name() const { switch(derivation) @@ -183,8 +185,6 @@ public: collation.collation= collation_arg->collation; collation.derivation= collation_arg->derivation; } - bool set_charset(CHARSET_INFO *cs1, Derivation dv1, - CHARSET_INFO *cs2, Derivation dv2); bool binary() const { return charset()->state & MY_CS_BINSORT ? 1 : 0 ; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 035f85a45ba3e24d7e0596013b24ad7c5f416747..52bd14ed5159d2547d9951e92d4650e3b2d85dcd 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -96,72 +96,26 @@ static bool convert_constant_item(Field *field, Item **item) return 0; } -bool Item_bool_func2::set_cmp_charset(CHARSET_INFO *cs1, Derivation co1, - CHARSET_INFO *cs2, Derivation co2) -{ - if (cs1 == &my_charset_bin || cs2 == &my_charset_bin) - { - cmp_charset= &my_charset_bin; - //coercibility= co1 > co2 ? co1 : co2; - return 0; - } - - if (!my_charset_same(cs1, cs2)) - { - /* - We do allow to use BLOBS together with character strings - BLOBS have more precedance - */ - if ((co1 <= co2) && (cs1==&my_charset_bin)) - { - cmp_charset= cs1; - //coercibility= co1; - } - else if ((co2 <= co1) && (cs2==&my_charset_bin)) - { - cmp_charset= cs2; - //coercibility= co2; - } - else - { - cmp_charset= 0; - //coercibility= DERIVATION_NOCOLL; - return 1; - } - } - else if (co1 < co2) - { - cmp_charset= cs1; - //coercibility= co1; - } - else if (co2 < co1) - { - cmp_charset= cs2; - //coercibility= co1; - } - else - { - if (cs1 == cs2) - { - cmp_charset= cs1; - //coercibility= co1; - } - else - { - //coercibility= DERIVATION_NOCOLL; - cmp_charset= 0; - return (co1 == DERIVATION_EXPLICIT) ? 1 : 0; - } - } - return 0; -} - 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() +{ + max_length= 1; // Function returns 0 or 1 + + /* + As some compare functions are generated after sql_yacc, + we have to check for out of memory conditions here + */ + if (!args[0] || !args[1]) + return; /* We allow to convert to Unicode character sets in some cases. @@ -209,35 +163,12 @@ bool Item_bool_func2::fix_fields(THD *thd, struct st_table_list *tables, else { conv= new Item_func_conv_charset(args[weak],args[strong]->charset()); - //conv->coercibility= args[weak]->derivation(); + conv->collation.set(args[weak]->derivation()); } args[weak]= conv ? conv : args[weak]; - set_cmp_charset(args[0]->charset(), args[0]->derivation(), - args[1]->charset(), args[1]->derivation()); } } - if (!cmp_charset) - { - /* set_cmp_charset() failed */ - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); - return 1; - } - return 0; -} - - -void Item_bool_func2::fix_length_and_dec() -{ - max_length= 1; // Function returns 0 or 1 - - /* - As some compare functions are generated after sql_yacc, - we have to check for out of memory conditions here - */ - if (!args[0] || !args[1]) - return; - - + // Make a special case of compare with fields to get nicer DATE comparisons if (args[0]->type() == FIELD_ITEM) { @@ -248,7 +179,8 @@ void Item_bool_func2::fix_length_and_dec() { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, INT_RESULT); // Works for all types. - cmp_charset= &my_charset_bin; // For test in fix_fields + cmp_collation.set(&my_charset_bin, + DERIVATION_NONE); // For test in fix_fields return; } } @@ -262,7 +194,8 @@ void Item_bool_func2::fix_length_and_dec() { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, INT_RESULT); // Works for all types. - cmp_charset= &my_charset_bin; // For test in fix_fields + cmp_collation.set(&my_charset_bin, + DERIVATION_NONE); // For test in fix_fields return; } } @@ -272,8 +205,12 @@ void Item_bool_func2::fix_length_and_dec() We must set cmp_charset here as we may be called from for an automatic generated item, like in natural join */ - set_cmp_charset(args[0]->charset(), args[0]->derivation(), - args[1]->charset(), args[1]->derivation()); + 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; + } } @@ -315,7 +252,7 @@ int Arg_comparator::compare_string() if ((res2= (*b)->val_str(&owner->tmp_value2))) { owner->null_value= 0; - return sortcmp(res1,res2,owner->cmp_charset); + return sortcmp(res1,res2,owner->cmp_collation.collation); } } owner->null_value= 1; @@ -329,7 +266,7 @@ int Arg_comparator::compare_e_string() res2= (*b)->val_str(&owner->tmp_value2); if (!res1 || !res2) return test(res1 == res2); - return test(sortcmp(res1, res2, owner->cmp_charset) == 0); + return test(sortcmp(res1, res2, owner->cmp_collation.collation) == 0); } @@ -558,7 +495,7 @@ longlong Item_func_strcmp::val_int() null_value=1; return 0; } - int value= sortcmp(a,b,cmp_charset); + int value= sortcmp(a,b,cmp_collation.collation); null_value=0; return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1); } @@ -750,8 +687,7 @@ Item_func_ifnull::fix_length_and_dec() args[1]->result_type())) != REAL_RESULT) decimals= 0; - if (set_charset(args[0]->charset(),args[0]->derivation(), - args[1]->charset(),args[1]->derivation())) + if (collation.set(args[0]->collation,args[1]->collation)) my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); } @@ -828,8 +764,7 @@ Item_func_if::fix_length_and_dec() else if (arg1_type == STRING_RESULT || arg2_type == STRING_RESULT) { cached_result_type = STRING_RESULT; - if (set_charset(args[1]->charset(), args[1]->derivation(), - args[2]->charset(), args[2]->derivation())) + if (collation.set(args[1]->collation, args[2]->collation)) { my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); return; @@ -1944,7 +1879,7 @@ longlong Item_func_like::val_int() null_value=0; if (canDoTurboBM) return turboBM_matches(res->ptr(), res->length()) ? 1 : 0; - return my_wildcmp(cmp_charset, + return my_wildcmp(cmp_collation.collation, res->ptr(),res->ptr()+res->length(), res2->ptr(),res2->ptr()+res2->length(), escape,wild_one,wild_many) ? 0 : 1; @@ -2148,7 +2083,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff) *splm1 = pattern_len; - if (cmp_charset == &my_charset_bin) + if (cmp_collation.collation == &my_charset_bin) { int i; for (i = pattern_len - 2; i >= 0; i--) @@ -2251,7 +2186,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts() for (i = bmBc; i < end; i++) *i = pattern_len; - if (cmp_charset == &my_charset_bin) + if (cmp_collation.collation == &my_charset_bin) { for (j = 0; j < plm1; j++) bmBc[(uint) (uchar) pattern[j]] = plm1 - j; @@ -2282,7 +2217,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const const int tlmpl= text_len - pattern_len; /* Searching */ - if (cmp_charset == &my_charset_bin) + if (cmp_collation.collation == &my_charset_bin) { while (j <= tlmpl) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index b38248d87e149ac188c3fec822e9ae2fea3033f6..70e477402d989805aca42ba563fc44dfe4bc8d67 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -112,25 +112,25 @@ class Item_bool_func2 :public Item_int_func protected: Arg_comparator cmp; String tmp_value1,tmp_value2; - CHARSET_INFO *cmp_charset; + DTCollation cmp_collation; public: Item_bool_func2(Item *a,Item *b): - Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), cmp_charset(0) {} + 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 set_cmp_func() { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1); } - bool set_cmp_charset(CHARSET_INFO *cs1, Derivation co1, - CHARSET_INFO *cs2, Derivation co2); optimize_type select_optimize() const { return OPTIMIZE_OP; } virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; } bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; } void print(String *str) { Item_func::print_op(str); } bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } - virtual bool binary() const { return test(cmp_charset->state & MY_CS_BINSORT); } + virtual bool binary() const + { return test(cmp_collation.collation->state & MY_CS_BINSORT); } static Item_bool_func2* eq_creator(Item *a, Item *b); static Item_bool_func2* ne_creator(Item *a, Item *b); diff --git a/sql/item_func.cc b/sql/item_func.cc index 170260c6819a42859138555a8f71644eb11bed15..d0362ea9369d428881533843b6a63a93df3debe8 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -867,9 +867,8 @@ void Item_func_min_max::fix_length_and_dec() maybe_null=0; cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); if (i==0) - set_charset(*args[i]); - else if (set_charset(charset(), derivation(), - args[i]->charset(), args[i]->derivation())) + collation.set(args[0]->collation); + if (collation.aggregate(args[i]->collation)) { my_coll_agg_error(collation, args[i]->collation, func_name()); break; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 23df49c81bec9f412bbe068e424e874a533338f3..1c7704567930a65e6f86ea96560f706c35952f0d 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -324,12 +324,11 @@ void Item_func_concat::fix_length_and_dec() bool first_coll= 1; max_length=0; - set_charset(*args[0]); + collation.set(args[0]->collation); for (uint i=0 ; i < arg_count ; i++) { max_length+=args[i]->max_length; - if (set_charset(charset(), derivation(), - args[i]->charset(), args[i]->derivation())) + if (collation.aggregate(args[i]->collation)) { my_coll_agg_error(collation, args[i]->collation, func_name()); break; @@ -627,13 +626,12 @@ void Item_func_concat_ws::split_sum_func(Item **ref_pointer_array, void Item_func_concat_ws::fix_length_and_dec() { - set_charset(*separator); + collation.set(separator->collation); max_length=separator->max_length*(arg_count-1); for (uint i=0 ; i < arg_count ; i++) { max_length+=args[i]->max_length; - if (set_charset(charset(), derivation(), - args[i]->charset(), args[i]->derivation())) + if (collation.aggregate(args[i]->collation)) { my_coll_agg_error(collation, args[i]->collation, func_name()); break; @@ -828,12 +826,11 @@ void Item_func_replace::fix_length_and_dec() max_length=MAX_BLOB_WIDTH; maybe_null=1; } - set_charset(*args[0]); + collation.set(args[0]->collation); for (i=1; i<3; i++) { - if (set_charset(charset(), derivation(), - args[i]->charset(), args[i]->derivation())) + if (collation.aggregate(args[i]->collation)) { my_coll_agg_error(collation, args[i]->collation, func_name()); break; @@ -875,10 +872,10 @@ null: void Item_func_insert::fix_length_and_dec() { - if (set_charset(args[0]->charset(), args[0]->derivation(), - args[3]->charset(), args[3]->derivation())) + if (collation.set(args[0]->collation, args[3]->collation)) { my_coll_agg_error(args[0]->collation, args[3]->collation, func_name()); + return; } max_length=args[0]->max_length+args[3]->max_length; if (max_length > MAX_BLOB_WIDTH) @@ -1316,13 +1313,12 @@ void Item_func_trim::fix_length_and_dec() max_length= args[0]->max_length; if (arg_count == 1) { - set_charset(*args[0]); + collation.set(args[0]->collation); remove.set_charset(charset()); remove.set_ascii(" ",1); } else - if (set_charset(args[1]->charset(), args[1]->derivation(), - args[0]->charset(), args[0]->derivation())) + if (collation.set(args[1]->collation, args[0]->collation)) { my_coll_agg_error(args[1]->collation, args[0]->collation, func_name()); } @@ -1668,11 +1664,10 @@ void Item_func_elt::fix_length_and_dec() set_if_bigger(max_length,args[i]->max_length); set_if_bigger(decimals,args[i]->decimals); if (i == 0) - set_charset(*args[0]); + collation.set(args[0]->collation); else { - if (set_charset(charset(), derivation(), - args[i]->charset(), args[i]->derivation())) + if (collation.aggregate(args[i]->collation)) { my_coll_agg_error(collation, args[i]->collation, func_name()); break; @@ -1770,12 +1765,11 @@ void Item_func_make_set::split_sum_func(Item **ref_pointer_array, void Item_func_make_set::fix_length_and_dec() { max_length=arg_count-1; - set_charset(*args[0]); + collation.set(args[0]->collation); for (uint i=0 ; i < arg_count ; i++) { max_length+=args[i]->max_length; - if (set_charset(charset(), derivation(), - args[i]->charset(), args[i]->derivation())) + if (collation.aggregate(args[i]->collation)) { my_coll_agg_error(collation, args[i]->collation, func_name()); break; @@ -1963,10 +1957,10 @@ err: void Item_func_rpad::fix_length_and_dec() { - if (set_charset(args[0]->charset(), args[0]->derivation(), - args[2]->charset(), args[2]->derivation())) + if (collation.set(args[0]->collation, args[2]->collation)) { my_coll_agg_error(args[0]->collation, args[2]->collation, func_name()); + return; } if (args[1]->const_item()) @@ -2029,10 +2023,10 @@ String *Item_func_rpad::val_str(String *str) void Item_func_lpad::fix_length_and_dec() { - if (set_charset(args[0]->charset(), args[0]->derivation(), - args[2]->charset(), args[2]->derivation())) + if (collation.set(args[0]->collation, args[2]->collation)) { my_coll_agg_error(args[0]->collation, args[2]->collation, func_name()); + return; } if (args[1]->const_item()) @@ -2152,9 +2146,8 @@ String *Item_func_conv_charset::val_str(String *str) void Item_func_conv_charset::fix_length_and_dec() { - set_charset(conv_charset); - max_length = args[0]->max_length*conv_charset->mbmaxlen; set_charset(conv_charset, DERIVATION_IMPLICIT); + max_length = args[0]->max_length*conv_charset->mbmaxlen; } @@ -2449,11 +2442,10 @@ void Item_func_export_set::fix_length_and_dec() uint sep_length=(arg_count > 3 ? args[3]->max_length : 1); max_length=length*64+sep_length*63; - set_charset(*args[1]); + collation.set(args[1]->collation); for (i=2 ; i < 4 && i < arg_count ; i++) { - if (set_charset(charset(), derivation(), - args[i]->charset(), args[i]->derivation())) + if (collation.aggregate(args[i]->collation)) { my_coll_agg_error(collation, args[i]->collation, func_name()); break;