mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-17318 CAST(LEAST(zero_date,non_zero_date) AS numeric_data_type) returns a wrong result
Also fixes: MDEV-17330 Wrong result for 0 + LEAST(TIME'-10:00:00',TIME'10:00:00') Problems: 1. These methods did not take into account the current session date flags and passed date_mode_t(0) to func->get_date(): Type_handler_temporal_result::Item_func_min_max_val_real Type_handler_temporal_result::Item_func_min_max_val_int Type_handler_temporal_result::Item_func_min_max_val_decimal Fixing to pass sql_mode_for_dates(thd) instead of date_mode_t(0). Note, sql_mode_for_dates(thd) is only needed for DATE/DATETIME data types. It is not needed for TIME. So splitting value methods Type_handler_temporal_result::Item_func_min_max_xxx into individual implementations for Type_handler_{time|date|datetime|timestamp}_common and, instead of calling get_date(), reusing inside classes Time(), Date(), Datetime() and their methods to_longlong(). sql_mode_for_dates(thd) is automatically passed to get_date() inside Date() and Datetime() constructors. The switch to classes also fixed the problem reported in MDEV-17330. Type_handler_temporal_result::Item_func_min_max_val_int() used to call TIME_to_ulonglong(), which was not correct for TIME. Changing the code to use Time().to_longlong() solved this. 2. Type_handler_temporal_result::Item_func_min_max_get_date also did not take into account the current session date flags in case of conversion from DATE/DATETIME to time and passed date_mode_t(0) to get_date_native(). Fixing to pass sql_mode_for_dates(thd) in case of conversion from DATE/DATETIME to TIME.
This commit is contained in:
@ -3873,5 +3873,75 @@ t1 CREATE TABLE `t1` (
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SET sql_mode=DEFAULT;
|
SET sql_mode=DEFAULT;
|
||||||
#
|
#
|
||||||
|
# MDEV-17318 CAST(LEAST(zero_date,non_zero_date) AS numeric_data_type) returns a wrong result
|
||||||
|
#
|
||||||
|
SET sql_mode='NO_ZERO_DATE,NO_ZERO_IN_DATE';
|
||||||
|
SELECT
|
||||||
|
LEAST('0000-00-00',DATE'2001-01-01') AS c0,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS CHAR) AS string,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DATE) AS date,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DATETIME) AS datetime,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS TIME) AS time,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DECIMAL) AS dc,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DOUBLE) AS dbl,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS SIGNED) AS sint,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS UNSIGNED) AS uint;
|
||||||
|
c0 string date datetime time dc dbl sint uint
|
||||||
|
NULL NULL NULL NULL NULL NULL NULL NULL NULL
|
||||||
|
Warnings:
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
CREATE TABLE t1 AS SELECT
|
||||||
|
LEAST('0000-00-00',DATE'2001-01-01') AS c0,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS CHAR) AS string,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DATE) AS date,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DATETIME) AS datetime,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS TIME) AS time,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DECIMAL) AS dc,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DOUBLE) AS dbl,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS SIGNED) AS sint,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS UNSIGNED) AS uint;
|
||||||
|
Warnings:
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
Warning 1292 Incorrect datetime value: '0000-00-00'
|
||||||
|
SELECT * FROM t1;
|
||||||
|
c0 string date datetime time dc dbl sint uint
|
||||||
|
NULL NULL NULL NULL NULL NULL NULL NULL NULL
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`c0` date DEFAULT NULL,
|
||||||
|
`string` varchar(10) DEFAULT NULL,
|
||||||
|
`date` date DEFAULT NULL,
|
||||||
|
`datetime` datetime DEFAULT NULL,
|
||||||
|
`time` time DEFAULT NULL,
|
||||||
|
`dc` decimal(10,0) DEFAULT NULL,
|
||||||
|
`dbl` double DEFAULT NULL,
|
||||||
|
`sint` bigint(10) DEFAULT NULL,
|
||||||
|
`uint` bigint(20) unsigned DEFAULT NULL
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET sql_mode=DEFAULT;
|
||||||
|
#
|
||||||
|
# MDEV-17330 Wrong result for 0 + LEAST(TIME'-10:00:00',TIME'10:00:00')
|
||||||
|
#
|
||||||
|
SELECT 0 + LEAST(TIME'-10:00:00',TIME'10:00:00') AS c;
|
||||||
|
c
|
||||||
|
-100000
|
||||||
|
#
|
||||||
# End of 10.4 tests
|
# End of 10.4 tests
|
||||||
#
|
#
|
||||||
|
@ -682,6 +682,40 @@ SHOW CREATE TABLE t1;
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SET sql_mode=DEFAULT;
|
SET sql_mode=DEFAULT;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-17318 CAST(LEAST(zero_date,non_zero_date) AS numeric_data_type) returns a wrong result
|
||||||
|
--echo #
|
||||||
|
SET sql_mode='NO_ZERO_DATE,NO_ZERO_IN_DATE';
|
||||||
|
SELECT
|
||||||
|
LEAST('0000-00-00',DATE'2001-01-01') AS c0,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS CHAR) AS string,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DATE) AS date,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DATETIME) AS datetime,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS TIME) AS time,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DECIMAL) AS dc,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DOUBLE) AS dbl,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS SIGNED) AS sint,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS UNSIGNED) AS uint;
|
||||||
|
CREATE TABLE t1 AS SELECT
|
||||||
|
LEAST('0000-00-00',DATE'2001-01-01') AS c0,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS CHAR) AS string,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DATE) AS date,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DATETIME) AS datetime,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS TIME) AS time,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DECIMAL) AS dc,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS DOUBLE) AS dbl,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS SIGNED) AS sint,
|
||||||
|
CAST(LEAST('0000-00-00',DATE'2001-01-01') AS UNSIGNED) AS uint;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET sql_mode=DEFAULT;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-17330 Wrong result for 0 + LEAST(TIME'-10:00:00',TIME'10:00:00')
|
||||||
|
--echo #
|
||||||
|
SELECT 0 + LEAST(TIME'-10:00:00',TIME'10:00:00') AS c;
|
||||||
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.4 tests
|
--echo # End of 10.4 tests
|
||||||
|
100
sql/sql_type.cc
100
sql/sql_type.cc
@ -4639,13 +4639,30 @@ double Type_handler_string_result::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double Type_handler_temporal_result::
|
double Type_handler_time_common::
|
||||||
Item_func_min_max_val_real(Item_func_min_max *func) const
|
Item_func_min_max_val_real(Item_func_min_max *func) const
|
||||||
{
|
{
|
||||||
MYSQL_TIME ltime;
|
return Time(current_thd, func).to_double();
|
||||||
if (func->get_date(current_thd, <ime, date_mode_t(0)))
|
}
|
||||||
return 0;
|
|
||||||
return TIME_to_double(<ime);
|
|
||||||
|
double Type_handler_date_common::
|
||||||
|
Item_func_min_max_val_real(Item_func_min_max *func) const
|
||||||
|
{
|
||||||
|
return Date(current_thd, func).to_double();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double Type_handler_datetime_common::
|
||||||
|
Item_func_min_max_val_real(Item_func_min_max *func) const
|
||||||
|
{
|
||||||
|
return Datetime(current_thd, func).to_double();
|
||||||
|
}
|
||||||
|
|
||||||
|
double Type_handler_timestamp_common::
|
||||||
|
Item_func_min_max_val_real(Item_func_min_max *func) const
|
||||||
|
{
|
||||||
|
return Datetime(current_thd, func).to_double();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4663,13 +4680,31 @@ longlong Type_handler_string_result::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
longlong Type_handler_temporal_result::
|
longlong Type_handler_time_common::
|
||||||
Item_func_min_max_val_int(Item_func_min_max *func) const
|
Item_func_min_max_val_int(Item_func_min_max *func) const
|
||||||
{
|
{
|
||||||
MYSQL_TIME ltime;
|
return Time(current_thd, func).to_longlong();
|
||||||
if (func->get_date(current_thd, <ime, date_mode_t(0)))
|
}
|
||||||
return 0;
|
|
||||||
return TIME_to_ulonglong(<ime);
|
|
||||||
|
longlong Type_handler_date_common::
|
||||||
|
Item_func_min_max_val_int(Item_func_min_max *func) const
|
||||||
|
{
|
||||||
|
return Date(current_thd, func).to_longlong();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
longlong Type_handler_datetime_common::
|
||||||
|
Item_func_min_max_val_int(Item_func_min_max *func) const
|
||||||
|
{
|
||||||
|
return Datetime(current_thd, func).to_longlong();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
longlong Type_handler_timestamp_common::
|
||||||
|
Item_func_min_max_val_int(Item_func_min_max *func) const
|
||||||
|
{
|
||||||
|
return Datetime(current_thd, func).to_longlong();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4696,14 +4731,35 @@ my_decimal *Type_handler_numeric::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
my_decimal *Type_handler_temporal_result::
|
my_decimal *Type_handler_time_common::
|
||||||
Item_func_min_max_val_decimal(Item_func_min_max *func,
|
Item_func_min_max_val_decimal(Item_func_min_max *func,
|
||||||
my_decimal *dec) const
|
my_decimal *dec) const
|
||||||
{
|
{
|
||||||
MYSQL_TIME ltime;
|
return Time(current_thd, func).to_decimal(dec);
|
||||||
if (func->get_date(current_thd, <ime, date_mode_t(0)))
|
}
|
||||||
return 0;
|
|
||||||
return date2my_decimal(<ime, dec);
|
|
||||||
|
my_decimal *Type_handler_date_common::
|
||||||
|
Item_func_min_max_val_decimal(Item_func_min_max *func,
|
||||||
|
my_decimal *dec) const
|
||||||
|
{
|
||||||
|
return Date(current_thd, func).to_decimal(dec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my_decimal *Type_handler_datetime_common::
|
||||||
|
Item_func_min_max_val_decimal(Item_func_min_max *func,
|
||||||
|
my_decimal *dec) const
|
||||||
|
{
|
||||||
|
return Datetime(current_thd, func).to_decimal(dec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my_decimal *Type_handler_timestamp_common::
|
||||||
|
Item_func_min_max_val_decimal(Item_func_min_max *func,
|
||||||
|
my_decimal *dec) const
|
||||||
|
{
|
||||||
|
return Datetime(current_thd, func).to_decimal(dec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4733,7 +4789,19 @@ bool Type_handler_temporal_result::
|
|||||||
Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
|
Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
|
||||||
MYSQL_TIME *ltime, date_mode_t fuzzydate) const
|
MYSQL_TIME *ltime, date_mode_t fuzzydate) const
|
||||||
{
|
{
|
||||||
return func->get_date_native(thd, ltime, fuzzydate);
|
/*
|
||||||
|
- If the caller specified TIME_TIME_ONLY, then it's going to convert
|
||||||
|
a DATETIME or DATE to TIME. So we pass the default flags for date. This is
|
||||||
|
exactly the same with what Item_func_min_max_val_{int|real|decimal|str} or
|
||||||
|
Item_send_datetime() do. We return the value in accordance with the
|
||||||
|
current session date flags and let the caller further convert it to TIME.
|
||||||
|
- If the caller did not specify TIME_TIME_ONLY, then return the value
|
||||||
|
according to the flags supplied by the caller.
|
||||||
|
*/
|
||||||
|
return func->get_date_native(thd, ltime,
|
||||||
|
fuzzydate & TIME_TIME_ONLY ?
|
||||||
|
sql_mode_for_dates(thd) :
|
||||||
|
fuzzydate);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Type_handler_time_common::
|
bool Type_handler_time_common::
|
||||||
|
@ -3308,10 +3308,6 @@ public:
|
|||||||
Item_func_hybrid_field_type *,
|
Item_func_hybrid_field_type *,
|
||||||
MYSQL_TIME *,
|
MYSQL_TIME *,
|
||||||
date_mode_t fuzzydate) const;
|
date_mode_t fuzzydate) const;
|
||||||
double Item_func_min_max_val_real(Item_func_min_max *) const;
|
|
||||||
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
|
|
||||||
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
|
|
||||||
my_decimal *) const;
|
|
||||||
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
|
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
|
||||||
MYSQL_TIME *, date_mode_t fuzzydate) const;
|
MYSQL_TIME *, date_mode_t fuzzydate) const;
|
||||||
bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
|
bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
|
||||||
@ -3939,6 +3935,10 @@ public:
|
|||||||
MYSQL_TIME *,
|
MYSQL_TIME *,
|
||||||
date_mode_t fuzzydate) const;
|
date_mode_t fuzzydate) const;
|
||||||
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
|
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
|
||||||
|
double Item_func_min_max_val_real(Item_func_min_max *) const;
|
||||||
|
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
|
||||||
|
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
|
||||||
|
my_decimal *) const;
|
||||||
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
|
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
|
||||||
MYSQL_TIME *, date_mode_t fuzzydate) const;
|
MYSQL_TIME *, date_mode_t fuzzydate) const;
|
||||||
longlong Item_func_between_val_int(Item_func_between *func) const;
|
longlong Item_func_between_val_int(Item_func_between *func) const;
|
||||||
@ -4056,6 +4056,10 @@ public:
|
|||||||
String *print_item_value(THD *thd, Item *item, String *str) const;
|
String *print_item_value(THD *thd, Item *item, String *str) const;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||||
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
|
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
|
||||||
|
double Item_func_min_max_val_real(Item_func_min_max *) const;
|
||||||
|
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
|
||||||
|
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
|
||||||
|
my_decimal *) const;
|
||||||
bool Item_hybrid_func_fix_attributes(THD *thd,
|
bool Item_hybrid_func_fix_attributes(THD *thd,
|
||||||
const char *name,
|
const char *name,
|
||||||
Type_handler_hybrid_field_type *,
|
Type_handler_hybrid_field_type *,
|
||||||
@ -4152,6 +4156,10 @@ public:
|
|||||||
String *print_item_value(THD *thd, Item *item, String *str) const;
|
String *print_item_value(THD *thd, Item *item, String *str) const;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||||
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
|
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
|
||||||
|
double Item_func_min_max_val_real(Item_func_min_max *) const;
|
||||||
|
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
|
||||||
|
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
|
||||||
|
my_decimal *) const;
|
||||||
bool Item_hybrid_func_fix_attributes(THD *thd,
|
bool Item_hybrid_func_fix_attributes(THD *thd,
|
||||||
const char *name,
|
const char *name,
|
||||||
Type_handler_hybrid_field_type *,
|
Type_handler_hybrid_field_type *,
|
||||||
@ -4252,6 +4260,10 @@ public:
|
|||||||
String *print_item_value(THD *thd, Item *item, String *str) const;
|
String *print_item_value(THD *thd, Item *item, String *str) const;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
|
||||||
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
|
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
|
||||||
|
double Item_func_min_max_val_real(Item_func_min_max *) const;
|
||||||
|
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
|
||||||
|
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
|
||||||
|
my_decimal *) const;
|
||||||
bool Item_hybrid_func_fix_attributes(THD *thd,
|
bool Item_hybrid_func_fix_attributes(THD *thd,
|
||||||
const char *name,
|
const char *name,
|
||||||
Type_handler_hybrid_field_type *,
|
Type_handler_hybrid_field_type *,
|
||||||
|
Reference in New Issue
Block a user