diff --git a/sql/item_func.cc b/sql/item_func.cc
index cbd272f..363bdc5 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -830,240 +830,6 @@ void Item_func_num1::fix_length_and_dec()
 }
 
 
-String *Item_func_hybrid_field_type::val_str(String *str)
-{
-  DBUG_ASSERT(fixed == 1);
-  switch (Item_func_hybrid_field_type::cmp_type()) {
-  case DECIMAL_RESULT:
-  {
-    my_decimal decimal_value, *val;
-    if (!(val= decimal_op_with_null_check(&decimal_value)))
-      return 0;                                 // null is set
-    my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
-    str->set_charset(collation.collation);
-    my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
-    break;
-  }
-  case INT_RESULT:
-  {
-    longlong nr= int_op();
-    if (null_value)
-      return 0; /* purecov: inspected */
-    str->set_int(nr, unsigned_flag, collation.collation);
-    break;
-  }
-  case REAL_RESULT:
-  {
-    double nr= real_op();
-    if (null_value)
-      return 0; /* purecov: inspected */
-    str->set_real(nr, decimals, collation.collation);
-    break;
-  }
-  case TIME_RESULT:
-  {
-    MYSQL_TIME ltime;
-    if (date_op_with_null_check(&ltime) ||
-        (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
-      return (String *) 0;
-    ltime.time_type= mysql_type_to_time_type(field_type());
-    str->length(my_TIME_to_str(&ltime, const_cast<char*>(str->ptr()), decimals));
-    str->set_charset(&my_charset_bin);
-    DBUG_ASSERT(!null_value);
-    return str;
-  }
-  case STRING_RESULT:
-    return str_op_with_null_check(&str_value);
-  case ROW_RESULT:
-    DBUG_ASSERT(0);
-  }
-  DBUG_ASSERT(!null_value || (str == NULL));
-  return str;
-}
-
-
-double Item_func_hybrid_field_type::val_real()
-{
-  DBUG_ASSERT(fixed == 1);
-  switch (Item_func_hybrid_field_type::cmp_type()) {
-  case DECIMAL_RESULT:
-  {
-    my_decimal decimal_value, *val;
-    double result;
-    if (!(val= decimal_op_with_null_check(&decimal_value)))
-      return 0.0;                               // null is set
-    my_decimal2double(E_DEC_FATAL_ERROR, val, &result);
-    return result;
-  }
-  case INT_RESULT:
-  {
-    longlong result= int_op();
-    return unsigned_flag ? (double) ((ulonglong) result) : (double) result;
-  }
-  case REAL_RESULT:
-    return real_op();
-  case TIME_RESULT:
-  {
-    MYSQL_TIME ltime;
-    if (date_op_with_null_check(&ltime))
-      return 0;
-    ltime.time_type= mysql_type_to_time_type(field_type());
-    return TIME_to_double(&ltime);
-  }
-  case STRING_RESULT:
-  {
-    String *res= str_op_with_null_check(&str_value);
-    return res ? double_from_string_with_check(res) : 0.0;
-  }
-  case ROW_RESULT:
-    DBUG_ASSERT(0);
-  }
-  return 0.0;
-}
-
-
-longlong Item_func_hybrid_field_type::val_int()
-{
-  DBUG_ASSERT(fixed == 1);
-  switch (Item_func_hybrid_field_type::cmp_type()) {
-  case DECIMAL_RESULT:
-  {
-    my_decimal decimal_value, *val;
-    if (!(val= decimal_op_with_null_check(&decimal_value)))
-      return 0;                                 // null is set
-    longlong result;
-    my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
-    return result;
-  }
-  case INT_RESULT:
-    return int_op();
-  case REAL_RESULT:
-    return (longlong) rint(real_op());
-  case TIME_RESULT:
-  {
-    MYSQL_TIME ltime;
-    if (date_op_with_null_check(&ltime))
-      return 0;
-    ltime.time_type= mysql_type_to_time_type(field_type());
-    return TIME_to_ulonglong(&ltime);
-  }
-  case STRING_RESULT:
-  {
-    String *res= str_op_with_null_check(&str_value);
-    return res ? longlong_from_string_with_check(res) : 0;
-  }
-  case ROW_RESULT:
-    DBUG_ASSERT(0);
-  }
-  return 0;
-}
-
-
-my_decimal *Item_func_hybrid_field_type::val_decimal(my_decimal *decimal_value)
-{
-  my_decimal *val= decimal_value;
-  DBUG_ASSERT(fixed == 1);
-  switch (Item_func_hybrid_field_type::cmp_type()) {
-  case DECIMAL_RESULT:
-    val= decimal_op_with_null_check(decimal_value);
-    break;
-  case INT_RESULT:
-  {
-    longlong result= int_op();
-    if (null_value)
-      return NULL;
-    int2my_decimal(E_DEC_FATAL_ERROR, result, unsigned_flag, decimal_value);
-    break;
-  }
-  case REAL_RESULT:
-  {
-    double result= (double)real_op();
-    if (null_value)
-      return NULL;
-    double2my_decimal(E_DEC_FATAL_ERROR, result, decimal_value);
-    break;
-  }
-  case TIME_RESULT:
-  {
-    MYSQL_TIME ltime;
-    if (date_op_with_null_check(&ltime))
-    {
-      my_decimal_set_zero(decimal_value);
-      return 0;
-    }
-    ltime.time_type= mysql_type_to_time_type(field_type());
-    return date2my_decimal(&ltime, decimal_value);
-  }
-  case STRING_RESULT:
-  {
-    String *res= str_op_with_null_check(&str_value);
-    return res ? decimal_from_string_with_check(decimal_value, res) : 0;
-  }  
-  case ROW_RESULT:
-    DBUG_ASSERT(0);
-  }
-  return val;
-}
-
-
-bool Item_func_hybrid_field_type::get_date(MYSQL_TIME *ltime,
-                                            ulonglong fuzzydate)
-{
-  DBUG_ASSERT(fixed == 1);
-  switch (Item_func_hybrid_field_type::cmp_type()) {
-  case DECIMAL_RESULT:
-  {
-    my_decimal value, *res;
-    if (!(res= decimal_op_with_null_check(&value)) ||
-        decimal_to_datetime_with_warn(res, ltime, fuzzydate,
-                                      field_name_or_null()))
-      goto err;
-    break;
-  }
-  case INT_RESULT:
-  {
-    longlong value= int_op();
-    bool neg= !unsigned_flag && value < 0;
-    if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
-                                                ltime, fuzzydate,
-                                                field_name_or_null()))
-      goto err;
-    break;
-  }
-  case REAL_RESULT:
-  {
-    double value= real_op();
-    if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate,
-                                                   field_name_or_null()))
-      goto err;
-    break;
-  }
-  case TIME_RESULT:
-    return date_op(ltime,
-                   fuzzydate |
-                   (field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0));
-  case STRING_RESULT:
-  {
-    char buff[40];
-    String tmp(buff,sizeof(buff), &my_charset_bin),*res;
-    if (!(res= str_op_with_null_check(&tmp)) ||
-        str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
-                                  ltime, fuzzydate))
-      goto err;
-    break;
-  }
-  case ROW_RESULT:
-    DBUG_ASSERT(0);
-  }
-
-  return (null_value= 0);
-
-err:
-  bzero(ltime, sizeof(*ltime));
-  return null_value|= !(fuzzydate & TIME_FUZZY_DATES);  
-}
-
-
 void Item_func_signed::print(String *str, enum_query_type query_type)
 {
   str->append(STRING_WITH_LEN("cast("));
diff --git a/sql/item_func.h b/sql/item_func.h
index aaf1df0..bb613a4 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -428,6 +428,7 @@ class Item_hybrid_func: public Item_func,
 */
 class Item_func_hybrid_field_type: public Item_hybrid_func
 {
+protected:
   /*
     Helper methods to make sure that the result of
     decimal_op(), str_op() and date_op() is properly synched with null_value.
@@ -451,6 +452,11 @@ class Item_func_hybrid_field_type: public Item_hybrid_func
     DBUG_ASSERT((res != NULL) ^ null_value);
     return res;
   }
+  bool make_zero_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate)
+  {
+    bzero(ltime, sizeof(*ltime));
+    return null_value|= !(fuzzydate & TIME_FUZZY_DATES);
+  }
 
 public:
   Item_func_hybrid_field_type(THD *thd):
@@ -469,11 +475,38 @@ class Item_func_hybrid_field_type: public Item_hybrid_func
     Item_hybrid_func(thd, list)
   { collation.set_numeric(); }
 
-  double val_real();
-  longlong val_int();
-  my_decimal *val_decimal(my_decimal *);
-  String *val_str(String*str);
-  bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+  double val_real()
+  {
+    DBUG_ASSERT(fixed);
+    return Item_func_hybrid_field_type::type_handler()->
+           Item_func_hybrid_field_type_val_real(this);
+  }
+  longlong val_int()
+  {
+    DBUG_ASSERT(fixed);
+    return Item_func_hybrid_field_type::type_handler()->
+           Item_func_hybrid_field_type_val_int(this);
+  }
+  my_decimal *val_decimal(my_decimal *dec)
+  {
+    DBUG_ASSERT(fixed);
+    return Item_func_hybrid_field_type::type_handler()->
+           Item_func_hybrid_field_type_val_decimal(this, dec);
+  }
+  String *val_str(String*str)
+  {
+    DBUG_ASSERT(fixed);
+    String *res= Item_func_hybrid_field_type::type_handler()->
+                 Item_func_hybrid_field_type_val_str(this, str);
+    DBUG_ASSERT(null_value == (res == NULL));
+    return res;
+  }
+  bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)
+  {
+    DBUG_ASSERT(fixed);
+    return Item_func_hybrid_field_type::type_handler()->
+           Item_func_hybrid_field_type_get_date(this, res, fuzzy_date);
+  }
 
   /**
      @brief Performs the operation that this functions implements when the
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index a80417f..d7f5a54 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -17,6 +17,7 @@
 #include "sql_type.h"
 #include "sql_const.h"
 #include "sql_class.h"
+#include "sql_time.h"
 #include "item.h"
 #include "log.h"
 
@@ -640,3 +641,509 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table,
                    metadata & 0x00ff/*pack_length()*/,
                    ((const Field_enum*) target)->typelib, target->charset());
 }
+
+
+/***************************************************************************/
+
+/**
+  The classes Item_func_hybrid_field_type_xxx are used only in static_cast
+  in various value extraction methods,
+  e.g. Type_handler_decimal_result::Item_func_hybrid_field_type_val_int().
+  We never create instances of these classes, hence no constructor.
+
+  Every data type has its own class Item_func_hybrid_field_type_xxx.
+  The purpose of these classes include:
+  - data type conversion from the native representation returned by xxx_op()
+    to the requested representation
+  - access to protected members and methods of Item_func_hybrid_field_type
+
+  Every data type handler Type_handler_xxx:
+  - casts Item_func_hybrid_type to its own Item_func_hybrid_type_xxx
+  - calls Item_func_hybrid_type_xxx::val_XXX() statically.
+*/
+class Item_func_hybrid_field_type_decimal_result:
+      public Item_func_hybrid_field_type
+{
+public:
+  String *val_str(String *str)
+  {
+    my_decimal decimal_value, *val;
+    if (!(val= decimal_op_with_null_check(&decimal_value)))
+      return 0;                                 // null is set
+    DBUG_ASSERT(!null_value);
+    my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
+    str->set_charset(collation.collation);
+    my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
+    return str;
+  }
+  double val_real()
+  {
+    DBUG_ASSERT(fixed == 1);
+    my_decimal decimal_value, *val;
+    double result;
+    if (!(val= decimal_op_with_null_check(&decimal_value)))
+      return 0.0;                               // null is set
+    my_decimal2double(E_DEC_FATAL_ERROR, val, &result);
+    return result;
+  }
+  longlong val_int()
+  {
+    my_decimal decimal_value, *val;
+    if (!(val= decimal_op_with_null_check(&decimal_value)))
+      return 0;                                 // null is set
+    longlong result;
+    my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
+    return result;
+  }
+  my_decimal *val_decimal(my_decimal *decimal_value)
+  {
+    return decimal_op_with_null_check(decimal_value);
+  }
+  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+  {
+    my_decimal value, *res;
+    if (!(res= decimal_op_with_null_check(&value)) ||
+        decimal_to_datetime_with_warn(res, ltime, fuzzydate,
+                                      field_name_or_null()))
+      return make_zero_mysql_time(ltime, fuzzydate);
+    return (null_value= 0);
+  }
+};
+
+
+String *
+Type_handler_decimal_result::Item_func_hybrid_field_type_val_str(
+                                              Item_func_hybrid_field_type *item,
+                                              String *str) const
+{
+  // The type qualifier in the call below is to call the method statically
+  return static_cast<Item_func_hybrid_field_type_decimal_result*>(item)->
+    Item_func_hybrid_field_type_decimal_result::val_str(str);
+}
+
+
+double
+Type_handler_decimal_result::Item_func_hybrid_field_type_val_real(
+                                              Item_func_hybrid_field_type *item)
+                                              const
+{
+  return static_cast<Item_func_hybrid_field_type_decimal_result*>(item)->
+    Item_func_hybrid_field_type_decimal_result::val_real();
+}
+
+
+longlong
+Type_handler_decimal_result::Item_func_hybrid_field_type_val_int(
+                                              Item_func_hybrid_field_type *item)
+                                              const
+{
+  return static_cast<Item_func_hybrid_field_type_decimal_result*>(item)->
+    Item_func_hybrid_field_type_decimal_result::val_int();
+}
+
+
+my_decimal *
+Type_handler_decimal_result::Item_func_hybrid_field_type_val_decimal(
+                                              Item_func_hybrid_field_type *item,
+                                              my_decimal *dec) const
+{
+  return static_cast<Item_func_hybrid_field_type_decimal_result*>(item)->
+    Item_func_hybrid_field_type_decimal_result::val_decimal(dec);
+}
+
+
+bool
+Type_handler_decimal_result::Item_func_hybrid_field_type_get_date(
+                                             Item_func_hybrid_field_type *item,
+                                             MYSQL_TIME *ltime,
+                                             ulonglong fuzzydate) const
+{
+  return static_cast<Item_func_hybrid_field_type_decimal_result*>(item)->
+    Item_func_hybrid_field_type_decimal_result::get_date(ltime, fuzzydate);
+}
+
+
+/***************************************************************************/
+
+
+class Item_func_hybrid_field_type_int_result:
+      public Item_func_hybrid_field_type
+{
+public:
+  String *val_str(String *str)
+  {
+    longlong nr= int_op();
+    if (null_value)
+      return 0; /* purecov: inspected */
+    str->set_int(nr, unsigned_flag, collation.collation);
+    return str;
+  }
+  double val_real()
+  {
+    longlong result= int_op();
+    return unsigned_flag ? (double) ((ulonglong) result) : (double) result;
+  }
+  longlong val_int()
+  {
+    return int_op();
+  }
+  my_decimal *val_decimal(my_decimal *decimal_value)
+  {
+    longlong result= int_op();
+    if (null_value)
+      return NULL;
+    int2my_decimal(E_DEC_FATAL_ERROR, result, unsigned_flag, decimal_value);
+    return decimal_value;
+  }
+  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+  {
+    longlong value= int_op();
+    bool neg= !unsigned_flag && value < 0;
+    if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
+                                                ltime, fuzzydate,
+                                                field_name_or_null()))
+      return make_zero_mysql_time(ltime, fuzzydate);
+    return (null_value= 0);
+  }
+};
+
+
+String *
+Type_handler_int_result::Item_func_hybrid_field_type_val_str(
+                                          Item_func_hybrid_field_type *item,
+                                          String *str) const
+{
+  return static_cast<Item_func_hybrid_field_type_int_result*>(item)->
+    Item_func_hybrid_field_type_int_result::val_str(str);
+}
+
+
+double
+Type_handler_int_result::Item_func_hybrid_field_type_val_real(
+                                          Item_func_hybrid_field_type *item)
+                                          const
+{
+  return static_cast<Item_func_hybrid_field_type_int_result*>(item)->
+    Item_func_hybrid_field_type_int_result::val_real();
+}
+
+
+longlong
+Type_handler_int_result::Item_func_hybrid_field_type_val_int(
+                                          Item_func_hybrid_field_type *item)
+                                          const
+{
+  return static_cast<Item_func_hybrid_field_type_int_result*>(item)->
+    Item_func_hybrid_field_type_int_result::val_int();
+}
+
+
+my_decimal *
+Type_handler_int_result::Item_func_hybrid_field_type_val_decimal(
+                                          Item_func_hybrid_field_type *item,
+                                          my_decimal *dec) const
+{
+  return static_cast<Item_func_hybrid_field_type_int_result*>(item)->
+    Item_func_hybrid_field_type_int_result::val_decimal(dec);
+}
+
+
+bool
+Type_handler_int_result::Item_func_hybrid_field_type_get_date(
+                                          Item_func_hybrid_field_type *item,
+                                          MYSQL_TIME *ltime,
+                                          ulonglong fuzzydate) const
+{
+  return static_cast<Item_func_hybrid_field_type_int_result*>(item)->
+    Item_func_hybrid_field_type_int_result::get_date(ltime, fuzzydate);
+}
+
+
+
+/***************************************************************************/
+
+class Item_func_hybrid_field_type_real_result:
+      public Item_func_hybrid_field_type
+{
+public:
+  String *val_str(String *str)
+  {
+    double nr= real_op();
+    if (null_value)
+      return 0; /* purecov: inspected */
+    str->set_real(nr, decimals, collation.collation);
+    return str;
+  }
+  double val_real()
+  {
+    return real_op();
+  }
+  longlong val_int()
+  {
+    return (longlong) rint(real_op());
+  }
+  my_decimal *val_decimal(my_decimal *decimal_value)
+  {
+    double result= (double)real_op();
+    if (null_value)
+      return NULL;
+    double2my_decimal(E_DEC_FATAL_ERROR, result, decimal_value);
+    return decimal_value;
+  }
+  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+  {
+    double value= real_op();
+    if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate,
+                                                   field_name_or_null()))
+      return make_zero_mysql_time(ltime, fuzzydate);
+    return (null_value= 0);
+  }
+};
+
+
+String *
+Type_handler_real_result::Item_func_hybrid_field_type_val_str(
+                                           Item_func_hybrid_field_type *item,
+                                           String *str) const
+{
+  return static_cast<Item_func_hybrid_field_type_real_result*>(item)->
+    Item_func_hybrid_field_type_real_result::val_str(str);
+}
+
+
+double
+Type_handler_real_result::Item_func_hybrid_field_type_val_real(
+                                           Item_func_hybrid_field_type *item)
+                                           const
+{
+  return static_cast<Item_func_hybrid_field_type_real_result*>(item)->
+    Item_func_hybrid_field_type_real_result::val_real();
+}
+
+
+longlong
+Type_handler_real_result::Item_func_hybrid_field_type_val_int(
+                                           Item_func_hybrid_field_type *item)
+                                           const
+{
+  return static_cast<Item_func_hybrid_field_type_real_result*>(item)->
+    Item_func_hybrid_field_type_real_result::val_int();
+}
+
+
+my_decimal *
+Type_handler_real_result::Item_func_hybrid_field_type_val_decimal(
+                                           Item_func_hybrid_field_type *item,
+                                           my_decimal *dec) const
+{
+  return static_cast<Item_func_hybrid_field_type_real_result*>(item)->
+    Item_func_hybrid_field_type_real_result::val_decimal(dec);
+}
+
+
+bool
+Type_handler_real_result::Item_func_hybrid_field_type_get_date(
+                                             Item_func_hybrid_field_type *item,
+                                             MYSQL_TIME *ltime,
+                                             ulonglong fuzzydate) const
+{
+  return static_cast<Item_func_hybrid_field_type_real_result*>(item)->
+    Item_func_hybrid_field_type_real_result::get_date(ltime, fuzzydate);
+}
+
+
+/***************************************************************************/
+
+class Item_func_hybrid_field_type_temporal_result:
+      public Item_func_hybrid_field_type
+{
+public:
+  String *val_str(String *str)
+  {
+    MYSQL_TIME ltime;
+    if (date_op_with_null_check(&ltime) ||
+        (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
+      return (String *) 0;
+    ltime.time_type= mysql_type_to_time_type(field_type());
+    str->length(my_TIME_to_str(&ltime, const_cast<char*>(str->ptr()), decimals));
+    str->set_charset(&my_charset_bin);
+    DBUG_ASSERT(!null_value);
+    return str;
+  }
+  double val_real()
+  {
+    MYSQL_TIME ltime;
+    if (date_op_with_null_check(&ltime))
+      return 0;
+    ltime.time_type= mysql_type_to_time_type(field_type());
+    return TIME_to_double(&ltime);
+  }
+  longlong val_int()
+  {
+    MYSQL_TIME ltime;
+    if (date_op_with_null_check(&ltime))
+      return 0;
+    ltime.time_type= mysql_type_to_time_type(field_type());
+    return TIME_to_ulonglong(&ltime);
+  }
+  my_decimal *val_decimal(my_decimal *decimal_value)
+  {
+    MYSQL_TIME ltime;
+    if (date_op_with_null_check(&ltime))
+    {
+      my_decimal_set_zero(decimal_value);
+      return 0;
+    }
+    ltime.time_type= mysql_type_to_time_type(field_type());
+    return date2my_decimal(&ltime, decimal_value);
+  }
+  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+  {
+    return date_op(ltime,
+                   fuzzydate |
+                   (field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0));
+  }
+};
+
+
+String *
+Type_handler_temporal_result::Item_func_hybrid_field_type_val_str(
+                                        Item_func_hybrid_field_type *item,
+                                        String *str) const
+{
+  return static_cast<Item_func_hybrid_field_type_temporal_result*>(item)->
+    Item_func_hybrid_field_type_temporal_result::val_str(str);
+}
+
+
+double
+Type_handler_temporal_result::Item_func_hybrid_field_type_val_real(
+                                        Item_func_hybrid_field_type *item)
+                                        const
+{
+  return static_cast<Item_func_hybrid_field_type_temporal_result*>(item)->
+    Item_func_hybrid_field_type_temporal_result::val_real();
+}
+
+
+longlong
+Type_handler_temporal_result::Item_func_hybrid_field_type_val_int(
+                                        Item_func_hybrid_field_type *item)
+                                        const
+{
+  return static_cast<Item_func_hybrid_field_type_temporal_result*>(item)->
+    Item_func_hybrid_field_type_temporal_result::val_int();
+}
+
+
+my_decimal *
+Type_handler_temporal_result::Item_func_hybrid_field_type_val_decimal(
+                                        Item_func_hybrid_field_type *item,
+                                        my_decimal *dec) const
+{
+  return static_cast<Item_func_hybrid_field_type_temporal_result*>(item)->
+    Item_func_hybrid_field_type_temporal_result::val_decimal(dec);
+}
+
+
+bool
+Type_handler_temporal_result::Item_func_hybrid_field_type_get_date(
+                                        Item_func_hybrid_field_type *item,
+                                        MYSQL_TIME *ltime,
+                                        ulonglong fuzzydate) const
+{
+  return static_cast<Item_func_hybrid_field_type_temporal_result*>(item)->
+    Item_func_hybrid_field_type_temporal_result::get_date(ltime, fuzzydate);
+}
+
+
+
+/***************************************************************************/
+
+class Item_func_hybrid_field_type_string_result:
+      public Item_func_hybrid_field_type
+{
+public:
+  String *val_str(String *str)
+  {
+    return str_op_with_null_check(&str_value);
+  }
+  double val_real()
+  {
+    String *res= str_op_with_null_check(&str_value);
+    return res ? double_from_string_with_check(res) : 0.0;
+  }
+  longlong val_int()
+  {
+    String *res= str_op_with_null_check(&str_value);
+    return res ? longlong_from_string_with_check(res) : 0;
+  }
+  my_decimal *val_decimal(my_decimal *decimal_value)
+  {
+    String *res= str_op_with_null_check(&str_value);
+    return res ? decimal_from_string_with_check(decimal_value, res) : 0;
+  }
+  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+  {
+    StringBuffer<40> tmp;
+    String *res;
+    if (!(res= str_op_with_null_check(&tmp)) ||
+        str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
+                                  ltime, fuzzydate))
+      return make_zero_mysql_time(ltime, fuzzydate);
+    return (null_value= 0);
+  }
+};
+
+
+String *
+Type_handler_string_result::Item_func_hybrid_field_type_val_str(
+                                             Item_func_hybrid_field_type *item,
+                                             String *str) const
+{
+  return static_cast<Item_func_hybrid_field_type_string_result*>(item)->
+    Item_func_hybrid_field_type_string_result::val_str(str);
+}
+
+
+double
+Type_handler_string_result::Item_func_hybrid_field_type_val_real(
+                                             Item_func_hybrid_field_type *item)
+                                             const
+{
+  return static_cast<Item_func_hybrid_field_type_string_result*>(item)->
+    Item_func_hybrid_field_type_string_result::val_real();
+}
+
+
+longlong
+Type_handler_string_result::Item_func_hybrid_field_type_val_int(
+                                             Item_func_hybrid_field_type *item)
+                                             const
+{
+  return static_cast<Item_func_hybrid_field_type_string_result*>(item)->
+    Item_func_hybrid_field_type_string_result::val_int();
+}
+
+
+my_decimal *
+Type_handler_string_result::Item_func_hybrid_field_type_val_decimal(
+                                              Item_func_hybrid_field_type *item,
+                                              my_decimal *dec) const
+{
+  return static_cast<Item_func_hybrid_field_type_string_result*>(item)->
+    Item_func_hybrid_field_type_string_result::val_decimal(dec);
+}
+
+
+bool
+Type_handler_string_result::Item_func_hybrid_field_type_get_date(
+                                             Item_func_hybrid_field_type *item,
+                                             MYSQL_TIME *ltime,
+                                             ulonglong fuzzydate) const
+{
+  return static_cast<Item_func_hybrid_field_type_string_result*>(item)->
+    Item_func_hybrid_field_type_string_result::get_date(ltime, fuzzydate);
+}
+
+/***************************************************************************/
diff --git a/sql/sql_type.h b/sql/sql_type.h
index de5c31a..d22f472 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -25,6 +25,7 @@
 
 class Field;
 class Item;
+class Item_func_hybrid_field_type;
 class Type_std_attributes;
 class Sort_param;
 struct TABLE;
@@ -272,6 +273,24 @@ class Type_handler
   virtual void sortlength(THD *thd,
                           const Type_std_attributes *item,
                           SORT_FIELD_ATTR *attr) const= 0;
+
+  virtual
+  String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
+                                              String *) const= 0;
+  virtual
+  double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
+                                              const= 0;
+  virtual
+  longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
+                                               const= 0;
+  virtual
+  my_decimal *Item_func_hybrid_field_type_val_decimal(
+                                              Item_func_hybrid_field_type *,
+                                              my_decimal *) const= 0;
+  virtual
+  bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+                                            MYSQL_TIME *,
+                                            ulonglong fuzzydate) const= 0;
 };
 
 
@@ -288,6 +307,18 @@ class Type_handler_real_result: public Type_handler
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
+  String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
+                                              String *) const;
+  double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
+                                              const;
+  longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
+                                               const;
+  my_decimal *Item_func_hybrid_field_type_val_decimal(
+                                              Item_func_hybrid_field_type *,
+                                              my_decimal *) const;
+  bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+                                            MYSQL_TIME *,
+                                            ulonglong fuzzydate) const;
 };
 
 
@@ -303,6 +334,18 @@ class Type_handler_decimal_result: public Type_handler
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
+  String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
+                                              String *) const;
+  double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
+                                              const;
+  longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
+                                               const;
+  my_decimal *Item_func_hybrid_field_type_val_decimal(
+                                              Item_func_hybrid_field_type *,
+                                              my_decimal *) const;
+  bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+                                            MYSQL_TIME *,
+                                            ulonglong fuzzydate) const;
 };
 
 
@@ -318,6 +361,18 @@ class Type_handler_int_result: public Type_handler
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
+  String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
+                                              String *) const;
+  double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
+                                              const;
+  longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
+                                               const;
+  my_decimal *Item_func_hybrid_field_type_val_decimal(
+                                              Item_func_hybrid_field_type *,
+                                              my_decimal *) const;
+  bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+                                            MYSQL_TIME *,
+                                            ulonglong fuzzydate) const;
 };
 
 
@@ -332,6 +387,18 @@ class Type_handler_temporal_result: public Type_handler
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
+  String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
+                                              String *) const;
+  double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
+                                              const;
+  longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
+                                               const;
+  my_decimal *Item_func_hybrid_field_type_val_decimal(
+                                              Item_func_hybrid_field_type *,
+                                              my_decimal *) const;
+  bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+                                            MYSQL_TIME *,
+                                            ulonglong fuzzydate) const;
 };
 
 
@@ -349,6 +416,18 @@ class Type_handler_string_result: public Type_handler
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
+  String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
+                                              String *) const;
+  double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
+                                              const;
+  longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
+                                               const;
+  my_decimal *Item_func_hybrid_field_type_val_decimal(
+                                              Item_func_hybrid_field_type *,
+                                              my_decimal *) const;
+  bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+                                            MYSQL_TIME *,
+                                            ulonglong fuzzydate) const;
 };
 
 
