3600 Alexander Barkov 2011-11-18 [merge]
Merging latest bug fixes from mysql-trunk-wl946
modified:
mysql-test/r/timezone2.result
mysql-test/r/type_temporal_fractional.result
mysql-test/t/timezone2.test
mysql-test/t/type_temporal_fractional.test
sql/field.cc
sql/field.h
sql/item.cc
sql/item.h
sql/item_cmpfunc.cc
sql/item_timefunc.cc
sql/sql_time.cc
sql/sql_time.h
unittest/gunit/field-t.cc
3599 Mayank Prasad 2011-11-18
WL#5885
details:
- Added test case for IS_ROUTINES/PARAMETERS tables
to test DATETIME PRECISION for values 1-6.
modified:
mysql-test/r/information_schema_parameters.result
mysql-test/r/information_schema_routines.result
mysql-test/t/information_schema_parameters.test
mysql-test/t/information_schema_routines.test
=== modified file 'mysql-test/r/timezone2.result'
--- a/mysql-test/r/timezone2.result 2010-08-06 19:29:37 +0000
+++ b/mysql-test/r/timezone2.result 2011-11-18 09:52:00 +0000
@@ -309,3 +309,33 @@ CONVERT_TZ(1, 1, a)
NULL
DROP TABLE t1;
End of 5.1 tests
+#
+# Start of 5.6 tests
+#
+SET time_zone='Europe/Moscow';
+CREATE TABLE t1 (a TIMESTAMP, b VARCHAR(30));
+INSERT INTO t1 VALUES
+('2003-03-30 01:59:59', 'Before the gap'),
+('2003-03-30 02:30:00', 'Inside the gap'),
+('2003-03-30 03:00:00', 'After the gap');
+Warnings:
+Warning 1299 Invalid TIMESTAMP value in column 'a' at row 2
+SELECT a, UNIX_TIMESTAMP(a), b FROM t1;
+a UNIX_TIMESTAMP(a) b
+2003-03-30 01:59:59 1048978799 Before the gap
+2003-03-30 03:00:00 1048978800 Inside the gap
+2003-03-30 03:00:00 1048978800 After the gap
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP('2003-03-30 01:59:59'), 'Before the gap' AS b;
+UNIX_TIMESTAMP('2003-03-30 01:59:59') b
+1048978799 Before the gap
+SELECT UNIX_TIMESTAMP('2003-03-30 02:30:00'), 'Inside the gap' AS b;
+UNIX_TIMESTAMP('2003-03-30 02:30:00') b
+1048978800 Inside the gap
+SELECT UNIX_TIMESTAMP('2003-03-30 03:00:00'), 'After the gap' AS b;
+UNIX_TIMESTAMP('2003-03-30 03:00:00') b
+1048978800 After the gap
+SET time_zone=DEFAULT;
+#
+# End of 5.6 tests
+#
=== modified file 'mysql-test/r/type_temporal_fractional.result'
--- a/mysql-test/r/type_temporal_fractional.result 2011-11-17 13:41:28 +0000
+++ b/mysql-test/r/type_temporal_fractional.result 2011-11-18 13:26:35 +0000
@@ -16647,3 +16647,151 @@ Warning 1292 Truncated incorrect time va
Warning 1292 Truncated incorrect time value: '2002-11-24'
DROP VIEW v1;
DROP TABLE t1;
+#
+# Bug#13401354 ITEM->FIELD_TYPE() == MYSQL_TYPE_TIME || ITEM->FIELD_TYPE() == MYSQL_TYPE_NULL
+#
+CREATE TABLE t1 (col_time_not_null TIME NOT NULL);
+SELECT * FROM t1
+WHERE col_time_not_null = DATE(NULL) AND col_time_not_null = TIME(NULL);
+col_time_not_null
+DROP TABLE t1;
+CREATE TABLE t1 (
+col_date DATE,
+col_time_not_null TIME not null,
+pk TIMESTAMP(6),
+col_timestamp_3_not_null_key TIMESTAMP(3) NOT NULL,
+col_date_not_null DATE NOT NULL,
+col_time_3_key TIME(3),
+col_timestamp_6_key TIMESTAMP(6) NOT NULL,
+col_datetime DATETIME,
+col_datetime_6 DATETIME(6),
+col_timestamp_3_key TIMESTAMP(3) NOT NULL,
+col_time_6_not_null TIME(6) NOT NULL,
+col_time_6 TIME(6),
+col_time_6_not_null_key TIME(6) NOT NULL,
+col_datetime_not_null DATETIME NOT NULL,
+col_datetime_3_not_null_key DATETIME(3) NOT NULL,
+KEY (col_datetime_3_not_null_key));
+SELECT col_time_6 AS c1, NOW() AS c2 FROM t1
+WHERE
+col_datetime_not_null BETWEEN SUBTIME('0000-00-00','00:00:00') AND col_date_not_null
+AND
+col_time_not_null=STR_TO_DATE(DATE_FORMAT(TIME('00:00:00.000000'),CONCAT_WS('-','%s','%k' )),CONCAT_WS(':','%i','%M'))
+AND
+col_date BETWEEN UNIX_TIMESTAMP('0000-00-00 00:00:00') AND col_timestamp_3_key
+AND
+col_datetime_6 NOT IN (col_time_6_not_null,'0000-00-00')
+AND
+col_time_not_null = TIMEDIFF(CURDATE(),'00:00:00.000000')
+AND
+col_time_3_key NOT IN (col_timestamp_6_key,pk)
+AND
+col_timestamp_3_not_null_key < col_datetime;
+c1 c2
+Warnings:
+Warning 1411 Incorrect datetime value: '00-0' for function str_to_date
+Warning 1411 Incorrect datetime value: '00-0' for function str_to_date
+DROP TABLE t1;
+#
+# Bug#13399082 - ASSERTION `MON > 0 && MON < 13' FAILED IN TZTIME.CC | SEC_SINCE_EPOCH
+#
+SET TIME_ZONE='+02:00';
+SELECT UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y'));
+UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y'))
+0
+SET TIME_ZONE=DEFAULT;
+# This should return NULL
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES(NULL);
+SELECT UNIX_TIMESTAMP(a) FROM t1;
+UNIX_TIMESTAMP(a)
+NULL
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP(NULL);
+UNIX_TIMESTAMP(NULL)
+NULL
+SELECT UNIX_TIMESTAMP(DATE(NULL));
+UNIX_TIMESTAMP(DATE(NULL))
+NULL
+SELECT UNIX_TIMESTAMP(TIME(NULL));
+UNIX_TIMESTAMP(TIME(NULL))
+NULL
+SELECT UNIX_TIMESTAMP(TIMESTAMP(NULL));
+UNIX_TIMESTAMP(TIMESTAMP(NULL))
+NULL
+# This should return 0
+CREATE TABLE t1 (a VARCHAR(30));
+INSERT INTO t1 VALUES
+('0000-01-01 00:00:00'),('2001-00-01 00:00:01'),('2001-01-00 00:00:00'),
+('0000-00-00 00:00:01'),('0000-00-00 00:00:00.1');
+SELECT UNIX_TIMESTAMP(a) FROM t1;
+UNIX_TIMESTAMP(a)
+0.000000
+0.000000
+0.000000
+0.000000
+0.000000
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP('0000-01-01 00:00:00');
+UNIX_TIMESTAMP('0000-01-01 00:00:00')
+0
+SELECT UNIX_TIMESTAMP('2001-00-01 00:00:00');
+UNIX_TIMESTAMP('2001-00-01 00:00:00')
+0
+SELECT UNIX_TIMESTAMP('2001-01-00 00:00:00');
+UNIX_TIMESTAMP('2001-01-00 00:00:00')
+0
+SELECT UNIX_TIMESTAMP('0000-00-00 10:10:20');
+UNIX_TIMESTAMP('0000-00-00 10:10:20')
+0
+SELECT UNIX_TIMESTAMP('0000-00-00 00:00:00.1');
+UNIX_TIMESTAMP('0000-00-00 00:00:00.1')
+0.0
+SELECT UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 10:10:20');
+UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 10:10:20')
+0
+SELECT UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 00:00:00.1');
+UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 00:00:00.1')
+0.0
+SELECT UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 10:10:20'));
+UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 10:10:20'))
+0
+SELECT UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 00:00:00.1'));
+UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 00:00:00.1'))
+0.0
+#
+# Bug#13354387 - CRASH IN IN MY_DECIMAL::OPERATOR FOR VIEW AND FUNCTION UNIX_TIMESTAMP
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-18 14:36:00');
+CREATE TABLE t1 (
+pk time(2) NOT NULL DEFAULT '00:00:00.00',
+col_timestamp_3_not_null timestamp(3) NULL DEFAULT '0000-00-00 00:00:00.000',
+col_datetime_1_key datetime(1) DEFAULT NULL,
+col_datetime_6_not_null_key datetime(6) NOT NULL,
+col_datetime_2_not_null datetime(2) NOT NULL,
+PRIMARY KEY (pk),
+KEY col_datetime_1_key (col_datetime_1_key),
+KEY col_datetime_6_not_null_key (col_datetime_6_not_null_key))
+ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES ('19:14:35.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','2000-08-28 07:34:20.051690','2009-09-20 07:32:39.06');
+INSERT INTO t1 VALUES ('19:14:37.36','2005-07-04 08:03:50.051','0000-00-00 00:00:00.0','0000-00-00 00:00:00.000000','0000-00-00 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:39.36','0000-00-00 00:00:00.000',NULL,'2005-10-11 07:24:45.059064','2009-11-19 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:41.36','2005-11-22 21:00:00.000',NULL,'0000-00-00 00:00:00.000000','0000-00-00 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:43.36','2009-11-06 21:00:00.000','2007-07-03 11:13:08.0','2002-09-02 00:17:37.037583','2003-09-25 09:29:41.00');
+INSERT INTO t1 VALUES ('19:14:36.36','2009-08-15 05:43:18.029','2009-01-18 00:00:00.0','0000-00-00 00:00:00.000000','2007-07-20 08:31:37.02');
+INSERT INTO t1 VALUES ('19:14:38.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','0000-00-00 00:00:00.000000','2004-08-16 05:11:47.04');
+INSERT INTO t1 VALUES ('19:14:40.36','2000-04-16 21:00:00.000',NULL,'2004-04-27 00:00:00.000000','2009-06-03 00:18:49.04');
+INSERT INTO t1 VALUES ('19:14:42.36','2009-01-18 20:46:41.035','2003-03-23 11:37:04.0','0000-00-00 00:00:00.000000','2009-12-26 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:44.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','2005-09-14 15:13:53.062460','0000-00-00 00:00:00.00');
+CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1;
+SELECT UNIX_TIMESTAMP(col_datetime_2_not_null) AS c1
+FROM v1
+WHERE col_datetime_6_not_null_key > col_datetime_1_key
+AND col_timestamp_3_not_null IS NOT NULL
+ORDER BY 1;
+c1
+0.00
+1253421159.06
+DROP VIEW v1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
=== modified file 'mysql-test/t/timezone2.test'
--- a/mysql-test/t/timezone2.test 2010-08-06 19:29:37 +0000
+++ b/mysql-test/t/timezone2.test 2011-11-18 09:52:00 +0000
@@ -284,3 +284,25 @@ SELECT CONVERT_TZ(1, 1, a) FROM t1;
DROP TABLE t1;
--echo End of 5.1 tests
+
+--echo #
+--echo # Start of 5.6 tests
+--echo #
+SET time_zone='Europe/Moscow';
+CREATE TABLE t1 (a TIMESTAMP, b VARCHAR(30));
+# Testing values around winter/summer time change
+# Expect non-zero UNIX_TIMESTAMP value for all of them
+INSERT INTO t1 VALUES
+('2003-03-30 01:59:59', 'Before the gap'),
+('2003-03-30 02:30:00', 'Inside the gap'),
+('2003-03-30 03:00:00', 'After the gap');
+SELECT a, UNIX_TIMESTAMP(a), b FROM t1;
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP('2003-03-30 01:59:59'), 'Before the gap' AS b;
+SELECT UNIX_TIMESTAMP('2003-03-30 02:30:00'), 'Inside the gap' AS b;
+SELECT UNIX_TIMESTAMP('2003-03-30 03:00:00'), 'After the gap' AS b;
+SET time_zone=DEFAULT;
+
+--echo #
+--echo # End of 5.6 tests
+--echo #
=== modified file 'mysql-test/t/type_temporal_fractional.test'
--- a/mysql-test/t/type_temporal_fractional.test 2011-11-17 13:41:28 +0000
+++ b/mysql-test/t/type_temporal_fractional.test 2011-11-18 13:26:35 +0000
@@ -7220,6 +7220,118 @@ DROP VIEW v1;
DROP TABLE t1;
+--echo #
+--echo # Bug#13401354 ITEM->FIELD_TYPE() == MYSQL_TYPE_TIME || ITEM->FIELD_TYPE() == MYSQL_TYPE_NULL
+--echo #
+CREATE TABLE t1 (col_time_not_null TIME NOT NULL);
+SELECT * FROM t1
+WHERE col_time_not_null = DATE(NULL) AND col_time_not_null = TIME(NULL);
+DROP TABLE t1;
+CREATE TABLE t1 (
+ col_date DATE,
+ col_time_not_null TIME not null,
+ pk TIMESTAMP(6),
+ col_timestamp_3_not_null_key TIMESTAMP(3) NOT NULL,
+ col_date_not_null DATE NOT NULL,
+ col_time_3_key TIME(3),
+ col_timestamp_6_key TIMESTAMP(6) NOT NULL,
+ col_datetime DATETIME,
+ col_datetime_6 DATETIME(6),
+ col_timestamp_3_key TIMESTAMP(3) NOT NULL,
+ col_time_6_not_null TIME(6) NOT NULL,
+ col_time_6 TIME(6),
+ col_time_6_not_null_key TIME(6) NOT NULL,
+ col_datetime_not_null DATETIME NOT NULL,
+ col_datetime_3_not_null_key DATETIME(3) NOT NULL,
+ KEY (col_datetime_3_not_null_key));
+SELECT col_time_6 AS c1, NOW() AS c2 FROM t1
+WHERE
+ col_datetime_not_null BETWEEN SUBTIME('0000-00-00','00:00:00') AND col_date_not_null
+AND
+ col_time_not_null=STR_TO_DATE(DATE_FORMAT(TIME('00:00:00.000000'),CONCAT_WS('-','%s','%k' )),CONCAT_WS(':','%i','%M'))
+AND
+ col_date BETWEEN UNIX_TIMESTAMP('0000-00-00 00:00:00') AND col_timestamp_3_key
+AND
+ col_datetime_6 NOT IN (col_time_6_not_null,'0000-00-00')
+AND
+ col_time_not_null = TIMEDIFF(CURDATE(),'00:00:00.000000')
+AND
+ col_time_3_key NOT IN (col_timestamp_6_key,pk)
+AND
+ col_timestamp_3_not_null_key < col_datetime;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Bug#13399082 - ASSERTION `MON > 0 && MON < 13' FAILED IN TZTIME.CC | SEC_SINCE_EPOCH
+--echo #
+SET TIME_ZONE='+02:00';
+SELECT UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y'));
+SET TIME_ZONE=DEFAULT;
+
+--echo # This should return NULL
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES(NULL);
+SELECT UNIX_TIMESTAMP(a) FROM t1;
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP(NULL);
+SELECT UNIX_TIMESTAMP(DATE(NULL));
+SELECT UNIX_TIMESTAMP(TIME(NULL));
+SELECT UNIX_TIMESTAMP(TIMESTAMP(NULL));
+
+--echo # This should return 0
+CREATE TABLE t1 (a VARCHAR(30));
+INSERT INTO t1 VALUES
+('0000-01-01 00:00:00'),('2001-00-01 00:00:01'),('2001-01-00 00:00:00'),
+('0000-00-00 00:00:01'),('0000-00-00 00:00:00.1');
+SELECT UNIX_TIMESTAMP(a) FROM t1;
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP('0000-01-01 00:00:00');
+SELECT UNIX_TIMESTAMP('2001-00-01 00:00:00');
+SELECT UNIX_TIMESTAMP('2001-01-00 00:00:00');
+SELECT UNIX_TIMESTAMP('0000-00-00 10:10:20');
+SELECT UNIX_TIMESTAMP('0000-00-00 00:00:00.1');
+SELECT UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 10:10:20');
+SELECT UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 00:00:00.1');
+SELECT UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 10:10:20'));
+SELECT UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 00:00:00.1'));
+
+
+--echo #
+--echo # Bug#13354387 - CRASH IN IN MY_DECIMAL::OPERATOR FOR VIEW AND FUNCTION UNIX_TIMESTAMP
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-18 14:36:00');
+CREATE TABLE t1 (
+ pk time(2) NOT NULL DEFAULT '00:00:00.00',
+ col_timestamp_3_not_null timestamp(3) NULL DEFAULT '0000-00-00 00:00:00.000',
+ col_datetime_1_key datetime(1) DEFAULT NULL,
+ col_datetime_6_not_null_key datetime(6) NOT NULL,
+ col_datetime_2_not_null datetime(2) NOT NULL,
+ PRIMARY KEY (pk),
+ KEY col_datetime_1_key (col_datetime_1_key),
+ KEY col_datetime_6_not_null_key (col_datetime_6_not_null_key))
+ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES ('19:14:35.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','2000-08-28 07:34:20.051690','2009-09-20 07:32:39.06');
+INSERT INTO t1 VALUES ('19:14:37.36','2005-07-04 08:03:50.051','0000-00-00 00:00:00.0','0000-00-00 00:00:00.000000','0000-00-00 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:39.36','0000-00-00 00:00:00.000',NULL,'2005-10-11 07:24:45.059064','2009-11-19 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:41.36','2005-11-22 21:00:00.000',NULL,'0000-00-00 00:00:00.000000','0000-00-00 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:43.36','2009-11-06 21:00:00.000','2007-07-03 11:13:08.0','2002-09-02 00:17:37.037583','2003-09-25 09:29:41.00');
+INSERT INTO t1 VALUES ('19:14:36.36','2009-08-15 05:43:18.029','2009-01-18 00:00:00.0','0000-00-00 00:00:00.000000','2007-07-20 08:31:37.02');
+INSERT INTO t1 VALUES ('19:14:38.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','0000-00-00 00:00:00.000000','2004-08-16 05:11:47.04');
+INSERT INTO t1 VALUES ('19:14:40.36','2000-04-16 21:00:00.000',NULL,'2004-04-27 00:00:00.000000','2009-06-03 00:18:49.04');
+INSERT INTO t1 VALUES ('19:14:42.36','2009-01-18 20:46:41.035','2003-03-23 11:37:04.0','0000-00-00 00:00:00.000000','2009-12-26 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:44.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','2005-09-14 15:13:53.062460','0000-00-00 00:00:00.00');
+CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1;
+SELECT UNIX_TIMESTAMP(col_datetime_2_not_null) AS c1
+FROM v1
+WHERE col_datetime_6_not_null_key > col_datetime_1_key
+AND col_timestamp_3_not_null IS NOT NULL
+ORDER BY 1;
+DROP VIEW v1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+
## TS-TODO: SELECT CAST('00:00:00' AS DATETIME) -> should it use curdate?
## TS-TODO: reuse count_datetime_length()/count_string_result_length()
=== modified file 'sql/field.cc'
--- a/sql/field.cc 2011-11-17 13:41:28 +0000
+++ b/sql/field.cc 2011-11-18 13:26:35 +0000
@@ -1797,15 +1797,12 @@ bool Field::get_time(MYSQL_TIME *ltime)
}
-bool Field::get_timestamp(struct timeval *tm)
+bool Field::get_timestamp(struct timeval *tm, int *warnings)
{
MYSQL_TIME ltime;
- if (get_date(<ime, TIME_FUZZY_DATE))
- return true;
- my_bool not_used;
- tm->tv_sec= TIME_to_timestamp(current_thd, <ime, ¬_used);
- tm->tv_usec= ltime.second_part;
- return false;
+ DBUG_ASSERT(!is_null());
+ return get_date(<ime, TIME_FUZZY_DATE) ||
+ datetime_to_timeval(current_thd, <ime, tm, warnings);
}
@@ -5159,30 +5156,14 @@ Field_temporal_with_date_and_time::conve
struct timeval *tm,
int *warnings)
{
- my_bool in_dst_time_gap;
- /* Only convert a correct date (not a zero date) */
- if (!ltime->month)
+ /*
+ No needs to do check_date(TIME_NO_ZERO_IN_DATE),
+ because it has been done earlier in
+ store_time(), number_to_datetime() or str_to_datetime().
+ */
+ if (datetime_with_no_zero_in_date_to_timeval(thd, ltime, tm, warnings))
{
tm->tv_sec= tm->tv_usec= 0;
- if (ltime->second_part)
- {
- /* Don't allow zero timestamp with microseconds */
- *warnings|= MYSQL_TIME_WARN_TRUNCATED;
- return true;
- }
- return false;
- }
-
- tm->tv_usec= ltime->second_part;
-
- if (!(tm->tv_sec= TIME_to_timestamp(thd, ltime, &in_dst_time_gap)))
- {
- *warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
- return true;
- }
- else if (in_dst_time_gap)
- {
- *warnings|= MYSQL_TIME_WARN_INVALID_TIMESTAMP;
return true;
}
return false;
@@ -5361,7 +5342,7 @@ bool Field_timestamp::get_date_internal(
/**
Get TIMESTAMP field value as seconds since begging of Unix Epoch
*/
-bool Field_timestamp::get_timestamp(struct timeval *tm)
+bool Field_timestamp::get_timestamp(struct timeval *tm, int *warnings)
{
if (is_null())
return true;
@@ -5570,12 +5551,11 @@ Field_timestampf::get_date_internal(MYSQ
}
-bool Field_timestampf::get_timestamp(struct timeval *tm)
+bool Field_timestampf::get_timestamp(struct timeval *tm, int *warnings)
{
THD *thd= table ? table->in_use : current_thd;
thd->time_zone_used= 1;
- if (is_null())
- return true;
+ DBUG_ASSERT(!is_null());
my_timestamp_from_binary(tm, ptr, dec);
return false;
}
=== modified file 'sql/field.h'
--- a/sql/field.h 2011-11-17 13:41:28 +0000
+++ b/sql/field.h 2011-11-18 13:26:35 +0000
@@ -539,7 +539,7 @@ public:
This method is used in "SELECT UNIX_TIMESTAMP(field)"
to avoid conversion from timestamp to MYSQL_TIME and back.
*/
- virtual bool get_timestamp(struct timeval *tm);
+ virtual bool get_timestamp(struct timeval *tm, int *warnings);
/**
Stores a timestamp value in "struct timeval" format into a field.
Note, store_timestamp(), get_timestamp() and store_time()
@@ -2174,7 +2174,7 @@ public:
Field::set_default();
}
/* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
- bool get_timestamp(struct timeval *tm);
+ bool get_timestamp(struct timeval *tm, int *warnings);
bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
Field_timestamp *clone(MEM_ROOT *mem_root) const {
DBUG_ASSERT(type() == MYSQL_TYPE_TIMESTAMP);
@@ -2269,7 +2269,7 @@ public:
else
Field::set_default();
}
- bool get_timestamp(struct timeval *tm);
+ bool get_timestamp(struct timeval *tm, int *warnings);
};
=== modified file 'sql/item.cc'
--- a/sql/item.cc 2011-11-17 13:41:28 +0000
+++ b/sql/item.cc 2011-11-18 13:26:35 +0000
@@ -1375,17 +1375,14 @@ bool Item::get_time_from_non_temporal(MY
}
return (null_value= true); // Impossible result type
}
-
-bool Item::get_timeval(struct timeval *tm)
+
+bool Item::get_timeval(struct timeval *tm, int *warnings)
{
MYSQL_TIME ltime;
- if (get_date(<ime, 0))
- return true;
- my_bool not_used;
- tm->tv_sec= TIME_to_timestamp(current_thd, <ime, ¬_used);
- tm->tv_usec= ltime.second_part;
- return false;
+ return (null_value=
+ (get_date(<ime, TIME_FUZZY_DATE) ||
+ datetime_to_timeval(current_thd, <ime, tm, warnings)));
}
@@ -2677,9 +2674,10 @@ bool Item_field::get_time(MYSQL_TIME *lt
return 0;
}
-bool Item_field::get_timeval(struct timeval *tm)
+bool Item_field::get_timeval(struct timeval *tm, int *warnings)
{
- return ((null_value= field->get_timestamp(tm)));
+ return (null_value= (field->is_null() ||
+ field->get_timestamp(tm, warnings)));
}
double Item_field::val_result()
=== modified file 'sql/item.h'
--- a/sql/item.h 2011-11-10 14:58:23 +0000
+++ b/sql/item.h 2011-11-18 09:52:00 +0000
@@ -1082,7 +1082,7 @@ public:
@retval false on success
@retval true on error
*/
- virtual bool get_timeval(struct timeval *tm);
+ virtual bool get_timeval(struct timeval *tm, int *warnings);
virtual bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate)
{ return get_date(ltime,fuzzydate); }
/*
@@ -1989,7 +1989,7 @@ public:
bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate);
bool get_time(MYSQL_TIME *ltime);
- bool get_timeval(struct timeval *tm);
+ bool get_timeval(struct timeval *tm, int *warnings);
bool is_null() { return field->is_null(); }
void update_null_value();
Item *get_tmp_table_item(THD *thd);
=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc 2011-11-17 13:41:28 +0000
+++ b/sql/item_cmpfunc.cc 2011-11-18 13:26:35 +0000
@@ -910,8 +910,32 @@ get_time_value(THD *thd, Item ***item_ar
longlong value;
Item *item= **item_arg;
+ /*
+ Note, it's wrong to assume that we always get
+ a TIME expression or NULL here:
+
DBUG_ASSERT(item->field_type() == MYSQL_TYPE_TIME ||
item->field_type() == MYSQL_TYPE_NULL);
+
+ because when this condition is optimized:
+
+ WHERE time_column=DATE(NULL) AND time_column=TIME(NULL);
+
+ rhe first AND part is eliminated and DATE(NULL) is substituted
+ to the second AND part like this:
+
+ WHERE DATE(NULL) = TIME(NULL) // as TIME
+
+ whose Arg_comparator has already get_time_value set for both arguments.
+ Therefore, get_time_value is executed for DATE(NULL).
+ This condition is further evaluated as impossible condition.
+
+ TS-TODO: perhaps such cases should be evaluated without
+ calling get_time_value at all.
+
+ See a similar comment in Arg_comparator::compare_temporal_packed,
+ for DATETIME comparison.
+ */
value= item->val_time_temporal();
*is_null= item->null_value;
=== modified file 'sql/item_timefunc.cc'
--- a/sql/item_timefunc.cc 2011-11-17 13:41:28 +0000
+++ b/sql/item_timefunc.cc 2011-11-18 13:26:35 +0000
@@ -1474,14 +1474,19 @@ bool Item_func_unix_timestamp::val_timev
tm->tv_usec= 0;
return false; // no args: null_value is set in constructor and is always 0.
}
- if (args[0]->get_timeval(tm)) // Don't set null_value here
+ int warnings= 0;
+ if (args[0]->get_timeval(tm, &warnings)) // Don't set null_value here
{
- tm->tv_sec= tm->tv_usec= 0;
/*
- We set null_value only if args[0] returned null.
+ We set null_value only if args[0]->get_date() invoked
+ inside args[0]->get_timeval() returned null,
+ which is indicated by "warnings == 0".
In case of wrong non-null datetime parameter we return 0.
+ "warnings" will not be equal to 0 in this case.
*/
- return (null_value= args[0]->null_value);
+ if (warnings == 0)
+ return (null_value= true);
+ tm->tv_sec= tm->tv_usec= 0;
}
return (null_value= false);
}
@@ -1502,10 +1507,9 @@ longlong Item_func_unix_timestamp::val_i
DBUG_ASSERT(arg_count == 1 &&
args[0]->type() == Item::FIELD_ITEM &&
args[0]->field_type() == MYSQL_TYPE_TIMESTAMP);
- Field *field=((Item_field*) args[0])->field;
/* Leave the incl_endp intact */
struct timeval tm;
- return (null_value= field->get_timestamp(&tm)) ? 0 : tm.tv_sec;
+ return val_timeval(&tm) ? 0 : tm.tv_sec;
}
=== modified file 'sql/sql_time.cc'
--- a/sql/sql_time.cc 2011-11-03 09:33:45 +0000
+++ b/sql/sql_time.cc 2011-11-18 09:52:00 +0000
@@ -637,6 +637,116 @@ my_time_t TIME_to_timestamp(THD *thd, co
}
+/**
+ Convert a datetime MYSQL_TIME representation
+ to corresponding "struct timeval" value.
+
+ ltime must previously be checked for TIME_NO_ZERO_IN_DATE.
+ Things like '0000-01-01', '2000-00-01', '2000-01-00' are not allowed
+ and asserted.
+
+ Things like '0000-00-00 10:30:30' or '0000-00-00 00:00:00.123456'
+ (i.e. empty date with non-empty time) return error.
+
+ Zero datetime '0000-00-00 00:00:00.000000'
+ is allowed and is mapper to {tv_sec=0, tv_usec=0}.
+
+ Note: In case of error, tm value is not initialized.
+
+ Note: "warnings" is not initialized to zero,
+ so new warnings are added to the old ones.
+ Caller must make sure to initialize "warnings".
+
+ @param IN thd current thd
+ @param IN ltime datetime value
+ @param OUT tm timeval value
+ @param OUT warnings pointer to warnings vector
+ @return
+ @retval false on success
+ @retval true on error
+*/
+bool datetime_with_no_zero_in_date_to_timeval(THD *thd,
+ const MYSQL_TIME *ltime,
+ struct timeval *tm,
+ int *warnings)
+{
+ if (!ltime->month) /* Zero date */
+ {
+ DBUG_ASSERT(!ltime->year && !ltime->day);
+ if (non_zero_time(ltime))
+ {
+ /*
+ Return error for zero date with non-zero time, e.g.:
+ '0000-00-00 10:20:30' or '0000-00-00 00:00:00.123456'
+ */
+ *warnings|= MYSQL_TIME_WARN_TRUNCATED;
+ return true;
+ }
+ tm->tv_sec= tm->tv_usec= 0; // '0000-00-00 00:00:00.000000'
+ return false;
+ }
+
+ my_bool in_dst_time_gap;
+ if (!(tm->tv_sec= TIME_to_timestamp(current_thd, ltime, &in_dst_time_gap)))
+ {
+ /*
+ Date was outside of the supported timestamp range.
+ For example: '3001-01-01 00:00:00' or '1000-01-01 00:00:00'
+ */
+ *warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ return true;
+ }
+ else if (in_dst_time_gap)
+ {
+ /*
+ Set MYSQL_TIME_WARN_INVALID_TIMESTAMP warning to indicate
+ that date was fine but pointed to winter/summer time switch gap.
+ In this case tm is set to the fist second after gap.
+ For example: '2003-03-30 02:30:00 MSK' -> '2003-03-30 03:00:00 MSK'
+ */
+ *warnings|= MYSQL_TIME_WARN_INVALID_TIMESTAMP;
+ }
+ tm->tv_usec= ltime->second_part;
+ return false;
+}
+
+
+/**
+ Convert a datetime MYSQL_TIME representation
+ to corresponding "struct timeval" value.
+
+ Things like '0000-01-01', '2000-00-01', '2000-01-00'
+ (i.e. incomplete date) return error.
+
+ Things like '0000-00-00 10:30:30' or '0000-00-00 00:00:00.123456'
+ (i.e. empty date with non-empty time) return error.
+
+ Zero datetime '0000-00-00 00:00:00.000000'
+ is allowed and is mapper to {tv_sec=0, tv_usec=0}.
+
+ Note: In case of error, tm value is not initialized.
+
+ Note: "warnings" is not initialized to zero,
+ so new warnings are added to the old ones.
+ Caller must make sure to initialize "warnings".
+
+ @param IN thd current thd
+ @param IN ltime datetime value
+ @param OUT tm timeval value
+ @param OUT warnings pointer to warnings vector
+ @return
+ @retval false on success
+ @retval true on error
+*/
+bool datetime_to_timeval(THD *thd, const MYSQL_TIME *ltime,
+ struct timeval *tm, int *warnings)
+{
+ return
+ check_date(ltime, non_zero_date(ltime), TIME_NO_ZERO_IN_DATE, warnings) ||
+ datetime_with_no_zero_in_date_to_timeval(current_thd, ltime, tm, warnings);
+}
+
+
/*
Convert a time string to a MYSQL_TIME struct and produce a warning
if string was cut during conversion.
=== modified file 'sql/sql_time.h'
--- a/sql/sql_time.h 2011-11-07 11:50:35 +0000
+++ b/sql/sql_time.h 2011-11-18 09:52:00 +0000
@@ -36,6 +36,11 @@ ulong convert_month_to_period(ulong mont
void mix_date_and_time(MYSQL_TIME *ldate, const MYSQL_TIME *ltime);
void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
+bool datetime_with_no_zero_in_date_to_timeval(THD *thd, const MYSQL_TIME *t,
+ struct timeval *tm,
+ int *warnings);
+bool datetime_to_timeval(THD *thd, const MYSQL_TIME *t,
+ struct timeval *tm, int *warnings);
bool str_to_datetime_with_warn(String *str, MYSQL_TIME *l_time, uint flags);
bool my_decimal_to_datetime_with_warn(const my_decimal *decimal,
MYSQL_TIME *ltime, uint flags);
=== modified file 'unittest/gunit/field-t.cc'
--- a/unittest/gunit/field-t.cc 2011-11-01 11:52:24 +0000
+++ b/unittest/gunit/field-t.cc 2011-11-18 11:49:13 +0000
@@ -258,7 +258,8 @@ TEST_F(FieldTest, FieldTimef)
// it requires a mock table
struct timeval tv;
- EXPECT_EQ(0, f->get_timestamp(&tv));
+ int warnings= 0;
+ EXPECT_EQ(0, f->get_timestamp(&tv, &warnings));
// EXPECT_EQ(40992, tv.tv_sec); // This is 11:23:12. Why? Time zone?
EXPECT_EQ(123400, tv.tv_usec);
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (alexander.barkov:3599 to 3600) | Alexander Barkov | 21 Nov |