diff options
author | Alexander Barkov <bar@mnogosearch.org> | 2014-04-18 12:19:51 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mnogosearch.org> | 2014-04-18 12:19:51 +0400 |
commit | 8db600f951005b0b23b23dcd0ddd848303aa13ac (patch) | |
tree | 48a761aeab9aaeaecf6232407e65dc97962c8375 /sql | |
parent | 13dc299a4fa50627aff42480c8e995347283e475 (diff) | |
download | mariadb-git-8db600f951005b0b23b23dcd0ddd848303aa13ac.tar.gz |
MDEV-5041 Inserting a TIME with hour>24 into a DATETIME column produces a wrong value
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 8 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 32 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/time.cc | 50 |
4 files changed, 68 insertions, 25 deletions
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. |