← Back to team overview

maria-developers team mailing list archive

MDEV-11337 Split Item::save_in_field() into virtual methods in Type_handler

 

Hello Nirbhay,

Can you please review a patch for 10.3:

MDEV-11337 Split Item::save_in_field() into virtual methods in Type_handler


It also automatically fixed two problems:

MDEV-11331 Wrong result for INSERT INTO t1 (datetime_field) VALUES (hybrid_function_of_TIME_data_type) MDEV-11333 Expect "Impossible where condition" for WHERE timestamp_field>=DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR)

because the new code is now symmetric for all data types.

Thanks!
commit c93ced460124e2c3c8dd55580c841b0c6624409e
Author: Alexander Barkov <bar@xxxxxxxxxxx>
Date:   Tue Nov 22 21:31:13 2016 +0400

    MDEV-11337 Split Item::save_in_field() into virtual methods in Type_handler
    
    Also fixes:
    MDEV-11331 Wrong result for INSERT INTO t1 (datetime_field) VALUES (hybrid_function_of_TIME_data_type)
    MDEV-11333 Expect "Impossible where condition" for WHERE timestamp_field>=DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR)
    
    This patch does the following:
    1. Splits the function Item::save_in_field() into pieces:
    - Item::save_str_in_field()
    - Item::save_real_in_field()
    - Item::save_real_in_field()
    - Item::save_decimal_in_field()
    - Item::save_int_in_field()
    
    2. Adds the missing "no_conversion" parameters to
       Item::save_time_in_field() and Item::save_date_in_field(),
       so this parameter is now correctly passed to
       set_field_to_null_with_conversions().
       This fixes the problem reported in 11333.
    
    3. Introduces a new virtual method Type_handler::Item_save_in_field()
       and uses the methods Item::save_xxx_in_field() from the implementations
       of Type_handler_xxx::Item_save_in_field().
    
    These changes additionally fix the problem reported in MDEV-11331,
    as the old code erroneously handled expressions like
    COALESE(datetime-expression) through the STRING_RESULT branch of
    Item::save_in_field() and therefore looked like string type expressions
    for the target fields. Now such expressions are correctly handled by
    Item::save_date_in_field().

diff --git a/mysql-test/r/default.result b/mysql-test/r/default.result
index 386837a..96ac8fc 100644
--- a/mysql-test/r/default.result
+++ b/mysql-test/r/default.result
@@ -986,14 +986,9 @@ t1	CREATE TABLE `t1` (
   `a` decimal(30,6) DEFAULT COALESCE(CURRENT_TIMESTAMP(6))
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 INSERT INTO t1 VALUES();
-Warnings:
-Warning	1265	Data truncated for column 'a' at row 1
 INSERT IGNORE INTO t1 VALUES();
-Warnings:
-Warning	1265	Data truncated for column 'a' at row 1
 SET sql_mode = 'STRICT_ALL_TABLES';
 INSERT INTO t1 VALUES();
-ERROR 01000: Data truncated for column 'a' at row 1
 SET sql_mode = DEFAULT;
 DROP TABLE t1;
 #
@@ -1006,8 +1001,6 @@ t1	CREATE TABLE `t1` (
   `a` decimal(30,6) DEFAULT COALESCE(CURRENT_TIME(6))
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 INSERT INTO t1 VALUES();
-Warnings:
-Warning	1265	Data truncated for column 'a' at row 1
 DROP TABLE t1;
 #
 # DECIMAL + CURRENT_DATE, no truncation
@@ -1019,8 +1012,6 @@ t1	CREATE TABLE `t1` (
   `a` decimal(30,6) DEFAULT COALESCE(CURRENT_DATE)
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 INSERT INTO t1 VALUES();
-Warnings:
-Warning	1265	Data truncated for column 'a' at row 1
 DROP TABLE t1;
 #
 # COALESCE for SQL Standard <datetime value function>
@@ -1077,10 +1068,10 @@ t1	CREATE TABLE `t1` (
 INSERT INTO t1 VALUES ();
 Warnings:
 Note	1265	Data truncated for column 'a' at row 1
-Warning	1265	Data truncated for column 'b' at row 1
+Note	1265	Data truncated for column 'b' at row 1
 SELECT * FROM t1;
 a	b
-20010101102030	2001
+20010101102030	20010101102030
 DROP TABLE t1;
 #
 # Check DEFAULT() function
diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result
index 41696aa..298d022 100644
--- a/mysql-test/r/type_datetime.result
+++ b/mysql-test/r/type_datetime.result
@@ -1199,3 +1199,24 @@ DROP TABLE t1;
 #
 # End of 10.2 tests
 #
+#
+# Start of 10.3 tests
+#
+#
+# MDEV-11331 Wrong result for INSERT INTO t1 (datetime_field) VALUES (hybrid_function_of_TIME_data_type)
+#
+SET timestamp=UNIX_TIMESTAMP('2001-02-03 10:00:00');
+CREATE TABLE t1 (a DATETIME);
+INSERT INTO t1 VALUES (TIME'10:20:30');
+INSERT INTO t1 VALUES (COALESCE(TIME'10:20:30'));
+INSERT INTO t1 VALUES (LEAST(TIME'10:20:30',TIME'10:20:30'));
+SELECT * FROM t1;
+a
+2001-02-03 10:20:30
+2001-02-03 10:20:30
+2001-02-03 10:20:30
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+#
+# End of 10.3 tests
+#
diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result
index 69c9f68..d4afed8 100644
--- a/mysql-test/r/type_timestamp.result
+++ b/mysql-test/r/type_timestamp.result
@@ -950,3 +950,35 @@ DROP TABLE t1;
 #
 # End of 10.1 tests
 #
+#
+# Start of 10.3 tests
+#
+#
+# MDEV-11333     MDEV-11333 Expect "Impossible where condition" for WHERE timestamp_field>=DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR)
+#
+SELECT DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR);
+DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR)
+NULL
+Warnings:
+Warning	1441	Datetime function: datetime field overflow
+CREATE TABLE t1 (a TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, KEY(a)) ENGINE=MyISAM;
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+EXPLAIN SELECT * FROM t1 WHERE a >= DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+Warnings:
+Warning	1441	Datetime function: datetime field overflow
+EXPLAIN SELECT * FROM t1 WHERE a >= COALESCE(DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+Warnings:
+Warning	1441	Datetime function: datetime field overflow
+DROP TABLE t1;
+#
+# End of 10.3 tests
+#
diff --git a/mysql-test/t/default.test b/mysql-test/t/default.test
index 6c87152..d0e672a 100644
--- a/mysql-test/t/default.test
+++ b/mysql-test/t/default.test
@@ -755,11 +755,9 @@ DROP TABLE t1;
 
 CREATE TABLE t1 (a DECIMAL(30,6) DEFAULT COALESCE(CURRENT_TIMESTAMP(6)));
 SHOW CREATE TABLE t1;
-# Same as insert into t1 values ("2016-06-05 12:54:52.342095");
 INSERT INTO t1 VALUES();
 INSERT IGNORE INTO t1 VALUES();
 SET sql_mode = 'STRICT_ALL_TABLES';
---error WARN_DATA_TRUNCATED
 INSERT INTO t1 VALUES();
 SET sql_mode = DEFAULT;
 DROP TABLE t1;
diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test
index b16d426..1809f30 100644
--- a/mysql-test/t/type_datetime.test
+++ b/mysql-test/t/type_datetime.test
@@ -751,3 +751,24 @@ DROP TABLE t1;
 --echo #
 --echo # End of 10.2 tests
 --echo #
+
+--echo #
+--echo # Start of 10.3 tests
+--echo #
+
+--echo #
+--echo # MDEV-11331 Wrong result for INSERT INTO t1 (datetime_field) VALUES (hybrid_function_of_TIME_data_type)
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2001-02-03 10:00:00');
+CREATE TABLE t1 (a DATETIME);
+INSERT INTO t1 VALUES (TIME'10:20:30');
+INSERT INTO t1 VALUES (COALESCE(TIME'10:20:30'));
+INSERT INTO t1 VALUES (LEAST(TIME'10:20:30',TIME'10:20:30'));
+SELECT * FROM t1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+
+--echo #
+--echo # End of 10.3 tests
+--echo #
diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test
index 460769f..2dad92b 100644
--- a/mysql-test/t/type_timestamp.test
+++ b/mysql-test/t/type_timestamp.test
@@ -555,3 +555,27 @@ let defval='0000-00-00 00:00:00';
 --echo #
 --echo # End of 10.1 tests
 --echo #
+
+--echo #
+--echo # Start of 10.3 tests
+--echo #
+
+--echo #
+--echo # MDEV-11333     MDEV-11333 Expect "Impossible where condition" for WHERE timestamp_field>=DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR)
+--echo #
+
+SELECT DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR);
+CREATE TABLE t1 (a TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, KEY(a)) ENGINE=MyISAM;
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+INSERT INTO t1 VALUES('2001-01-01'),('2002-02-02'),('2003-03-03');
+EXPLAIN SELECT * FROM t1 WHERE a >= DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR);
+EXPLAIN SELECT * FROM t1 WHERE a >= COALESCE(DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR));
+DROP TABLE t1;
+
+--echo #
+--echo # End of 10.3 tests
+--echo #
diff --git a/sql/item.cc b/sql/item.cc
index 70b7383..ee453fd 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -418,21 +418,21 @@ longlong Item::val_int_from_decimal()
   return result;
 }
 
-int Item::save_time_in_field(Field *field)
+int Item::save_time_in_field(Field *field, bool no_conversions)
 {
   MYSQL_TIME ltime;
   if (get_time(&ltime))
-    return set_field_to_null_with_conversions(field, 0);
+    return set_field_to_null_with_conversions(field, no_conversions);
   field->set_notnull();
   return field->store_time_dec(&ltime, decimals);
 }
 
 
-int Item::save_date_in_field(Field *field)
+int Item::save_date_in_field(Field *field, bool no_conversions)
 {
   MYSQL_TIME ltime;
   if (get_date(&ltime, sql_mode_for_dates(field->table->in_use)))
-    return set_field_to_null_with_conversions(field, 0);
+    return set_field_to_null_with_conversions(field, no_conversions);
   field->set_notnull();
   return field->store_time_dec(&ltime, decimals);
 }
@@ -6146,54 +6146,62 @@ int Item_null::save_safe_in_field(Field *field)
   Note: all Item_XXX::val_str(str) methods must NOT assume that
   str != str_value. For example, see fix for bug #44743.
 */
+int Item::save_str_in_field(Field *field, bool no_conversions)
+{
+  String *result;
+  CHARSET_INFO *cs= collation.collation;
+  char buff[MAX_FIELD_WIDTH];		// Alloc buffer for small columns
+  str_value.set_quick(buff, sizeof(buff), cs);
+  result=val_str(&str_value);
+  if (null_value)
+  {
+    str_value.set_quick(0, 0, cs);
+    return set_field_to_null_with_conversions(field, no_conversions);
+  }
 
-int Item::save_in_field(Field *field, bool no_conversions)
+  /* NOTE: If null_value == FALSE, "result" must be not NULL.  */
+
+  field->set_notnull();
+  int error= field->store(result->ptr(),result->length(),cs);
+  str_value.set_quick(0, 0, cs);
+  return error;
+}
+
+
+int Item::save_real_in_field(Field *field, bool no_conversions)
 {
-  int error;
-  if (result_type() == STRING_RESULT)
-  {
-    String *result;
-    CHARSET_INFO *cs= collation.collation;
-    char buff[MAX_FIELD_WIDTH];		// Alloc buffer for small columns
-    str_value.set_quick(buff, sizeof(buff), cs);
-    result=val_str(&str_value);
-    if (null_value)
-    {
-      str_value.set_quick(0, 0, cs);
-      return set_field_to_null_with_conversions(field, no_conversions);
-    }
+  double nr= val_real();
+  if (null_value)
+    return set_field_to_null_with_conversions(field, no_conversions);
+  field->set_notnull();
+  return field->store(nr);
+}
 
-    /* NOTE: If null_value == FALSE, "result" must be not NULL.  */
 
-    field->set_notnull();
-    error=field->store(result->ptr(),result->length(),cs);
-    str_value.set_quick(0, 0, cs);
-  }
-  else if (result_type() == REAL_RESULT)
-  {
-    double nr= val_real();
-    if (null_value)
-      return set_field_to_null_with_conversions(field, no_conversions);
-    field->set_notnull();
-    error=field->store(nr);
-  }
-  else if (result_type() == DECIMAL_RESULT)
-  {
-    my_decimal decimal_value;
-    my_decimal *value= val_decimal(&decimal_value);
-    if (null_value)
-      return set_field_to_null_with_conversions(field, no_conversions);
-    field->set_notnull();
-    error=field->store_decimal(value);
-  }
-  else
-  {
-    longlong nr=val_int();
-    if (null_value)
-      return set_field_to_null_with_conversions(field, no_conversions);
-    field->set_notnull();
-    error=field->store(nr, unsigned_flag);
-  }
+int Item::save_decimal_in_field(Field *field, bool no_conversions)
+{
+  my_decimal decimal_value;
+  my_decimal *value= val_decimal(&decimal_value);
+  if (null_value)
+    return set_field_to_null_with_conversions(field, no_conversions);
+  field->set_notnull();
+  return field->store_decimal(value);
+}
+
+
+int Item::save_int_in_field(Field *field, bool no_conversions)
+{
+  longlong nr= val_int();
+  if (null_value)
+    return set_field_to_null_with_conversions(field, no_conversions);
+  field->set_notnull();
+  return field->store(nr, unsigned_flag);
+}
+
+
+int Item::save_in_field(Field *field, bool no_conversions)
+{
+  int error= type_handler()->Item_save_in_field(this, field, no_conversions);
   return error ? error : (field->table->in_use->is_error() ? 1 : 0);
 }
 
diff --git a/sql/item.h b/sql/item.h
index 30d8a39..3b21176 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -965,8 +965,13 @@ class Item: public Value_source,
   // Check NULL value for a TIME, DATE or DATETIME expression
   bool is_null_from_temporal();
 
-  int save_time_in_field(Field *field);
-  int save_date_in_field(Field *field);
+  int save_time_in_field(Field *field, bool no_conversions);
+  int save_date_in_field(Field *field, bool no_conversions);
+  int save_str_in_field(Field *field, bool no_conversions);
+  int save_real_in_field(Field *field, bool no_conversions);
+  int save_int_in_field(Field *field, bool no_conversions);
+  int save_decimal_in_field(Field *field, bool no_conversions);
+
   int save_str_value_in_field(Field *field, String *result);
 
   virtual Field *get_tmp_table_field() { return 0; }
@@ -3491,7 +3496,7 @@ class Item_temporal_literal :public Item_basic_constant
   my_decimal *val_decimal(my_decimal *decimal_value)
   { return  val_decimal_from_date(decimal_value); }
   int save_in_field(Field *field, bool no_conversions)
-  { return save_date_in_field(field); }
+  { return save_date_in_field(field, no_conversions); }
 };
 
 
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 76340b9..4502796 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -546,7 +546,7 @@ class Item_temporal_func: public Item_func
   Field *create_field_for_create_select(TABLE *table)
   { return tmp_table_field_from_field_type(table, false, false); }
   int save_in_field(Field *field, bool no_conversions)
-  { return save_date_in_field(field); }
+  { return save_date_in_field(field, no_conversions); }
   void fix_length_and_dec();
 };
 
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index a80417f..42aa37a 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -640,3 +640,47 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table,
                    metadata & 0x00ff/*pack_length()*/,
                    ((const Field_enum*) target)->typelib, target->charset());
 }
+
+/*************************************************************************/
+
+int Type_handler_time_common::Item_save_in_field(Item *item, Field *field,
+                                                 bool no_conversions) const
+{
+  return item->save_time_in_field(field, no_conversions);
+}
+
+int Type_handler_temporal_with_date::Item_save_in_field(Item *item,
+                                                        Field *field,
+                                                        bool no_conversions)
+                                                        const
+{
+  return item->save_date_in_field(field, no_conversions);
+}
+
+
+int Type_handler_string_result::Item_save_in_field(Item *item, Field *field,
+                                                   bool no_conversions) const
+{
+  return item->save_str_in_field(field, no_conversions);
+}
+
+
+int Type_handler_real_result::Item_save_in_field(Item *item, Field *field,
+                                                 bool no_conversions) const
+{
+  return item->save_real_in_field(field, no_conversions);
+}
+
+
+int Type_handler_decimal_result::Item_save_in_field(Item *item, Field *field,
+                                                    bool no_conversions) const
+{
+  return item->save_decimal_in_field(field, no_conversions);
+}
+
+
+int Type_handler_int_result::Item_save_in_field(Item *item, Field *field,
+                                                bool no_conversions) const
+{
+  return item->save_int_in_field(field, no_conversions);
+}
diff --git a/sql/sql_type.h b/sql/sql_type.h
index de5c31a..0147ee5 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -272,6 +272,9 @@ class Type_handler
   virtual void sortlength(THD *thd,
                           const Type_std_attributes *item,
                           SORT_FIELD_ATTR *attr) const= 0;
+
+  virtual int Item_save_in_field(Item *item, Field *field,
+                                 bool no_conversions) const= 0;
 };
 
 
@@ -288,6 +291,7 @@ class Type_handler_real_result: public Type_handler
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
+  int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
 };
 
 
@@ -303,6 +307,7 @@ class Type_handler_decimal_result: public Type_handler
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
+  int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
 };
 
 
@@ -318,6 +323,7 @@ class Type_handler_int_result: public Type_handler
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
+  int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
 };
 
 
@@ -349,6 +355,7 @@ class Type_handler_string_result: public Type_handler
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
+  int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
 };
 
 
@@ -463,28 +470,43 @@ class Type_handler_double: public Type_handler_real_result
 };
 
 
-class Type_handler_time: public Type_handler_temporal_result
+class Type_handler_time_common: public Type_handler_temporal_result
 {
 public:
-  virtual ~Type_handler_time() {}
+  virtual ~Type_handler_time_common() { }
   enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
+  int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
+};
+
+
+class Type_handler_time: public Type_handler_time_common
+{
+public:
+  virtual ~Type_handler_time() {}
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
 };
 
 
-class Type_handler_time2: public Type_handler_temporal_result
+class Type_handler_time2: public Type_handler_time_common
 {
 public:
   virtual ~Type_handler_time2() {}
-  enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
   enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
 };
 
 
-class Type_handler_date: public Type_handler_temporal_result
+class Type_handler_temporal_with_date: public Type_handler_temporal_result
+{
+public:
+  virtual ~Type_handler_temporal_with_date() {}
+  int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
+};
+
+
+class Type_handler_date: public Type_handler_temporal_with_date
 {
 public:
   virtual ~Type_handler_date() {}
@@ -494,7 +516,7 @@ class Type_handler_date: public Type_handler_temporal_result
 };
 
 
-class Type_handler_newdate: public Type_handler_temporal_result
+class Type_handler_newdate: public Type_handler_temporal_with_date
 {
 public:
   virtual ~Type_handler_newdate() {}
@@ -504,7 +526,7 @@ class Type_handler_newdate: public Type_handler_temporal_result
 };
 
 
-class Type_handler_datetime: public Type_handler_temporal_result
+class Type_handler_datetime: public Type_handler_temporal_with_date
 {
 public:
   virtual ~Type_handler_datetime() {}
@@ -514,7 +536,7 @@ class Type_handler_datetime: public Type_handler_temporal_result
 };
 
 
-class Type_handler_datetime2: public Type_handler_temporal_result
+class Type_handler_datetime2: public Type_handler_temporal_with_date
 {
 public:
   virtual ~Type_handler_datetime2() {}
@@ -525,7 +547,7 @@ class Type_handler_datetime2: public Type_handler_temporal_result
 };
 
 
-class Type_handler_timestamp: public Type_handler_temporal_result
+class Type_handler_timestamp: public Type_handler_temporal_with_date
 {
 public:
   virtual ~Type_handler_timestamp() {}
@@ -535,7 +557,7 @@ class Type_handler_timestamp: public Type_handler_temporal_result
 };
 
 
-class Type_handler_timestamp2: public Type_handler_temporal_result
+class Type_handler_timestamp2: public Type_handler_temporal_with_date
 {
 public:
   virtual ~Type_handler_timestamp2() {}

Follow ups