summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mnogosearch.org>2014-04-18 12:19:51 +0400
committerAlexander Barkov <bar@mnogosearch.org>2014-04-18 12:19:51 +0400
commit8db600f951005b0b23b23dcd0ddd848303aa13ac (patch)
tree48a761aeab9aaeaecf6232407e65dc97962c8375
parent13dc299a4fa50627aff42480c8e995347283e475 (diff)
downloadmariadb-git-8db600f951005b0b23b23dcd0ddd848303aa13ac.tar.gz
MDEV-5041 Inserting a TIME with hour>24 into a DATETIME column produces a wrong value
-rw-r--r--mysql-test/r/type_date.result46
-rw-r--r--mysql-test/r/type_datetime.result40
-rw-r--r--mysql-test/t/type_date.test28
-rw-r--r--mysql-test/t/type_datetime.test29
-rw-r--r--sql/field.cc8
-rw-r--r--sql/item_timefunc.cc32
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/time.cc50
8 files changed, 211 insertions, 25 deletions
diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result
index b7776d67651..e16054ef591 100644
--- a/mysql-test/r/type_date.result
+++ b/mysql-test/r/type_date.result
@@ -345,5 +345,51 @@ Warning 1292 Incorrect datetime value: '0'
Warning 1292 Incorrect datetime value: '0'
SET @@timestamp=DEFAULT;
#
+# MDEV-5041 Inserting a TIME with hour>24 into a DATETIME column produces a wrong value
+#
+SELECT CAST(TIME('-800:20:30') AS DATE);
+CAST(TIME('-800:20:30') AS DATE)
+NULL
+Warnings:
+Warning 1292 Truncated incorrect date value: '-800:20:30'
+SELECT CAST(TIME('800:20:30') AS DATE);
+CAST(TIME('800:20:30') AS DATE)
+0000-01-02
+SELECT CAST(TIME('33 08:20:30') AS DATE);
+CAST(TIME('33 08:20:30') AS DATE)
+0000-01-02
+CREATE TABLE t1 (a DATE);
+INSERT INTO t1 VALUES (TIME('800:20:30'));
+Warnings:
+Note 1265 Data truncated for column 'a' at row 1
+INSERT INTO t1 VALUES (TIME('33 08:20:30'));
+Warnings:
+Note 1265 Data truncated for column 'a' at row 1
+SET SQL_MODE=NO_ZERO_IN_DATE;
+INSERT INTO t1 VALUES (TIME('48:20:30'));
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+SET SQL_MODE=DEFAULT;
+SELECT * FROM t1;
+a
+0000-01-02
+0000-01-02
+0000-00-00
+DROP TABLE t1;
+CREATE PROCEDURE test5041()
+BEGIN
+DECLARE t TIME;
+DECLARE d DATE;
+SET t= TIME('800:00:00');
+SET d= t;
+SELECT d;
+END;|
+call test5041();
+d
+0000-01-02
+Warnings:
+Note 1265 Data truncated for column 'd' at row 1
+drop procedure test5041;
+#
# End of 5.3 tests
#
diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result
index 317af8d6b38..d20506288ad 100644
--- a/mysql-test/r/type_datetime.result
+++ b/mysql-test/r/type_datetime.result
@@ -684,4 +684,44 @@ CONVERT_TZ(GREATEST(TIMESTAMP('2021-00-00'),TIMESTAMP('2022-00-00')),'+00:00','+
NULL
Warnings:
Warning 1292 Incorrect datetime value: '2022-00-00 00:00:00'
+#
+# MDEV-5041 Inserting a TIME with hour>24 into a DATETIME column produces a wrong value
+#
+SELECT CAST(TIME('-800:20:30') AS DATETIME);
+CAST(TIME('-800:20:30') AS DATETIME)
+NULL
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '-800:20:30'
+SELECT CAST(TIME('800:20:30') AS DATETIME);
+CAST(TIME('800:20:30') AS DATETIME)
+0000-01-02 08:20:30
+SELECT CAST(TIME('33 08:20:30') AS DATETIME);
+CAST(TIME('33 08:20:30') AS DATETIME)
+0000-01-02 08:20:30
+CREATE TABLE t1 (a DATETIME);
+INSERT INTO t1 VALUES (TIME('800:20:30'));
+INSERT INTO t1 VALUES (TIME('33 08:20:30'));
+SET SQL_MODE=NO_ZERO_IN_DATE;
+INSERT INTO t1 VALUES (TIME('48:20:30'));
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+SET SQL_MODE=DEFAULT;
+SELECT * FROM t1;
+a
+0000-01-02 08:20:30
+0000-01-02 08:20:30
+0000-00-00 00:00:00
+DROP TABLE t1;
+CREATE PROCEDURE test5041()
+BEGIN
+DECLARE t TIME;
+DECLARE dt DATETIME;
+SET t= TIME('800:20:30');
+SET dt= t;
+SELECT dt;
+END;|
+call test5041();
+dt
+0000-01-02 08:20:30
+drop procedure test5041;
End of 5.3 tests
diff --git a/mysql-test/t/type_date.test b/mysql-test/t/type_date.test
index 8a47d324406..7454033a83d 100644
--- a/mysql-test/t/type_date.test
+++ b/mysql-test/t/type_date.test
@@ -310,5 +310,33 @@ SELECT
SET @@timestamp=DEFAULT;
--echo #
+--echo # MDEV-5041 Inserting a TIME with hour>24 into a DATETIME column produces a wrong value
+--echo #
+SELECT CAST(TIME('-800:20:30') AS DATE);
+SELECT CAST(TIME('800:20:30') AS DATE);
+SELECT CAST(TIME('33 08:20:30') AS DATE);
+CREATE TABLE t1 (a DATE);
+INSERT INTO t1 VALUES (TIME('800:20:30'));
+INSERT INTO t1 VALUES (TIME('33 08:20:30'));
+SET SQL_MODE=NO_ZERO_IN_DATE;
+INSERT INTO t1 VALUES (TIME('48:20:30'));
+SET SQL_MODE=DEFAULT;
+SELECT * FROM t1;
+DROP TABLE t1;
+DELIMITER |;
+CREATE PROCEDURE test5041()
+BEGIN
+ DECLARE t TIME;
+ DECLARE d DATE;
+ SET t= TIME('800:00:00');
+ SET d= t;
+ SELECT d;
+END;|
+DELIMITER ;|
+call test5041();
+drop procedure test5041;
+
+
+--echo #
--echo # End of 5.3 tests
--echo #
diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test
index 87f74530bb3..2fdc33ab079 100644
--- a/mysql-test/t/type_datetime.test
+++ b/mysql-test/t/type_datetime.test
@@ -491,5 +491,34 @@ drop table t1,t2;
--echo #
SELECT CONVERT_TZ(GREATEST(TIMESTAMP('2021-00-00'),TIMESTAMP('2022-00-00')),'+00:00','+7:5');
+
+--echo #
+--echo # MDEV-5041 Inserting a TIME with hour>24 into a DATETIME column produces a wrong value
+--echo #
+SELECT CAST(TIME('-800:20:30') AS DATETIME);
+SELECT CAST(TIME('800:20:30') AS DATETIME);
+SELECT CAST(TIME('33 08:20:30') AS DATETIME);
+CREATE TABLE t1 (a DATETIME);
+INSERT INTO t1 VALUES (TIME('800:20:30'));
+INSERT INTO t1 VALUES (TIME('33 08:20:30'));
+SET SQL_MODE=NO_ZERO_IN_DATE;
+INSERT INTO t1 VALUES (TIME('48:20:30'));
+SET SQL_MODE=DEFAULT;
+SELECT * FROM t1;
+DROP TABLE t1;
+DELIMITER |;
+CREATE PROCEDURE test5041()
+BEGIN
+ DECLARE t TIME;
+ DECLARE dt DATETIME;
+ SET t= TIME('800:20:30');
+ SET dt= t;
+ SELECT dt;
+END;|
+DELIMITER ;|
+call test5041();
+drop procedure test5041;
+
+
--echo End of 5.3 tests
diff --git a/sql/field.cc b/sql/field.cc
index 17398714d5b..78d39a79194 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -5173,6 +5173,13 @@ int Field_temporal::store_time_dec(MYSQL_TIME *ltime, uint dec)
int error = 0, have_smth_to_conv= 1;
MYSQL_TIME l_time= *ltime;
Lazy_string_time str(ltime);
+
+ if (l_time.time_type == MYSQL_TIMESTAMP_TIME && time_to_datetime(&l_time))
+ {
+ have_smth_to_conv= 0;
+ error= 1;
+ goto store;
+ }
/*
We don't perform range checking here since values stored in TIME
structure always fit into DATETIME range.
@@ -5181,6 +5188,7 @@ int Field_temporal::store_time_dec(MYSQL_TIME *ltime, uint dec)
(current_thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES)), &error);
+store:
return store_TIME_with_warning(&l_time, &str, error, have_smth_to_conv);
}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index ebc61e02a82..fbc7bc36842 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2317,10 +2317,11 @@ bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
return 1;
- ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
- ltime->time_type= MYSQL_TIMESTAMP_DATE;
- return (null_value= check_date_with_warn(ltime, fuzzy_date,
- MYSQL_TIMESTAMP_DATE));
+
+ if (make_date_with_warn(ltime, fuzzy_date, MYSQL_TIMESTAMP_DATE))
+ return (null_value= 1);
+
+ return 0;
}
@@ -2332,28 +2333,9 @@ bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
if (decimals < TIME_SECOND_PART_DIGITS)
ltime->second_part= sec_part_truncate(ltime->second_part, decimals);
+ if (make_date_with_warn(ltime, fuzzy_date, MYSQL_TIMESTAMP_DATETIME))
+ return (null_value= 1);
- /*
- ltime is valid MYSQL_TYPE_TIME (according to fuzzy_date).
- But not every valid TIME value is a valid DATETIME value!
- */
- if (ltime->time_type == MYSQL_TIMESTAMP_TIME)
- {
- if (ltime->neg)
- {
- Lazy_string_time str(ltime);
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- &str, MYSQL_TIMESTAMP_DATETIME, 0);
- return (null_value= 1);
- }
-
- uint day= ltime->hour/24;
- ltime->hour %= 24;
- ltime->month= day / 31;
- ltime->day= day % 31;
- }
-
- ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
return 0;
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index d39038b1332..2f04f02064c 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -2526,6 +2526,7 @@ bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time,
ulong fuzzydate);
timestamp_type str_to_datetime_with_warn(const char *str, uint length,
MYSQL_TIME *l_time, ulong flags);
+bool time_to_datetime(MYSQL_TIME *l_time);
void time_to_daytime_interval(MYSQL_TIME *l_time);
void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
@@ -2581,6 +2582,8 @@ check_date(const MYSQL_TIME *ltime, ulonglong flags, int *was_cut)
}
bool check_date_with_warn(const MYSQL_TIME *ltime, uint fuzzy_date,
timestamp_type ts_type);
+bool make_date_with_warn(MYSQL_TIME *ltime,
+ uint fuzzy_date, timestamp_type ts_type);
bool adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec);
int test_if_number(char *str,int *res,bool allow_wildcards);
void change_byte(uchar *,uint,char,char);
diff --git a/sql/time.cc b/sql/time.cc
index 4dce2f4135a..b91ddad6cd4 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -1060,6 +1060,56 @@ int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b)
}
+/**
+ Convert TIME to DATETIME.
+ @param ltime The value to convert.
+ @return false on success, true of error (negative time).
+*/
+bool time_to_datetime(MYSQL_TIME *ltime)
+{
+ DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_TIME);
+ DBUG_ASSERT(ltime->year == 0);
+ DBUG_ASSERT(ltime->month == 0);
+ DBUG_ASSERT(ltime->day == 0);
+ if (ltime->neg)
+ return true;
+ uint day= ltime->hour / 24;
+ ltime->hour%= 24;
+ ltime->month= day / 31;
+ ltime->day= day % 31;
+ return false;
+}
+
+
+/**
+ Return a valid DATE or DATETIME value from an arbitrary MYSQL_TIME.
+ If ltime is TIME, it's first converted to DATETIME.
+ If ts_type is DATE, yymmss is set to zero.
+ The date part of the result is checked against fuzzy_date.
+
+ @param ltime The value to convert.
+ @param fuzzy_date Flags to check date.
+ @param ts_type The type to convert to.
+ @return false on success, true of error (negative time).*/
+bool
+make_date_with_warn(MYSQL_TIME *ltime, uint fuzzy_date, timestamp_type ts_type)
+{
+ DBUG_ASSERT(ts_type == MYSQL_TIMESTAMP_DATE ||
+ ts_type == MYSQL_TIMESTAMP_DATETIME);
+ if (ltime->time_type == MYSQL_TIMESTAMP_TIME && time_to_datetime(ltime))
+ {
+ /* e.g. negative time */
+ Lazy_string_time str(ltime);
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ &str, ts_type, 0);
+ return true;
+ }
+ if ((ltime->time_type= ts_type) == MYSQL_TIMESTAMP_DATE)
+ ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
+ return check_date_with_warn(ltime, fuzzy_date, ts_type);
+}
+
+
/*
Convert a TIME value to DAY-TIME interval, e.g. for extraction:
EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc.