From 23d03a1b1e486da353f20964a1b91068bec209c0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 27 Jun 2016 15:41:51 +0200 Subject: parse negative numbers into one item use Item->neg to convert generate negative Item_num's instead of Item_func_neg(Item_num). Based on the following commit: Author: Monty Date: Mon May 30 22:44:00 2016 +0300 Make negative number their own token The negation (-) operator will call Item->neg() one underlying numeric constants and remove itself (like the NOT() function does today for other NOT functions. This simplifies things - -1 is not anymore an expression but a basic_const_item - improves optimizer - DEFAULT -1 doesn't need special handling anymore - When we add DEFAULT expressions, -1 will be treated exactly like 1 - printing of items doesn't anymore put braces around all negative numbers Other things fixed: - Fixed that longlong converted to decimal's has a more appropriate size - Fixed that "-0.0" read into a decimal is interpreted as 0.0 --- sql/field.cc | 12 ++++++------ sql/item.cc | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- sql/item.h | 16 ++++++---------- sql/sql_yacc.yy | 2 +- 4 files changed, 70 insertions(+), 19 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 0e2bc724db0..f15e9979ff2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9769,12 +9769,6 @@ bool Column_definition::check(THD *thd) } } - if (length > MAX_FIELD_BLOBLENGTH) - { - my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, MAX_FIELD_BLOBLENGTH); - DBUG_RETURN(TRUE); - } - if (def) { /* @@ -10080,6 +10074,12 @@ bool Column_definition::check(THD *thd) field_name, max_field_charlength); /* purecov: inspected */ DBUG_RETURN(TRUE); } + else if (length > MAX_FIELD_BLOBLENGTH) + { + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, MAX_FIELD_BLOBLENGTH); + DBUG_RETURN(1); + } + if ((~allowed_type_modifier) & flags & conditional_type_modifiers) { my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name); 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); } diff --git a/sql/item.h b/sql/item.h index 67d683b15ff..22e44719706 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1846,6 +1846,8 @@ public: /* how much position should be reserved for Exists2In transformation */ virtual uint exists2in_reserved_items() { return 0; }; + virtual Item *neg(THD *thd); + /** Inform the item that it is located under a NOT, which is a top-level item. */ @@ -2261,7 +2263,6 @@ class Item_num: public Item_basic_constant { public: Item_num(THD *thd): Item_basic_constant(thd) { collation.set_numeric(); } - virtual Item_num *neg(THD *thd)= 0; Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); bool check_partition_func_processor(uchar *int_arg) { return FALSE;} bool check_vcol_func_processor(uchar *arg) { return FALSE;} @@ -2834,7 +2835,7 @@ public: bool basic_const_item() const { return 1; } Item *clone_item(THD *thd); virtual void print(String *str, enum_query_type query_type); - Item_num *neg(THD *thd) { value= -value; return this; } + Item *neg(THD *thd); uint decimal_precision() const { return (uint) (max_length - MY_TEST(value < 0)); } bool eq(const Item *item, bool binary_cmp) const @@ -2855,7 +2856,7 @@ public: String *val_str(String*); Item *clone_item(THD *thd); virtual void print(String *str, enum_query_type query_type); - Item_num *neg(THD *thd); + Item *neg(THD *thd); uint decimal_precision() const { return max_length; } }; @@ -2899,12 +2900,7 @@ public: bool basic_const_item() const { return 1; } Item *clone_item(THD *thd); virtual void print(String *str, enum_query_type query_type); - Item_num *neg(THD *thd) - { - my_decimal_neg(&decimal_value); - unsigned_flag= !decimal_value.sign(); - return this; - } + Item *neg(THD *thd); uint decimal_precision() const { return decimal_value.precision(); } bool eq(const Item *, bool binary_cmp) const; void set_decimal_value(my_decimal *value_par); @@ -2954,7 +2950,7 @@ public: my_decimal *val_decimal(my_decimal *); bool basic_const_item() const { return 1; } Item *clone_item(THD *thd); - Item_num *neg(THD *thd) { value= -value; return this; } + Item *neg(THD *thd); virtual void print(String *str, enum_query_type query_type); bool eq(const Item *item, bool binary_cmp) const { return real_eq(value, item); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7ab11716f93..c971373d31b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9461,7 +9461,7 @@ simple_expr: } | '-' simple_expr %prec NEG { - $$= new (thd->mem_root) Item_func_neg(thd, $2); + $$= $2->neg(thd); if ($$ == NULL) MYSQL_YYABORT; } -- cgit v1.2.1