← Back to team overview

maria-developers team mailing list archive

Please review MDEV-12199 Split Item_func_{abs|neg|int_val}::fix_length_and_dec() into methods in Type_handler

 

Hello Alexey,

Please review a patch for MDEV-12199.

Thanks!
diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result
index 07945d6..0b5741f 100644
--- a/mysql-test/r/gis.result
+++ b/mysql-test/r/gis.result
@@ -3720,5 +3720,34 @@ DROP TABLE t1;
 SELECT ROUND(POINT(1,1));
 ERROR HY000: Illegal parameter data type geometry for operation 'round'
 #
+# Split
+#
+CREATE TABLE t1 (a GEOMETRY);
+SELECT -a FROM t1;
+ERROR HY000: Illegal parameter data type geometry for operation '-'
+SELECT ABS(a) FROM t1;
+ERROR HY000: Illegal parameter data type geometry for operation 'abs'
+SELECT CEILING(a) FROM t1;
+ERROR HY000: Illegal parameter data type geometry for operation 'ceiling'
+SELECT FLOOR(a) FROM t1;
+ERROR HY000: Illegal parameter data type geometry for operation 'floor'
+SELECT -COALESCE(a) FROM t1;
+ERROR HY000: Illegal parameter data type geometry for operation '-'
+SELECT ABS(COALESCE(a)) FROM t1;
+ERROR HY000: Illegal parameter data type geometry for operation 'abs'
+SELECT CEILING(COALESCE(a)) FROM t1;
+ERROR HY000: Illegal parameter data type geometry for operation 'ceiling'
+SELECT FLOOR(COALESCE(a)) FROM t1;
+ERROR HY000: Illegal parameter data type geometry for operation 'floor'
+DROP TABLE t1;
+SELECT -POINT(1,1);
+ERROR HY000: Illegal parameter data type geometry for operation '-'
+SELECT ABS(POINT(1,1));
+ERROR HY000: Illegal parameter data type geometry for operation 'abs'
+SELECT CEILING(POINT(1,1));
+ERROR HY000: Illegal parameter data type geometry for operation 'ceiling'
+SELECT FLOOR(POINT(1,1));
+ERROR HY000: Illegal parameter data type geometry for operation 'floor'
+#
 # End of 10.3 tests
 #
diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test
index 7d6c3ba..d32d646 100644
--- a/mysql-test/t/gis.test
+++ b/mysql-test/t/gis.test
@@ -1880,6 +1880,40 @@ DROP TABLE t1;
 --error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
 SELECT ROUND(POINT(1,1));
 
+
+--echo #
+--echo # Split
+--echo #
+CREATE TABLE t1 (a GEOMETRY);
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT -a FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT ABS(a) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CEILING(a) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT FLOOR(a) FROM t1;
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT -COALESCE(a) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT ABS(COALESCE(a)) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CEILING(COALESCE(a)) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT FLOOR(COALESCE(a)) FROM t1;
+DROP TABLE t1;
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT -POINT(1,1);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT ABS(POINT(1,1));
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CEILING(POINT(1,1));
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT FLOOR(POINT(1,1));
+
 --echo #
 --echo # End of 10.3 tests
 --echo #
diff --git a/sql/field.h b/sql/field.h
index 7755641..7d59373 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -851,6 +851,10 @@ class Field: public Value_source
   virtual bool str_needs_quotes() { return FALSE; }
   virtual Item_result result_type () const=0;
   virtual Item_result cmp_type () const { return result_type(); }
+  virtual const Type_handler *cast_to_int_type_handler() const
+  {
+    return Type_handler::get_handler_by_field_type(type());
+  }
   static bool type_can_have_key_part(enum_field_types);
   static enum_field_types field_type_merge(enum_field_types, enum_field_types);
   virtual bool eq(Field *field)
@@ -3461,6 +3465,10 @@ class Field_enum :public Field_str {
   Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
   enum_field_types type() const { return MYSQL_TYPE_STRING; }
   enum Item_result cmp_type () const { return INT_RESULT; }
+  const Type_handler *cast_to_int_type_handler() const
+  {
+    return &type_handler_longlong;
+  }
   enum ha_base_keytype key_type() const;
   Copy_func *get_copy_func(const Field *from) const
   {
diff --git a/sql/item.h b/sql/item.h
index 3908fe2..96ae714 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -699,6 +699,10 @@ class Item: public Value_source,
   {
     return Type_handler::get_handler_by_field_type(field_type());
   }
+  virtual const Type_handler *cast_to_int_type_handler() const
+  {
+    return type_handler();
+  }
   /* result_type() of an item specifies how the value should be returned */
   virtual Item_result result_type() const
   {
@@ -709,7 +713,6 @@ class Item: public Value_source,
   {
     return type_handler()->cmp_type();
   }
-  virtual Item_result cast_to_int_type() const { return cmp_type(); }
   enum_field_types string_field_type() const
   {
     return Type_handler::string_type_handler(max_length)->field_type();
@@ -2388,9 +2391,9 @@ class Item_field :public Item_ident
   {
     return field->result_type();
   }
-  Item_result cast_to_int_type() const
+  const Type_handler *cast_to_int_type_handler() const
   {
-    return field->cmp_type();
+    return field->cast_to_int_type_handler();
   }
   enum_field_types field_type() const
   {
@@ -3408,7 +3411,7 @@ class Item_hex_constant: public Item_basic_constant
   bool eq(const Item *item, bool binary_cmp) const
   {
     return item->basic_const_item() && item->type() == type() &&
-           item->cast_to_int_type() == cast_to_int_type() &&
+           item->cast_to_int_type_handler() == cast_to_int_type_handler() &&
            str_value.bin_eq(&((Item_hex_constant*)item)->str_value);
   }
   String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
@@ -3450,7 +3453,10 @@ class Item_hex_hybrid: public Item_hex_constant
     field->set_notnull();
     return field->store_hex_hybrid(str_value.ptr(), str_value.length());
   }
-  enum Item_result cast_to_int_type() const { return INT_RESULT; }
+  const Type_handler *cast_to_int_type_handler() const
+  {
+    return &type_handler_longlong;
+  }
   void print(String *str, enum_query_type query_type);
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_hex_hybrid>(thd, mem_root, this); }
@@ -3492,7 +3498,6 @@ class Item_hex_string: public Item_hex_constant
     return field->store(str_value.ptr(), str_value.length(), 
                         collation.collation);
   }
-  enum Item_result cast_to_int_type() const { return STRING_RESULT; }
   void print(String *str, enum_query_type query_type);
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_hex_string>(thd, mem_root, this); }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index cd5b94f..3a9f61e 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -723,8 +723,8 @@ void Item_num_op::fix_length_and_dec(void)
   DBUG_ENTER("Item_num_op::fix_length_and_dec");
   DBUG_PRINT("info", ("name %s", func_name()));
   DBUG_ASSERT(arg_count == 2);
-  Item_result r0= args[0]->cast_to_int_type();
-  Item_result r1= args[1]->cast_to_int_type();
+  Item_result r0= args[0]->cast_to_int_type_handler()->cmp_type();
+  Item_result r1= args[1]->cast_to_int_type_handler()->cmp_type();
 
   if (r0 == REAL_RESULT || r1 == REAL_RESULT ||
       r0 == STRING_RESULT || r1 ==STRING_RESULT)
@@ -758,47 +758,6 @@ void Item_num_op::fix_length_and_dec(void)
 }
 
 
-/**
-  Set result type for a numeric function of one argument
-  (can be also used by a numeric function of many arguments, if the result
-  type depends only on the first argument)
-*/
-
-void Item_func_num1::fix_length_and_dec()
-{
-  DBUG_ENTER("Item_func_num1::fix_length_and_dec");
-  DBUG_PRINT("info", ("name %s", func_name()));
-  // Note, cast_to_int_type() can return TIME_RESULT
-  switch (args[0]->cast_to_int_type()) {
-  case INT_RESULT:
-    set_handler_by_result_type(INT_RESULT);
-    max_length= args[0]->max_length;
-    unsigned_flag= args[0]->unsigned_flag;
-    break;
-  case STRING_RESULT:
-  case REAL_RESULT:
-    set_handler_by_result_type(REAL_RESULT);
-    decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC
-    max_length= float_length(decimals);
-    break;
-  case TIME_RESULT:
-  case DECIMAL_RESULT:
-    set_handler_by_result_type(DECIMAL_RESULT);
-    decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC
-    max_length= args[0]->max_length;
-    break;
-  case ROW_RESULT:
-    DBUG_ASSERT(0);
-  }
-  DBUG_PRINT("info", ("Type: %s",
-                      (result_type() == REAL_RESULT ? "REAL_RESULT" :
-                       result_type() == DECIMAL_RESULT ? "DECIMAL_RESULT" :
-                       result_type() == INT_RESULT ? "INT_RESULT" :
-                       "--ILLEGAL!!!--")));
-  DBUG_VOID_RETURN;
-}
-
-
 String *Item_func_hybrid_field_type::val_str_from_decimal_op(String *str)
 {
   my_decimal decimal_value, *val;
@@ -1025,7 +984,7 @@ longlong Item::val_int_from_str(int *error)
 
 longlong Item::val_int_signed_typecast()
 {
-  if (cast_to_int_type() != STRING_RESULT)
+  if (cast_to_int_type_handler()->cmp_type() != STRING_RESULT)
     return val_int();
 
   int error;
@@ -1047,7 +1006,7 @@ void Item_func_unsigned::print(String *str, enum_query_type query_type)
 
 longlong Item::val_int_unsigned_typecast()
 {
-  if (cast_to_int_type() == DECIMAL_RESULT)
+  if (cast_to_int_type_handler()->cmp_type() == DECIMAL_RESULT)
   {
     longlong value;
     my_decimal tmp, *dec= val_decimal(&tmp);
@@ -1057,7 +1016,7 @@ longlong Item::val_int_unsigned_typecast()
       value= 0;
     return value;
   }
-  else if (cast_to_int_type() != STRING_RESULT)
+  else if (cast_to_int_type_handler()->cmp_type() != STRING_RESULT)
   {
     longlong value= val_int();
     if (!null_value && unsigned_flag == 0 && value < 0)
@@ -1897,11 +1856,9 @@ my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value)
 }
 
 
-void Item_func_neg::fix_length_and_dec()
+void Item_func_neg::fix_length_and_dec_int()
 {
-  DBUG_ENTER("Item_func_neg::fix_length_and_dec");
-  Item_func_num1::fix_length_and_dec();
-  /* 1 add because sign can appear */
+  set_handler(&type_handler_longlong);
   max_length= args[0]->max_length + 1;
 
   /*
@@ -1910,7 +1867,7 @@ void Item_func_neg::fix_length_and_dec()
     Use val() to get value as arg_type doesn't mean that item is
     Item_int or Item_float due to existence of Item_param.
   */
-  if (Item_func_neg::result_type() == INT_RESULT && args[0]->const_item())
+  if (args[0]->const_item())
   {
     longlong val= args[0]->val_int();
     if ((ulonglong) val >= (ulonglong) LONGLONG_MIN &&
@@ -1925,7 +1882,34 @@ void Item_func_neg::fix_length_and_dec()
       DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
     }
   }
-  unsigned_flag= 0;
+  unsigned_flag= false;
+}
+
+
+void Item_func_neg::fix_length_and_dec_double()
+{
+  set_handler(&type_handler_double);
+  decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC
+  max_length= args[0]->max_length + 1;
+  unsigned_flag= false;
+}
+
+
+void Item_func_neg::fix_length_and_dec_decimal()
+{
+  set_handler(&type_handler_newdecimal);
+  decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC
+  max_length= args[0]->max_length + 1;
+  unsigned_flag= false;
+}
+
+
+void Item_func_neg::fix_length_and_dec()
+{
+  DBUG_ENTER("Item_func_neg::fix_length_and_dec");
+  DBUG_PRINT("info", ("name %s", func_name()));
+  args[0]->cast_to_int_type_handler()->Item_func_neg_fix_length_and_dec(this);
+  DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr()));
   DBUG_VOID_RETURN;
 }
 
@@ -1966,13 +1950,42 @@ my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value)
 }
 
 
-void Item_func_abs::fix_length_and_dec()
+void Item_func_abs::fix_length_and_dec_int()
+{
+  set_handler(&type_handler_longlong);
+  max_length= args[0]->max_length;
+  unsigned_flag= args[0]->unsigned_flag;
+}
+
+
+void Item_func_abs::fix_length_and_dec_double()
+{
+  set_handler(&type_handler_double);
+  decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC
+  max_length= float_length(decimals);
+  unsigned_flag= args[0]->unsigned_flag;
+}
+
+
+void Item_func_abs::fix_length_and_dec_decimal()
 {
-  Item_func_num1::fix_length_and_dec();
+  set_handler(&type_handler_newdecimal);
+  decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC
+  max_length= args[0]->max_length;
   unsigned_flag= args[0]->unsigned_flag;
 }
 
 
+void Item_func_abs::fix_length_and_dec()
+{
+  DBUG_ENTER("Item_func_abs::fix_length_and_dec");
+  DBUG_PRINT("info", ("name %s", func_name()));
+  args[0]->cast_to_int_type_handler()->Item_func_abs_fix_length_and_dec(this);
+  DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr()));
+  DBUG_VOID_RETURN;
+}
+
+
 /** Gateway to natural LOG function. */
 double Item_func_ln::val_real()
 {
@@ -2201,11 +2214,8 @@ longlong Item_func_bit_neg::val_int()
 
 // Conversion functions
 
-void Item_func_int_val::fix_length_and_dec()
+void Item_func_int_val::fix_length_and_dec_int_or_decimal()
 {
-  DBUG_ENTER("Item_func_int_val::fix_length_and_dec");
-  DBUG_PRINT("info", ("name %s", func_name()));
-
   ulonglong tmp_max_length= (ulonglong ) args[0]->max_length - 
     (args[0]->decimals ? args[0]->decimals + 1 : 0) + 2;
   max_length= tmp_max_length > (ulonglong) 4294967295U ?
@@ -2214,41 +2224,37 @@ void Item_func_int_val::fix_length_and_dec()
   set_if_smaller(max_length,tmp);
   decimals= 0;
 
-  // Note, cast_to_int_type() can return TIME_RESULT
-  switch (args[0]->cast_to_int_type())
+  /*
+    -2 because in most high position can't be used any digit for longlong
+    and one position for increasing value during operation
+  */
+  if (args[0]->max_length - args[0]->decimals >= DECIMAL_LONGLONG_DIGITS - 2)
   {
-  case STRING_RESULT:
-  case REAL_RESULT:
-    set_handler_by_result_type(REAL_RESULT);
-    max_length= float_length(decimals);
-    break;
-  case INT_RESULT:
-  case TIME_RESULT:
-  case DECIMAL_RESULT:
-    /*
-      -2 because in most high position can't be used any digit for longlong
-      and one position for increasing value during operation
-    */
-    if ((args[0]->max_length - args[0]->decimals) >=
-        (DECIMAL_LONGLONG_DIGITS - 2))
-    {
-      set_handler_by_result_type(DECIMAL_RESULT);
-    }
-    else
-    {
-      unsigned_flag= args[0]->unsigned_flag;
-      set_handler_by_result_type(INT_RESULT);
-    }
-    break;
-  case ROW_RESULT:
-    DBUG_ASSERT(0);
+    set_handler(&type_handler_newdecimal);
   }
-  DBUG_PRINT("info", ("Type: %s",
-                      (result_type() == REAL_RESULT ? "REAL_RESULT" :
-                       result_type() == DECIMAL_RESULT ? "DECIMAL_RESULT" :
-                       result_type() == INT_RESULT ? "INT_RESULT" :
-                       "--ILLEGAL!!!--")));
+  else
+  {
+    unsigned_flag= args[0]->unsigned_flag;
+    set_handler(&type_handler_longlong);
+  }
+}
+
+
+void Item_func_int_val::fix_length_and_dec_double()
+{
+  set_handler(&type_handler_double);
+  max_length= float_length(0);
+  decimals= 0;
+}
 
+
+void Item_func_int_val::fix_length_and_dec()
+{
+  DBUG_ENTER("Item_func_int_val::fix_length_and_dec");
+  DBUG_PRINT("info", ("name %s", func_name()));
+  args[0]->cast_to_int_type_handler()->
+    Item_func_int_val_fix_length_and_dec(this);
+  DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr()));
   DBUG_VOID_RETURN;
 }
 
diff --git a/sql/item_func.h b/sql/item_func.h
index f9c079a..8b53631 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -678,7 +678,8 @@ class Item_func_num1: public Item_func_numhybrid
 public:
   Item_func_num1(THD *thd, Item *a): Item_func_numhybrid(thd, a) {}
   Item_func_num1(THD *thd, Item *a, Item *b): Item_func_numhybrid(thd, a, b) {}
-  void fix_length_and_dec();
+  bool check_partition_func_processor(void *int_arg) { return FALSE; }
+  bool check_vcol_func_processor(void *arg) { return FALSE; }
 };
 
 
@@ -974,10 +975,11 @@ class Item_func_neg :public Item_func_num1
     str->append(func_name());
     args[0]->print_parenthesised(str, query_type, precedence());
   }
+  void fix_length_and_dec_int();
+  void fix_length_and_dec_double();
+  void fix_length_and_dec_decimal();
   void fix_length_and_dec();
   uint decimal_precision() const { return args[0]->decimal_precision(); }
-  bool check_partition_func_processor(void *int_arg) {return FALSE;}
-  bool check_vcol_func_processor(void *arg) { return FALSE;}
   bool need_parentheses_in_default() { return true; }
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_func_neg>(thd, mem_root, this); }
@@ -992,9 +994,10 @@ class Item_func_abs :public Item_func_num1
   longlong int_op();
   my_decimal *decimal_op(my_decimal *);
   const char *func_name() const { return "abs"; }
+  void fix_length_and_dec_int();
+  void fix_length_and_dec_double();
+  void fix_length_and_dec_decimal();
   void fix_length_and_dec();
-  bool check_partition_func_processor(void *int_arg) {return FALSE;}
-  bool check_vcol_func_processor(void *arg) { return FALSE;}
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_func_abs>(thd, mem_root, this); }
 };
@@ -1167,6 +1170,8 @@ class Item_func_int_val :public Item_func_num1
 {
 public:
   Item_func_int_val(THD *thd, Item *a): Item_func_num1(thd, a) {}
+  void fix_length_and_dec_double();
+  void fix_length_and_dec_int_or_decimal();
   void fix_length_and_dec();
 };
 
@@ -1179,8 +1184,6 @@ class Item_func_ceiling :public Item_func_int_val
   longlong int_op();
   double real_op();
   my_decimal *decimal_op(my_decimal *);
-  bool check_partition_func_processor(void *int_arg) {return FALSE;}
-  bool check_vcol_func_processor(void *arg) { return FALSE;}
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_func_ceiling>(thd, mem_root, this); }
 };
@@ -1194,8 +1197,6 @@ class Item_func_floor :public Item_func_int_val
   longlong int_op();
   double real_op();
   my_decimal *decimal_op(my_decimal *);
-  bool check_partition_func_processor(void *int_arg) {return FALSE;}
-  bool check_vcol_func_processor(void *arg) { return FALSE;}
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_func_floor>(thd, mem_root, this); }
 };
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 07755d6..d5e972c 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1295,7 +1295,7 @@ void Item_sum_sum::fix_length_and_dec()
   DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
   maybe_null=null_value=1;
   decimals= args[0]->decimals;
-  switch (args[0]->cast_to_int_type()) {
+  switch (args[0]->cast_to_int_type_handler()->cmp_type()) {
   case REAL_RESULT:
   case STRING_RESULT:
     set_handler_by_field_type(MYSQL_TYPE_DOUBLE);
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 6de1af2..4d4694d 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -39,9 +39,6 @@ static Type_handler_tiny_blob   type_handler_tiny_blob;
 static Type_handler_medium_blob type_handler_medium_blob;
 static Type_handler_long_blob   type_handler_long_blob;
 static Type_handler_blob        type_handler_blob;
-#ifdef HAVE_SPATIAL
-static Type_handler_geometry    type_handler_geometry;
-#endif
 static Type_handler_enum        type_handler_enum;
 static Type_handler_set         type_handler_set;
 
@@ -55,6 +52,10 @@ Type_handler_newdecimal  type_handler_newdecimal;
 Type_handler_datetime    type_handler_datetime;
 Type_handler_bit         type_handler_bit;
 
+#ifdef HAVE_SPATIAL
+Type_handler_geometry    type_handler_geometry;
+#endif
+
 
 Type_aggregator type_aggregator_for_result;
 Type_aggregator type_aggregator_for_comparison;
@@ -2215,3 +2216,183 @@ bool Type_handler_geometry::
 #endif
 
 /***************************************************************************/
+
+bool Type_handler_row::
+       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+  DBUG_ASSERT(0);
+  return false;
+}
+
+
+bool Type_handler_int_result::
+       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+  item->fix_length_and_dec_int_or_decimal();
+  return false;
+}
+
+
+bool Type_handler_real_result::
+       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+  item->fix_length_and_dec_double();
+  return false;
+}
+
+
+bool Type_handler_decimal_result::
+       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+  item->fix_length_and_dec_int_or_decimal();
+  return false;
+}
+
+
+bool Type_handler_temporal_result::
+       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+  item->fix_length_and_dec_int_or_decimal();
+  return false;
+}
+
+
+bool Type_handler_string_result::
+       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+  item->fix_length_and_dec_double();
+  return false;
+}
+
+
+#ifdef HAVE_SPATIAL
+bool Type_handler_geometry::
+       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+  my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+           type_handler_geometry.name().ptr(), item->func_name());
+  return true;
+}
+#endif
+
+/***************************************************************************/
+
+bool Type_handler_row::
+       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+  DBUG_ASSERT(0);
+  return false;
+}
+
+
+bool Type_handler_int_result::
+       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+  item->fix_length_and_dec_int();
+  return false;
+}
+
+
+bool Type_handler_real_result::
+       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+  item->fix_length_and_dec_double();
+  return false;
+}
+
+
+bool Type_handler_decimal_result::
+       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+  item->fix_length_and_dec_decimal();
+  return false;
+}
+
+
+bool Type_handler_temporal_result::
+       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+  item->fix_length_and_dec_decimal();
+  return false;
+}
+
+
+bool Type_handler_string_result::
+       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+  item->fix_length_and_dec_double();
+  return false;
+}
+
+
+#ifdef HAVE_SPATIAL
+bool Type_handler_geometry::
+       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+  my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+           type_handler_geometry.name().ptr(), item->func_name());
+  return true;
+}
+#endif
+
+/***************************************************************************/
+
+bool Type_handler_row::
+       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+  DBUG_ASSERT(0);
+  return false;
+}
+
+
+bool Type_handler_int_result::
+       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+  item->fix_length_and_dec_int();
+  return false;
+}
+
+
+bool Type_handler_real_result::
+       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+  item->fix_length_and_dec_double();
+  return false;
+}
+
+
+bool Type_handler_decimal_result::
+       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+  item->fix_length_and_dec_decimal();
+  return false;
+}
+
+
+bool Type_handler_temporal_result::
+       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+  item->fix_length_and_dec_decimal();
+  return false;
+}
+
+
+bool Type_handler_string_result::
+       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+  item->fix_length_and_dec_double();
+  return false;
+}
+
+
+#ifdef HAVE_SPATIAL
+bool Type_handler_geometry::
+       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+  my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+           type_handler_geometry.name().ptr(), item->func_name());
+  return true;
+}
+#endif
+
+/***************************************************************************/
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 45ffef5..bc8b170 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -36,6 +36,9 @@ class Item_bool_func2;
 class Item_func_between;
 class Item_func_in;
 class Item_func_round;
+class Item_func_int_val;
+class Item_func_abs;
+class Item_func_neg;
 class cmp_item;
 class in_vector;
 class Type_std_attributes;
@@ -447,6 +450,15 @@ class Type_handler
 
   virtual bool
   Item_func_round_fix_length_and_dec(Item_func_round *round) const= 0;
+
+  virtual bool
+  Item_func_int_val_fix_length_and_dec(Item_func_int_val *func) const= 0;
+
+  virtual bool
+  Item_func_abs_fix_length_and_dec(Item_func_abs *func) const= 0;
+
+  virtual bool
+  Item_func_neg_fix_length_and_dec(Item_func_neg *func) const= 0;
 };
 
 
@@ -599,6 +611,9 @@ class Type_handler_row: public Type_handler
   bool Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                     Item_func_in *) const;
   bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
+  bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
+  bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
+  bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
 };
 
 
@@ -668,6 +683,9 @@ class Type_handler_real_result: public Type_handler_numeric
                                                     Item_func_in *) const;
 
   bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
+  bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
+  bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
+  bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
 };
 
 
@@ -711,6 +729,9 @@ class Type_handler_decimal_result: public Type_handler_numeric
   bool Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                     Item_func_in *) const;
   bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
+  bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
+  bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
+  bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
 };
 
 
@@ -753,6 +774,9 @@ class Type_handler_int_result: public Type_handler_numeric
   bool Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                     Item_func_in *) const;
   bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
+  bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
+  bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
+  bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
 };
 
 
@@ -799,6 +823,9 @@ class Type_handler_temporal_result: public Type_handler
   bool Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                     Item_func_in *) const;
   bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
+  bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
+  bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
+  bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
 };
 
 
@@ -859,6 +886,9 @@ class Type_handler_string_result: public Type_handler
   bool Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                     Item_func_in *) const;
   bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
+  bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
+  bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
+  bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
 };
 
 
@@ -1274,7 +1304,12 @@ class Type_handler_geometry: public Type_handler_string_result
     return false;
   }
   bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
+  bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
+  bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
+  bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
 };
+
+extern Type_handler_geometry type_handler_geometry;
 #endif