diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 61 |
1 files changed, 30 insertions, 31 deletions
diff --git a/sql/item.cc b/sql/item.cc index 95a8272ac09..c15fd948b5a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -601,16 +601,8 @@ bool Item::eq(const Item *item, bool binary_cmp) const Item *Item::safe_charset_converter(CHARSET_INFO *tocs) { - /* - Allow conversion from and to "binary". - Don't allow automatic conversion to non-Unicode charsets, - as it potentially loses data. - */ - if (collation.collation != &my_charset_bin && - tocs != &my_charset_bin && - !(tocs->state & MY_CS_UNICODE)) - return NULL; // safe conversion is not possible - return new Item_func_conv_charset(this, tocs); + Item_func_conv_charset *conv= new Item_func_conv_charset(this, tocs, 1); + return conv->safe ? conv : NULL; } @@ -700,23 +692,15 @@ Item *Item_param::safe_charset_converter(CHARSET_INFO *tocs) { if (const_item()) { - Item_string *conv; uint cnv_errors; - char buf[MAX_FIELD_WIDTH]; - String tmp(buf, sizeof(buf), &my_charset_bin); - String cstr, *ostr= val_str(&tmp); - /* - As safe_charset_converter is not executed for - a parameter bound to NULL, ostr should never be 0. - */ - cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &cnv_errors); - if (cnv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(), - cstr.charset(), - collation.derivation))) - return NULL; - conv->str_value.copy(); - conv->str_value.mark_as_const(); - return conv; + String *ostr= val_str(&cnvstr); + cnvitem->str_value.copy(ostr->ptr(), ostr->length(), + ostr->charset(), tocs, &cnv_errors); + if (cnv_errors) + return NULL; + cnvitem->str_value.mark_as_const(); + cnvitem->max_length= cnvitem->str_value.numchars() * tocs->mbmaxlen; + return cnvitem; } return NULL; } @@ -2104,6 +2088,8 @@ Item_param::Item_param(unsigned pos_in_query_arg) : value is set. */ maybe_null= 1; + cnvitem= new Item_string("", 0, &my_charset_bin, DERIVATION_COERCIBLE); + cnvstr.set(cnvbuf, sizeof(cnvbuf), &my_charset_bin); } @@ -2473,7 +2459,7 @@ longlong Item_param::val_int() { switch (state) { case REAL_VALUE: - return (longlong) (value.real + (value.real > 0 ? 0.5 : -0.5)); + return (longlong) rint(value.real); case INT_VALUE: return value.integer; case DECIMAL_VALUE: @@ -5260,7 +5246,7 @@ Item_result item_cmp_type(Item_result a,Item_result b) void resolve_const_item(THD *thd, Item **ref, Item *comp_item) { Item *item= *ref; - Item *new_item; + Item *new_item= NULL; if (item->basic_const_item()) return; // Can't be better Item_result res_type=item_cmp_type(comp_item->result_type(), @@ -5293,7 +5279,16 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) break; } case ROW_RESULT: + if (item->type() == Item::ROW_ITEM && comp_item->type() == Item::ROW_ITEM) { + /* + Substitute constants only in Item_rows. Don't affect other Items + with ROW_RESULT (eg Item_singlerow_subselect). + + For such Items more optimal is to detect if it is constant and replace + it with Item_row. This would optimize queries like this: + SELECT * FROM t1 WHERE (a,b) = (SELECT a,b FROM t2 LIMIT 1); + */ Item_row *item_row= (Item_row*) item; Item_row *comp_item_row= (Item_row*) comp_item; uint col; @@ -5311,6 +5306,7 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) resolve_const_item(thd, item_row->addr(col), comp_item_row->el(col)); break; } + /* Fallthrough */ case REAL_RESULT: { // It must REAL_RESULT double result= item->val_real(); @@ -5445,7 +5441,7 @@ void Item_cache_real::store(Item *item) longlong Item_cache_real::val_int() { DBUG_ASSERT(fixed == 1); - return (longlong) (value+(value > 0 ? 0.5 : -0.5)); + return (longlong) rint(value); } @@ -5816,8 +5812,11 @@ bool Item_type_holder::join_types(THD *thd, Item *item) { int delta1= max_length_orig - decimals_orig; int delta2= item->max_length - item->decimals; - max_length= min(max(delta1, delta2) + decimals, - (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7); + if (fld_type == MYSQL_TYPE_DECIMAL) + max_length= max(delta1, delta2) + decimals; + else + max_length= min(max(delta1, delta2) + decimals, + (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7); } else max_length= (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7; |