Skip to content

Commit b697dce

Browse files
committed
MDEV-29149 Assertion `!is_valid_datetime() || fraction_remainder(((item->decimals) < (6) ? (item->decimals) : (6))) == 0' failed in Datetime_truncation_not_needed::Datetime_truncation_not_needed
TIME-alike string and numeric arguments to TIMEDIFF() can get additional fractional seconds during the supported TIME range adjustment in get_time(). For example, during TIMEDIFF('839:00:00','00:00:00') evaluation in Item_func_timediff::get_date(), the call for args[0]->get_time() returns MYSQL_TIME '838:59:59.999999'. Item_func_timediff::get_date() did not handle these extra digits and returned a MYSQL_TIME result with fractional digits outside of Item_func_timediff::decimals. This mismatch could further be caught by a DBUG_ASSERT() in various other pieces of the code, leading to a crash. Fix: In case if get_time() returned MYSQL_TIMESTAMP_TIME, let's truncate all extra digits using my_time_trunc(&l_time,decimals). This guarantees that the rest of the code returns a MYSQL_TIME with second_part not conflicting with Item_func_timediff::decimals.
1 parent 0304dbc commit b697dce

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed

mysql-test/main/func_time.result

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6373,3 +6373,57 @@ NULL
63736373
SELECT FROM_UNIXTIME(LEAST(3696610869, NULL));
63746374
FROM_UNIXTIME(LEAST(3696610869, NULL))
63756375
NULL
6376+
#
6377+
# Start of 10.5 tests
6378+
#
6379+
#
6380+
# MDEV-29149 Assertion `!is_valid_datetime() || fraction_remainder(((item->decimals) < (6) ? (item->decimals) : (6))) == 0' failed in Datetime_truncation_not_needed::Datetime_truncation_not_needed
6381+
#
6382+
SET @@timestamp= UNIX_TIMESTAMP('2022-07-21 23:00:00');
6383+
SELECT DATE_SUB('2022-07-21 00:00:00', INTERVAL 800 HOUR) AS expected_result;
6384+
expected_result
6385+
2022-06-17 16:00:00
6386+
SELECT
6387+
IF(1,TIMEDIFF('38:59:59','839:00:00'),CAST('2022-12-12' AS DATE)) AS c1,
6388+
IF(1,TIMEDIFF('-839:00:00','-38:59:59'),CAST('2022-12-12' AS DATE)) AS c2;
6389+
c1 c2
6390+
2022-06-17 16:00:00 2022-06-17 16:00:00
6391+
Warnings:
6392+
Warning 1292 Truncated incorrect time value: '839:00:00'
6393+
Warning 1292 Truncated incorrect time value: '-839:00:00'
6394+
SELECT
6395+
IF(1,TIMEDIFF(385959,8390000),CAST('2022-12-12' AS DATE)) AS c1,
6396+
IF(1,TIMEDIFF(-8390000,-385959),CAST('2022-12-12' AS DATE)) AS c2;
6397+
c1 c2
6398+
2022-06-17 16:00:00 2022-06-17 16:00:00
6399+
Warnings:
6400+
Warning 1292 Truncated incorrect time value: '8390000'
6401+
Warning 1292 Truncated incorrect time value: '-8390000'
6402+
SELECT
6403+
TIMEDIFF('38:59:59','839:00:00') AS c1,
6404+
CAST(TIMEDIFF('38:59:59','839:00:00') AS TIME(6)) AS c2,
6405+
TIMEDIFF('839:00:00','38:59:59') AS c3,
6406+
CAST(TIMEDIFF('839:00:00','38:59:59') AS TIME(6)) AS c4;
6407+
c1 c2 c3 c4
6408+
-800:00:00 -800:00:00.000000 800:00:00 800:00:00.000000
6409+
Warnings:
6410+
Warning 1292 Truncated incorrect time value: '839:00:00'
6411+
Warning 1292 Truncated incorrect time value: '839:00:00'
6412+
Warning 1292 Truncated incorrect time value: '839:00:00'
6413+
Warning 1292 Truncated incorrect time value: '839:00:00'
6414+
SELECT
6415+
TIMEDIFF(385959,8390000) AS c1,
6416+
CAST(TIMEDIFF(385959,8390000) AS TIME(6)) AS c2,
6417+
TIMEDIFF(8390000,385959) AS c3,
6418+
CAST(TIMEDIFF(8390000,385959) AS TIME(6)) AS c4;
6419+
c1 c2 c3 c4
6420+
-800:00:00 -800:00:00.000000 800:00:00 800:00:00.000000
6421+
Warnings:
6422+
Warning 1292 Truncated incorrect time value: '8390000'
6423+
Warning 1292 Truncated incorrect time value: '8390000'
6424+
Warning 1292 Truncated incorrect time value: '8390000'
6425+
Warning 1292 Truncated incorrect time value: '8390000'
6426+
SET @@timestamp= DEFAULT;
6427+
#
6428+
# End of 10.5 tests
6429+
#

mysql-test/main/func_time.test

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,3 +3213,42 @@ SELECT CONCAT(MAKETIME('01', '01', LEAST( -100, NULL )));
32133213
--echo #
32143214

32153215
SELECT FROM_UNIXTIME(LEAST(3696610869, NULL));
3216+
3217+
3218+
--echo #
3219+
--echo # Start of 10.5 tests
3220+
--echo #
3221+
3222+
--echo #
3223+
--echo # MDEV-29149 Assertion `!is_valid_datetime() || fraction_remainder(((item->decimals) < (6) ? (item->decimals) : (6))) == 0' failed in Datetime_truncation_not_needed::Datetime_truncation_not_needed
3224+
--echo #
3225+
3226+
SET @@timestamp= UNIX_TIMESTAMP('2022-07-21 23:00:00');
3227+
3228+
SELECT DATE_SUB('2022-07-21 00:00:00', INTERVAL 800 HOUR) AS expected_result;
3229+
3230+
SELECT
3231+
IF(1,TIMEDIFF('38:59:59','839:00:00'),CAST('2022-12-12' AS DATE)) AS c1,
3232+
IF(1,TIMEDIFF('-839:00:00','-38:59:59'),CAST('2022-12-12' AS DATE)) AS c2;
3233+
3234+
SELECT
3235+
IF(1,TIMEDIFF(385959,8390000),CAST('2022-12-12' AS DATE)) AS c1,
3236+
IF(1,TIMEDIFF(-8390000,-385959),CAST('2022-12-12' AS DATE)) AS c2;
3237+
3238+
SELECT
3239+
TIMEDIFF('38:59:59','839:00:00') AS c1,
3240+
CAST(TIMEDIFF('38:59:59','839:00:00') AS TIME(6)) AS c2,
3241+
TIMEDIFF('839:00:00','38:59:59') AS c3,
3242+
CAST(TIMEDIFF('839:00:00','38:59:59') AS TIME(6)) AS c4;
3243+
3244+
SELECT
3245+
TIMEDIFF(385959,8390000) AS c1,
3246+
CAST(TIMEDIFF(385959,8390000) AS TIME(6)) AS c2,
3247+
TIMEDIFF(8390000,385959) AS c3,
3248+
CAST(TIMEDIFF(8390000,385959) AS TIME(6)) AS c4;
3249+
3250+
SET @@timestamp= DEFAULT;
3251+
3252+
--echo #
3253+
--echo # End of 10.5 tests
3254+
--echo #

sql/item_timefunc.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,6 +2706,24 @@ bool Item_func_timediff::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzy
27062706
if (l_time1.neg != l_time2.neg)
27072707
l_sign= -l_sign;
27082708

2709+
if (l_time1.time_type == MYSQL_TIMESTAMP_TIME)
2710+
{
2711+
/*
2712+
In case of TIME-alike arguments:
2713+
TIMEDIFF('38:59:59', '839:00:00')
2714+
let's truncate extra fractional seconds that might appear if the argument
2715+
values were out of the supported TIME range. For example, args[n]->get_time()
2716+
for the string literal '839:00:00' returns TIME'838:59:59.999999'.
2717+
The fractional part must be truncated according to this->decimals,
2718+
to avoid returning more fractional seconds than it was detected
2719+
during this->fix_length_and_dec().
2720+
Note, the thd rounding mode should not be important here, as we're removing
2721+
redundant digits from the maximum possible value: '838:59:59.999999'.
2722+
*/
2723+
my_time_trunc(&l_time1, decimals);
2724+
my_time_trunc(&l_time2, decimals);
2725+
}
2726+
27092727
if (calc_time_diff(&l_time1, &l_time2, l_sign, &l_time3, fuzzydate))
27102728
return (null_value= 1);
27112729

0 commit comments

Comments
 (0)