← Back to team overview

maria-developers team mailing list archive

merge for MySQL56 temporal literals

 

Hi Serg,

Please review the patch merging MySQL-5.6 temporal literals.

Thanks.

=== modified file 'client/mysqlbinlog.cc'
--- client/mysqlbinlog.cc	2013-04-15 13:09:22 +0000
+++ client/mysqlbinlog.cc	2013-06-21 13:31:28 +0000
@@ -1541,13 +1541,14 @@ the mysql command line client.\n\n");
 
 static my_time_t convert_str_to_timestamp(const char* str)
 {
-  int was_cut;
+  MYSQL_TIME_STATUS status;
   MYSQL_TIME l_time;
   long dummy_my_timezone;
   uint dummy_in_dst_time_gap;
+  
   /* We require a total specification (date AND time) */
-  if (str_to_datetime(str, (uint) strlen(str), &l_time, 0, &was_cut) !=
-      MYSQL_TIMESTAMP_DATETIME || was_cut)
+  if (str_to_datetime(str, (uint) strlen(str), &l_time, 0, &status) ||
+      l_time.time_type != MYSQL_TIMESTAMP_DATETIME || status.warnings)
   {
     error("Incorrect date and time argument: %s", str);
     exit(1);

=== modified file 'include/my_time.h'
--- include/my_time.h	2013-05-24 15:09:59 +0000
+++ include/my_time.h	2013-06-25 06:28:08 +0000
@@ -78,14 +78,27 @@ extern uchar days_in_month[];
 #define TIME_MAX_VALUE_SECONDS (TIME_MAX_HOUR * 3600L + \
                                 TIME_MAX_MINUTE * 60L + TIME_MAX_SECOND)
 
+/*
+  Structure to return status from
+    str_to_datetime(), str_to_time(), number_to_datetime(), number_to_time()
+*/
+typedef struct st_mysql_time_status
+{
+  int warnings;
+  uint fractional_digits;
+} MYSQL_TIME_STATUS;
+
+static inline void my_time_status_init(MYSQL_TIME_STATUS *status)
+{
+  status->warnings= status->fractional_digits= 0;
+}
+
 my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date,
                    ulonglong flags, int *was_cut);
-enum enum_mysql_timestamp_type
-str_to_time(const char *str, uint length, MYSQL_TIME *l_time, 
-            ulonglong flag, int *warning);
-enum enum_mysql_timestamp_type
-str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
-                ulonglong flags, int *was_cut);
+my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time, 
+                    ulonglong flag, MYSQL_TIME_STATUS *status);
+my_bool str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
+                        ulonglong flags, MYSQL_TIME_STATUS *status);
 longlong number_to_datetime(longlong nr, ulong sec_part, MYSQL_TIME *time_res,
                             ulonglong flags, int *was_cut);
 
@@ -107,7 +120,7 @@ ulonglong TIME_to_ulonglong_time(const M
 ulonglong TIME_to_ulonglong(const MYSQL_TIME *);
 double TIME_to_double(const MYSQL_TIME *my_time);
 
-longlong pack_time(MYSQL_TIME *my_time);
+longlong pack_time(const MYSQL_TIME *my_time);
 MYSQL_TIME *unpack_time(longlong packed, MYSQL_TIME *my_time);
 
 int check_time_range(struct st_mysql_time *my_time, uint dec, int *warning);

=== modified file 'mysql-test/r/cast.result'
--- mysql-test/r/cast.result	2013-05-07 11:05:09 +0000
+++ mysql-test/r/cast.result	2013-06-24 07:08:00 +0000
@@ -180,24 +180,24 @@ select 10.0+'10';
 select 10E+0+'10';
 10E+0+'10'
 20
-select CONVERT(DATE "2004-01-22 21:45:33" USING latin1);
-CONVERT(DATE "2004-01-22 21:45:33" USING latin1)
+select CONVERT(TIMESTAMP "2004-01-22 21:45:33" USING latin1);
+CONVERT(TIMESTAMP "2004-01-22 21:45:33" USING latin1)
 2004-01-22 21:45:33
-select CONVERT(DATE "2004-01-22 21:45:33",CHAR);
-CONVERT(DATE "2004-01-22 21:45:33",CHAR)
+select CONVERT(TIMESTAMP "2004-01-22 21:45:33",CHAR);
+CONVERT(TIMESTAMP "2004-01-22 21:45:33",CHAR)
 2004-01-22 21:45:33
-select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4));
-CONVERT(DATE "2004-01-22 21:45:33",CHAR(4))
+select CONVERT(TIMESTAMP "2004-01-22 21:45:33",CHAR(4));
+CONVERT(TIMESTAMP "2004-01-22 21:45:33",CHAR(4))
 2004
 Warnings:
 Warning	1292	Truncated incorrect CHAR(4) value: '2004-01-22 21:45:33'
-select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4));
-CONVERT(DATE "2004-01-22 21:45:33",BINARY(4))
+select CONVERT(TIMESTAMP "2004-01-22 21:45:33",BINARY(4));
+CONVERT(TIMESTAMP "2004-01-22 21:45:33",BINARY(4))
 2004
 Warnings:
 Warning	1292	Truncated incorrect BINARY(4) value: '2004-01-22 21:45:33'
-select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4));
-CAST(DATE "2004-01-22 21:45:33" AS BINARY(4))
+select CAST(TIMESTAMP "2004-01-22 21:45:33" AS BINARY(4));
+CAST(TIMESTAMP "2004-01-22 21:45:33" AS BINARY(4))
 2004
 Warnings:
 Warning	1292	Truncated incorrect BINARY(4) value: '2004-01-22 21:45:33'

=== modified file 'mysql-test/r/partition_innodb.result'
--- mysql-test/r/partition_innodb.result	2013-06-06 19:32:29 +0000
+++ mysql-test/r/partition_innodb.result	2013-06-24 07:06:25 +0000
@@ -51,8 +51,8 @@ p200912	0
 p201103	1
 p201912	0
 SELECT count(*) FROM t1 p where c3 in
-(select c3 from t1 t where t.c3 < date '2011-04-26 19:19:44'
- and t.c3 > date '2011-04-26 19:18:44') ;
+(select c3 from t1 t where t.c3 < timestamp '2011-04-26 19:19:44'
+ and t.c3 > timestamp '2011-04-26 19:18:44') ;
 count(*)
 0
 DROP TABLE t1;

=== added file 'mysql-test/r/temporal_literal.result'
--- mysql-test/r/temporal_literal.result	1970-01-01 00:00:00 +0000
+++ mysql-test/r/temporal_literal.result	2013-06-26 09:12:13 +0000
@@ -0,0 +1,412 @@
+DROP TABLE IF EXISTS t1, t2;
+SET NAMES latin1;
+#
+# Testing DATE literals
+#
+SELECT DATE'xxxx';
+ERROR HY000: Incorrect DATE value: 'xxxx'
+SELECT DATE'01';
+ERROR HY000: Incorrect DATE value: '01'
+SELECT DATE'01-01';
+ERROR HY000: Incorrect DATE value: '01-01'
+SELECT DATE'2001';
+ERROR HY000: Incorrect DATE value: '2001'
+SELECT DATE'2001-01';
+ERROR HY000: Incorrect DATE value: '2001-01'
+SELECT DATE'2001-00-00';
+DATE'2001-00-00'
+2001-00-00
+SELECT DATE'2001-01-00';
+DATE'2001-01-00'
+2001-01-00
+SELECT DATE'0000-00-00';
+DATE'0000-00-00'
+0000-00-00
+SELECT DATE'2001-01-01 00:00:00';
+ERROR HY000: Incorrect DATE value: '2001-01-01 00:00:00'
+SELECT DATE'01:01:01';
+DATE'01:01:01'
+2001-01-01
+SELECT DATE'01-01-01';
+DATE'01-01-01'
+2001-01-01
+SELECT DATE'2010-01-01';
+DATE'2010-01-01'
+2010-01-01
+SELECT DATE '2010-01-01';
+DATE '2010-01-01'
+2010-01-01
+CREATE TABLE t1 AS SELECT DATE'2010-01-01';
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `DATE'2010-01-01'` date NOT NULL DEFAULT '0000-00-00'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT
+{d'2001-01-01'},
+{d'2001-01-01 10:10:10'};
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `{d'2001-01-01'}` date NOT NULL DEFAULT '0000-00-00',
+  `2001-01-01 10:10:10` varchar(19) NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+EXPLAIN EXTENDED SELECT {d'2010-01-01'};
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select DATE'2010-01-01' AS `{d'2010-01-01'}`
+EXPLAIN EXTENDED SELECT DATE'2010-01-01';
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select DATE'2010-01-01' AS `DATE'2010-01-01'`
+#
+# Testing DATE literals in non-default sql_mode
+#
+SET sql_mode=no_zero_in_date;
+SELECT DATE'2001-00-00';
+ERROR HY000: Incorrect DATE value: '2001-00-00'
+SELECT DATE'2001-01-00';
+ERROR HY000: Incorrect DATE value: '2001-01-00'
+SELECT DATE'0000-00-00';
+DATE'0000-00-00'
+0000-00-00
+SET sql_mode=no_zero_date;
+SELECT DATE'0000-00-00';
+ERROR HY000: Incorrect DATE value: '0000-00-00'
+SET sql_mode=default;
+#
+# Testing TIME literals
+#
+SELECT TIME'xxxx';
+ERROR HY000: Incorrect TIME value: 'xxxx'
+SELECT TIME'900:00:00';
+ERROR HY000: Incorrect TIME value: '900:00:00'
+SELECT TIME'-900:00:00';
+ERROR HY000: Incorrect TIME value: '-900:00:00'
+SELECT TIME'1 24:00:00';
+TIME'1 24:00:00'
+48:00:00
+SELECT TIME'30 24:00:00';
+TIME'30 24:00:00'
+744:00:00
+SELECT TIME'0000-00-00 00:00:00';
+ERROR HY000: Incorrect TIME value: '0000-00-00 00:00:00'
+SELECT TIME'40 24:00:00';
+ERROR HY000: Incorrect TIME value: '40 24:00:00'
+SELECT TIME'10';
+TIME'10'
+00:00:10
+SELECT TIME'10:10';
+TIME'10:10'
+10:10:00
+SELECT TIME'10:11.12';
+TIME'10:11.12'
+10:11:00.12
+SELECT TIME'10:10:10';
+TIME'10:10:10'
+10:10:10
+SELECT TIME'10:10:10.';
+TIME'10:10:10.'
+10:10:10
+SELECT TIME'10:10:10.1';
+TIME'10:10:10.1'
+10:10:10.1
+SELECT TIME'10:10:10.12';
+TIME'10:10:10.12'
+10:10:10.12
+SELECT TIME'10:10:10.123';
+TIME'10:10:10.123'
+10:10:10.123
+SELECT TIME'10:10:10.1234';
+TIME'10:10:10.1234'
+10:10:10.1234
+SELECT TIME'10:10:10.12345';
+TIME'10:10:10.12345'
+10:10:10.12345
+SELECT TIME'10:10:10.123456';
+TIME'10:10:10.123456'
+10:10:10.123456
+SELECT TIME'-10:00:00';
+TIME'-10:00:00'
+-10:00:00
+SELECT TIME '10:11:12';
+TIME '10:11:12'
+10:11:12
+CREATE TABLE t1 AS SELECT
+TIME'10:10:10',
+TIME'10:10:10.',
+TIME'10:10:10.1',
+TIME'10:10:10.12',
+TIME'10:10:10.123',
+TIME'10:10:10.1234',
+TIME'10:10:10.12345',
+TIME'10:10:10.123456';
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `TIME'10:10:10'` time NOT NULL DEFAULT '00:00:00',
+  `TIME'10:10:10.'` time NOT NULL DEFAULT '00:00:00',
+  `TIME'10:10:10.1'` time(1) NOT NULL DEFAULT '00:00:00.0',
+  `TIME'10:10:10.12'` time(2) NOT NULL DEFAULT '00:00:00.00',
+  `TIME'10:10:10.123'` time(3) NOT NULL DEFAULT '00:00:00.000',
+  `TIME'10:10:10.1234'` time(4) NOT NULL DEFAULT '00:00:00.0000',
+  `TIME'10:10:10.12345'` time(5) NOT NULL DEFAULT '00:00:00.00000',
+  `TIME'10:10:10.123456'` time(6) NOT NULL DEFAULT '00:00:00.000000'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT
+{t'10:10:10'},
+{t'10:10:10.'},
+{t'10:10:10.123456'},
+{t'2001-01-01'};
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `{t'10:10:10'}` time NOT NULL DEFAULT '00:00:00',
+  `{t'10:10:10.'}` time NOT NULL DEFAULT '00:00:00',
+  `{t'10:10:10.123456'}` time(6) NOT NULL DEFAULT '00:00:00.000000',
+  `2001-01-01` varchar(10) NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+EXPLAIN EXTENDED SELECT {t'10:01:01'};
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select TIME'10:01:01' AS `{t'10:01:01'}`
+EXPLAIN EXTENDED SELECT TIME'10:01:01';
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select TIME'10:01:01' AS `TIME'10:01:01'`
+#
+# Testing TIMESTAMP literals
+#
+SELECT TIMESTAMP'xxxx';
+ERROR HY000: Incorrect DATETIME value: 'xxxx'
+SELECT TIMESTAMP'2010';
+ERROR HY000: Incorrect DATETIME value: '2010'
+SELECT TIMESTAMP'2010-01';
+ERROR HY000: Incorrect DATETIME value: '2010-01'
+SELECT TIMESTAMP'2010-01-01';
+ERROR HY000: Incorrect DATETIME value: '2010-01-01'
+SELECT TIMESTAMP'2010-01-01 00';
+TIMESTAMP'2010-01-01 00'
+2010-01-01 00:00:00
+SELECT TIMESTAMP'2010-01-01 00:01';
+TIMESTAMP'2010-01-01 00:01'
+2010-01-01 00:01:00
+SELECT TIMESTAMP'2010-01-01 10:10:10';
+TIMESTAMP'2010-01-01 10:10:10'
+2010-01-01 10:10:10
+SELECT TIMESTAMP'2010-01-01 10:10:10.';
+TIMESTAMP'2010-01-01 10:10:10.'
+2010-01-01 10:10:10
+SELECT TIMESTAMP'2010-01-01 10:10:10.1';
+TIMESTAMP'2010-01-01 10:10:10.1'
+2010-01-01 10:10:10.1
+SELECT TIMESTAMP'2010-01-01 10:10:10.12';
+TIMESTAMP'2010-01-01 10:10:10.12'
+2010-01-01 10:10:10.12
+SELECT TIMESTAMP'2010-01-01 10:10:10.123';
+TIMESTAMP'2010-01-01 10:10:10.123'
+2010-01-01 10:10:10.123
+SELECT TIMESTAMP'2010-01-01 10:10:10.1234';
+TIMESTAMP'2010-01-01 10:10:10.1234'
+2010-01-01 10:10:10.1234
+SELECT TIMESTAMP'2010-01-01 10:10:10.12345';
+TIMESTAMP'2010-01-01 10:10:10.12345'
+2010-01-01 10:10:10.12345
+SELECT TIMESTAMP'2010-01-01 10:10:10.123456';
+TIMESTAMP'2010-01-01 10:10:10.123456'
+2010-01-01 10:10:10.123456
+SELECT TIMESTAMP '2010-01-01 10:20:30';
+TIMESTAMP '2010-01-01 10:20:30'
+2010-01-01 10:20:30
+CREATE TABLE t1 AS SELECT
+TIMESTAMP'2010-01-01 10:10:10',
+TIMESTAMP'2010-01-01 10:10:10.',
+TIMESTAMP'2010-01-01 10:10:10.1',
+TIMESTAMP'2010-01-01 10:10:10.12',
+TIMESTAMP'2010-01-01 10:10:10.123',
+TIMESTAMP'2010-01-01 10:10:10.1234',
+TIMESTAMP'2010-01-01 10:10:10.12345',
+TIMESTAMP'2010-01-01 10:10:10.123456';
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `TIMESTAMP'2010-01-01 10:10:10'` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+  `TIMESTAMP'2010-01-01 10:10:10.'` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+  `TIMESTAMP'2010-01-01 10:10:10.1'` datetime(1) NOT NULL DEFAULT '0000-00-00 00:00:00.0',
+  `TIMESTAMP'2010-01-01 10:10:10.12'` datetime(2) NOT NULL DEFAULT '0000-00-00 00:00:00.00',
+  `TIMESTAMP'2010-01-01 10:10:10.123'` datetime(3) NOT NULL DEFAULT '0000-00-00 00:00:00.000',
+  `TIMESTAMP'2010-01-01 10:10:10.1234'` datetime(4) NOT NULL DEFAULT '0000-00-00 00:00:00.0000',
+  `TIMESTAMP'2010-01-01 10:10:10.12345'` datetime(5) NOT NULL DEFAULT '0000-00-00 00:00:00.00000',
+  `TIMESTAMP'2010-01-01 10:10:10.123456'` datetime(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT
+{ts'2001-01-01 10:10:10'},
+{ts'2001-01-01 10:10:10.'},
+{ts'2001-01-01 10:10:10.123456'},
+{ts'2001-01-01'};
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `{ts'2001-01-01 10:10:10'}` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+  `{ts'2001-01-01 10:10:10.'}` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+  `{ts'2001-01-01 10:10:10.123456'}` datetime(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000',
+  `2001-01-01` varchar(10) NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+EXPLAIN EXTENDED SELECT {ts'2010-01-01 10:10:10'};
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select TIMESTAMP'2010-01-01 10:10:10' AS `{ts'2010-01-01 10:10:10'}`
+EXPLAIN EXTENDED SELECT TIMESTAMP'2010-01-01 10:10:10';
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select TIMESTAMP'2010-01-01 10:10:10' AS `TIMESTAMP'2010-01-01 10:10:10'`
+#
+# Testing nanosecond rounding for TIMESTAMP literals with bad dates
+#
+SELECT TIMESTAMP'2001-00-00 00:00:00.999999';
+TIMESTAMP'2001-00-00 00:00:00.999999'
+2001-00-00 00:00:00.999999
+SELECT TIMESTAMP'2001-00-01 00:00:00.999999';
+TIMESTAMP'2001-00-01 00:00:00.999999'
+2001-00-01 00:00:00.999999
+SELECT TIMESTAMP'2001-01-00 00:00:00.999999';
+TIMESTAMP'2001-01-00 00:00:00.999999'
+2001-01-00 00:00:00.999999
+SELECT TIMESTAMP'2001-00-00 00:00:00.9999999';
+ERROR HY000: Incorrect DATETIME value: '2001-00-00 00:00:00.9999999'
+SELECT TIMESTAMP'2001-00-01 00:00:00.9999999';
+ERROR HY000: Incorrect DATETIME value: '2001-00-01 00:00:00.9999999'
+SELECT TIMESTAMP'2001-01-00 00:00:00.9999999';
+ERROR HY000: Incorrect DATETIME value: '2001-01-00 00:00:00.9999999'
+#
+# String literal with bad dates and nanoseconds to DATETIME(N)
+#
+CREATE TABLE t1 (a DATETIME(6));
+INSERT INTO t1 VALUES ('2001-00-00 00:00:00.9999999');
+Warnings:
+Warning	1265	Data truncated for column 'a' at row 1
+INSERT INTO t1 VALUES ('2001-00-01 00:00:00.9999999');
+Warnings:
+Warning	1265	Data truncated for column 'a' at row 1
+INSERT INTO t1 VALUES ('2001-01-00 00:00:00.9999999');
+Warnings:
+Warning	1265	Data truncated for column 'a' at row 1
+SELECT * FROM t1;
+a
+2001-00-00 00:00:00.999999
+2001-00-01 00:00:00.999999
+2001-01-00 00:00:00.999999
+DROP TABLE t1;
+CREATE TABLE t1 (a DATETIME(5));
+INSERT INTO t1 VALUES ('2001-00-00 00:00:00.9999999');
+Warnings:
+Warning	1265	Data truncated for column 'a' at row 1
+INSERT INTO t1 VALUES ('2001-00-01 00:00:00.9999999');
+Warnings:
+Warning	1265	Data truncated for column 'a' at row 1
+INSERT INTO t1 VALUES ('2001-01-00 00:00:00.9999999');
+Warnings:
+Warning	1265	Data truncated for column 'a' at row 1
+SELECT * FROM t1;
+a
+2001-00-00 00:00:00.99999
+2001-00-01 00:00:00.99999
+2001-01-00 00:00:00.99999
+DROP TABLE t1;
+CREATE TABLE t1 (a DATETIME);
+INSERT INTO t1 VALUES ('2001-00-00 00:00:00.9999999');
+Warnings:
+Warning	1265	Data truncated for column 'a' at row 1
+INSERT INTO t1 VALUES ('2001-00-01 00:00:00.9999999');
+Warnings:
+Warning	1265	Data truncated for column 'a' at row 1
+INSERT INTO t1 VALUES ('2001-01-00 00:00:00.9999999');
+Warnings:
+Warning	1265	Data truncated for column 'a' at row 1
+SELECT * FROM t1;
+a
+2001-00-00 00:00:00
+2001-00-01 00:00:00
+2001-01-00 00:00:00
+DROP TABLE t1;
+#
+# Testing Item_date_literal::eq
+#
+CREATE TABLE t1 (a DATE);
+INSERT INTO t1 VALUES ('2001-01-01'),('2003-01-01');
+SELECT * FROM t1 WHERE a BETWEEN DATE'2001-01-01' AND DATE'2002-01-01';
+a
+2001-01-01
+SELECT DATE'2001-01-01' FROM t1 GROUP BY DATE'2001-01-01';
+DATE'2001-01-01'
+2001-01-01
+DROP TABLE t1;
+#
+# TIME literals in no-zero date context
+#
+SELECT TO_DAYS(TIME'00:00:00');
+TO_DAYS(TIME'00:00:00')
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '00:00:00'
+SELECT TO_SECONDS(TIME'00:00:00');
+TO_SECONDS(TIME'00:00:00')
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '00:00:00'
+SELECT DAYOFYEAR(TIME'00:00:00');
+DAYOFYEAR(TIME'00:00:00')
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '00:00:00'
+SELECT WEEK(TIME'00:00:00');
+WEEK(TIME'00:00:00')
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '00:00:00'
+SELECT YEARWEEK(TIME'00:00:00');
+YEARWEEK(TIME'00:00:00')
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '00:00:00'
+SELECT WEEKDAY(TIME'00:00:00');
+WEEKDAY(TIME'00:00:00')
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '00:00:00'
+SELECT CONVERT_TZ(TIME'00:00:00','+00:00','+01:00');
+CONVERT_TZ(TIME'00:00:00','+00:00','+01:00')
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '00:00:00'
+SELECT DATE_ADD(TIME'00:00:00', INTERVAL 1 HOUR);
+DATE_ADD(TIME'00:00:00', INTERVAL 1 HOUR)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '00:00:00'
+SELECT TIMESTAMPDIFF(SECOND,TIME'00:00:00', TIME'00:00:00');
+TIMESTAMPDIFF(SECOND,TIME'00:00:00', TIME'00:00:00')
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '00:00:00'
+#
+# Testing Item_func::fix_fields()
+#
+SELECT 'a' LIKE 'a' ESCAPE DATE'2001-01-01';
+ERROR HY000: Incorrect arguments to ESCAPE
+SELECT 'a' LIKE 'a' ESCAPE TIMESTAMP'2001-01-01 00:00:00';
+ERROR HY000: Incorrect arguments to ESCAPE
+SELECT 'a' LIKE 'a' ESCAPE TIME'00:00:00';
+ERROR HY000: Incorrect arguments to ESCAPE

=== modified file 'mysql-test/t/cast.test'
--- mysql-test/t/cast.test	2013-05-07 11:05:09 +0000
+++ mysql-test/t/cast.test	2013-06-24 07:07:17 +0000
@@ -74,11 +74,11 @@ select 10E+0+'10';
 
 # The following cast creates warnings
 
-select CONVERT(DATE "2004-01-22 21:45:33" USING latin1);
-select CONVERT(DATE "2004-01-22 21:45:33",CHAR);
-select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4));
-select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4));
-select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4));
+select CONVERT(TIMESTAMP "2004-01-22 21:45:33" USING latin1);
+select CONVERT(TIMESTAMP "2004-01-22 21:45:33",CHAR);
+select CONVERT(TIMESTAMP "2004-01-22 21:45:33",CHAR(4));
+select CONVERT(TIMESTAMP "2004-01-22 21:45:33",BINARY(4));
+select CAST(TIMESTAMP "2004-01-22 21:45:33" AS BINARY(4));
 select CAST(0xb3 as signed);
 select CAST(0x8fffffffffffffff as signed);
 select CAST(0xffffffffffffffff as unsigned);

=== modified file 'mysql-test/t/partition_innodb.test'
--- mysql-test/t/partition_innodb.test	2013-01-31 08:48:19 +0000
+++ mysql-test/t/partition_innodb.test	2013-06-24 07:05:45 +0000
@@ -60,8 +60,8 @@ insert into t1(c2,c3) values ("Test row"
 
 SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'test';
 SELECT count(*) FROM t1 p where c3 in
-(select c3 from t1 t where t.c3 < date '2011-04-26 19:19:44'
- and t.c3 > date '2011-04-26 19:18:44') ;
+(select c3 from t1 t where t.c3 < timestamp '2011-04-26 19:19:44'
+ and t.c3 > timestamp '2011-04-26 19:18:44') ;
 
 DROP TABLE t1;
 

=== added file 'mysql-test/t/temporal_literal.test'
--- mysql-test/t/temporal_literal.test	1970-01-01 00:00:00 +0000
+++ mysql-test/t/temporal_literal.test	2013-06-26 09:12:06 +0000
@@ -0,0 +1,214 @@
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+SET NAMES latin1;
+
+
+--echo #
+--echo # Testing DATE literals
+--echo #
+--error ER_WRONG_VALUE
+SELECT DATE'xxxx';
+--error ER_WRONG_VALUE
+SELECT DATE'01';
+--error ER_WRONG_VALUE
+SELECT DATE'01-01';
+--error ER_WRONG_VALUE
+SELECT DATE'2001';
+--error ER_WRONG_VALUE
+SELECT DATE'2001-01';
+SELECT DATE'2001-00-00';
+SELECT DATE'2001-01-00';
+SELECT DATE'0000-00-00';
+--error ER_WRONG_VALUE
+SELECT DATE'2001-01-01 00:00:00';
+SELECT DATE'01:01:01';
+SELECT DATE'01-01-01';
+SELECT DATE'2010-01-01';
+SELECT DATE '2010-01-01';
+CREATE TABLE t1 AS SELECT DATE'2010-01-01';
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT
+  {d'2001-01-01'},
+  {d'2001-01-01 10:10:10'};
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+EXPLAIN EXTENDED SELECT {d'2010-01-01'};
+EXPLAIN EXTENDED SELECT DATE'2010-01-01';
+
+--echo #
+--echo # Testing DATE literals in non-default sql_mode
+--echo #
+SET sql_mode=no_zero_in_date;
+--error ER_WRONG_VALUE
+SELECT DATE'2001-00-00';
+--error ER_WRONG_VALUE
+SELECT DATE'2001-01-00';
+SELECT DATE'0000-00-00';
+
+SET sql_mode=no_zero_date;
+--error ER_WRONG_VALUE
+SELECT DATE'0000-00-00';
+SET sql_mode=default;
+
+--echo #
+--echo # Testing TIME literals
+--echo #
+--error ER_WRONG_VALUE
+SELECT TIME'xxxx';
+--error ER_WRONG_VALUE
+SELECT TIME'900:00:00';
+--error ER_WRONG_VALUE
+SELECT TIME'-900:00:00';
+SELECT TIME'1 24:00:00';
+SELECT TIME'30 24:00:00';
+--error ER_WRONG_VALUE
+SELECT TIME'0000-00-00 00:00:00';
+--error ER_WRONG_VALUE
+SELECT TIME'40 24:00:00';
+SELECT TIME'10';
+SELECT TIME'10:10';
+SELECT TIME'10:11.12';
+SELECT TIME'10:10:10';
+SELECT TIME'10:10:10.';
+SELECT TIME'10:10:10.1';
+SELECT TIME'10:10:10.12';
+SELECT TIME'10:10:10.123';
+SELECT TIME'10:10:10.1234';
+SELECT TIME'10:10:10.12345';
+SELECT TIME'10:10:10.123456';
+SELECT TIME'-10:00:00';
+SELECT TIME '10:11:12';
+CREATE TABLE t1 AS SELECT
+  TIME'10:10:10',
+  TIME'10:10:10.',
+  TIME'10:10:10.1',
+  TIME'10:10:10.12',
+  TIME'10:10:10.123',
+  TIME'10:10:10.1234',
+  TIME'10:10:10.12345',
+  TIME'10:10:10.123456';
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT
+  {t'10:10:10'},
+  {t'10:10:10.'},
+  {t'10:10:10.123456'},
+  {t'2001-01-01'};
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+EXPLAIN EXTENDED SELECT {t'10:01:01'};
+EXPLAIN EXTENDED SELECT TIME'10:01:01';
+
+
+--echo #
+--echo # Testing TIMESTAMP literals
+--echo #
+--error ER_WRONG_VALUE
+SELECT TIMESTAMP'xxxx';
+--error ER_WRONG_VALUE
+SELECT TIMESTAMP'2010';
+--error ER_WRONG_VALUE
+SELECT TIMESTAMP'2010-01';
+--error ER_WRONG_VALUE
+SELECT TIMESTAMP'2010-01-01';
+SELECT TIMESTAMP'2010-01-01 00';
+SELECT TIMESTAMP'2010-01-01 00:01';
+SELECT TIMESTAMP'2010-01-01 10:10:10';
+SELECT TIMESTAMP'2010-01-01 10:10:10.';
+SELECT TIMESTAMP'2010-01-01 10:10:10.1';
+SELECT TIMESTAMP'2010-01-01 10:10:10.12';
+SELECT TIMESTAMP'2010-01-01 10:10:10.123';
+SELECT TIMESTAMP'2010-01-01 10:10:10.1234';
+SELECT TIMESTAMP'2010-01-01 10:10:10.12345';
+SELECT TIMESTAMP'2010-01-01 10:10:10.123456';
+SELECT TIMESTAMP '2010-01-01 10:20:30';
+CREATE TABLE t1 AS SELECT
+  TIMESTAMP'2010-01-01 10:10:10',
+  TIMESTAMP'2010-01-01 10:10:10.',
+  TIMESTAMP'2010-01-01 10:10:10.1',
+  TIMESTAMP'2010-01-01 10:10:10.12',
+  TIMESTAMP'2010-01-01 10:10:10.123',
+  TIMESTAMP'2010-01-01 10:10:10.1234',
+  TIMESTAMP'2010-01-01 10:10:10.12345',
+  TIMESTAMP'2010-01-01 10:10:10.123456';
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT
+  {ts'2001-01-01 10:10:10'},
+  {ts'2001-01-01 10:10:10.'},
+  {ts'2001-01-01 10:10:10.123456'},
+  {ts'2001-01-01'};
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+EXPLAIN EXTENDED SELECT {ts'2010-01-01 10:10:10'};
+EXPLAIN EXTENDED SELECT TIMESTAMP'2010-01-01 10:10:10';
+
+--echo #
+--echo # Testing nanosecond rounding for TIMESTAMP literals with bad dates
+--echo #
+SELECT TIMESTAMP'2001-00-00 00:00:00.999999';
+SELECT TIMESTAMP'2001-00-01 00:00:00.999999';
+SELECT TIMESTAMP'2001-01-00 00:00:00.999999';
+--error ER_WRONG_VALUE
+SELECT TIMESTAMP'2001-00-00 00:00:00.9999999';
+--error ER_WRONG_VALUE
+SELECT TIMESTAMP'2001-00-01 00:00:00.9999999';
+--error ER_WRONG_VALUE
+SELECT TIMESTAMP'2001-01-00 00:00:00.9999999';
+
+--echo #
+--echo # String literal with bad dates and nanoseconds to DATETIME(N)
+--echo #
+CREATE TABLE t1 (a DATETIME(6));
+INSERT INTO t1 VALUES ('2001-00-00 00:00:00.9999999');
+INSERT INTO t1 VALUES ('2001-00-01 00:00:00.9999999');
+INSERT INTO t1 VALUES ('2001-01-00 00:00:00.9999999');
+SELECT * FROM t1;
+DROP TABLE t1;
+CREATE TABLE t1 (a DATETIME(5));
+INSERT INTO t1 VALUES ('2001-00-00 00:00:00.9999999');
+INSERT INTO t1 VALUES ('2001-00-01 00:00:00.9999999');
+INSERT INTO t1 VALUES ('2001-01-00 00:00:00.9999999');
+SELECT * FROM t1;
+DROP TABLE t1;
+CREATE TABLE t1 (a DATETIME);
+INSERT INTO t1 VALUES ('2001-00-00 00:00:00.9999999');
+INSERT INTO t1 VALUES ('2001-00-01 00:00:00.9999999');
+INSERT INTO t1 VALUES ('2001-01-00 00:00:00.9999999');
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing Item_date_literal::eq
+--echo #
+CREATE TABLE t1 (a DATE);
+INSERT INTO t1 VALUES ('2001-01-01'),('2003-01-01');
+SELECT * FROM t1 WHERE a BETWEEN DATE'2001-01-01' AND DATE'2002-01-01';
+SELECT DATE'2001-01-01' FROM t1 GROUP BY DATE'2001-01-01';
+DROP TABLE t1;
+
+--echo #
+--echo # TIME literals in no-zero date context
+--echo #
+SELECT TO_DAYS(TIME'00:00:00');
+SELECT TO_SECONDS(TIME'00:00:00');
+SELECT DAYOFYEAR(TIME'00:00:00');
+SELECT WEEK(TIME'00:00:00');
+SELECT YEARWEEK(TIME'00:00:00');
+SELECT WEEKDAY(TIME'00:00:00');
+SELECT CONVERT_TZ(TIME'00:00:00','+00:00','+01:00');
+SELECT DATE_ADD(TIME'00:00:00', INTERVAL 1 HOUR);
+SELECT TIMESTAMPDIFF(SECOND,TIME'00:00:00', TIME'00:00:00');
+
+--echo #
+--echo # Testing Item_func::fix_fields()
+--echo #
+--error ER_WRONG_ARGUMENTS
+SELECT 'a' LIKE 'a' ESCAPE DATE'2001-01-01';
+--error ER_WRONG_ARGUMENTS
+SELECT 'a' LIKE 'a' ESCAPE TIMESTAMP'2001-01-01 00:00:00';
+--error ER_WRONG_ARGUMENTS
+SELECT 'a' LIKE 'a' ESCAPE TIME'00:00:00';

=== modified file 'sql-common/my_time.c'
--- sql-common/my_time.c	2013-04-07 12:00:16 +0000
+++ sql-common/my_time.c	2013-06-26 09:23:23 +0000
@@ -217,9 +217,8 @@ static uint skip_digits(const char **str
                         TIME_NO_ZERO_IN_DATE	Don't allow partial dates
                         TIME_NO_ZERO_DATE	Don't allow 0000-00-00 date
                         TIME_INVALID_DATES	Allow 2000-02-31
-    was_cut             0	Value OK
-			1       If value was cut during conversion
-			2	check_date(date,flags) considers date invalid
+    status              Conversion status
+
 
   DESCRIPTION
     At least the following formats are recogniced (based on number of digits)
@@ -230,20 +229,43 @@ static uint skip_digits(const char **str
 
     The second part may have an optional .###### fraction part.
 
-  RETURN VALUES
+  NOTES
+   This function should work with a format position vector as long as the
+   following things holds:
+   - All date are kept together and all time parts are kept together
+   - Date and time parts must be separated by blank
+   - Second fractions must come after second part and be separated
+     by a '.'.  (The second fractions are optional)
+   - AM/PM must come after second fractions (or after seconds if no fractions)
+   - Year must always been specified.
+   - If time is before date, then we will use datetime format only if
+     the argument consist of two parts, separated by space.
+     Otherwise we will assume the argument is a date.
+   - The hour part must be specified in hour-minute-second order.
+
+    status->warnings is set to:
+    0                            Value OK
+    MYSQL_TIME_WARN_TRUNCATED    If value was cut during conversion
+    MYSQL_TIME_WARN_OUT_OF_RANGE check_date(date,flags) considers date invalid
+
+    l_time->time_type is set as follows:
     MYSQL_TIMESTAMP_NONE        String wasn't a timestamp, like
                                 [DD [HH:[MM:[SS]]]].fraction.
+                                l_time is not changed.
     MYSQL_TIMESTAMP_DATE        DATE string (YY MM and DD parts ok)
     MYSQL_TIMESTAMP_DATETIME    Full timestamp
     MYSQL_TIMESTAMP_ERROR       Timestamp with wrong values.
                                 All elements in l_time is set to 0
+  RETURN VALUES
+    0 - Ok
+    1 - Error
 */
 
 #define MAX_DATE_PARTS 8
 
-enum enum_mysql_timestamp_type
+my_bool
 str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
-                ulonglong flags, int *was_cut)
+                ulonglong flags, MYSQL_TIME_STATUS *status)
 {
   const char *end=str+length, *pos;
   uint number_of_fields= 0, digits, year_length, not_zero_date;
@@ -252,19 +274,20 @@ str_to_datetime(const char *str, uint le
 
   if (flags & TIME_TIME_ONLY)
   {
-    enum enum_mysql_timestamp_type ret;
-    ret= str_to_time(str, length, l_time, flags, was_cut);
+    my_bool ret= str_to_time(str, length, l_time, flags, status);
     DBUG_RETURN(ret);
   }
-  *was_cut= 0;
+
+  my_time_status_init(status);
 
   /* Skip space at start */
   for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++)
     ;
   if (str == end || ! my_isdigit(&my_charset_latin1, *str))
   {
-    *was_cut= 1;
-    DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
+    status->warnings= MYSQL_TIME_WARN_TRUNCATED;
+    l_time->time_type= MYSQL_TIMESTAMP_NONE;
+    DBUG_RETURN(1);
   }
 
   /*
@@ -293,50 +316,57 @@ str_to_datetime(const char *str, uint le
       (only numbers like [YY]YYMMDD[T][hhmmss[.uuuuuu]])
     */
     year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
-    *was_cut= get_digits(&l_time->year, &number_of_fields, &str, end, year_length) 
-           || get_digits(&l_time->month, &number_of_fields, &str, end, 2)
-           || get_digits(&l_time->day, &number_of_fields, &str, end, 2)
-           || get_maybe_T(&str, end)
-           || get_digits(&l_time->hour, &number_of_fields, &str, end, 2)
-           || get_digits(&l_time->minute, &number_of_fields, &str, end, 2)
-           || get_digits(&l_time->second, &number_of_fields, &str, end, 2);
+    if (get_digits(&l_time->year, &number_of_fields, &str, end, year_length) 
+        || get_digits(&l_time->month, &number_of_fields, &str, end, 2)
+        || get_digits(&l_time->day, &number_of_fields, &str, end, 2)
+        || get_maybe_T(&str, end)
+        || get_digits(&l_time->hour, &number_of_fields, &str, end, 2)
+        || get_digits(&l_time->minute, &number_of_fields, &str, end, 2)
+        || get_digits(&l_time->second, &number_of_fields, &str, end, 2))
+     status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
   }
   else
   {
     const char *start= str;
-    *was_cut = get_number(&l_time->year, &number_of_fields, &str, end);
+    if (get_number(&l_time->year, &number_of_fields, &str, end))
+      status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
     year_length= str - start;
 
-    if (!*was_cut)
-      *was_cut= get_punct(&str, end)
-             || get_number(&l_time->month, &number_of_fields, &str, end)
-             || get_punct(&str, end)
-             || get_number(&l_time->day, &number_of_fields, &str, end)
-             || get_date_time_separator(&number_of_fields, flags, &str, end)
-             || get_number(&l_time->hour, &number_of_fields, &str, end)
-             || get_punct(&str, end)
-             || get_number(&l_time->minute, &number_of_fields, &str, end)
-             || get_punct(&str, end)
-             || get_number(&l_time->second, &number_of_fields, &str, end);
+    if (!status->warnings &&
+        (get_punct(&str, end)
+         || get_number(&l_time->month, &number_of_fields, &str, end)
+         || get_punct(&str, end)
+         || get_number(&l_time->day, &number_of_fields, &str, end)
+         || get_date_time_separator(&number_of_fields, flags, &str, end)
+         || get_number(&l_time->hour, &number_of_fields, &str, end)
+         || get_punct(&str, end)
+         || get_number(&l_time->minute, &number_of_fields, &str, end)
+         || get_punct(&str, end)
+         || get_number(&l_time->second, &number_of_fields, &str, end)))
+      status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
   }
 
   if (number_of_fields < 3)
-    *was_cut= 1;
+    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
 
   /* we're ok if date part is correct. even if the rest is truncated */
-  if (*was_cut && number_of_fields < 3)
-    DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
+  if (status->warnings && number_of_fields < 3)
+  {
+    l_time->time_type= MYSQL_TIMESTAMP_NONE;
+    DBUG_RETURN(TRUE);
+  }
 
-  if (!*was_cut && str < end && *str == '.')
+  if (!status->warnings && str < end && *str == '.')
   {
-    uint second_part;
+    uint second_part= 0; // Init to 0 for this case: '2001-01-01 00:00:00.'
     const char *start= ++str;
-    *was_cut= get_digits(&second_part, &number_of_fields, &str, end, 6);
-    if (str - start < 6)
+    if (get_digits(&second_part, &number_of_fields, &str, end, 6))
+      status->warnings= MYSQL_TIME_WARN_TRUNCATED;
+    if ((status->fractional_digits= (str - start)) < 6)
       second_part*= log_10_int[6 - (str - start)];
     l_time->second_part= second_part;
     if (skip_digits(&str, end))
-      *was_cut= 1;
+      status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
   }
 
   not_zero_date = l_time->year || l_time->month || l_time->day ||
@@ -349,11 +379,11 @@ str_to_datetime(const char *str, uint le
   if (l_time->year > 9999 || l_time->month > 12 || l_time->day > 31 ||
       l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59)
   {
-    *was_cut= 1;
+    status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
     goto err;
   }
 
-  if (check_date(l_time, not_zero_date, flags, was_cut))
+  if (check_date(l_time, not_zero_date, flags, &status->warnings))
     goto err;
 
   l_time->time_type= (number_of_fields <= 3 ?
@@ -363,16 +393,17 @@ str_to_datetime(const char *str, uint le
   {
     if (!my_isspace(&my_charset_latin1,*str))
     {
-      *was_cut= 1;
+      status->warnings= MYSQL_TIME_WARN_TRUNCATED;
       break;
     }
   }
 
-  DBUG_RETURN(l_time->time_type);
+  DBUG_RETURN(FALSE);
 
 err:
   bzero((char*) l_time, sizeof(*l_time));
-  DBUG_RETURN(MYSQL_TIMESTAMP_ERROR);
+  l_time->time_type= MYSQL_TIMESTAMP_ERROR;
+  DBUG_RETURN(TRUE);
 }
 
 
@@ -401,9 +432,8 @@ str_to_datetime(const char *str, uint le
      MYSQL_TIMESTAMP_ERROR
 */
 
-enum enum_mysql_timestamp_type
-str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
-            ulonglong fuzzydate, int *warning)
+my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
+                    ulonglong fuzzydate, MYSQL_TIME_STATUS *status)
 {
   ulong date[5];
   ulonglong value;
@@ -411,7 +441,7 @@ str_to_time(const char *str, uint length
   my_bool found_days,found_hours, neg= 0;
   uint UNINIT_VAR(state);
 
-  *warning= 0;
+  my_time_status_init(status);
   for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++)
     length--;
   if (str != end && *str == '-')
@@ -421,22 +451,17 @@ str_to_time(const char *str, uint length
     length--;
   }
   if (str == end)
-    return MYSQL_TIMESTAMP_ERROR;
+    return TRUE;
 
   /* Check first if this is a full TIMESTAMP */
   if (length >= 12)
   {                                             /* Probably full timestamp */
-    int was_cut;
-    enum enum_mysql_timestamp_type
-      res= str_to_datetime(str, length, l_time,
+    (void) str_to_datetime(str, length, l_time,
                            (fuzzydate & ~TIME_TIME_ONLY) | TIME_DATETIME_ONLY,
-                           &was_cut);
-    if ((int) res >= (int) MYSQL_TIMESTAMP_ERROR)
-    {
-      if (was_cut)
-        *warning|= MYSQL_TIME_WARN_TRUNCATED;
-      return res;
-    }
+                            status);
+    if (l_time->time_type >= MYSQL_TIMESTAMP_ERROR)
+      return l_time->time_type == MYSQL_TIMESTAMP_ERROR;
+    my_time_status_init(status);
   }
 
   l_time->neg= neg;
@@ -513,12 +538,26 @@ str_to_time(const char *str, uint length
       if (field_length-- > 0)
         value= value*10 + (uint) (uchar) (*str - '0');
     }
-    if (field_length > 0)
-      value*= (long) log_10_int[field_length];
-    else if (field_length < 0)
-      *warning|= MYSQL_TIME_WARN_TRUNCATED;
+    if (field_length >= 0)
+    {
+      status->fractional_digits= TIME_SECOND_PART_DIGITS - field_length;
+      if (field_length > 0)
+        value*= (long) log_10_int[field_length];
+    }
+    else
+    {
+      /* Scan digits left after microseconds */
+      status->fractional_digits= 6;
+      for ( ; str != end && my_isdigit(&my_charset_latin1, *str); str++)
+      { }
+    }
     date[4]= (ulong) value;
   }
+  else if ((end - str) == 1 && *str == '.')
+  {
+    str++;
+    date[4]= 0;
+  }
   else
     date[4]=0;
     
@@ -530,7 +569,7 @@ str_to_time(const char *str, uint length
        ((str[1] == '-' || str[1] == '+') &&
         (end - str) > 2 &&
         my_isdigit(&my_charset_latin1, str[2]))))
-    return MYSQL_TIMESTAMP_ERROR;
+    return TRUE;
 
   if (internal_format_positions[7] != 255)
   {
@@ -553,7 +592,7 @@ str_to_time(const char *str, uint length
   if (date[0] > UINT_MAX || date[1] > UINT_MAX ||
       date[2] > UINT_MAX || date[3] > UINT_MAX ||
       date[4] > UINT_MAX)
-    return MYSQL_TIMESTAMP_ERROR;
+    return TRUE;
   
   l_time->year=         0;                      /* For protocol::store_time */
   l_time->month=        0;
@@ -565,9 +604,9 @@ str_to_time(const char *str, uint length
   l_time->time_type= MYSQL_TIMESTAMP_TIME;
 
   /* Check if the value is valid and fits into MYSQL_TIME range */
-  if (check_time_range(l_time, 6, warning))
-    return MYSQL_TIMESTAMP_ERROR;
-  
+  if (check_time_range(l_time, 6, &status->warnings))
+    return TRUE;
+
   /* Check if there is garbage at end of the MYSQL_TIME specification */
   if (str != end)
   {
@@ -575,12 +614,12 @@ str_to_time(const char *str, uint length
     {
       if (!my_isspace(&my_charset_latin1,*str))
       {
-        *warning|= MYSQL_TIME_WARN_TRUNCATED;
+        status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
         break;
       }
     } while (++str != end);
   }
-  return MYSQL_TIMESTAMP_TIME;
+  return FALSE;
 }
 
 
@@ -610,7 +649,10 @@ int check_time_range(struct st_mysql_tim
                                              999000, 999900, 999990, 999999};
 
   if (my_time->minute >= 60 || my_time->second >= 60)
+  {
+    *warning|= MYSQL_TIME_WARN_TRUNCATED;
     return 1;
+  }
 
   hour= my_time->hour + (24*my_time->day);
 
@@ -1357,7 +1399,7 @@ double TIME_to_double(const MYSQL_TIME *
   return my_time->neg ? -d : d;
 }
 
-longlong pack_time(MYSQL_TIME *my_time)
+longlong pack_time(const MYSQL_TIME *my_time)
 {
   return  ((((((my_time->year     * 13ULL +
                my_time->month)    * 32ULL +

=== modified file 'sql/field.cc'
--- sql/field.cc	2013-06-06 19:32:29 +0000
+++ sql/field.cc	2013-06-26 08:10:53 +0000
@@ -1822,7 +1822,7 @@ bool Field::get_date(MYSQL_TIME *ltime,u
   String tmp(buff,sizeof(buff),&my_charset_bin),*res;
   if (!(res=val_str(&tmp)) ||
       str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
-                                ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
+                                ltime, fuzzydate))
     return 1;
   return 0;
 }
@@ -4570,18 +4570,18 @@ int Field_timestamp::store_time_dec(MYSQ
 int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
 {
   MYSQL_TIME l_time;
-  int error;
-  int have_smth_to_conv;
+  MYSQL_TIME_STATUS status;
+  bool have_smth_to_conv;
   ErrConvString str(from, len, cs);
   THD *thd= get_thd();
 
   /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
-  have_smth_to_conv= (str_to_datetime(cs, from, len, &l_time,
+  have_smth_to_conv= !str_to_datetime(cs, from, len, &l_time,
                                       (thd->variables.sql_mode &
                                        MODE_NO_ZERO_DATE) |
-                                       MODE_NO_ZERO_IN_DATE, &error) >
-                      MYSQL_TIMESTAMP_ERROR);
-  return store_TIME_with_warning(thd, &l_time, &str, error, have_smth_to_conv);
+                                       MODE_NO_ZERO_IN_DATE, &status);
+  return store_TIME_with_warning(thd, &l_time, &str,
+                                 status.warnings, have_smth_to_conv);
 }
 
 
@@ -5060,18 +5060,16 @@ int Field_temporal::store_TIME_with_warn
 int Field_temporal::store(const char *from,uint len,CHARSET_INFO *cs)
 {
   MYSQL_TIME ltime;
-  int error;
-  enum enum_mysql_timestamp_type func_res;
+  MYSQL_TIME_STATUS status;
   THD *thd= get_thd();
   ErrConvString str(from, len, cs);
-
-  func_res= str_to_datetime(cs, from, len, &ltime,
-                            (TIME_FUZZY_DATE |
-                             (thd->variables.sql_mode &
-                              (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
-                               MODE_INVALID_DATES))),
-                            &error);
-  return store_TIME_with_warning(&ltime, &str, error, func_res > MYSQL_TIMESTAMP_ERROR);
+  bool func_res= !str_to_datetime(cs, from, len, &ltime,
+                                  (TIME_FUZZY_DATE |
+                                   (thd->variables.sql_mode &
+                                   (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+                                   MODE_INVALID_DATES))),
+                                  &status);
+  return store_TIME_with_warning(&ltime, &str, status.warnings, func_res);
 }
 
 
@@ -5157,16 +5155,17 @@ void Field_time::store_TIME(MYSQL_TIME *
 int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
 {
   MYSQL_TIME ltime;
+  MYSQL_TIME_STATUS status;
   ErrConvString str(from, len, cs);
-  int was_cut;
-  int have_smth_to_conv=
-    str_to_time(cs, from, len, &ltime,
+  bool have_smth_to_conv= 
+   !str_to_time(cs, from, len, &ltime,
                 get_thd()->variables.sql_mode &
                 (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
                  MODE_INVALID_DATES),
-                &was_cut) > MYSQL_TIMESTAMP_ERROR;
+                &status);
 
-  return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
+  return store_TIME_with_warning(&ltime, &str,
+                                 status.warnings, have_smth_to_conv);
 }
 
 

=== modified file 'sql/item.cc'
--- sql/item.cc	2013-06-06 19:32:29 +0000
+++ sql/item.cc	2013-06-24 07:00:46 +0000
@@ -1269,7 +1269,7 @@ bool Item::get_date(MYSQL_TIME *ltime,ul
     String tmp(buff,sizeof(buff), &my_charset_bin),*res;
     if (!(res=val_str(&tmp)) ||
         str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
-                                  ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
+                                  ltime, fuzzydate))
       goto err;
     break;
   }

=== modified file 'sql/item_cmpfunc.cc'
--- sql/item_cmpfunc.cc	2013-06-06 15:51:28 +0000
+++ sql/item_cmpfunc.cc	2013-06-26 08:12:33 +0000
@@ -721,19 +721,18 @@ bool get_mysql_time_from_str(THD *thd, S
                              const char *warn_name, MYSQL_TIME *l_time)
 {
   bool value;
-  int error;
-  enum_mysql_timestamp_type timestamp_type;
+  MYSQL_TIME_STATUS status;
   int flags= TIME_FUZZY_DATE | MODE_INVALID_DATES;
   ErrConvString err(str);
 
+  DBUG_ASSERT(warn_type != MYSQL_TIMESTAMP_TIME); // Serg: why the below code?
   if (warn_type == MYSQL_TIMESTAMP_TIME)
     flags|= TIME_TIME_ONLY;
 
-  timestamp_type= 
-    str_to_datetime(str->charset(), str->ptr(), str->length(),
-                    l_time, flags, &error);
-
-  if (timestamp_type > MYSQL_TIMESTAMP_ERROR)
+  if (!str_to_datetime(str->charset(), str->ptr(), str->length(),
+                       l_time, flags, &status) &&
+      (l_time->time_type == MYSQL_TIMESTAMP_DATETIME || 
+       l_time->time_type == MYSQL_TIMESTAMP_DATE))
     /*
       Do not return yet, we may still want to throw a "trailing garbage"
       warning.
@@ -741,11 +740,12 @@ bool get_mysql_time_from_str(THD *thd, S
     value= FALSE;
   else
   {
+    DBUG_ASSERT(l_time->time_type != MYSQL_TIMESTAMP_TIME); // Serg: see above
     value= TRUE;
-    error= 1;                                   /* force warning */
+    status.warnings= MYSQL_TIME_WARN_TRUNCATED;          /* force warning */
   }
 
-  if (error > 0)
+  if (status.warnings > 0)
     make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                                  &err, warn_type, warn_name);
 

=== modified file 'sql/item_create.cc'
--- sql/item_create.cc	2013-04-20 20:30:21 +0000
+++ sql/item_create.cc	2013-06-25 07:24:57 +0000
@@ -32,6 +32,7 @@
 #include "set_var.h"
 #include "sp_head.h"
 #include "sp.h"
+#include "sql_time.h"
 
 /*
 =============================================================================
@@ -5821,6 +5822,70 @@ create_func_cast(THD *thd, Item *a, Cast
 }
 
 
+/**
+  Builder for datetime literals:
+    TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'.
+  @param thd          The current thread
+  @param str          Character literal
+  @param length       Length of str
+  @param type         Type of literal (TIME, DATE or DATETIME)
+  @param send_error   Whether to generate an error on failure
+*/
+
+Item *create_temporal_literal(THD *thd,
+                              const char *str, uint length,
+                              CHARSET_INFO *cs,
+                              enum_field_types type,
+                              bool send_error)
+{
+  MYSQL_TIME_STATUS status;
+  MYSQL_TIME ltime;
+  Item *item= NULL;
+  ulonglong datetime_flags= thd->variables.sql_mode &
+                            (MODE_NO_ZERO_IN_DATE |
+                             MODE_NO_ZERO_DATE |
+                             MODE_INVALID_DATES);
+  ulonglong flags= TIME_FUZZY_DATE | datetime_flags;
+
+  switch(type)
+  {
+  case MYSQL_TYPE_DATE:
+  case MYSQL_TYPE_NEWDATE:
+    if (!str_to_datetime(cs, str, length, &ltime, flags, &status) &&
+        ltime.time_type == MYSQL_TIMESTAMP_DATE && !status.warnings)
+      item= new (thd->mem_root) Item_date_literal(&ltime);
+    break;
+  case MYSQL_TYPE_DATETIME:
+    if (!str_to_datetime(cs, str, length, &ltime, flags, &status) &&
+        ltime.time_type == MYSQL_TIMESTAMP_DATETIME && !status.warnings)
+      item= new (thd->mem_root) Item_datetime_literal(&ltime,
+                                                      status.fractional_digits);
+    break;
+  case MYSQL_TYPE_TIME:
+    if (!str_to_time(cs, str, length, &ltime, 0, &status) &&
+        ltime.time_type == MYSQL_TIMESTAMP_TIME && !status.warnings)
+      item= new (thd->mem_root) Item_time_literal(&ltime,
+                                                  status.fractional_digits);
+    break;
+  default:
+    DBUG_ASSERT(0);
+  }
+
+  if (item)
+    return item;
+
+  if (send_error)
+  {
+    const char *typestr=
+      (type == MYSQL_TYPE_DATE) ? "DATE" :
+      (type == MYSQL_TYPE_TIME) ? "TIME" : "DATETIME";
+    ErrConvString err(str, length, thd->variables.character_set_client);
+    my_error(ER_WRONG_VALUE, MYF(0), typestr, err.ptr());
+  }
+  return NULL;
+}
+
+
 static List<Item> *create_func_dyncol_prepare(THD *thd,
                                               DYNCALL_CREATE_DEF **dfs,
                                               List<DYNCALL_CREATE_DEF> &list)

=== modified file 'sql/item_create.h'
--- sql/item_create.h	2012-09-28 11:01:17 +0000
+++ sql/item_create.h	2013-06-25 07:25:26 +0000
@@ -168,6 +168,11 @@ create_func_cast(THD *thd, Item *a, Cast
                  const char *len, const char *dec,
                  CHARSET_INFO *cs);
 
+Item *create_temporal_literal(THD *thd,
+                              const char *str, uint length,
+                              CHARSET_INFO *cs,
+                              enum_field_types type,
+                              bool send_error);
 
 int item_create_init();
 void item_create_cleanup();

=== modified file 'sql/item_func.cc'
--- sql/item_func.cc	2013-06-07 21:16:00 +0000
+++ sql/item_func.cc	2013-06-25 08:15:19 +0000
@@ -174,7 +174,7 @@ Item_func::Item_func(THD *thd, Item_func
 bool
 Item_func::fix_fields(THD *thd, Item **ref)
 {
-  DBUG_ASSERT(fixed == 0);
+  DBUG_ASSERT(fixed == 0 || basic_const_item());
   Item **arg,**arg_end;
   uchar buff[STACK_BUFF_ALLOC];			// Max argument in function
 

=== modified file 'sql/item_strfunc.cc'
--- sql/item_strfunc.cc	2013-06-06 19:32:29 +0000
+++ sql/item_strfunc.cc	2013-06-24 07:01:05 +0000
@@ -4722,7 +4722,7 @@ bool Item_dyncol_get::get_date(MYSQL_TIM
     if (str_to_datetime_with_warn(&my_charset_numeric,
                                   val.x.string.value.str,
                                   val.x.string.value.length,
-                                  ltime, fuzzy_date) <= MYSQL_TIMESTAMP_ERROR)
+                                  ltime, fuzzy_date))
       goto null;
     return 0;
   case DYN_COL_DATETIME:

=== modified file 'sql/item_timefunc.cc'
--- sql/item_timefunc.cc	2013-04-07 12:00:16 +0000
+++ sql/item_timefunc.cc	2013-06-25 07:35:33 +0000
@@ -733,6 +733,95 @@ static bool get_interval_info(const char
 }
 
 
+bool Item_date_literal::eq(const Item *item, bool binary_cmp) const
+{
+  return
+    item->basic_const_item() && type() == item->type() &&
+    func_name() == ((Item_func *) item)->func_name() &&
+    !my_time_compare(&cached_time,
+                     &((Item_date_literal *) item)->cached_time);
+}
+
+
+void Item_date_literal::print(String *str, enum_query_type query_type)
+{
+  str->append("DATE'");
+  char buf[MAX_DATE_STRING_REP_LENGTH];
+  my_date_to_str(&cached_time, buf);
+  str->append(buf);
+  str->append('\'');
+}
+
+
+bool Item_date_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+{
+  DBUG_ASSERT(fixed);
+  *ltime= cached_time;
+  return (null_value= check_date_with_warn(ltime, fuzzy_date,
+                                           MYSQL_TIMESTAMP_ERROR));
+}
+
+
+bool Item_datetime_literal::eq(const Item *item, bool binary_cmp) const
+{
+  return
+    item->basic_const_item() && type() == item->type() &&
+    func_name() == ((Item_func *) item)->func_name() &&
+    !my_time_compare(&cached_time,
+                     &((Item_datetime_literal *) item)->cached_time);
+}
+
+
+void Item_datetime_literal::print(String *str, enum_query_type query_type)
+{
+  str->append("TIMESTAMP'");
+  char buf[MAX_DATE_STRING_REP_LENGTH];
+  my_datetime_to_str(&cached_time, buf, decimals);
+  str->append(buf);
+  str->append('\'');
+}
+
+
+bool Item_datetime_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+{
+  DBUG_ASSERT(fixed);
+  *ltime= cached_time;
+  return (null_value= check_date_with_warn(ltime, fuzzy_date,
+                                           MYSQL_TIMESTAMP_ERROR));
+}
+
+
+bool Item_time_literal::eq(const Item *item, bool binary_cmp) const
+{
+  return
+    item->basic_const_item() && type() == item->type() &&
+    func_name() == ((Item_func *) item)->func_name() &&
+    !my_time_compare(&cached_time,
+                     &((Item_time_literal *) item)->cached_time);
+}
+
+
+void Item_time_literal::print(String *str, enum_query_type query_type)
+{
+  str->append("TIME'");
+  char buf[MAX_DATE_STRING_REP_LENGTH];
+  my_time_to_str(&cached_time, buf, decimals);
+  str->append(buf);
+  str->append('\'');
+}
+
+
+bool Item_time_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+{
+  DBUG_ASSERT(fixed);
+  *ltime= cached_time;
+  if (fuzzy_date & TIME_TIME_ONLY)
+    return (null_value= false);
+  return (null_value= check_date_with_warn(ltime, fuzzy_date,
+                                           MYSQL_TIMESTAMP_ERROR));
+}
+
+
 longlong Item_func_period_add::val_int()
 {
   DBUG_ASSERT(fixed == 1);
@@ -2430,17 +2519,8 @@ bool Item_date_typecast::get_date(MYSQL_
 
   ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
   ltime->time_type= MYSQL_TIMESTAMP_DATE;
-
-  int unused;
-  if (check_date(ltime, ltime->year || ltime->month || ltime->day,
-                 fuzzy_date, &unused))
-  {
-    ErrConvTime str(ltime);
-    make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                                 &str, MYSQL_TIMESTAMP_DATE, 0);
-    return (null_value= 1);
-  }
-  return (null_value= 0);
+  return (null_value= check_date_with_warn(ltime, fuzzy_date,
+                                           MYSQL_TIMESTAMP_DATE));
 }
 
 

=== modified file 'sql/item_timefunc.h'
--- sql/item_timefunc.h	2013-03-13 21:33:52 +0000
+++ sql/item_timefunc.h	2013-06-24 07:26:29 +0000
@@ -526,6 +526,136 @@ class Item_timefunc :public Item_tempora
 };
 
 
+/**
+  DATE'2010-01-01'
+*/
+class Item_date_literal :public Item_datefunc
+{
+  MYSQL_TIME cached_time;
+public:
+  /**
+    Constructor for Item_date_literal.
+    @param ltime  DATE value.
+  */
+  Item_date_literal(MYSQL_TIME *ltime) :Item_datefunc()
+  {
+    cached_time= *ltime;
+    fix_length_and_dec();
+    fixed= 1;
+  }
+  const char *func_name() const { return "date_literal"; }
+  void print(String *str, enum_query_type query_type);
+  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+  void fix_length_and_dec()
+  {
+    Item_datefunc::fix_length_and_dec();
+    set_persist_maybe_null(false);
+  }
+  bool check_partition_func_processor(uchar *int_arg)
+  {
+    return FALSE;
+  }
+  bool basic_const_item() const { return true; }
+  bool const_item() const { return true; }
+  table_map used_tables() const { return (table_map) 0L; }
+  void cleanup()
+  {
+    // See Item_basic_const::cleanup()
+    if (orig_name)
+      name= orig_name;
+  }
+  bool eq(const Item *item, bool binary_cmp) const;
+};
+
+
+/**
+  TIME'10:10:10'
+*/
+class Item_time_literal :public Item_timefunc
+{
+  MYSQL_TIME cached_time;
+public:
+  /**
+    Constructor for Item_time_literal.
+    @param ltime    TIME value.
+    @param dec_arg  number of fractional digits in ltime.
+  */
+  Item_time_literal(MYSQL_TIME *ltime, uint dec_arg) :Item_timefunc()
+  {
+    decimals= MY_MIN(dec_arg, TIME_SECOND_PART_DIGITS);
+    cached_time= *ltime;
+    fix_length_and_dec();
+    fixed= 1;
+  }
+  const char *func_name() const { return "time_literal"; }
+  void print(String *str, enum_query_type query_type);
+  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+  void fix_length_and_dec()
+  {
+    Item_timefunc::fix_length_and_dec();
+    set_persist_maybe_null(false);
+  }
+  bool check_partition_func_processor(uchar *int_arg)
+  {
+    return FALSE;
+  }
+  bool basic_const_item() const { return true; }
+  bool const_item() const { return true; }
+  table_map used_tables() const { return (table_map) 0L; }
+  void cleanup()
+  {
+    // See Item_basic_const::cleanup()
+    if (orig_name)
+      name= orig_name;
+  }
+  bool eq(const Item *item, bool binary_cmp) const;
+};
+
+
+/**
+  TIMESTAMP'2001-01-01 10:20:30'
+*/
+class Item_datetime_literal :public Item_temporal_func
+{
+  MYSQL_TIME cached_time;
+public:
+  /**
+    Constructor for Item_datetime_literal.
+    @param ltime    DATETIME value.
+    @param dec_arg  number of fractional digits in ltime.
+  */
+  Item_datetime_literal(MYSQL_TIME *ltime, uint dec_arg) :Item_temporal_func()
+  {
+    decimals= MY_MIN(dec_arg, TIME_SECOND_PART_DIGITS);
+    cached_time= *ltime;
+    fix_length_and_dec();
+    fixed= 1;
+  }
+  const char *func_name() const { return "datetime_literal"; }
+  void print(String *str, enum_query_type query_type);
+  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+  void fix_length_and_dec()
+  {
+    Item_temporal_func::fix_length_and_dec();
+    set_persist_maybe_null(false);
+  }
+  bool check_partition_func_processor(uchar *int_arg)
+  {
+    return FALSE;
+  }
+  bool basic_const_item() const { return true; }
+  bool const_item() const { return true; }
+  table_map used_tables() const { return (table_map) 0L; }
+  void cleanup()
+  {
+    // See Item_basic_const::cleanup()
+    if (orig_name)
+      name= orig_name;
+  }
+  bool eq(const Item *item, bool binary_cmp) const;
+};
+
+
 /* Abstract CURTIME function. Children should define what time zone is used */
 
 class Item_func_curtime :public Item_timefunc

=== modified file 'sql/sql_time.cc'
--- sql/sql_time.cc	2013-04-07 12:00:16 +0000
+++ sql/sql_time.cc	2013-06-25 07:11:25 +0000
@@ -214,6 +214,22 @@ ulong convert_month_to_period(ulong mont
 }
 
 
+bool
+check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
+                     timestamp_type ts_type)
+{
+  int unused;
+  if (check_date(ltime, fuzzy_date, &unused))
+  {
+    ErrConvTime str(ltime);
+    make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                                 &str, ts_type, 0);
+    return true;
+  }
+  return false;
+}
+
+
 /*
   Convert a string to 8-bit representation,
   for use in str_to_time/str_to_date/str_to_date.
@@ -249,9 +265,9 @@ to_ascii(CHARSET_INFO *cs,
 
 
 /* Character set-aware version of str_to_time() */
-timestamp_type
+bool
 str_to_time(CHARSET_INFO *cs, const char *str,uint length,
-                 MYSQL_TIME *l_time, ulonglong fuzzydate, int *warning)
+                 MYSQL_TIME *l_time, ulonglong fuzzydate, MYSQL_TIME_STATUS *status)
 {
   char cnv[32];
   if ((cs->state & MY_CS_NONASCII) != 0)
@@ -259,14 +275,14 @@ str_to_time(CHARSET_INFO *cs, const char
     length= to_ascii(cs, str, length, cnv, sizeof(cnv));
     str= cnv;
   }
-  return str_to_time(str, length, l_time, fuzzydate, warning);
+  return str_to_time(str, length, l_time, fuzzydate, status);
 }
 
 
 /* Character set-aware version of str_to_datetime() */
-timestamp_type str_to_datetime(CHARSET_INFO *cs,
-                               const char *str, uint length,
-                               MYSQL_TIME *l_time, ulonglong flags, int *was_cut)
+bool str_to_datetime(CHARSET_INFO *cs, const char *str, uint length,
+                     MYSQL_TIME *l_time, ulonglong flags,
+                     MYSQL_TIME_STATUS *status)
 {
   char cnv[32];
   if ((cs->state & MY_CS_NONASCII) != 0)
@@ -274,7 +290,7 @@ timestamp_type str_to_datetime(CHARSET_I
     length= to_ascii(cs, str, length, cnv, sizeof(cnv));
     str= cnv;
   }
-  return str_to_datetime(str, length, l_time, flags, was_cut);
+  return str_to_datetime(str, length, l_time, flags, status);
 }
 
 
@@ -286,26 +302,24 @@ timestamp_type str_to_datetime(CHARSET_I
     See description of str_to_datetime() for more information.
 */
 
-timestamp_type
+bool
 str_to_datetime_with_warn(CHARSET_INFO *cs,
                           const char *str, uint length, MYSQL_TIME *l_time,
                           ulonglong flags)
 {
-  int was_cut;
+  MYSQL_TIME_STATUS status;
   THD *thd= current_thd;
-  timestamp_type ts_type;
-  
-  ts_type= str_to_datetime(cs, str, length, l_time,
+  bool ret_val= str_to_datetime(cs, str, length, l_time,
                            (flags | (sql_mode_for_dates(thd))),
-                           &was_cut);
-  if (was_cut || ts_type <= MYSQL_TIMESTAMP_ERROR)
+                           &status);
+  if (ret_val || status.warnings)
     make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                                  str, length, flags & TIME_TIME_ONLY ?
-                                 MYSQL_TIMESTAMP_TIME : ts_type, NullS);
+                                 MYSQL_TIMESTAMP_TIME : l_time->time_type, NullS);
   DBUG_EXECUTE_IF("str_to_datetime_warn",
                   push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                                ER_YES, str););
-  return ts_type;
+  return ret_val;
 }
 
 
@@ -1055,7 +1069,7 @@ calc_time_diff(MYSQL_TIME *l_time1, MYSQ
 
 */
 
-int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b)
+int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b)
 {
   ulonglong a_t= pack_time(a);
   ulonglong b_t= pack_time(b);

=== modified file 'sql/sql_time.h'
--- sql/sql_time.h	2012-08-31 12:15:52 +0000
+++ sql/sql_time.h	2013-06-26 08:53:59 +0000
@@ -35,11 +35,9 @@ ulong convert_period_to_month(ulong peri
 ulong convert_month_to_period(ulong month);
 bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
 my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code);
-bool str_to_time_with_warn(CHARSET_INFO *cs, const char *str, uint length,
-                           MYSQL_TIME *l_time, ulonglong fuzzydate);
-timestamp_type str_to_datetime_with_warn(CHARSET_INFO *cs, const char *str,
-                                         uint length, MYSQL_TIME *l_time,
-                                         ulonglong flags);
+bool str_to_datetime_with_warn(CHARSET_INFO *cs, const char *str,
+                               uint length, MYSQL_TIME *l_time,
+                               ulonglong flags);
 bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
                                   ulonglong fuzzydate,
                                   const char *name);
@@ -76,7 +74,7 @@ bool date_add_interval(MYSQL_TIME *ltime
                        INTERVAL interval);
 bool calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign,
                     longlong *seconds_out, long *microseconds_out);
-int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b);
+int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b);
 void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
 void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
 uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
@@ -86,12 +84,14 @@ bool parse_date_time_format(timestamp_ty
                             const char *format, uint format_length,
                             DATE_TIME_FORMAT *date_time_format);
 /* Character set-aware version of str_to_time() */
-timestamp_type str_to_time(CHARSET_INFO *cs, const char *str,uint length,
-                 MYSQL_TIME *l_time, ulonglong fuzzydate, int *warning);
+bool str_to_time(CHARSET_INFO *cs, const char *str,uint length,
+                 MYSQL_TIME *l_time, ulonglong fuzzydate,
+                 MYSQL_TIME_STATUS *status);
 /* Character set-aware version of str_to_datetime() */
-timestamp_type str_to_datetime(CHARSET_INFO *cs,
-                               const char *str, uint length,
-                               MYSQL_TIME *l_time, ulonglong flags, int *was_cut);
+bool str_to_datetime(CHARSET_INFO *cs,
+                     const char *str, uint length,
+                     MYSQL_TIME *l_time, ulonglong flags,
+                     MYSQL_TIME_STATUS *status);
 
 /* convenience wrapper */
 inline bool parse_date_time_format(timestamp_type format_type, 
@@ -110,4 +110,18 @@ extern DATE_TIME_FORMAT global_time_form
 extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
 extern LEX_STRING interval_type_to_name[];
 
+
+static inline bool
+non_zero_date(const MYSQL_TIME *ltime)
+{
+  return ltime->year || ltime->month || ltime->day;
+}
+static inline bool
+check_date(const MYSQL_TIME *ltime, ulonglong flags, int *was_cut)
+{
+ return check_date(ltime, non_zero_date(ltime), flags, was_cut);
+}
+bool check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
+                          timestamp_type ts_type);
+
 #endif /* SQL_TIME_INCLUDED */

=== modified file 'sql/sql_yacc.yy'
--- sql/sql_yacc.yy	2013-06-06 19:32:29 +0000
+++ sql/sql_yacc.yy	2013-06-20 11:21:37 +0000
@@ -32,6 +32,7 @@
 #define YYTHD ((THD *)yythd)
 #define YYLIP (& YYTHD->m_parser_state->m_lip)
 #define YYPS (& YYTHD->m_parser_state->m_yacc)
+#define YYCSCL  YYTHD->variables.character_set_client
 
 #define MYSQL_YACC
 #define YYINITDEPTH 100
@@ -899,10 +900,10 @@ bool my_yyoverflow(short **a, YYSTYPE **
 
 %pure_parser                                    /* We have threads */
 /*
-  Currently there are 170 shift/reduce conflicts.
+  Currently there are 167 shift/reduce conflicts.
   We should not introduce new conflicts any more.
 */
-%expect 170
+%expect 167
 
 /*
    Comments for TOKENS.
@@ -1628,7 +1629,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
         replace_lock_option opt_low_priority insert_lock_option load_data_lock
 
 %type <item>
-        literal text_literal insert_ident order_ident
+        literal text_literal insert_ident order_ident temporal_literal
         simple_ident expr opt_expr opt_else sum_expr in_sum_expr
         variable variable_aux bool_pri
         predicate bit_expr
@@ -8741,7 +8742,49 @@ simple_expr:
               MYSQL_YYABORT;
           }
         | '{' ident expr '}'
-          { $$= $3; }
+          {
+            Item_string *item;
+            $$= NULL;
+            /*
+              If "expr" is reasonably short pure ASCII string literal,
+              try to parse known ODBC style date, time or timestamp literals,
+              e.g:
+              SELECT {d'2001-01-01'};
+              SELECT {t'10:20:30'};
+              SELECT {ts'2001-01-01 10:20:30'};
+            */
+            if ($3->type() == Item::STRING_ITEM &&
+               (item= (Item_string *) $3) &&
+                item->collation.repertoire == MY_REPERTOIRE_ASCII &&
+                item->str_value.length() < MAX_DATE_STRING_REP_LENGTH * 4)
+            {
+              enum_field_types type= MYSQL_TYPE_STRING;
+              ErrConvString str(&item->str_value);
+              LEX_STRING *ls= &$2;
+              if (ls->length == 1)
+              {
+                if (ls->str[0] == 'd')  /* {d'2001-01-01'} */
+                  type= MYSQL_TYPE_DATE;
+                else if (ls->str[0] == 't') /* {t'10:20:30'} */
+                  type= MYSQL_TYPE_TIME;
+              }
+              else if (ls->length == 2) /* {ts'2001-01-01 10:20:30'} */
+              {
+                if (ls->str[0] == 't' && ls->str[1] == 's')
+                  type= MYSQL_TYPE_DATETIME;
+              }
+              if (type != MYSQL_TYPE_STRING)
+              {
+                const char *ascii= str.ptr();
+                $$= create_temporal_literal(YYTHD,
+                                            ascii, strlen(ascii),
+                                            system_charset_info,
+                                            type, false);
+              }
+            }
+            if ($$ == NULL)
+              $$= $3;
+          }
         | MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')'
           {
             $2->push_front($5);
@@ -12730,6 +12773,7 @@ signed_literal:
 literal:
           text_literal { $$ = $1; }
         | NUM_literal { $$ = $1; }
+        | temporal_literal { $$= $1; }
         | NULL_SYM
           {
             $$ = new (YYTHD->mem_root) Item_null();
@@ -12824,9 +12868,6 @@ literal:
 
             $$= item_str;
           }
-        | DATE_SYM text_literal { $$ = $2; }
-        | TIME_SYM text_literal { $$ = $2; }
-        | TIMESTAMP text_literal { $$ = $2; }
         ;
 
 NUM_literal:
@@ -12875,6 +12916,31 @@ NUM_literal:
           }
         ;
 
+
+temporal_literal:
+        DATE_SYM TEXT_STRING
+          {
+            if (!($$= create_temporal_literal(YYTHD, $2.str, $2.length, YYCSCL,
+                                              MYSQL_TYPE_DATE, true)))
+              MYSQL_YYABORT;
+          }
+        | TIME_SYM TEXT_STRING
+          {
+            if (!($$= create_temporal_literal(YYTHD, $2.str, $2.length, YYCSCL,
+                                              MYSQL_TYPE_TIME, true)))
+              MYSQL_YYABORT;
+          }
+        | TIMESTAMP TEXT_STRING
+          {
+            if (!($$= create_temporal_literal(YYTHD, $2.str, $2.length, YYCSCL,
+                                              MYSQL_TYPE_DATETIME, true)))
+              MYSQL_YYABORT;
+          }
+        ;
+
+
+
+
 /**********************************************************************
 ** Creating different items.
 **********************************************************************/


Follow ups