summaryrefslogtreecommitdiff
path: root/sql/compat56.cc
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2018-02-04 16:43:02 +0400
committerAlexander Barkov <bar@mariadb.org>2018-02-04 16:43:02 +0400
commit28d4cf0c1b3366c6471866d144ef28fced1e5390 (patch)
tree33739324408063de53681fe4ac8dfb6abdc45689 /sql/compat56.cc
parent2ecf2f9b2a2c2126b9c9bd0ba8b58280331f5849 (diff)
downloadmariadb-git-28d4cf0c1b3366c6471866d144ef28fced1e5390.tar.gz
MDEV-15176 Storing DATETIME-alike VARCHAR data into TIME produces wrong results
When storing '0001-01-01 10:20:30x', execution went throw the last code branch in Field_time::store_TIME_with_warning(), around the test for (ltime->year || ltime->month). This then resulted into wrong results because: 1. Field_time::store_TIME() does not check YYYYMM against zero. It assumes that ltime->days and ltime->hours are already properly set. So it mixed days to hours, even when YYYYMM was not zero. 2. Field_time_hires::store_TIME() does not check YYYYMM against zero. It assumes that ltime->year, ltime->month, ltime->days and ltime->hours are already properly set. So it always mixed days and even months(!) and years(!) to hours, using pack_time(). This gave even worse results comparing to #2. 3. Field_timef::store_TIME() did not check the entire YYYYMM for being zero. It only checked MM, but did not check YYYY. In case of a zero MM, it mixed days to hours, even if YYYY was not zero. The wrong code was in TIME_to_longlong_time_packed(). In the new reduction Field_time::store_TIME_with_warning() is responsible to prepare the YYYYYMMDD part properly in all code branches (with trailing garbage like 'x' and without trailing garbage). It was reorganized into a more straightforward style. Field_time:store_TIME(), Field_time_hires::store_TIME() and TIME_to_longlong_time_packed() were fixed to do a DBUG_ASSERT on non-zero ltime->year or ltime->month. The code testing ltime->month was removed from TIME_to_longlong_time_packed(), as it's now properly done on the caller level. Truncation was moved from Field_timef::store_TIME() to Field_time::store_TIME_with_warning(). So now all thee methods Field_time*::store_TIME() assume a properly set input value: - Only zero ltime->year and ltime->month are allowed. - The value must be already properly truncated according to decimals() (this will help to add rounding soon, see MDEV-8894) A "const" qualifier was added to the argument of Field_time*::store_TIME().
Diffstat (limited to 'sql/compat56.cc')
-rw-r--r--sql/compat56.cc6
1 files changed, 4 insertions, 2 deletions
diff --git a/sql/compat56.cc b/sql/compat56.cc
index 704d1db9a98..be54a8760aa 100644
--- a/sql/compat56.cc
+++ b/sql/compat56.cc
@@ -45,8 +45,10 @@
*/
longlong TIME_to_longlong_time_packed(const MYSQL_TIME *ltime)
{
- /* If month is 0, we mix day with hours: "1 00:10:10" -> "24:00:10" */
- long hms= (((ltime->month ? 0 : ltime->day * 24) + ltime->hour) << 12) |
+ DBUG_ASSERT(ltime->year == 0);
+ DBUG_ASSERT(ltime->month == 0);
+ // Mix days with hours: "1 00:10:10" -> "24:00:10"
+ long hms= ((ltime->day * 24 + ltime->hour) << 12) |
(ltime->minute << 6) | ltime->second;
longlong tmp= MY_PACKED_TIME_MAKE(hms, ltime->second_part);
return ltime->neg ? -tmp : tmp;