diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/sql/item.cc b/sql/item.cc index 6566f3ca533..05d4cc86f7a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5998,9 +5998,64 @@ Item *Item_int_with_ref::clone_item(THD *thd) } -Item_num *Item_uint::neg(THD *thd) +Item *Item::neg(THD *thd) { - Item_decimal *item= new (thd->mem_root) Item_decimal(thd, value, 1); + return new (thd->mem_root) Item_func_neg(thd, this); +} + +Item *Item_int::neg(THD *thd) +{ + /* + The following if should never be true with code generated by + our parser as LONGLONG_MIN values will be stored as decimal. + The code is here in case someone generates an int from inside + MariaDB + */ + if (unlikely(value == LONGLONG_MIN)) + { + /* Precision for int not big enough; Convert constant to decimal */ + Item_decimal *item= new (thd->mem_root) Item_decimal(thd, value, 0); + return item ? item->neg(thd) : item; + } + if (value > 0) + max_length++; + else if (value < 0 && max_length) + max_length--; + value= -value; + name= 0; + return this; +} + +Item *Item_decimal::neg(THD *thd) +{ + my_decimal_neg(&decimal_value); + unsigned_flag= 0; + name= 0; + max_length= my_decimal_precision_to_length_no_truncation( + decimal_value.intg + decimals, decimals, unsigned_flag); + return this; +} + +Item *Item_float::neg(THD *thd) +{ + if (value > 0) + max_length++; + else if (value < 0 && max_length) + max_length--; + value= -value; + name= presentation= 0 ; + return this; +} + +Item *Item_uint::neg(THD *thd) +{ + Item_decimal *item; + if (((ulonglong)value) <= LONGLONG_MAX) + return new (thd->mem_root) Item_int(thd, -value, max_length+1); + if (value == LONGLONG_MIN) + return new (thd->mem_root) Item_int(thd, value, max_length+1); + if (!(item= new (thd->mem_root) Item_decimal(thd, value, 1))) + return 0; return item->neg(thd); } |