List:Commits« Previous MessageNext Message »
From:Alexander Barkov Date:November 10 2011 2:59pm
Subject:bzr push into mysql-trunk branch (alexander.barkov:3554 to 3555)
Bug#13359097 WL#946
View as plain text  
 3555 Alexander Barkov	2011-11-10
      WL#946: Bug#13359097 ASSERT FAILURE IN MAKE_SORTKEY

    modified:
      mysql-test/r/type_temporal_fractional.result
      mysql-test/t/type_temporal_fractional.test
      sql/item.cc
      sql/item.h
      sql/item_cmpfunc.cc
      sql/item_cmpfunc.h
      sql/item_func.cc
      sql/item_func.h
      sql/item_row.h
      sql/item_strfunc.h
      sql/item_subselect.cc
      sql/item_subselect.h
      sql/item_sum.cc
      sql/item_sum.h
      sql/item_timefunc.cc
      sql/item_timefunc.h
      sql/procedure.h
 3554 Bernt M. Johnsen	2011-11-09
      WL#946 Added fractions to mysql_client_test.c

    modified:
      tests/mysql_client_test.c
=== modified file 'mysql-test/r/type_temporal_fractional.result'
--- a/mysql-test/r/type_temporal_fractional.result	2011-11-07 11:50:35 +0000
+++ b/mysql-test/r/type_temporal_fractional.result	2011-11-10 14:58:23 +0000
@@ -14605,6 +14605,292 @@ a + b
 99991231235960.000000
 DROP TABLE t1;
 #
+# Testing that IF always returns correct number of decimal digits
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+SELECT if(0, dt2, t3), CONCAT(if(0, dt2, t3)) FROM t1;
+if(0, dt2, t3)	CONCAT(if(0, dt2, t3))
+2011-11-10 00:00:00.567	2011-11-10 00:00:00.567
+SELECT if(1, dt2, t3), CONCAT(if(1, dt2, t3)) FROM t1;
+if(1, dt2, t3)	CONCAT(if(1, dt2, t3))
+2001-01-01 00:00:00.120	2001-01-01 00:00:00.120
+SELECT if(0, t3, dt2), CONCAT(if(0, t3, dt2)) FROM t1;
+if(0, t3, dt2)	CONCAT(if(0, t3, dt2))
+2001-01-01 00:00:00.120	2001-01-01 00:00:00.120
+SELECT if(1, t3, dt2), CONCAT(if(1, t3, dt2)) FROM t1;
+if(1, t3, dt2)	CONCAT(if(1, t3, dt2))
+2011-11-10 00:00:00.567	2011-11-10 00:00:00.567
+SELECT if(0, t3, d), CONCAT(if(0, t3, d)) FROM t1;
+if(0, t3, d)	CONCAT(if(0, t3, d))
+2002-01-01 00:00:00.000	2002-01-01 00:00:00.000
+SELECT if(1, t3, d), CONCAT(if(1, t3, d)) FROM t1;
+if(1, t3, d)	CONCAT(if(1, t3, d))
+2011-11-10 00:00:00.567	2011-11-10 00:00:00.567
+SELECT if(0, d, t3), CONCAT(if(0, d, t3)) FROM t1;
+if(0, d, t3)	CONCAT(if(0, d, t3))
+2011-11-10 00:00:00.567	2011-11-10 00:00:00.567
+SELECT if(1, d, t3), CONCAT(if(1, d, t3)) FROM t1;
+if(1, d, t3)	CONCAT(if(1, d, t3))
+2002-01-01 00:00:00.000	2002-01-01 00:00:00.000
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+#
+# Testing that CASE always returns correct number of decimal digits
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+SELECT CASE WHEN 0 THEN dt2 ELSE t3 END FROM t1;
+CASE WHEN 0 THEN dt2 ELSE t3 END
+2011-11-10 00:00:00.567
+SELECT CONCAT(CASE WHEN 0 THEN dt2 ELSE t3 END) FROM t1;
+CONCAT(CASE WHEN 0 THEN dt2 ELSE t3 END)
+2011-11-10 00:00:00.567
+SELECT CASE WHEN 1 THEN dt2 ELSE t3 END FROM t1;
+CASE WHEN 1 THEN dt2 ELSE t3 END
+2001-01-01 00:00:00.120
+SELECT CONCAT(CASE WHEN 1 THEN dt2 ELSE t3 END) FROM t1;
+CONCAT(CASE WHEN 1 THEN dt2 ELSE t3 END)
+2001-01-01 00:00:00.120
+SELECT CASE WHEN 0 THEN t3 ELSE dt2 END FROM t1;
+CASE WHEN 0 THEN t3 ELSE dt2 END
+2001-01-01 00:00:00.120
+SELECT CONCAT(CASE WHEN 0 THEN t3 ELSE dt2 END) FROM t1;
+CONCAT(CASE WHEN 0 THEN t3 ELSE dt2 END)
+2001-01-01 00:00:00.120
+SELECT CASE WHEN 1 THEN t3 ELSE dt2 END FROM t1;
+CASE WHEN 1 THEN t3 ELSE dt2 END
+2011-11-10 00:00:00.567
+SELECT CONCAT(CASE WHEN 1 THEN t3 ELSE dt2 END) FROM t1;
+CONCAT(CASE WHEN 1 THEN t3 ELSE dt2 END)
+2011-11-10 00:00:00.567
+SELECT CASE WHEN 0 THEN d ELSE t3 END FROM t1;
+CASE WHEN 0 THEN d ELSE t3 END
+2011-11-10 00:00:00.567
+SELECT CONCAT(CASE WHEN 0 THEN d ELSE t3 END) FROM t1;
+CONCAT(CASE WHEN 0 THEN d ELSE t3 END)
+2011-11-10 00:00:00.567
+SELECT CASE WHEN 1 THEN d ELSE t3 END FROM t1;
+CASE WHEN 1 THEN d ELSE t3 END
+2002-01-01 00:00:00.000
+SELECT CONCAT(CASE WHEN 1 THEN d ELSE t3 END) FROM t1;
+CONCAT(CASE WHEN 1 THEN d ELSE t3 END)
+2002-01-01 00:00:00.000
+SELECT CASE WHEN 0 THEN t3 ELSE d END FROM t1;
+CASE WHEN 0 THEN t3 ELSE d END
+2002-01-01 00:00:00.000
+SELECT CONCAT(CASE WHEN 0 THEN t3 ELSE d END) FROM t1;
+CONCAT(CASE WHEN 0 THEN t3 ELSE d END)
+2002-01-01 00:00:00.000
+SELECT CASE WHEN 1 THEN t3 ELSE d END FROM t1;
+CASE WHEN 1 THEN t3 ELSE d END
+2011-11-10 00:00:00.567
+SELECT CONCAT(CASE WHEN 1 THEN t3 ELSE d END) FROM t1;
+CONCAT(CASE WHEN 1 THEN t3 ELSE d END)
+2011-11-10 00:00:00.567
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+#
+# Testing that COALESCE always returns correct number of decimal digits
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+SELECT COALESCE(dt2, t3) FROM t1;
+COALESCE(dt2, t3)
+2001-01-01 00:00:00.120
+SELECT CONCAT(COALESCE(dt2, t3)) FROM t1;
+CONCAT(COALESCE(dt2, t3))
+2001-01-01 00:00:00.120
+SELECT COALESCE(t3, dt2) FROM t1;
+COALESCE(t3, dt2)
+2011-11-10 00:00:00.567
+SELECT CONCAT(COALESCE(t3, dt2)) FROM t1;
+CONCAT(COALESCE(t3, dt2))
+2011-11-10 00:00:00.567
+SELECT COALESCE(d, t3) FROM t1;
+COALESCE(d, t3)
+2002-01-01 00:00:00.000
+SELECT CONCAT(COALESCE(d, t3)) FROM t1;
+CONCAT(COALESCE(d, t3))
+2002-01-01 00:00:00.000
+SELECT COALESCE(t3, d) FROM t1;
+COALESCE(t3, d)
+2011-11-10 00:00:00.567
+SELECT CONCAT(COALESCE(t3, d)) FROM t1;
+CONCAT(COALESCE(t3, d))
+2011-11-10 00:00:00.567
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+#
+# Testing that IFNULL always returns correct number of decimal digits
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+SELECT IFNULL(dt2, t3) FROM t1;
+IFNULL(dt2, t3)
+2001-01-01 00:00:00.120
+SELECT CONCAT(IFNULL(dt2, t3)) FROM t1;
+CONCAT(IFNULL(dt2, t3))
+2001-01-01 00:00:00.120
+SELECT IFNULL(t3, dt2) FROM t1;
+IFNULL(t3, dt2)
+2011-11-10 00:00:00.567
+SELECT CONCAT(IFNULL(t3, dt2)) FROM t1;
+CONCAT(IFNULL(t3, dt2))
+2011-11-10 00:00:00.567
+SELECT IFNULL(d, t3) FROM t1;
+IFNULL(d, t3)
+2002-01-01 00:00:00.000
+SELECT CONCAT(IFNULL(d, t3)) FROM t1;
+CONCAT(IFNULL(d, t3))
+2002-01-01 00:00:00.000
+SELECT IFNULL(t3, d) FROM t1;
+IFNULL(t3, d)
+2011-11-10 00:00:00.567
+SELECT CONCAT(IFNULL(t3, d)) FROM t1;
+CONCAT(IFNULL(t3, d))
+2011-11-10 00:00:00.567
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+#
+# Testing that LEAST always returns correct number of decimal digits
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+INSERT INTO t1 VALUES ('2012-01-01 00:00:00.12', '00:00:00.567', '2013-01-01');
+SELECT LEAST(dt2, t3) FROM t1;
+LEAST(dt2, t3)
+2001-01-01 00:00:00.120
+2011-11-10 00:00:00.567
+SELECT CONCAT(LEAST(dt2, t3)) FROM t1;
+CONCAT(LEAST(dt2, t3))
+2001-01-01 00:00:00.120
+2011-11-10 00:00:00.567
+SELECT LEAST(t3, dt2) FROM t1;
+LEAST(t3, dt2)
+2001-01-01 00:00:00.120
+2011-11-10 00:00:00.567
+SELECT CONCAT(LEAST(t3, dt2)) FROM t1;
+CONCAT(LEAST(t3, dt2))
+2001-01-01 00:00:00.120
+2011-11-10 00:00:00.567
+SELECT LEAST(d, t3) FROM t1;
+LEAST(d, t3)
+2002-01-01 00:00:00.000
+2011-11-10 00:00:00.567
+SELECT CONCAT(LEAST(d, t3)) FROM t1;
+CONCAT(LEAST(d, t3))
+2002-01-01 00:00:00.000
+2011-11-10 00:00:00.567
+SELECT LEAST(t3, d) FROM t1;
+LEAST(t3, d)
+2002-01-01 00:00:00.000
+2011-11-10 00:00:00.567
+SELECT CONCAT(LEAST(t3, d)) FROM t1;
+CONCAT(LEAST(t3, d))
+2002-01-01 00:00:00.000
+2011-11-10 00:00:00.567
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+#
+# Testing that GREATEST always returns correct number of decimal digits
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+INSERT INTO t1 VALUES ('2012-01-01 00:00:00.12', '00:00:00.567', '2013-01-01');
+SELECT GREATEST(dt2, t3) FROM t1;
+GREATEST(dt2, t3)
+2011-11-10 00:00:00.567
+2012-01-01 00:00:00.120
+SELECT CONCAT(GREATEST(dt2, t3)) FROM t1;
+CONCAT(GREATEST(dt2, t3))
+2011-11-10 00:00:00.567
+2012-01-01 00:00:00.120
+SELECT GREATEST(t3, dt2) FROM t1;
+GREATEST(t3, dt2)
+2011-11-10 00:00:00.567
+2012-01-01 00:00:00.120
+SELECT CONCAT(GREATEST(t3, dt2)) FROM t1;
+CONCAT(GREATEST(t3, dt2))
+2011-11-10 00:00:00.567
+2012-01-01 00:00:00.120
+SELECT GREATEST(d, t3) FROM t1;
+GREATEST(d, t3)
+2011-11-10 00:00:00.567
+2013-01-01 00:00:00.000
+SELECT CONCAT(GREATEST(d, t3)) FROM t1;
+CONCAT(GREATEST(d, t3))
+2011-11-10 00:00:00.567
+2013-01-01 00:00:00.000
+SELECT GREATEST(t3, d) FROM t1;
+GREATEST(t3, d)
+2011-11-10 00:00:00.567
+2013-01-01 00:00:00.000
+SELECT CONCAT(GREATEST(t3, d)) FROM t1;
+CONCAT(GREATEST(t3, d))
+2011-11-10 00:00:00.567
+2013-01-01 00:00:00.000
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+#
+# Testing that hybrid type functions correctly convert
+# from DATETIME to TIME
+#
+CREATE TABLE t1 (a DATETIME(3));
+INSERT INTO t1 VALUES ('2001-01-01 10:20:30.123');
+SELECT CAST(IF(0, a, a) AS TIME(6)) FROM t1;
+CAST(IF(0, a, a) AS TIME(6))
+10:20:30.123000
+SELECT CAST(COALESCE(a, a) AS TIME(6)) FROM t1;
+CAST(COALESCE(a, a) AS TIME(6))
+10:20:30.123000
+SELECT CAST(IFNULL(a, a) AS TIME(6)) FROM t1;
+CAST(IFNULL(a, a) AS TIME(6))
+10:20:30.123000
+SELECT CAST(CASE WHEN 0 THEN a ELSE a END AS TIME(6)) FROM t1;
+CAST(CASE WHEN 0 THEN a ELSE a END AS TIME(6))
+10:20:30.123000
+SELECT CAST(GREATEST(a, a) AS TIME(6)) FROM t1;
+CAST(GREATEST(a, a) AS TIME(6))
+10:20:30.123000
+SELECT CAST(LEAST(a, a) AS TIME(6)) FROM t1;
+CAST(LEAST(a, a) AS TIME(6))
+10:20:30.123000
+DROP TABLE t1;
+#
+# Testing that hybrid type functions correctly convert
+# from TIME to DATETIME
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 00:00:00');
+CREATE TABLE t1 (a TIME(3));
+INSERT INTO t1 VALUES ('10:20:30.123');
+SELECT CAST(IF(0, a, a) AS DATETIME(6)) FROM t1;
+CAST(IF(0, a, a) AS DATETIME(6))
+2011-11-10 10:20:30.123000
+SELECT CAST(COALESCE(a, a) AS DATETIME(6)) FROM t1;
+CAST(COALESCE(a, a) AS DATETIME(6))
+2011-11-10 10:20:30.123000
+SELECT CAST(IFNULL(a, a) AS DATETIME(6)) FROM t1;
+CAST(IFNULL(a, a) AS DATETIME(6))
+2011-11-10 10:20:30.123000
+SELECT CAST(CASE WHEN 0 THEN a ELSE a END AS DATETIME(6)) FROM t1;
+CAST(CASE WHEN 0 THEN a ELSE a END AS DATETIME(6))
+2011-11-10 10:20:30.123000
+SELECT CAST(GREATEST(a, a) AS DATETIME(6)) FROM t1;
+CAST(GREATEST(a, a) AS DATETIME(6))
+2011-11-10 10:20:30.123000
+SELECT CAST(LEAST(a, a) AS DATETIME(6)) FROM t1;
+CAST(LEAST(a, a) AS DATETIME(6))
+2011-11-10 10:20:30.123000
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+#
 # Storing TIME functions into VARCHAR column
 #
 SET @@timestamp=1000000000;
@@ -16020,3 +16306,20 @@ c1	c2	c3
 2008-05-21 10:53:59.004633	0000-00-00 00:00:00	2001-11-07
 DROP TABLE t1;
 SET timestamp=DEFAULT;
+#
+# Bug#13359097 ASSERT FAILURE IN MAKE_SORTKEY
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-01 17:48:00');
+CREATE TABLE t1 (
+pk time(6) NOT NULL DEFAULT '00:00:00.000000',
+col_date_not_null date NOT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t1 VALUES ('00:00:00.000000','2001-09-10');
+INSERT INTO t1 VALUES ('12:07:41.148239','2000-05-23');
+SELECT GREATEST('2004-04-07', COALESCE (pk, col_date_not_null)) FROM  t1 ORDER BY 1;
+GREATEST('2004-04-07', COALESCE (pk, col_date_not_null))
+2011-11-01 00:00:00.000000
+2011-11-01 12:07:41.148239
+DROP TABLE t1;
+SET timestamp=DEFAULT;

=== modified file 'mysql-test/t/type_temporal_fractional.test'
--- a/mysql-test/t/type_temporal_fractional.test	2011-11-07 11:50:35 +0000
+++ b/mysql-test/t/type_temporal_fractional.test	2011-11-10 14:58:23 +0000
@@ -5578,6 +5578,150 @@ SELECT a + b FROM t1;
 DROP TABLE t1;
 
 --echo #
+--echo # Testing that IF always returns correct number of decimal digits
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+SELECT if(0, dt2, t3), CONCAT(if(0, dt2, t3)) FROM t1;
+SELECT if(1, dt2, t3), CONCAT(if(1, dt2, t3)) FROM t1;
+SELECT if(0, t3, dt2), CONCAT(if(0, t3, dt2)) FROM t1;
+SELECT if(1, t3, dt2), CONCAT(if(1, t3, dt2)) FROM t1;
+SELECT if(0, t3, d), CONCAT(if(0, t3, d)) FROM t1;
+SELECT if(1, t3, d), CONCAT(if(1, t3, d)) FROM t1;
+SELECT if(0, d, t3), CONCAT(if(0, d, t3)) FROM t1;
+SELECT if(1, d, t3), CONCAT(if(1, d, t3)) FROM t1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+--echo #
+--echo # Testing that CASE always returns correct number of decimal digits
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+SELECT CASE WHEN 0 THEN dt2 ELSE t3 END FROM t1;
+SELECT CONCAT(CASE WHEN 0 THEN dt2 ELSE t3 END) FROM t1;
+SELECT CASE WHEN 1 THEN dt2 ELSE t3 END FROM t1;
+SELECT CONCAT(CASE WHEN 1 THEN dt2 ELSE t3 END) FROM t1;
+SELECT CASE WHEN 0 THEN t3 ELSE dt2 END FROM t1;
+SELECT CONCAT(CASE WHEN 0 THEN t3 ELSE dt2 END) FROM t1;
+SELECT CASE WHEN 1 THEN t3 ELSE dt2 END FROM t1;
+SELECT CONCAT(CASE WHEN 1 THEN t3 ELSE dt2 END) FROM t1;
+SELECT CASE WHEN 0 THEN d ELSE t3 END FROM t1;
+SELECT CONCAT(CASE WHEN 0 THEN d ELSE t3 END) FROM t1;
+SELECT CASE WHEN 1 THEN d ELSE t3 END FROM t1;
+SELECT CONCAT(CASE WHEN 1 THEN d ELSE t3 END) FROM t1;
+SELECT CASE WHEN 0 THEN t3 ELSE d END FROM t1;
+SELECT CONCAT(CASE WHEN 0 THEN t3 ELSE d END) FROM t1;
+SELECT CASE WHEN 1 THEN t3 ELSE d END FROM t1;
+SELECT CONCAT(CASE WHEN 1 THEN t3 ELSE d END) FROM t1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+
+--echo #
+--echo # Testing that COALESCE always returns correct number of decimal digits
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+SELECT COALESCE(dt2, t3) FROM t1;
+SELECT CONCAT(COALESCE(dt2, t3)) FROM t1;
+SELECT COALESCE(t3, dt2) FROM t1;
+SELECT CONCAT(COALESCE(t3, dt2)) FROM t1;
+SELECT COALESCE(d, t3) FROM t1;
+SELECT CONCAT(COALESCE(d, t3)) FROM t1;
+SELECT COALESCE(t3, d) FROM t1;
+SELECT CONCAT(COALESCE(t3, d)) FROM t1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+--echo #
+--echo # Testing that IFNULL always returns correct number of decimal digits
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+SELECT IFNULL(dt2, t3) FROM t1;
+SELECT CONCAT(IFNULL(dt2, t3)) FROM t1;
+SELECT IFNULL(t3, dt2) FROM t1;
+SELECT CONCAT(IFNULL(t3, dt2)) FROM t1;
+SELECT IFNULL(d, t3) FROM t1;
+SELECT CONCAT(IFNULL(d, t3)) FROM t1;
+SELECT IFNULL(t3, d) FROM t1;
+SELECT CONCAT(IFNULL(t3, d)) FROM t1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+--echo #
+--echo # Testing that LEAST always returns correct number of decimal digits
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+INSERT INTO t1 VALUES ('2012-01-01 00:00:00.12', '00:00:00.567', '2013-01-01');
+SELECT LEAST(dt2, t3) FROM t1;
+SELECT CONCAT(LEAST(dt2, t3)) FROM t1;
+SELECT LEAST(t3, dt2) FROM t1;
+SELECT CONCAT(LEAST(t3, dt2)) FROM t1;
+SELECT LEAST(d, t3) FROM t1;
+SELECT CONCAT(LEAST(d, t3)) FROM t1;
+SELECT LEAST(t3, d) FROM t1;
+SELECT CONCAT(LEAST(t3, d)) FROM t1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+--echo #
+--echo # Testing that GREATEST always returns correct number of decimal digits
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 18:04:30');
+CREATE TABLE t1 (dt2 DATETIME(2), t3 TIME(3), d DATE);
+INSERT INTO t1 VALUES ('2001-01-01 00:00:00.12', '00:00:00.567', '2002-01-01');
+INSERT INTO t1 VALUES ('2012-01-01 00:00:00.12', '00:00:00.567', '2013-01-01');
+SELECT GREATEST(dt2, t3) FROM t1;
+SELECT CONCAT(GREATEST(dt2, t3)) FROM t1;
+SELECT GREATEST(t3, dt2) FROM t1;
+SELECT CONCAT(GREATEST(t3, dt2)) FROM t1;
+SELECT GREATEST(d, t3) FROM t1;
+SELECT CONCAT(GREATEST(d, t3)) FROM t1;
+SELECT GREATEST(t3, d) FROM t1;
+SELECT CONCAT(GREATEST(t3, d)) FROM t1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+--echo #
+--echo # Testing that hybrid type functions correctly convert
+--echo # from DATETIME to TIME
+--echo #
+CREATE TABLE t1 (a DATETIME(3));
+INSERT INTO t1 VALUES ('2001-01-01 10:20:30.123');
+SELECT CAST(IF(0, a, a) AS TIME(6)) FROM t1;
+SELECT CAST(COALESCE(a, a) AS TIME(6)) FROM t1;
+SELECT CAST(IFNULL(a, a) AS TIME(6)) FROM t1;
+SELECT CAST(CASE WHEN 0 THEN a ELSE a END AS TIME(6)) FROM t1;
+SELECT CAST(GREATEST(a, a) AS TIME(6)) FROM t1;
+SELECT CAST(LEAST(a, a) AS TIME(6)) FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that hybrid type functions correctly convert
+--echo # from TIME to DATETIME
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-10 00:00:00');
+CREATE TABLE t1 (a TIME(3));
+INSERT INTO t1 VALUES ('10:20:30.123');
+SELECT CAST(IF(0, a, a) AS DATETIME(6)) FROM t1;
+SELECT CAST(COALESCE(a, a) AS DATETIME(6)) FROM t1;
+SELECT CAST(IFNULL(a, a) AS DATETIME(6)) FROM t1;
+SELECT CAST(CASE WHEN 0 THEN a ELSE a END AS DATETIME(6)) FROM t1;
+SELECT CAST(GREATEST(a, a) AS DATETIME(6)) FROM t1;
+SELECT CAST(LEAST(a, a) AS DATETIME(6)) FROM t1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+--echo #
 --echo # Storing TIME functions into VARCHAR column
 --echo #
 SET @@timestamp=1000000000;
@@ -6809,8 +6953,23 @@ ORDER BY col_datetime_4_not_null_key , c
 DROP TABLE t1;
 SET timestamp=DEFAULT;
 
+--echo #
+--echo # Bug#13359097 ASSERT FAILURE IN MAKE_SORTKEY
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-01 17:48:00');
+CREATE TABLE t1 (
+  pk time(6) NOT NULL DEFAULT '00:00:00.000000',
+  col_date_not_null date NOT NULL,
+  PRIMARY KEY (pk)
+);
+INSERT INTO t1 VALUES ('00:00:00.000000','2001-09-10');
+INSERT INTO t1 VALUES ('12:07:41.148239','2000-05-23');
+SELECT GREATEST('2004-04-07', COALESCE (pk, col_date_not_null)) FROM  t1 ORDER BY 1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+
 ## TS-TODO: SELECT CAST('00:00:00' AS DATETIME) -> should it use curdate?
-## TS-TODO: Item::get_date() works via string for DECIMAL_RESULT/FLOAT_RESULT: select cast(20110512154559.616 as date)
 
 ## TS-TODO: reuse count_datetime_length()/count_string_result_length()
 ## in other hybrid functions: IF,CASE,GREATEST,LEAST
@@ -6849,5 +7008,3 @@ SET timestamp=DEFAULT;
 ## alter session set nls_timestamp_format='YYYY-MM-DD HH24:MI:SS.FF';
 ##select * from t1 where a=b;
 ##2011-04-09 15:36:32.225000 2011-04-09 15:36:32.225
-
-

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2011-11-01 11:52:24 +0000
+++ b/sql/item.cc	2011-11-10 14:58:23 +0000
@@ -275,6 +275,41 @@ String *Item::val_string_from_decimal(St
 }
 
 
+String *Item::val_string_from_datetime(String *str)
+{
+  DBUG_ASSERT(fixed == 1);
+  MYSQL_TIME ltime;
+  if (get_date(&ltime, 0) ||
+      (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
+    return (String *) 0;
+  make_datetime((DATE_TIME_FORMAT *) 0, &ltime, str, decimals);
+  return str;
+}
+
+
+String *Item::val_string_from_date(String *str)
+{
+  DBUG_ASSERT(fixed == 1);
+  MYSQL_TIME ltime;
+  if (get_date(&ltime, 0) ||
+      (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
+    return (String *) 0;
+  make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
+  return str;
+}
+
+
+String *Item::val_string_from_time(String *str)
+{
+  DBUG_ASSERT(fixed == 1);
+  MYSQL_TIME ltime;
+  if (get_time(&ltime) || (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
+    return (String *) 0;
+  make_time((DATE_TIME_FORMAT *) 0, &ltime, str, decimals);
+  return str;
+}
+
+
 my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value)
 {
   double nr= val_real();
@@ -428,6 +463,34 @@ longlong Item::val_int_from_decimal()
   return result;
 }
 
+
+longlong Item::val_int_from_time()
+{
+  DBUG_ASSERT(fixed == 1);
+  MYSQL_TIME ltime;
+  return get_time(&ltime) ?
+         0LL : (ltime.neg ? -1 : 1) * TIME_to_ulonglong_time_round(&ltime);
+}
+
+
+longlong Item::val_int_from_date()
+{
+  DBUG_ASSERT(fixed == 1);
+  MYSQL_TIME ltime;
+  return get_date(&ltime, TIME_FUZZY_DATE) ?
+         0LL : (longlong) TIME_to_ulonglong_date(&ltime);
+}
+
+
+longlong Item::val_int_from_datetime()
+{
+  DBUG_ASSERT(fixed == 1);
+  MYSQL_TIME ltime;
+  return get_date(&ltime, 0) ?
+         0LL: (longlong) TIME_to_ulonglong_datetime_round(&ltime);
+}
+
+
 int Item::save_time_in_field(Field *field)
 {
   MYSQL_TIME ltime;
@@ -1151,12 +1214,32 @@ bool Item::get_date_from_time(MYSQL_TIME
 }
 
 
+bool Item::get_date_from_numeric(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  switch (result_type())
+  {
+  case REAL_RESULT:
+    return get_date_from_real(ltime, fuzzydate);
+  case DECIMAL_RESULT:
+    return get_date_from_decimal(ltime, fuzzydate);
+  case INT_RESULT:
+    return get_date_from_int(ltime, fuzzydate);
+  case STRING_RESULT:
+  case ROW_RESULT:
+    DBUG_ASSERT(0);
+  }
+  return (null_value= true);  // Impossible result_type
+}
+
+
 /**
   Get the value of the function as a MYSQL_TIME structure.
   As a extra convenience the time structure is reset on error!
 */
-bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate)
+
+bool Item::get_date_from_non_temporal(MYSQL_TIME *ltime, uint fuzzydate)
 {
+  DBUG_ASSERT(!is_temporal());
   switch (result_type())
   {
   case STRING_RESULT:
@@ -1170,7 +1253,7 @@ bool Item::get_date(MYSQL_TIME *ltime,ui
   case ROW_RESULT:
     DBUG_ASSERT(0);
   }
-  return true;
+  return (null_value= true);  // Impossible result_type
 }
 
 
@@ -1224,13 +1307,56 @@ bool Item::get_time_from_int(MYSQL_TIME 
 }
 
 
+bool Item::get_time_from_date(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed == 1);
+  if (get_date(ltime, TIME_FUZZY_DATE)) // Need this check if NULL value
+    return true;
+  set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+  return false;
+}
+
+
+bool Item::get_time_from_datetime(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed == 1);
+  if (get_date(ltime, TIME_FUZZY_DATE))
+    return true;
+  datetime_to_time(ltime);
+  return false;
+}
+
+
+bool Item::get_time_from_numeric(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(!is_temporal());
+  switch (result_type())
+  {
+  case REAL_RESULT:
+    return get_time_from_real(ltime);
+  case DECIMAL_RESULT:
+    return get_time_from_decimal(ltime);
+  case INT_RESULT:
+    return get_time_from_int(ltime);
+  case STRING_RESULT:
+  case ROW_RESULT:
+    DBUG_ASSERT(0);
+  }
+  return (null_value= true); // Impossible result type
+}
+ 
+
+
+
 /**
-  Get time value.
+  Get time value from int, real, decimal or string.
 
   As a extra convenience the time structure is reset on error!
 */
-bool Item::get_time(MYSQL_TIME *ltime)
+
+bool Item::get_time_from_non_temporal(MYSQL_TIME *ltime)
 {
+  DBUG_ASSERT(!is_temporal());
   switch (result_type())
   {
   case STRING_RESULT:
@@ -1417,6 +1543,22 @@ my_decimal *Item_sp_variable::val_decima
 }
 
 
+bool Item_sp_variable::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  DBUG_ASSERT(fixed);
+  Item *it= this_item();
+  return (null_value= it->get_date(ltime, fuzzydate));
+}
+
+
+bool Item_sp_variable::get_time(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed);
+  Item *it= this_item();
+  return (null_value= it->get_time(ltime));
+}
+
+
 bool Item_sp_variable::is_null()
 {
   return this_item()->is_null();
@@ -1574,6 +1716,20 @@ my_decimal *Item_name_const::val_decimal
 }
 
 
+bool Item_name_const::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  DBUG_ASSERT(fixed);
+  return (null_value= value_item->get_date(ltime, fuzzydate));
+}
+
+
+bool Item_name_const::get_time(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed);
+  return (null_value= value_item->get_time(ltime));
+}
+
+
 bool Item_name_const::is_null()
 {
   return value_item->is_null();
@@ -3490,9 +3646,10 @@ bool Item_param::get_time(MYSQL_TIME *re
   }
   /*
     If parameter value isn't supplied assertion will fire in val_str()
-    which is called from Item::get_time().
+    which is called from Item::get_time_from_string().    
   */
-  return Item::get_time(res);
+  return is_temporal() ? get_time_from_string(res) :
+                         get_time_from_non_temporal(res);
 }
 
 
@@ -3503,7 +3660,8 @@ bool Item_param::get_date(MYSQL_TIME *re
     *res= value.time;
     return 0;
   }
-  return Item::get_date(res, fuzzydate);
+  return is_temporal() ? get_date_from_string(res, fuzzydate) :
+                         get_date_from_non_temporal(res, fuzzydate);
 }
 
 
@@ -4094,6 +4252,16 @@ my_decimal *Item_copy_string::val_decima
 }
 
 
+bool Item_copy_string::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  return get_date_from_string(ltime, fuzzydate);
+}
+
+bool Item_copy_string::get_time(MYSQL_TIME *ltime)
+{
+  return get_time_from_string(ltime);
+}
+
 /****************************************************************************
   Item_copy_int
 ****************************************************************************/
@@ -8249,6 +8417,73 @@ my_decimal *Item_cache_datetime::val_dec
   return my_decimal_from_datetime_packed(decimal_val, field_type(), int_value);
 }
 
+
+bool Item_cache_datetime::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  if ((value_cached || str_value_cached) && null_value)
+    return true;
+
+  if (str_value_cached) // TS-TODO: reuse MYSQL_TIME_cache eventually.
+    return get_date_from_string(ltime, fuzzydate);
+
+  if ((!value_cached && !cache_value_int()) || null_value)
+    return (null_value= true);
+
+
+  switch (cached_field_type)
+  {
+  case MYSQL_TYPE_TIME:
+    {
+      MYSQL_TIME tm;
+      TIME_from_longlong_time_packed(&tm, int_value);
+      time_to_datetime(current_thd, &tm, ltime);
+      return false;
+    }
+  case MYSQL_TYPE_DATE:
+    TIME_from_longlong_date_packed(ltime, int_value);
+    return false;
+  case MYSQL_TYPE_DATETIME:
+  case MYSQL_TYPE_TIMESTAMP:
+    TIME_from_longlong_datetime_packed(ltime, int_value);
+    return false;
+  default:
+    DBUG_ASSERT(0);
+  }
+  return true;
+}
+
+
+bool Item_cache_datetime::get_time(MYSQL_TIME *ltime)
+{
+  if ((value_cached || str_value_cached) && null_value)
+    return true;
+
+  if (str_value_cached) // TS-TODO: reuse MYSQL_TIME_cache eventually.
+    return get_time_from_string(ltime);
+
+  if ((!value_cached && !cache_value_int()) || null_value)
+    return true;
+
+  switch (cached_field_type)
+  {
+  case MYSQL_TYPE_TIME:
+    TIME_from_longlong_time_packed(ltime, int_value);
+    return false;
+  case MYSQL_TYPE_DATE:
+    set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+    return false;
+  case MYSQL_TYPE_DATETIME:
+  case MYSQL_TYPE_TIMESTAMP:
+    TIME_from_longlong_datetime_packed(ltime, int_value);
+    datetime_to_time(ltime);
+    return false;
+  default:
+    DBUG_ASSERT(0);
+  }
+  return true;
+}
+
+
 double Item_cache_datetime::val_real()
 {
   return val_real_from_decimal();

=== modified file 'sql/item.h'
--- a/sql/item.h	2011-11-07 14:35:16 +0000
+++ b/sql/item.h	2011-11-10 14:58:23 +0000
@@ -884,16 +884,24 @@ public:
   */
   virtual bool val_bool();
   virtual String *val_nodeset(String*) { return 0; }
+
+protected:
   /* Helper functions, see item_sum.cc */
   String *val_string_from_real(String *str);
   String *val_string_from_int(String *str);
   String *val_string_from_decimal(String *str);
+  String *val_string_from_date(String *str);
+  String *val_string_from_datetime(String *str);
+  String *val_string_from_time(String *str);
   my_decimal *val_decimal_from_real(my_decimal *decimal_value);
   my_decimal *val_decimal_from_int(my_decimal *decimal_value);
   my_decimal *val_decimal_from_string(my_decimal *decimal_value);
   my_decimal *val_decimal_from_date(my_decimal *decimal_value);
   my_decimal *val_decimal_from_time(my_decimal *decimal_value);
   longlong val_int_from_decimal();
+  longlong val_int_from_date();
+  longlong val_int_from_time();
+  longlong val_int_from_datetime();
   double val_real_from_decimal();
 
   /**
@@ -918,6 +926,16 @@ public:
   bool get_date_from_time(MYSQL_TIME *ltime);
 
   /**
+    Convert a numeric type to date
+  */
+  bool get_date_from_numeric(MYSQL_TIME *ltime, uint fuzzydate);
+
+  /**
+    Convert a non-temporal type to date
+  */
+  bool get_date_from_non_temporal(MYSQL_TIME *ltime, uint fuzzydate);
+
+  /**
     Convert val_str() to time in MYSQL_TIME
   */
   bool get_time_from_string(MYSQL_TIME *ltime);
@@ -933,6 +951,27 @@ public:
     Convert val_int() to time in MYSQL_TIME
   */
   bool get_time_from_int(MYSQL_TIME *ltime);
+  /**
+    Convert date to time
+  */
+  bool get_time_from_date(MYSQL_TIME *ltime);
+  /**
+    Convert datetime to time
+  */
+  bool get_time_from_datetime(MYSQL_TIME *ltime);
+
+  /**
+    Convert a numeric type to time
+  */
+  bool get_time_from_numeric(MYSQL_TIME *ltime);
+
+  /**
+    Convert a non-temporal type to time
+  */
+  bool get_time_from_non_temporal(MYSQL_TIME *ltime);
+
+
+public:
 
   int save_time_in_field(Field *field);
   int save_date_in_field(Field *field);
@@ -1036,8 +1075,8 @@ public:
   void split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
                        List<Item> &fields,
                        Item **ref, bool skip_registered);
-  virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
-  virtual bool get_time(MYSQL_TIME *ltime);
+  virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate)= 0;
+  virtual bool get_time(MYSQL_TIME *ltime)= 0;
   /**
     Get timestamp in "struct timeval" format.
     @retval  false on success
@@ -1483,6 +1522,8 @@ public:
   longlong val_int();
   String *val_str(String *sp);
   my_decimal *val_decimal(my_decimal *decimal_value);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);
   bool is_null();
 
 public:
@@ -1695,6 +1736,8 @@ public:
   longlong val_int();
   String *val_str(String *sp);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);
   bool is_null();
   virtual void print(String *str, enum_query_type query_type);
 
@@ -1845,6 +1888,14 @@ public:
   longlong val_int() { return field->val_int(); }
   String *val_str(String *str) { return field->val_str(str); }
   my_decimal *val_decimal(my_decimal *dec) { return field->val_decimal(dec); }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return field->get_date(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return field->get_time(ltime);
+  }
   void make_field(Send_field *tmp_field);
   CHARSET_INFO *charset_for_protocol(void) const
   { return (CHARSET_INFO *)field->charset_for_protocol(); }
@@ -2021,6 +2072,14 @@ public:
   longlong val_date_temporal() { return val_int(); }
   String *val_str(String *str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return true;
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return true;
+  }
   int save_in_field(Field *field, bool no_conversions);
   int save_safe_in_field(Field *field);
   bool send(Protocol *protocol, String *str);
@@ -2238,6 +2297,14 @@ public:
   double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
   my_decimal *val_decimal(my_decimal *);
   String *val_str(String*);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   int save_in_field(Field *field, bool no_conversions);
   bool basic_const_item() const { return 1; }
   Item *clone_item() { return new Item_int(name,value,max_length); }
@@ -2266,6 +2333,16 @@ public:
   Item *clone_item() { return new Item_temporal(value); }
   longlong val_time_temporal() { return val_int(); }
   longlong val_date_temporal() { return val_int(); }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    DBUG_ASSERT(0);
+    return false;
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    DBUG_ASSERT(0);
+    return false;
+  }
   enum_field_types field_type() const
   {
     // Currently we don't need to distinguish between DATE, DATETIME, or TIME.
@@ -2313,6 +2390,14 @@ public:
   double val_real();
   String *val_str(String*);
   my_decimal *val_decimal(my_decimal *val) { return &decimal_value; }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_decimal(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_decimal(ltime);
+  }
   int save_in_field(Field *field, bool no_conversions);
   bool basic_const_item() const { return 1; }
   Item *clone_item()
@@ -2372,6 +2457,14 @@ public:
   }
   String *val_str(String*);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_real(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_real(ltime);
+  }
   bool basic_const_item() const { return 1; }
   Item *clone_item()
   { return new Item_float(name, value, decimals, max_length); }
@@ -2469,6 +2562,14 @@ public:
     return (String*) &str_value;
   }
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_string(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_string(ltime);
+  }
   int save_in_field(Field *field, bool no_conversions);
   enum Item_result result_type () const { return STRING_RESULT; }
   enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
@@ -2640,6 +2741,14 @@ public:
   bool basic_const_item() const { return 1; }
   String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_string(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_string(ltime);
+  }
   int save_in_field(Field *field, bool no_conversions);
   enum Item_result result_type () const { return STRING_RESULT; }
   enum Item_result cast_to_int_type() const { return INT_RESULT; }
@@ -3060,6 +3169,17 @@ public:
   }
   enum_field_types field_type() const { return cached_field_type; }
   void print(String *str, enum_query_type query_type);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    DBUG_ASSERT(0);
+    return true;
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    DBUG_ASSERT(0);
+    return true;
+  }
+
 };
 
 
@@ -3238,6 +3358,8 @@ public:
   virtual my_decimal *val_decimal(my_decimal *) = 0;
   virtual double val_real() = 0;
   virtual longlong val_int() = 0;
+  virtual bool get_date(MYSQL_TIME *ltime, uint fuzzydate)= 0;
+  virtual bool get_time(MYSQL_TIME *ltime)= 0;
   virtual int save_in_field(Field *field, bool no_conversions) = 0;
 };
 
@@ -3255,6 +3377,8 @@ public:
   my_decimal *val_decimal(my_decimal *);
   double val_real();
   longlong val_int();
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);
   void copy();
   int save_in_field(Field *field, bool no_conversions);
 };
@@ -3278,6 +3402,14 @@ public:
   {
     return null_value ? LL(0) : cached_value;
   }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   virtual void copy();
 };
 
@@ -3316,6 +3448,14 @@ public:
   {
     return (longlong) rint(val_real());
   }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_real(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_real(ltime);
+  }
   void copy()
   {
     cached_value= item->val_real();
@@ -3339,6 +3479,14 @@ public:
   }
   double val_real();
   longlong val_int();
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_decimal(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_decimal(ltime);
+  }
   void copy();
 };
 
@@ -3690,6 +3838,14 @@ public:
   longlong val_date_temporal() { return val_int(); }
   String* val_str(String *str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   enum Item_result result_type() const { return INT_RESULT; }
   bool cache_value();
 };
@@ -3706,6 +3862,14 @@ public:
   longlong val_int();
   String* val_str(String *str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_real(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_real(ltime);
+  }
   enum Item_result result_type() const { return REAL_RESULT; }
   bool cache_value();
 };
@@ -3722,6 +3886,14 @@ public:
   longlong val_int();
   String* val_str(String *str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_decimal(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_decimal(ltime);
+  }
   enum Item_result result_type() const { return DECIMAL_RESULT; }
   bool cache_value();
 };
@@ -3746,6 +3918,14 @@ public:
   longlong val_int();
   String* val_str(String *);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_string(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_string(ltime);
+  }
   enum Item_result result_type() const { return STRING_RESULT; }
   const CHARSET_INFO *charset() const { return value->charset(); };
   int save_in_field(Field *field, bool no_conversions);
@@ -3798,6 +3978,16 @@ public:
     illegal_method_call((const char*)"val_decimal");
     return 0;
   };
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    illegal_method_call((const char *) "get_date");
+    return true;
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    illegal_method_call((const char *) "get_time");
+    return true;
+  }
 
   enum Item_result result_type() const { return ROW_RESULT; }
   
@@ -3843,6 +4033,8 @@ public:
   longlong val_date_temporal();
   String* val_str(String *str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);
   enum Item_result result_type() const { return STRING_RESULT; }
   /*
     In order to avoid INT <-> STRING conversion of a DATETIME value
@@ -3885,6 +4077,16 @@ public:
   longlong val_int();
   my_decimal *val_decimal(my_decimal *);
   String *val_str(String*);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    DBUG_ASSERT(0);
+    return true;
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    DBUG_ASSERT(0);
+    return true;
+  }
   bool join_types(THD *thd, Item *);
   Field *make_field_by_type(TABLE *table);
   static uint32 display_length(Item *item);

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2011-11-02 06:13:46 +0000
+++ b/sql/item_cmpfunc.cc	2011-11-10 14:58:23 +0000
@@ -1523,8 +1523,25 @@ int Arg_comparator::compare_int_signed()
 */
 int Arg_comparator::compare_temporal_packed()
 {
-  //DBUG_ASSERT((*a)->field_type() == MYSQL_TYPE_TIME); // TS-TODO
-  //DBUG_ASSERT((*b)->field_type() == MYSQL_TYPE_TIME); // TS-TODO
+  /*
+    Note, we cannot do this:
+    DBUG_ASSERT((*a)->field_type() == MYSQL_TYPE_TIME);
+    DBUG_ASSERT((*b)->field_type() == MYSQL_TYPE_TIME);
+    
+    SELECT col_time_key FROM t1
+    WHERE
+      col_time_key != UTC_DATE()
+    AND
+      col_time_key = MAKEDATE(43, -2852);
+
+    is rewritten to:
+
+    SELECT col_time_key FROM t1
+    WHERE
+      MAKEDATE(43, -2852) != UTC_DATE()
+    AND
+      col_time_key = MAKEDATE(43, -2852);
+  */
   longlong val1= (*a)->val_time_temporal();
   if (!(*a)->null_value)
   {
@@ -2762,6 +2779,24 @@ my_decimal *Item_func_ifnull::decimal_op
 }
 
 
+bool Item_func_ifnull::date_op(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  DBUG_ASSERT(fixed == 1);
+  if (!args[0]->get_date(ltime, fuzzydate))
+    return (null_value= false);
+  return (null_value= args[1]->get_date(ltime, fuzzydate));
+}
+
+
+bool Item_func_ifnull::time_op(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed == 1);
+  if (!args[0]->get_time(ltime))
+    return (null_value= false);
+  return (null_value= args[1]->get_time(ltime));
+}
+
+
 String *
 Item_func_ifnull::str_op(String *str)
 {
@@ -2922,12 +2957,30 @@ String *
 Item_func_if::val_str(String *str)
 {
   DBUG_ASSERT(fixed == 1);
-  Item *arg= args[0]->val_bool() ? args[1] : args[2];
-  String *res=arg->val_str(str);
-  if (res)
-    res->set_charset(collation.collation);
-  null_value=arg->null_value;
-  return res;
+
+  switch (field_type())
+  {
+  case MYSQL_TYPE_DATETIME:
+  case MYSQL_TYPE_TIMESTAMP:
+    return val_string_from_datetime(str);
+  case MYSQL_TYPE_DATE:
+    return val_string_from_date(str);
+  case MYSQL_TYPE_TIME:
+    return val_string_from_time(str);
+  default:
+    {
+      Item *item= args[0]->val_bool() ? args[1] : args[2];
+      String *res;
+      if ((res= item->val_str(str)))
+      {
+        res->set_charset(collation.collation);
+        null_value= 0;
+        return res;   
+      }
+    }
+  }
+  null_value= true;
+  return (String *) 0;
 }
 
 
@@ -2942,6 +2995,22 @@ Item_func_if::val_decimal(my_decimal *de
 }
 
 
+bool Item_func_if::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  DBUG_ASSERT(fixed == 1);
+  Item *arg= args[0]->val_bool() ? args[1] : args[2];
+  return (null_value= arg->get_date(ltime, fuzzydate));
+}
+
+
+bool Item_func_if::get_time(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed == 1);
+  Item *arg= args[0]->val_bool() ? args[1] : args[2];
+  return (null_value= arg->get_time(ltime));
+}
+
+
 void
 Item_func_nullif::fix_length_and_dec()
 {
@@ -3103,18 +3172,31 @@ Item *Item_func_case::find_item(String *
 String *Item_func_case::val_str(String *str)
 {
   DBUG_ASSERT(fixed == 1);
-  String *res;
-  Item *item=find_item(str);
-
-  if (!item)
-  {
-    null_value=1;
-    return 0;
+  switch (field_type()) {
+  case MYSQL_TYPE_DATETIME:
+  case MYSQL_TYPE_TIMESTAMP:
+    return val_string_from_datetime(str);
+  case MYSQL_TYPE_DATE:
+    return val_string_from_date(str);
+  case MYSQL_TYPE_TIME:
+    return val_string_from_time(str);
+  default:
+    {
+      Item *item= find_item(str);
+      if (item)
+      {
+        String *res;
+        if ((res= item->val_str(str)))
+        {
+          res->set_charset(collation.collation);
+          null_value= 0;
+          return res;
+        }
+      }
+    }
   }
-  null_value= 0;
-  if (!(res=item->val_str(str)))
-    null_value= 1;
-  return res;
+  null_value= true;
+  return (String *) 0;
 }
 
 
@@ -3175,6 +3257,30 @@ my_decimal *Item_func_case::val_decimal(
 }
 
 
+bool Item_func_case::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  DBUG_ASSERT(fixed == 1);
+  char buff[MAX_FIELD_WIDTH];
+  String dummy_str(buff, sizeof(buff), default_charset());
+  Item *item= find_item(&dummy_str);
+  if (!item)
+    return (null_value= true);
+  return (null_value= item->get_date(ltime, fuzzydate));
+}
+
+
+bool Item_func_case::get_time(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed == 1);
+  char buff[MAX_FIELD_WIDTH];
+  String dummy_str(buff, sizeof(buff), default_charset());
+  Item *item= find_item(&dummy_str);
+  if (!item)
+    return (null_value= true);
+  return (null_value= item->get_time(ltime));
+}
+
+
 bool Item_func_case::fix_fields(THD *thd, Item **ref)
 {
   /*
@@ -3486,6 +3592,31 @@ my_decimal *Item_func_coalesce::decimal_
 }
 
 
+
+bool Item_func_coalesce::date_op(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  DBUG_ASSERT(fixed == 1);
+  for (uint i= 0; i < arg_count; i++)
+  {
+    if (!args[i]->get_date(ltime, fuzzydate))
+      return (null_value= false);
+  }
+  return (null_value= true);
+}
+
+
+bool Item_func_coalesce::time_op(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed == 1);
+  for (uint i= 0; i < arg_count; i++)
+  {
+    if (!args[i]->get_time(ltime))
+      return (null_value= false);
+  }
+  return (null_value= true);
+}
+
+
 void Item_func_coalesce::fix_length_and_dec()
 {
   cached_field_type= agg_field_type(args, arg_count);

=== modified file 'sql/item_cmpfunc.h'
--- a/sql/item_cmpfunc.h	2011-11-01 11:52:24 +0000
+++ b/sql/item_cmpfunc.h	2011-11-10 14:58:23 +0000
@@ -780,6 +780,8 @@ public:
   double real_op();
   longlong int_op();
   String *str_op(String *);
+  bool date_op(MYSQL_TIME *ltime, uint fuzzydate);
+  bool time_op(MYSQL_TIME *ltime);
   my_decimal *decimal_op(my_decimal *);
   void fix_length_and_dec();
   void find_num_type() {}
@@ -799,6 +801,8 @@ public:
   double real_op();
   longlong int_op();
   String *str_op(String *str);
+  bool date_op(MYSQL_TIME *ltime, uint fuzzydate);
+  bool time_op(MYSQL_TIME *ltime);
   my_decimal *decimal_op(my_decimal *);
   void fix_length_and_dec();
   const char *func_name() const { return "ifnull"; }
@@ -819,6 +823,8 @@ public:
   longlong val_int();
   String *val_str(String *str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);
   enum Item_result result_type () const { return cached_result_type; }
   enum_field_types field_type() const { return cached_field_type; }
   bool fix_fields(THD *, Item **);
@@ -1305,6 +1311,8 @@ public:
   longlong val_int();
   String *val_str(String *);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);
   bool fix_fields(THD *thd, Item **ref);
   void fix_length_and_dec();
   uint decimal_precision() const;

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2011-11-01 11:52:24 +0000
+++ b/sql/item_func.cc	2011-11-10 14:58:23 +0000
@@ -898,6 +898,16 @@ String *Item_func_numhybrid::val_str(Str
     break;
   }
   case STRING_RESULT:
+    switch (field_type()) {
+    case MYSQL_TYPE_DATETIME:
+      return val_string_from_datetime(str);
+    case MYSQL_TYPE_DATE:
+      return val_string_from_date(str);
+    case MYSQL_TYPE_TIME:
+      return val_string_from_time(str);
+    default:
+      break;
+    }
     return str_op(&str_value);
   default:
     DBUG_ASSERT(0);
@@ -928,6 +938,15 @@ double Item_func_numhybrid::val_real()
     return real_op();
   case STRING_RESULT:
   {
+    switch (field_type())
+    {
+    case MYSQL_TYPE_TIME:
+    case MYSQL_TYPE_DATE:
+    case MYSQL_TYPE_DATETIME:
+      return val_real_from_decimal();
+    default:
+      break;
+    }
     char *end_not_used;
     int err_not_used;
     String *res= str_op(&str_value);
@@ -960,6 +979,17 @@ longlong Item_func_numhybrid::val_int()
     return (longlong) rint(real_op());
   case STRING_RESULT:
   {
+    switch (field_type())
+    {
+    case MYSQL_TYPE_DATE:
+      return val_int_from_date();
+    case MYSQL_TYPE_DATETIME:
+      return val_int_from_datetime();
+    case MYSQL_TYPE_TIME:
+      return val_int_from_time();
+    default:
+      break;
+    }
     int err_not_used;
     String *res;
     if (!(res= str_op(&str_value)))
@@ -998,6 +1028,16 @@ my_decimal *Item_func_numhybrid::val_dec
   }
   case STRING_RESULT:
   {
+    switch (field_type())
+    {
+    case MYSQL_TYPE_DATE:
+    case MYSQL_TYPE_DATETIME:
+      return val_decimal_from_date(decimal_value);
+    case MYSQL_TYPE_TIME:
+      return val_decimal_from_time(decimal_value);
+    default:
+      break;
+    }
     String *res;
     if (!(res= str_op(&str_value)))
       return NULL;
@@ -1014,6 +1054,39 @@ my_decimal *Item_func_numhybrid::val_dec
 }
 
 
+bool Item_func_numhybrid::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  DBUG_ASSERT(fixed == 1);
+  switch (field_type())
+  {
+  case MYSQL_TYPE_DATE:
+  case MYSQL_TYPE_DATETIME:
+    return date_op(ltime, fuzzydate);
+  case MYSQL_TYPE_TIME:
+    return get_date_from_time(ltime);
+  default:
+    return Item::get_date_from_non_temporal(ltime, fuzzydate);
+  }
+}
+
+
+bool Item_func_numhybrid::get_time(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed == 1);
+  switch (field_type())
+  {
+  case MYSQL_TYPE_TIME:
+    return time_op(ltime);
+  case MYSQL_TYPE_DATE:
+    return get_time_from_date(ltime);
+  case MYSQL_TYPE_DATETIME:
+    return get_time_from_datetime(ltime);
+  default:
+    return Item::get_time_from_non_temporal(ltime);
+  }
+}
+
+
 void Item_func_signed::print(String *str, enum_query_type query_type)
 {
   str->append(STRING_WITH_LEN("cast("));
@@ -2717,6 +2790,27 @@ uint Item_func_min_max::cmp_datetimes(lo
 }
 
 
+uint Item_func_min_max::cmp_times(longlong *value)
+{
+  longlong UNINIT_VAR(min_max);
+  uint min_max_idx= 0;
+  for (uint i=0; i < arg_count ; i++)
+  {
+    longlong res= args[i]->val_time_temporal();
+    if ((null_value= args[i]->null_value))
+      return 0;
+    if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0)
+    {
+      min_max= res;
+      min_max_idx= i;
+    }
+  }
+  if (value)
+    *value= min_max;
+  return min_max_idx;
+}
+
+
 String *Item_func_min_max::val_str(String *str)
 {
   DBUG_ASSERT(fixed == 1);
@@ -2822,6 +2916,70 @@ String *Item_func_min_max::val_str(Strin
 }
 
 
+bool Item_func_min_max::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  DBUG_ASSERT(fixed == 1);
+  if (compare_as_dates)
+  {
+    longlong result;
+    cmp_datetimes(&result);
+    if (null_value)
+      return true;
+    TIME_from_longlong_packed(ltime, field_type(), result);
+    return false;
+  }
+
+  switch (field_type())
+  {
+  case MYSQL_TYPE_TIME:
+    return get_date_from_time(ltime);
+  case MYSQL_TYPE_DATETIME:
+  case MYSQL_TYPE_TIMESTAMP:
+  case MYSQL_TYPE_DATE:
+    DBUG_ASSERT(0); // Should have been processed in "compare_as_dates" block.
+  default:
+    return get_date_from_non_temporal(ltime, fuzzydate);
+  }
+}
+
+
+bool Item_func_min_max::get_time(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed == 1);
+  if (compare_as_dates)
+  {
+    longlong result;
+    cmp_datetimes(&result);
+    if (null_value)
+      return true;
+    TIME_from_longlong_packed(ltime, field_type(), result);
+    datetime_to_time(ltime);
+    return false;
+  }
+
+  switch (field_type())
+  {
+  case MYSQL_TYPE_TIME:
+    {
+      longlong result;
+      cmp_times(&result);
+      if (null_value)
+        return true;
+      TIME_from_longlong_time_packed(ltime, result);
+      return false;
+    }
+    break;
+  case MYSQL_TYPE_DATE:
+  case MYSQL_TYPE_TIMESTAMP:
+  case MYSQL_TYPE_DATETIME:
+    DBUG_ASSERT(0); // Should have been processed in "compare_as_dates" block.
+  default:
+    return get_time_from_non_temporal(ltime);
+    break;
+  }
+}
+
+
 double Item_func_min_max::val_real()
 {
   DBUG_ASSERT(fixed == 1);

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2011-11-01 11:52:24 +0000
+++ b/sql/item_func.h	2011-11-10 14:58:23 +0000
@@ -359,6 +359,14 @@ public:
   my_decimal *val_decimal(my_decimal *decimal_value);
   longlong val_int()
     { DBUG_ASSERT(fixed == 1); return (longlong) rint(val_real()); }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_real(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_real(ltime);
+  }
   enum Item_result result_type () const { return REAL_RESULT; }
   void fix_length_and_dec()
   { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); }
@@ -388,7 +396,8 @@ public:
   longlong val_int();
   my_decimal *val_decimal(my_decimal *);
   String *val_str(String*str);
-
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);
   /**
      @brief Performs the operation that this functions implements when the
      result type is INT.
@@ -424,6 +433,14 @@ public:
      @return The result of the operation.
   */
   virtual String *str_op(String *)= 0;
+  /**
+     @brief Performs the operation that this functions implements when the
+     result type is MYSQL_TYPE_DATE or MYSQL_TYPE_DATETIME.
+
+     @return The result of the operation.
+  */
+  virtual bool date_op(MYSQL_TIME *ltime, uint fuzzydate)= 0;
+  virtual bool time_op(MYSQL_TIME *ltime)= 0;
   bool is_null() { update_null_value(); return null_value; }
 };
 
@@ -437,6 +454,10 @@ public:
   void fix_num_length_and_dec();
   void find_num_type();
   String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
+  bool date_op(MYSQL_TIME *ltime, uint fuzzydate)
+  { DBUG_ASSERT(0); return 0; }
+  bool time_op(MYSQL_TIME *ltime)
+  { DBUG_ASSERT(0); return 0; }
 };
 
 
@@ -454,6 +475,10 @@ class Item_num_op :public Item_func_numh
 
   void find_num_type();
   String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
+  bool date_op(MYSQL_TIME *ltime, uint fuzzydate)
+  { DBUG_ASSERT(0); return 0; }
+  bool time_op(MYSQL_TIME *ltime)
+  { DBUG_ASSERT(0); return 0; }
 };
 
 
@@ -474,6 +499,14 @@ public:
   { collation.set_numeric(); }
   double val_real();
   String *val_str(String*str);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   enum Item_result result_type () const { return INT_RESULT; }
   void fix_length_and_dec() {}
 };
@@ -536,6 +569,14 @@ public:
   String *val_str(String *str);
   double val_real();
   longlong val_int();
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_decimal(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_decimal(ltime);
+  }
   my_decimal *val_decimal(my_decimal*);
   enum Item_result result_type () const { return DECIMAL_RESULT; }
   enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
@@ -907,6 +948,8 @@ class Item_func_min_max :public Item_fun
   THD *thd;
 protected:
   enum_field_types cached_field_type;
+  uint cmp_datetimes(longlong *value);
+  uint cmp_times(longlong *value);
 public:
   Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list),
     cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(FALSE),
@@ -915,17 +958,8 @@ public:
   longlong val_int();
   String *val_str(String *);
   my_decimal *val_decimal(my_decimal *);
-  /*
-    TS-TODO: implement own get_date() and get_time() for performance reasons.
-    Otherwise Item generic functions are used which involve val_str()
-    followed by string-to-time and string-to-datetime conversion.
-    Similar happens for other hybrid function, like COALESCE.
-
-    The other classes that may need their own implementations are:
-    Item_func_coalesce, Item_func_if, Item_func_case, Item_func_min_max,
-    Item_singlerow_subselect, Item_sum_min, Item_sum_max
-    Item_func_add_time, Item_date_add_interval, Item_func_str_to_date
-  */
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);  
   void fix_length_and_dec();
   enum Item_result result_type () const { return cmp_type; }
   enum Item_result cast_to_int_type () const
@@ -936,7 +970,6 @@ public:
     */
     return compare_as_dates ? INT_RESULT : result_type();
   }
-  uint cmp_datetimes(longlong *value);
   enum_field_types field_type() const { return cached_field_type; }
 };
 
@@ -972,6 +1005,14 @@ public:
   longlong val_int() { return args[0]->val_int(); }
   String *val_str(String *str) { return args[0]->val_str(str); }
   my_decimal *val_decimal(my_decimal *dec) { return args[0]->val_decimal(dec); }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return args[0]->get_date(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return args[0]->get_time(ltime);
+  }
   const char *func_name() const { return "rollup_const"; }
   bool const_item() const { return 0; }
   Item_result result_type() const { return args[0]->result_type(); }
@@ -1304,6 +1345,14 @@ class Item_func_udf_float :public Item_u
   }
   double val_real();
   String *val_str(String *str);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_real(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_real(ltime);
+  }
   void fix_length_and_dec() { fix_num_length_and_dec(); }
 };
 
@@ -1319,6 +1368,14 @@ public:
   longlong val_int();
   double val_real() { return (double) Item_func_udf_int::val_int(); }
   String *val_str(String *str);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   enum Item_result result_type () const { return INT_RESULT; }
   void fix_length_and_dec() { decimals= 0; max_length= 21; }
 };
@@ -1335,6 +1392,14 @@ public:
   double val_real();
   my_decimal *val_decimal(my_decimal *);
   String *val_str(String *str);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_decimal(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_decimal(ltime);
+  }
   enum Item_result result_type () const { return DECIMAL_RESULT; }
   void fix_length_and_dec();
 };
@@ -1372,12 +1437,21 @@ public:
     string2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf);
     return dec_buf;
   }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_string(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_string(ltime);
+  }
   enum Item_result result_type () const { return STRING_RESULT; }
   void fix_length_and_dec();
 };
 
 #else /* Dummy functions to get sql_yacc.cc compiled */
 
+
 class Item_func_udf_float :public Item_real_func
 {
  public:
@@ -1471,11 +1545,33 @@ public:
 };
 
 
+/**
+  Common class for:
+    Item_func_get_system_var
+    Item_func_get_user_var
+    Item_func_set_user_var
+*/
+class Item_var_func :public Item_func
+{
+public:
+  Item_var_func() :Item_func() { }
+  Item_var_func(Item *a) :Item_func(a) { }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_non_temporal(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_non_temporal(ltime);
+  }
+};
+
+
 /* Handling of user definable variables */
 
 class user_var_entry;
 
-class Item_func_set_user_var :public Item_func
+class Item_func_set_user_var :public Item_var_func
 {
   enum Item_result cached_result_type;
   user_var_entry *entry;
@@ -1505,7 +1601,7 @@ class Item_func_set_user_var :public Ite
 public:
   LEX_STRING name; // keep it public
   Item_func_set_user_var(LEX_STRING a,Item *b)
-    :Item_func(b), cached_result_type(INT_RESULT),
+    :Item_var_func(b), cached_result_type(INT_RESULT),
      entry(NULL), entry_thread_id(0), name(a)
   {}
   enum Functype functype() const { return SUSERVAR_FUNC; }
@@ -1545,7 +1641,7 @@ public:
 };
 
 
-class Item_func_get_user_var :public Item_func,
+class Item_func_get_user_var :public Item_var_func,
                               private Settable_routine_parameter
 {
   user_var_entry *var_entry;
@@ -1554,7 +1650,7 @@ class Item_func_get_user_var :public Ite
 public:
   LEX_STRING name; // keep it public
   Item_func_get_user_var(LEX_STRING a):
-    Item_func(), m_cached_result_type(STRING_RESULT), name(a) {}
+    Item_var_func(), m_cached_result_type(STRING_RESULT), name(a) {}
   enum Functype functype() const { return GUSERVAR_FUNC; }
   LEX_STRING get_name() { return name; }
   double val_real();
@@ -1606,6 +1702,17 @@ public:
   longlong val_int();
   String *val_str(String *str);
   my_decimal *val_decimal(my_decimal *decimal_buffer);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    DBUG_ASSERT(0);
+    return true;
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    DBUG_ASSERT(0);
+    return true;
+  }
+
   /* fix_fields() binds variable name with its entry structure */
   bool fix_fields(THD *thd, Item **ref);
   virtual void print(String *str, enum_query_type query_type);
@@ -1620,7 +1727,7 @@ public:
 #define GET_SYS_VAR_CACHE_DOUBLE   2
 #define GET_SYS_VAR_CACHE_STRING   4
 
-class Item_func_get_system_var :public Item_func
+class Item_func_get_system_var :public Item_var_func
 {
   sys_var *var;
   enum_var_type var_type, orig_var_type;
@@ -1827,6 +1934,20 @@ public:
     return sp_result_field->val_real();
   }
 
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    if (execute())
+      return true;
+    return sp_result_field->get_date(ltime, fuzzydate);
+  }
+
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    if (execute())
+      return true;
+    return sp_result_field->get_time(ltime);
+  }
+
   my_decimal *val_decimal(my_decimal *dec_buf)
   {
     if (execute())

=== modified file 'sql/item_row.h'
--- a/sql/item_row.h	2011-07-03 23:56:47 +0000
+++ b/sql/item_row.h	2011-11-10 14:58:23 +0000
@@ -62,6 +62,17 @@ public:
     illegal_method_call((const char*)"val_decimal");
     return 0;
   };
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    illegal_method_call((const char *) "get_date");
+    return true;
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    illegal_method_call((const char *) "get_time");
+    return true;
+  }
+
   bool fix_fields(THD *thd, Item **ref);
   void fix_after_pullout(st_select_lex *parent_select,
                          st_select_lex *removed_select, Item **ref);

=== modified file 'sql/item_strfunc.h'
--- a/sql/item_strfunc.h	2011-11-01 11:52:24 +0000
+++ b/sql/item_strfunc.h	2011-11-10 14:58:23 +0000
@@ -44,6 +44,14 @@ public:
   longlong val_int();
   double val_real();
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_string(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_string(ltime);
+  }
   enum Item_result result_type () const { return STRING_RESULT; }
   void left_right_max_length();
   bool fix_fields(THD *thd, Item **ref);

=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc	2011-10-18 10:23:09 +0000
+++ b/sql/item_subselect.cc	2011-11-10 14:58:23 +0000
@@ -806,6 +806,36 @@ my_decimal *Item_singlerow_subselect::va
 }
 
 
+bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  if (!exec() && !value->null_value)
+  {
+    null_value= false;
+    return value->get_date(ltime, fuzzydate);
+  }
+  else
+  {
+    reset();
+    return true;
+  }
+}
+
+
+bool Item_singlerow_subselect::get_time(MYSQL_TIME *ltime)
+{
+  if (!exec() && !value->null_value)
+  {
+    null_value= false;
+    return value->get_time(ltime);
+  }
+  else
+  {
+    reset();
+    return true;
+  }
+}
+
+
 bool Item_singlerow_subselect::val_bool()
 {
   if (!exec() && !value->null_value)

=== modified file 'sql/item_subselect.h'
--- a/sql/item_subselect.h	2011-10-05 10:19:50 +0000
+++ b/sql/item_subselect.h	2011-11-10 14:58:23 +0000
@@ -203,6 +203,8 @@ public:
   longlong val_int ();
   String *val_str (String *);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);
   bool val_bool();
   enum Item_result result_type() const;
   enum_field_types field_type() const;
@@ -306,6 +308,14 @@ public:
   String *val_str(String*);
   my_decimal *val_decimal(my_decimal *);
   bool val_bool();
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   void fix_length_and_dec();
   virtual void print(String *str, enum_query_type query_type);
 

=== modified file 'sql/item_sum.cc'
--- a/sql/item_sum.cc	2011-11-01 11:52:24 +0000
+++ b/sql/item_sum.cc	2011-11-10 14:58:23 +0000
@@ -1953,6 +1953,24 @@ my_decimal *Item_sum_hybrid::val_decimal
 }
 
 
+bool Item_sum_hybrid::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+  DBUG_ASSERT(fixed == 1);
+  if (null_value)
+    return 0;
+  return (null_value= value->get_date(ltime, fuzzydate));
+}
+
+
+bool Item_sum_hybrid::get_time(MYSQL_TIME *ltime)
+{
+  DBUG_ASSERT(fixed == 1);
+  if (null_value)
+    return 0;
+  return (null_value= value->get_time(ltime));
+}
+
+
 String *
 Item_sum_hybrid::val_str(String *str)
 {
@@ -2575,12 +2593,6 @@ double Item_avg_field::val_real()
 }
 
 
-longlong Item_avg_field::val_int()
-{
-  return (longlong) rint(val_real());
-}
-
-
 my_decimal *Item_avg_field::val_decimal(my_decimal *dec_buf)
 {
   // fix_fields() never calls for this Item

=== modified file 'sql/item_sum.h'
--- a/sql/item_sum.h	2011-11-01 11:52:24 +0000
+++ b/sql/item_sum.h	2011-11-10 14:58:23 +0000
@@ -672,6 +672,14 @@ public:
   }
   String *val_str(String*str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_numeric(ltime, fuzzydate); /* Decimal or real */
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_numeric(ltime); /* Decimal or real */
+  }
   void reset_field();
 };
 
@@ -685,6 +693,14 @@ public:
   double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
   String *val_str(String*str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   enum Item_result result_type () const { return INT_RESULT; }
   void fix_length_and_dec()
   { decimals=0; max_length=21; maybe_null=null_value=0; }
@@ -784,27 +800,51 @@ class Item_sum_count :public Item_sum_in
 
 class Item_sum_avg;
 
-class Item_avg_field :public Item_result_field
+/**
+  Common abstract class for:
+    Item_avg_field
+    Item_variance_field
+*/
+class Item_sum_num_field: public Item_result_field
 {
-public:
+protected:
   Field *field;
   Item_result hybrid_type;
+public:
+  longlong val_int()
+  {
+    /* can't be fix_fields()ed */
+    return (longlong) rint(val_real());
+  }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_numeric(ltime, fuzzydate); /* Decimal or real */
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_numeric(ltime); /* Decimal or real */
+  }
+  enum_field_types field_type() const
+  {
+    return hybrid_type == DECIMAL_RESULT ?
+      MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
+  }
+  enum Item_result result_type () const { return hybrid_type; }
+  bool is_null() { update_null_value(); return null_value; }
+};
+
+
+class Item_avg_field :public Item_sum_num_field
+{
+public:
   uint f_precision, f_scale, dec_bin_size;
   uint prec_increment;
   Item_avg_field(Item_result res_type, Item_sum_avg *item);
   enum Type type() const { return FIELD_AVG_ITEM; }
   double val_real();
-  longlong val_int();
   my_decimal *val_decimal(my_decimal *);
-  bool is_null() { update_null_value(); return null_value; }
   String *val_str(String*);
-  enum_field_types field_type() const
-  {
-    return hybrid_type == DECIMAL_RESULT ?
-      MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
-  }
   void fix_length_and_dec() {}
-  enum Item_result result_type () const { return hybrid_type; }
   const char *func_name() const { DBUG_ASSERT(0); return "avg_field"; }
 };
 
@@ -815,7 +855,6 @@ public:
   ulonglong count;
   uint prec_increment;
   uint f_precision, f_scale, dec_bin_size;
-
   Item_sum_avg(Item *item_par, bool distinct) 
     :Item_sum_sum(item_par, distinct), count(0) 
   {}
@@ -855,33 +894,23 @@ public:
 
 class Item_sum_variance;
 
-class Item_variance_field :public Item_result_field
+class Item_variance_field :public Item_sum_num_field
 {
-public:
-  Field *field;
-  Item_result hybrid_type;
+protected:
   uint f_precision0, f_scale0;
   uint f_precision1, f_scale1;
   uint dec_bin_size0, dec_bin_size1;
   uint sample;
   uint prec_increment;
+public:
   Item_variance_field(Item_sum_variance *item);
   enum Type type() const {return FIELD_VARIANCE_ITEM; }
   double val_real();
-  longlong val_int()
-  { /* can't be fix_fields()ed */ return (longlong) rint(val_real()); }
   String *val_str(String *str)
   { return val_string_from_real(str); }
   my_decimal *val_decimal(my_decimal *dec_buf)
   { return val_decimal_from_real(dec_buf); }
-  bool is_null() { update_null_value(); return null_value; }
-  enum_field_types field_type() const
-  {
-    return hybrid_type == DECIMAL_RESULT ?
-      MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
-  }
   void fix_length_and_dec() {}
-  enum Item_result result_type () const { return hybrid_type; }
   const char *func_name() const { DBUG_ASSERT(0); return "variance_field"; }
 };
 
@@ -1015,6 +1044,8 @@ protected:
   longlong val_time_temporal();
   longlong val_date_temporal();
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+  bool get_time(MYSQL_TIME *ltime);
   void reset_field();
   String *val_str(String *);
   bool keep_field_type(void) const { return 1; }
@@ -1186,6 +1217,14 @@ class Item_sum_udf_float :public Item_ud
   double val_real();
   String *val_str(String*str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_real(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_real(ltime);
+  }
   void fix_length_and_dec() { fix_num_length_and_dec(); }
   Item *copy_or_same(THD* thd);
 };
@@ -1205,6 +1244,14 @@ public:
     { DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); }
   String *val_str(String*str);
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   enum Item_result result_type () const { return INT_RESULT; }
   void fix_length_and_dec() { decimals=0; max_length=21; }
   Item *copy_or_same(THD* thd);
@@ -1244,6 +1291,14 @@ public:
     return cs->cset->strtoll10(cs, res->ptr(), &end, &err_not_used);
   }
   my_decimal *val_decimal(my_decimal *dec);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_string(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_string(ltime);
+  }
   enum Item_result result_type () const { return STRING_RESULT; }
   void fix_length_and_dec();
   Item *copy_or_same(THD* thd);
@@ -1263,6 +1318,14 @@ public:
   double val_real();
   longlong val_int();
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_decimal(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_decimal(ltime);
+  }
   enum Item_result result_type () const { return DECIMAL_RESULT; }
   void fix_length_and_dec() { fix_num_length_and_dec(); }
   Item *copy_or_same(THD* thd);
@@ -1445,6 +1508,14 @@ public:
   {
     return val_decimal_from_string(decimal_value);
   }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_string(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_string(ltime);
+  }
   String* val_str(String* str);
   Item *copy_or_same(THD* thd);
   void no_rows_in_result() {}

=== modified file 'sql/item_timefunc.cc'
--- a/sql/item_timefunc.cc	2011-11-07 12:02:15 +0000
+++ b/sql/item_timefunc.cc	2011-11-10 14:58:23 +0000
@@ -914,26 +914,6 @@ String *Item_temporal_hybrid_func::val_s
 }
 
 
-String *Item_time_func::val_str(String *str)
-{
-  DBUG_ASSERT(fixed == 1);
-  MYSQL_TIME ltime;
-  if (get_time(&ltime) || (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
-    return (String *) 0;
-  make_time((DATE_TIME_FORMAT *) 0, &ltime, str, decimals);
-  return str;
-}
-
-
-longlong Item_time_func::val_int()
-{
-  DBUG_ASSERT(fixed == 1);
-  MYSQL_TIME ltime;
-  return get_time(&ltime) ?
-         0LL : (ltime.neg ? -1 : 1) * TIME_to_ulonglong_time_round(&ltime);
-}
-
-
 longlong Item_time_func::val_time_temporal()
 {
   DBUG_ASSERT(fixed == 1);
@@ -942,47 +922,6 @@ longlong Item_time_func::val_time_tempor
 }
 
 
-bool Item_date_func::get_time(MYSQL_TIME *ltime)
-{
-  DBUG_ASSERT(fixed == 1);
-  if (get_date(ltime, TIME_FUZZY_DATE)) // Need this check if NULL value
-    return true;
-  set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
-  return false;
-}
-
-
-bool Item_datetime_func::get_time(MYSQL_TIME *ltime)
-{
-  DBUG_ASSERT(fixed == 1);
-  if (get_date(ltime, TIME_FUZZY_DATE)) // Need this check if NULL value
-    return true;
-  datetime_to_time(ltime);
-  return false;
-}
-
-
-String *Item_date_func::val_str(String *str)
-{
-  DBUG_ASSERT(fixed == 1);
-  MYSQL_TIME ltime;
-  if (get_date(&ltime, TIME_FUZZY_DATE) ||
-      (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
-    return (String *) 0;
-  make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
-  return str;
-}
-
-
-longlong Item_date_func::val_int()
-{
-  DBUG_ASSERT(fixed == 1);
-  MYSQL_TIME ltime;
-  return get_date(&ltime, TIME_FUZZY_DATE) ?
-         0LL : (longlong) TIME_to_ulonglong_date(&ltime);
-}
-
-
 longlong Item_date_func::val_date_temporal()
 {
   DBUG_ASSERT(fixed == 1);
@@ -992,28 +931,6 @@ longlong Item_date_func::val_date_tempor
 }
 
 
-String *Item_datetime_func::val_str(String *str)
-{
-  DBUG_ASSERT(fixed == 1);
-  MYSQL_TIME ltime;
-
-  if (get_date(&ltime, 0) ||
-      (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
-    return (String *) 0;
-  make_datetime((DATE_TIME_FORMAT *) 0, &ltime, str, decimals);
-  return str;
-}
-
-
-longlong Item_datetime_func::val_int()
-{
-  DBUG_ASSERT(fixed == 1);
-  MYSQL_TIME ltime;
-  return get_date(&ltime, 0) ?
-         0LL: (longlong) TIME_to_ulonglong_datetime_round(&ltime);
-}
-
-
 longlong Item_datetime_func::val_date_temporal()
 {
   DBUG_ASSERT(fixed == 1);

=== modified file 'sql/item_timefunc.h'
--- a/sql/item_timefunc.h	2011-11-07 14:35:16 +0000
+++ b/sql/item_timefunc.h	2011-11-10 14:58:23 +0000
@@ -122,6 +122,9 @@ public:
 };
 
 
+/**
+  TS-TODO: This should probably have Item_int_func as parent class.
+*/
 class Item_func_month :public Item_func
 {
 public:
@@ -137,6 +140,14 @@ public:
     str->set(nr, collation.collation);
     return str;
   }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   const char *func_name() const { return "month"; }
   enum Item_result result_type () const { return INT_RESULT; }
   void fix_length_and_dec() 
@@ -316,6 +327,9 @@ public:
 };
 
 
+/**
+  TS-TODO: This should probably have Item_int_func as parent class.
+*/
 class Item_func_weekday :public Item_func
 {
   bool odbc_type;
@@ -330,6 +344,14 @@ public:
     str->set(val_int(), &my_charset_bin);
     return null_value ? 0 : str;
   }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   const char *func_name() const
   {
      return (odbc_type ? "dayofweek" : "weekday");
@@ -347,6 +369,11 @@ public:
   }
 };
 
+/**
+  TS-TODO: Item_func_dayname should be derived from Item_str_func.
+  In the current implementation funny things can happen:
+  select dayname(now())+1 -> 4
+*/
 class Item_func_dayname :public Item_func_weekday
 {
   MY_LOCALE *locale;
@@ -354,6 +381,14 @@ class Item_func_dayname :public Item_fun
   Item_func_dayname(Item *a) :Item_func_weekday(a,0) {}
   const char *func_name() const { return "dayname"; }
   String *val_str(String *str);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_string(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_string(ltime);
+  }
   enum Item_result result_type () const { return STRING_RESULT; }
   void fix_length_and_dec();
   bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
@@ -379,6 +414,14 @@ public:
   double val_real();
   String *val_str(String *str);
   my_decimal *val_decimal(my_decimal *decimal_value);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_numeric(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_numeric(ltime);
+  }
   enum Item_result result_type() const
   {
     return decimals ? DECIMAL_RESULT : INT_RESULT;
@@ -560,9 +603,18 @@ public:
   Item_date_func(Item *a, Item *b) :Item_temporal_func(a, b)
   { unsigned_flag= 1; }
   enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
-  bool get_time(MYSQL_TIME *ltime);
-  String *val_str(String *str);
-  longlong val_int();
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_date(ltime);
+  }
+  String *val_str(String *str)
+  {
+    return val_string_from_date(str);
+  }
+  longlong val_int()
+  {  
+    return val_int_from_date();
+  }
   longlong val_date_temporal();
   double val_real() { return (double) val_int(); }
   const char *func_name() const { return "date"; }
@@ -602,8 +654,14 @@ public:
   { unsigned_flag= 1; }
   enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
   double val_real() { return val_real_from_decimal(); }
-  String *val_str(String *str);
-  longlong val_int();
+  String *val_str(String *str)
+  {
+    return val_string_from_datetime(str);
+  }
+  longlong val_int()
+  {
+    return val_int_from_datetime();
+  }
   longlong val_date_temporal();
   my_decimal *val_decimal(my_decimal *decimal_value)
   {
@@ -614,7 +672,10 @@ public:
   {
     return save_date_in_field(field);
   }
-  bool get_time(MYSQL_TIME *ltime);
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_datetime(ltime);
+  }
   // All datetime functions must implement get_date()
   // to avoid use of generic Item::get_date()
   // which converts to string and then parses the string as DATETIME.
@@ -643,13 +704,19 @@ public:
   {
     return save_time_in_field(field);
   }
-  longlong val_int();
+  longlong val_int()
+  {
+    return val_int_from_time();
+  }
   longlong val_time_temporal();
   bool get_date(MYSQL_TIME *res, uint fuzzy_date)
   {
     return get_date_from_time(res);
   }
-  String *val_str(String *str);
+  String *val_str(String *str)
+  {
+    return val_string_from_time(str);
+  }
   // All time functions must implement get_time()
   // to avoid use of generic Item::get_time()
   // which converts to string and then parses the string as TIME.

=== modified file 'sql/procedure.h'
--- a/sql/procedure.h	2011-06-30 15:50:45 +0000
+++ b/sql/procedure.h	2011-11-10 14:58:23 +0000
@@ -78,6 +78,14 @@ public:
     return s;
   }
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_real(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_real(ltime);
+  }
   unsigned int size_of() { return sizeof(*this);}
 };
 
@@ -97,6 +105,14 @@ public:
   longlong val_int() { return value; }
   String *val_str(String *s) { s->set(value, default_charset()); return s; }
   my_decimal *val_decimal(my_decimal *);
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_int(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_int(ltime);
+  }
   unsigned int size_of() { return sizeof(*this);}
 };
 
@@ -126,6 +142,14 @@ public:
     const CHARSET_INFO *cs=str_value.charset();
     return my_strntoll(cs,str_value.ptr(),str_value.length(),10,NULL,&err);
   }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzydate)
+  {
+    return get_date_from_string(ltime, fuzzydate);
+  }
+  bool get_time(MYSQL_TIME *ltime)
+  {
+    return get_time_from_string(ltime);
+  }
   String *val_str(String*)
   {
     return null_value ? (String*) 0 : (String*) &str_value;

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (alexander.barkov:3554 to 3555)Bug#13359097 WL#946Alexander Barkov11 Nov