Commit 9e5c1fb5 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-23838 Possibly wrong result or Assertion `0' failed in Item_func_round::native_op

Change history in the affected code:

- Since 10.4.8 (MDEV-20397 and MDEV-23311), functions ROUND(), CEILING(),
  FLOOR() return a TIME value for a TIME input.
- Since 10.4.14 (MDEV-23525), MIN() and MAX() calculate a result for a TIME
  input using val_native() rather than val_str().

Problem:

The patch for MDEV-23525 did not take into account combinations like
MIN(ROUND(time)), MAX(FLOOR(time)), etc.

MIN() and MAX() with ROUND(time), CEILING(time), FLOOR(time) as an argument
call the method val_native() of the undelying classes Item_func_round and
Item_func_int_val. However these classes implemented the method val_native()
as DBUG_ASSERT(0).

Fix:

This patch adds a TIME-specific code inside:
- Item_func_round::val_native()
- Item_func_int_val::val_native()
still with DBUG_ASSERT(0) for all other data types,
as other data types do not call val_native() of these classes.

We'll need a more generic solition eventualy, e.g.
turn Item_func_round and Item_func_int_val into Item_handled_func.
However, this change would be too risky for 10.4 at this point.
parent fbc157ab
...@@ -2446,5 +2446,49 @@ DROP TABLE t1; ...@@ -2446,5 +2446,49 @@ DROP TABLE t1;
SET @@time_zone=DEFAULT; SET @@time_zone=DEFAULT;
SET TIMESTAMP=DEFAULT; SET TIMESTAMP=DEFAULT;
# #
# MDEV-23838 Possibly wrong result or Assertion `0' failed in Item_func_round::native_op
#
CREATE TABLE t1 (a TIME, b INT);
INSERT INTO t1 VALUES ('07:26:24',NULL),('23:55:04',NULL);
SELECT MAX(ROUND(a, 0)) FROM t1 GROUP BY 1 << b;
MAX(ROUND(a, 0))
23:55:04
DROP TABLE t1;
CREATE TABLE t1 (a TIME(6), b INT);
INSERT INTO t1 VALUES ('07:26:24.12',NULL),('23:55:04.34',NULL);
SELECT MAX(ROUND(a, 2)) FROM t1 GROUP BY 1 << b;
MAX(ROUND(a, 2))
23:55:04.34
DROP TABLE t1;
SET sql_mode='';
CREATE TABLE t1 (a TIME);
INSERT INTO t1 VALUES (0),(0);
SELECT MAX(ROUND (a,a)) FROM t1 GROUP BY a;
MAX(ROUND (a,a))
00:00:00
DROP TABLE t1;
SET sql_mode=DEFAULT;
CREATE TABLE t1 (a TIME, b INT);
INSERT INTO t1 VALUES ('07:26:24',1),('23:55:04',1);
SELECT MIN(CEILING(a)), MAX(CEILING(a)) FROM t1 GROUP BY b;
MIN(CEILING(a)) MAX(CEILING(a))
07:26:24 23:55:04
SELECT MIN(FLOOR(a)), MAX(FLOOR(a)) FROM t1 GROUP BY b;
MIN(FLOOR(a)) MAX(FLOOR(a))
07:26:24 23:55:04
DROP TABLE t1;
CREATE TABLE t1 (a TIME(6), b INT);
INSERT INTO t1 VALUES ('00:00:00.5',1),('00:01:00.5',1);
INSERT INTO t1 VALUES ('-00:00:00.5',2),('-00:01:00.5',2);
SELECT MIN(CEILING(a)), MAX(CEILING(a)) FROM t1 GROUP BY b;
MIN(CEILING(a)) MAX(CEILING(a))
00:00:01 00:01:01
-00:01:00 00:00:00
SELECT MIN(FLOOR(a)), MAX(FLOOR(a)) FROM t1 GROUP BY b;
MIN(FLOOR(a)) MAX(FLOOR(a))
00:00:00 00:01:00
-00:01:01 -00:00:01
DROP TABLE t1;
#
# End of 10.4 tests # End of 10.4 tests
# #
...@@ -1585,6 +1585,41 @@ SET @@time_zone=DEFAULT; ...@@ -1585,6 +1585,41 @@ SET @@time_zone=DEFAULT;
SET TIMESTAMP=DEFAULT; SET TIMESTAMP=DEFAULT;
--echo #
--echo # MDEV-23838 Possibly wrong result or Assertion `0' failed in Item_func_round::native_op
--echo #
CREATE TABLE t1 (a TIME, b INT);
INSERT INTO t1 VALUES ('07:26:24',NULL),('23:55:04',NULL);
SELECT MAX(ROUND(a, 0)) FROM t1 GROUP BY 1 << b;
DROP TABLE t1;
CREATE TABLE t1 (a TIME(6), b INT);
INSERT INTO t1 VALUES ('07:26:24.12',NULL),('23:55:04.34',NULL);
SELECT MAX(ROUND(a, 2)) FROM t1 GROUP BY 1 << b;
DROP TABLE t1;
SET sql_mode='';
CREATE TABLE t1 (a TIME);
INSERT INTO t1 VALUES (0),(0);
SELECT MAX(ROUND (a,a)) FROM t1 GROUP BY a;
DROP TABLE t1;
SET sql_mode=DEFAULT;
CREATE TABLE t1 (a TIME, b INT);
INSERT INTO t1 VALUES ('07:26:24',1),('23:55:04',1);
SELECT MIN(CEILING(a)), MAX(CEILING(a)) FROM t1 GROUP BY b;
SELECT MIN(FLOOR(a)), MAX(FLOOR(a)) FROM t1 GROUP BY b;
DROP TABLE t1;
CREATE TABLE t1 (a TIME(6), b INT);
INSERT INTO t1 VALUES ('00:00:00.5',1),('00:01:00.5',1);
INSERT INTO t1 VALUES ('-00:00:00.5',2),('-00:01:00.5',2);
SELECT MIN(CEILING(a)), MAX(CEILING(a)) FROM t1 GROUP BY b;
SELECT MIN(FLOOR(a)), MAX(FLOOR(a)) FROM t1 GROUP BY b;
DROP TABLE t1;
--echo # --echo #
--echo # End of 10.4 tests --echo # End of 10.4 tests
--echo # --echo #
...@@ -2233,6 +2233,16 @@ bool Item_func_int_val::fix_length_and_dec() ...@@ -2233,6 +2233,16 @@ bool Item_func_int_val::fix_length_and_dec()
} }
bool Item_func_int_val::native_op(THD *thd, Native *to)
{
// TODO: turn Item_func_int_val into Item_handled_func eventually.
if (type_handler()->mysql_timestamp_type() == MYSQL_TIMESTAMP_TIME)
return Time(thd, this).to_native(to, decimals);
DBUG_ASSERT(0);
return true;
}
longlong Item_func_ceiling::int_op() longlong Item_func_ceiling::int_op()
{ {
switch (args[0]->result_type()) { switch (args[0]->result_type()) {
...@@ -2661,6 +2671,16 @@ bool Item_func_round::date_op(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) ...@@ -2661,6 +2671,16 @@ bool Item_func_round::date_op(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate)
} }
bool Item_func_round::native_op(THD *thd, Native *to)
{
// TODO: turn Item_func_round into Item_handled_func eventually.
if (type_handler()->mysql_timestamp_type() == MYSQL_TIMESTAMP_TIME)
return Time(thd, this).to_native(to, decimals);
DBUG_ASSERT(0);
return true;
}
void Item_func_rand::seed_random(Item *arg) void Item_func_rand::seed_random(Item *arg)
{ {
/* /*
......
...@@ -1748,11 +1748,7 @@ class Item_func_int_val :public Item_func_hybrid_field_type ...@@ -1748,11 +1748,7 @@ class Item_func_int_val :public Item_func_hybrid_field_type
} }
bool fix_length_and_dec(); bool fix_length_and_dec();
String *str_op(String *str) { DBUG_ASSERT(0); return 0; } String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
bool native_op(THD *thd, Native *to) bool native_op(THD *thd, Native *to);
{
DBUG_ASSERT(0);
return true;
}
}; };
...@@ -1804,11 +1800,7 @@ class Item_func_round :public Item_func_hybrid_field_type ...@@ -1804,11 +1800,7 @@ class Item_func_round :public Item_func_hybrid_field_type
my_decimal *decimal_op(my_decimal *); my_decimal *decimal_op(my_decimal *);
bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool time_op(THD *thd, MYSQL_TIME *ltime); bool time_op(THD *thd, MYSQL_TIME *ltime);
bool native_op(THD *thd, Native *to) bool native_op(THD *thd, Native *to);
{
DBUG_ASSERT(0);
return true;
}
String *str_op(String *str) String *str_op(String *str)
{ {
DBUG_ASSERT(0); DBUG_ASSERT(0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment