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 List-Archive: http://lists.mysql.com/commits/141787 X-Bug: 13359097 Message-Id: <201111101459.pAAExPfD011681@bar.myoffice.izhnet.ru> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 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(<ime, 0) || + (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH))) + return (String *) 0; + make_datetime((DATE_TIME_FORMAT *) 0, <ime, str, decimals); + return str; +} + + +String *Item::val_string_from_date(String *str) +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + if (get_date(<ime, 0) || + (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH))) + return (String *) 0; + make_date((DATE_TIME_FORMAT *) 0, <ime, str); + return str; +} + + +String *Item::val_string_from_time(String *str) +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + if (get_time(<ime) || (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH))) + return (String *) 0; + make_time((DATE_TIME_FORMAT *) 0, <ime, 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(<ime) ? + 0LL : (ltime.neg ? -1 : 1) * TIME_to_ulonglong_time_round(<ime); +} + + +longlong Item::val_int_from_date() +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + return get_date(<ime, TIME_FUZZY_DATE) ? + 0LL : (longlong) TIME_to_ulonglong_date(<ime); +} + + +longlong Item::val_int_from_datetime() +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + return get_date(<ime, 0) ? + 0LL: (longlong) TIME_to_ulonglong_datetime_round(<ime); +} + + 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 &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 &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(<ime) || (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH))) - return (String *) 0; - make_time((DATE_TIME_FORMAT *) 0, <ime, str, decimals); - return str; -} - - -longlong Item_time_func::val_int() -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - return get_time(<ime) ? - 0LL : (ltime.neg ? -1 : 1) * TIME_to_ulonglong_time_round(<ime); -} - - 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(<ime, TIME_FUZZY_DATE) || - (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH))) - return (String *) 0; - make_date((DATE_TIME_FORMAT *) 0, <ime, str); - return str; -} - - -longlong Item_date_func::val_int() -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - return get_date(<ime, TIME_FUZZY_DATE) ? - 0LL : (longlong) TIME_to_ulonglong_date(<ime); -} - - 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(<ime, 0) || - (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH))) - return (String *) 0; - make_datetime((DATE_TIME_FORMAT *) 0, <ime, str, decimals); - return str; -} - - -longlong Item_datetime_func::val_int() -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - return get_date(<ime, 0) ? - 0LL: (longlong) TIME_to_ulonglong_datetime_round(<ime); -} - - 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).