Adding support for the SQL-standard temporal literals.

added:
  mysql-test/r/temporal_literal.result
  mysql-test/t/temporal_literal.test
modified:
  client/mysqlbinlog.cc
  include/my_time.h
  mysql-test/r/cast.result
  mysql-test/r/partition_innodb.result
  mysql-test/t/cast.test
  mysql-test/t/partition_innodb.test
  sql-common/my_time.c
  sql/field.cc
  sql/item.cc
  sql/item.h
  sql/item_cmpfunc.cc
  sql/item_create.cc
  sql/item_create.h
  sql/item_strfunc.cc
  sql/item_timefunc.cc
  sql/item_timefunc.h
  sql/sql_select.cc
  sql/sql_time.cc
  sql/sql_time.h
  sql/sql_yacc.yy
  storage/spider/spd_db_mysql.cc
This commit is contained in:
Alexander Barkov 2013-07-10 12:12:27 +04:00
parent 17f3ae267f
commit d98584f56a
23 changed files with 1256 additions and 216 deletions

View File

@ -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);

View File

@ -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().
*/
typedef struct st_mysql_time_status
{
int warnings;
uint precision;
} MYSQL_TIME_STATUS;
static inline void my_time_status_init(MYSQL_TIME_STATUS *status)
{
status->warnings= status->precision= 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 MYSQL_TIME *);
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);

View File

@ -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'

View File

@ -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;

View File

@ -0,0 +1,418 @@
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' },
{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',
`{ 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.'},
{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.'}` 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.'},
{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.'}` 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

View File

@ -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);

View File

@ -60,8 +60,8 @@ insert into t1(c2,c3) values ("Test row",'2010-01-01 00:00:00');
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;

View File

@ -0,0 +1,217 @@
--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' },
{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.'},
{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.'},
{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';

View File

@ -130,6 +130,7 @@ static int get_digits(uint *val, uint *number_of_fields, const char **str,
return get_number(val, number_of_fields, str, min(end, *str + length));
}
static int get_punct(const char **str, const char *end)
{
if (*str >= end)
@ -203,6 +204,24 @@ static uint skip_digits(const char **str, const char *end)
return s - start;
}
static void get_microseconds(ulong *val, MYSQL_TIME_STATUS *status,
uint *number_of_fields,
const char **str, const char *end)
{
const char *start= *str;
uint tmp= 0; /* For the case '10:10:10.' */
if (get_digits(&tmp, number_of_fields, str, end, 6))
status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
if ((status->precision= (*str - start)) < 6)
*val= tmp * log_10_int[6 - (*str - start)];
else
*val= tmp;
if (skip_digits(str, end))
status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
}
/*
Convert a timestamp string to a MYSQL_TIME value.
@ -217,9 +236,8 @@ static uint skip_digits(const char **str, const char *end)
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 +248,29 @@ static uint skip_digits(const char **str, const char *end)
The second part may have an optional .###### fraction part.
RETURN VALUES
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 +279,20 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
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 +321,49 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
(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;
/* 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 (!*was_cut && str < end && *str == '.')
if (number_of_fields < 3)
{
uint second_part;
const char *start= ++str;
*was_cut= get_digits(&second_part, &number_of_fields, &str, end, 6);
if (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;
l_time->time_type= MYSQL_TIMESTAMP_NONE;
status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
DBUG_RETURN(TRUE);
}
if (!status->warnings && str < end && *str == '.')
{
str++;
get_microseconds(&l_time->second_part, status,
&number_of_fields, &str, end);
}
not_zero_date = l_time->year || l_time->month || l_time->day ||
@ -349,11 +376,11 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
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 +390,17 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
{
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);
}
@ -387,23 +415,26 @@ err:
There may be an optional [.second_part] after seconds
length Length of str
l_time Store result here
warning Set MYSQL_TIME_WARN_TRUNCATED flag if the input string
was cut during conversion, and/or
MYSQL_TIME_WARN_OUT_OF_RANGE flag, if the value is
out of range.
status Conversion status
NOTES
Because of the extra days argument, this function can only
work with times where the time arguments are in the above order.
status->warnings is set as follows:
MYSQL_TIME_WARN_TRUNCATED if the input string was cut during conversion,
and/or
MYSQL_TIME_WARN_OUT_OF_RANGE flag is set if the value is out of range.
RETURN
MYSQL_TIMESTAMP_TIME
MYSQL_TIMESTAMP_ERROR
FALSE on success
TRUE on 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 +442,7 @@ str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
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 +452,20 @@ str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
length--;
}
if (str == end)
return MYSQL_TIMESTAMP_ERROR;
{
status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
goto err;
}
/* 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;
@ -504,24 +533,15 @@ str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
fractional:
/* Get fractional second part */
if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1]))
if (!status->warnings && str < end && *str == '.')
{
int field_length= 5;
str++; value=(uint) (uchar) (*str - '0');
while (++str != end && my_isdigit(&my_charset_latin1, *str))
{
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;
date[4]= (ulong) value;
uint number_of_fields= 0;
str++;
get_microseconds(&date[4], status, &number_of_fields, &str, end);
}
else
date[4]=0;
date[4]= 0;
/* Check for exponent part: E<gigit> | E<sign><digit> */
/* (may occur as result of %g formatting of time value) */
if ((end - str) > 1 &&
@ -530,7 +550,10 @@ fractional:
((str[1] == '-' || str[1] == '+') &&
(end - str) > 2 &&
my_isdigit(&my_charset_latin1, str[2]))))
return MYSQL_TIMESTAMP_ERROR;
{
status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
goto err;
}
if (internal_format_positions[7] != 255)
{
@ -553,8 +576,11 @@ fractional:
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;
{
status->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
goto err;
}
l_time->year= 0; /* For protocol::store_time */
l_time->month= 0;
l_time->day= date[0];
@ -565,9 +591,9 @@ fractional:
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 +601,17 @@ fractional:
{
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;
err:
bzero((char*) l_time, sizeof(*l_time));
l_time->time_type= MYSQL_TIMESTAMP_ERROR;
return TRUE;
}
@ -610,7 +641,10 @@ int check_time_range(struct st_mysql_time *my_time, uint dec, int *warning)
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 +1391,7 @@ double TIME_to_double(const MYSQL_TIME *my_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 +

View File

@ -1822,7 +1822,7 @@ bool Field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
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(MYSQL_TIME *ltime, uint dec)
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_warning(MYSQL_TIME *ltime,
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 *ltime)
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);
}

View File

@ -377,6 +377,27 @@ my_decimal *Item::val_decimal_from_time(my_decimal *decimal_value)
}
longlong Item::val_int_from_date()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return 0;
longlong v= TIME_to_ulonglong(&ltime);
return ltime.neg ? -v : v;
}
double Item::val_real_from_date()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return 0;
return TIME_to_double(&ltime);
}
double Item::val_real_from_decimal()
{
/* Note that fix_fields may not be called for Item_avg_field items */
@ -1269,7 +1290,7 @@ bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
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;
}
@ -6286,6 +6307,76 @@ Item_bin_string::Item_bin_string(const char *str, uint str_length)
}
bool Item_temporal_literal::eq(const Item *item, bool binary_cmp) const
{
return
item->basic_const_item() && type() == item->type() &&
field_type() == ((Item_temporal_literal *) item)->field_type() &&
!my_time_compare(&cached_time,
&((Item_temporal_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));
}
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));
}
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));
}
/**
Pack data in buffer for sending.
*/

View File

@ -599,7 +599,8 @@ public:
SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM,
XPATH_NODESET, XPATH_NODESET_CMP,
VIEW_FIXER_ITEM, EXPR_CACHE_ITEM};
VIEW_FIXER_ITEM, EXPR_CACHE_ITEM,
DATE_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
@ -956,7 +957,9 @@ public:
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();
double val_real_from_decimal();
double val_real_from_date();
int save_time_in_field(Field *field);
int save_date_in_field(Field *field);
@ -1113,8 +1116,8 @@ public:
*/
virtual CHARSET_INFO *charset_for_protocol(void) const
{
return result_type() == STRING_RESULT ? collation.collation :
&my_charset_bin;
return cmp_type() == STRING_RESULT ? collation.collation :
&my_charset_bin;
};
virtual bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
@ -2877,6 +2880,110 @@ public:
Item_bin_string(const char *str,uint str_length);
};
class Item_temporal_literal :public Item_basic_constant
{
//sql_mode= current_thd->variables.sql_mode &
// (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
protected:
MYSQL_TIME cached_time;
public:
/**
Constructor for Item_date_literal.
@param ltime DATE value.
*/
Item_temporal_literal(MYSQL_TIME *ltime) :Item_basic_constant()
{
collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII);
decimals= 0;
cached_time= *ltime;
}
Item_temporal_literal(MYSQL_TIME *ltime, uint dec_arg) :Item_basic_constant()
{
collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII);
decimals= dec_arg;
cached_time= *ltime;
}
bool basic_const_item() const { return true; }
bool const_item() const { return true; }
enum Type type() const { return DATE_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
enum Item_result result_type () const { return STRING_RESULT; }
Item_result cmp_type() const { return TIME_RESULT; }
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool check_vcol_func_processor(uchar *arg) { return FALSE;}
String *val_str(String *str)
{ return val_string_from_date(str); }
longlong val_int()
{ return val_int_from_date(); }
double val_real()
{ return val_real_from_date(); }
my_decimal *val_decimal(my_decimal *decimal_value)
{ return val_decimal_from_date(decimal_value); }
Field *tmp_table_field(TABLE *table)
{ return tmp_table_field_from_field_type(table, 0); }
int save_in_field(Field *field, bool no_conversions)
{ return save_date_in_field(field); }
};
/**
DATE'2010-01-01'
*/
class Item_date_literal: public Item_temporal_literal
{
public:
Item_date_literal(MYSQL_TIME *ltime)
:Item_temporal_literal(ltime)
{
max_length= MAX_DATE_WIDTH;
fixed= 1;
}
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
void print(String *str, enum_query_type query_type);
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
};
/**
TIME'10:10:10'
*/
class Item_time_literal: public Item_temporal_literal
{
public:
Item_time_literal(MYSQL_TIME *ltime, uint dec_arg)
:Item_temporal_literal(ltime, dec_arg)
{
max_length= MIN_TIME_WIDTH + (decimals ? decimals + 1 : 0);
fixed= 1;
}
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
void print(String *str, enum_query_type query_type);
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
};
/**
TIMESTAMP'2001-01-01 10:20:30'
*/
class Item_datetime_literal: public Item_temporal_literal
{
public:
Item_datetime_literal(MYSQL_TIME *ltime, uint dec_arg)
:Item_temporal_literal(ltime, dec_arg)
{
max_length= MAX_DATETIME_WIDTH + (decimals ? decimals + 1 : 0);
fixed= 1;
}
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
void print(String *str, enum_query_type query_type);
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
};
class Item_result_field :public Item /* Item with result field */
{
public:

View File

@ -721,31 +721,31 @@ bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type,
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);
if (warn_type == MYSQL_TIMESTAMP_TIME)
flags|= TIME_TIME_ONLY;
DBUG_ASSERT(warn_type != MYSQL_TIMESTAMP_TIME);
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))
{
DBUG_ASSERT(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.
*/
value= FALSE;
}
else
{
DBUG_ASSERT(l_time->time_type != MYSQL_TIMESTAMP_TIME);
DBUG_ASSERT(status.warnings != 0); // Must be set by set_to_datetime()
value= TRUE;
error= 1; /* force warning */
}
if (error > 0)
if (status.warnings > 0)
make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
&err, warn_type, warn_name);

View File

@ -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_target cast_type,
}
/**
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.precision);
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.precision);
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)

View File

@ -168,6 +168,11 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
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();

View File

@ -4722,7 +4722,7 @@ bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
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:

View File

@ -2430,17 +2430,8 @@ bool Item_date_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
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));
}

View File

@ -489,7 +489,6 @@ public:
Item_temporal_func(Item *a, Item *b) :Item_func(a,b) {}
Item_temporal_func(Item *a, Item *b, Item *c) :Item_func(a,b,c) {}
enum Item_result result_type () const { return STRING_RESULT; }
CHARSET_INFO *charset_for_protocol(void) const { return &my_charset_bin; }
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
Item_result cmp_type() const { return TIME_RESULT; }
String *val_str(String *str);

View File

@ -14696,6 +14696,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::REAL_ITEM:
case Item::DECIMAL_ITEM:
case Item::STRING_ITEM:
case Item::DATE_ITEM:
case Item::REF_ITEM:
case Item::NULL_ITEM:
case Item::VARBIN_ITEM:

View File

@ -214,6 +214,22 @@ ulong convert_month_to_period(ulong month)
}
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 *str,uint length,
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_INFO *cs,
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_INFO *cs,
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, MYSQL_TIME *l_time2, int l_sign, longlong *s
*/
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);

View File

@ -35,11 +35,9 @@ ulong convert_period_to_month(ulong period);
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_type int_type,
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_type format_type,
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_format;
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 */

View File

@ -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 **b, ulong *yystacksize);
%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 **b, ulong *yystacksize);
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,48 @@ 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;
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)
{
$$= create_temporal_literal(YYTHD,
item->str_value.ptr(),
item->str_value.length(),
item->str_value.charset(),
type, false);
}
}
if ($$ == NULL)
$$= $3;
}
| MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')'
{
$2->push_front($5);
@ -12730,6 +12772,7 @@ signed_literal:
literal:
text_literal { $$ = $1; }
| NUM_literal { $$ = $1; }
| temporal_literal { $$= $1; }
| NULL_SYM
{
$$ = new (YYTHD->mem_root) Item_null();
@ -12824,9 +12867,6 @@ literal:
$$= item_str;
}
| DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; }
| TIMESTAMP text_literal { $$ = $2; }
;
NUM_literal:
@ -12875,6 +12915,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.
**********************************************************************/

View File

@ -567,7 +567,7 @@ int spider_db_mysql_result::fetch_table_status(
#else
my_bool not_used_my_bool;
#endif
int not_used_int;
MYSQL_TIME_STATUS time_status;
long not_used_long;
DBUG_ENTER("spider_db_mysql_result::fetch_table_status");
DBUG_PRINT("info",("spider this=%p", this));
@ -628,8 +628,9 @@ int spider_db_mysql_result::fetch_table_status(
("spider auto_increment_value=%lld", auto_increment_value));
if (mysql_row[11])
{
my_time_status_init(&time_status);
str_to_datetime(mysql_row[11], strlen(mysql_row[11]), &mysql_time, 0,
&not_used_int);
&time_status);
#ifdef MARIADB_BASE_VERSION
create_time = (time_t) my_system_gmt_sec(&mysql_time,
&not_used_long, &not_used_uint);
@ -650,8 +651,9 @@ int spider_db_mysql_result::fetch_table_status(
#endif
if (mysql_row[12])
{
my_time_status_init(&time_status);
str_to_datetime(mysql_row[12], strlen(mysql_row[12]), &mysql_time, 0,
&not_used_int);
&time_status);
#ifdef MARIADB_BASE_VERSION
update_time = (time_t) my_system_gmt_sec(&mysql_time,
&not_used_long, &not_used_uint);
@ -672,8 +674,9 @@ int spider_db_mysql_result::fetch_table_status(
#endif
if (mysql_row[13])
{
my_time_status_init(&time_status);
str_to_datetime(mysql_row[13], strlen(mysql_row[13]), &mysql_time, 0,
&not_used_int);
&time_status);
#ifdef MARIADB_BASE_VERSION
check_time = (time_t) my_system_gmt_sec(&mysql_time,
&not_used_long, &not_used_uint);
@ -737,8 +740,9 @@ int spider_db_mysql_result::fetch_table_status(
("spider auto_increment_value=%lld", auto_increment_value));
if (mysql_row[6])
{
my_time_status_init(&time_status);
str_to_datetime(mysql_row[6], strlen(mysql_row[6]), &mysql_time, 0,
&not_used_int);
&time_status);
#ifdef MARIADB_BASE_VERSION
create_time = (time_t) my_system_gmt_sec(&mysql_time,
&not_used_long, &not_used_uint);
@ -759,8 +763,9 @@ int spider_db_mysql_result::fetch_table_status(
#endif
if (mysql_row[7])
{
my_time_status_init(&time_status);
str_to_datetime(mysql_row[7], strlen(mysql_row[7]), &mysql_time, 0,
&not_used_int);
&time_status);
#ifdef MARIADB_BASE_VERSION
update_time = (time_t) my_system_gmt_sec(&mysql_time,
&not_used_long, &not_used_uint);
@ -781,8 +786,9 @@ int spider_db_mysql_result::fetch_table_status(
#endif
if (mysql_row[8])
{
my_time_status_init(&time_status);
str_to_datetime(mysql_row[8], strlen(mysql_row[8]), &mysql_time, 0,
&not_used_int);
&time_status);
#ifdef MARIADB_BASE_VERSION
check_time = (time_t) my_system_gmt_sec(&mysql_time,
&not_used_long, &not_used_uint);