mirror of
https://github.com/MariaDB/server.git
synced 2025-10-28 17:15:19 +03:00
MDEV-15340 Wrong result HOUR(case_expression_with_time_and_datetime)
The problem was that Item_func_hybrid_field_type::get_date() did not
convert the result to the correct data type, so MYSQL_TIME::time_type
of the get_date() result could be not in sync with field_type().
Changes:
1. Adding two new classes Datetime and Date to store MYSQL_TIMESTAMP_DATETIME
and MYSQL_TIMESTAMP_DATE values respectively
(in addition to earlier added class Time, for MYSQL_TIMESTAMP_TIME values).
2. Adding Item_func_hybrid_field_type::time_op().
It performs the operation using TIME representation,
and always returns a MYSQL_TIME value with time_type=MYSQL_TIMESTAMP_TIME.
Implementing time_op() for all affected children classes.
3. Fixing all implementations of date_op() to perform the operation
using strictly DATETIME representation. Now they always return a MYSQL_TIME
value with time_type=MYSQL_TIMESTAMP_{DATE|DATETIME},
according to the result data type.
4. Removing assignment of ltime.time_type to mysql_timestamp_type()
from all val_xxx_from_date_op(), because now date_op() makes sure
to return a proper MYSQL_TIME value with a good time_type (and other member)
5. Adding Item_func_hybrid_field_type::val_xxx_from_time_op().
6. Overriding Type_handler_time_common::Item_func_hybrid_field_type_val_xxx()
to call val_xxx_from_time_op() instead of val_xxx_from_date_op().
7. Modified Item_func::get_arg0_date() to return strictly a TIME value
if TIME_TIME_ONLY is passed, or return strictly a DATETIME value otherwise.
If args[0] returned a value of a different temporal type,
(for example a TIME value when TIME_TIME_ONLY was not passed,
or a DATETIME value when TIME_TIME_ONLY was passed), the conversion
is automatically applied.
Earlier, get_arg0_date() did not guarantee a result in
accordance to TIME_TIME_ONLY flag.
This commit is contained in:
@@ -121,15 +121,41 @@ bool Type_handler_data::init()
|
||||
Type_handler_data *type_handler_data= NULL;
|
||||
|
||||
|
||||
void Time::make_from_item(Item *item)
|
||||
void Time::make_from_item(Item *item, sql_mode_t flags)
|
||||
{
|
||||
if (item->get_time(this))
|
||||
if (item->get_date(this, flags))
|
||||
time_type= MYSQL_TIMESTAMP_NONE;
|
||||
else
|
||||
valid_MYSQL_TIME_to_valid_value();
|
||||
}
|
||||
|
||||
|
||||
void Temporal_with_date::make_from_item(THD *thd, Item *item, sql_mode_t flags)
|
||||
{
|
||||
flags&= ~TIME_TIME_ONLY;
|
||||
/*
|
||||
Some TIME type items return error when trying to do get_date()
|
||||
without TIME_TIME_ONLY set (e.g. Item_field for Field_time).
|
||||
In the SQL standard time->datetime conversion mode we add TIME_TIME_ONLY.
|
||||
In the legacy time->datetime conversion mode we do not add TIME_TIME_ONLY
|
||||
and leave it to get_date() to check date.
|
||||
*/
|
||||
ulonglong time_flag= (item->field_type() == MYSQL_TYPE_TIME &&
|
||||
!(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST)) ?
|
||||
TIME_TIME_ONLY : 0;
|
||||
if (item->get_date(this, flags | time_flag))
|
||||
time_type= MYSQL_TIMESTAMP_NONE;
|
||||
else if (time_type == MYSQL_TIMESTAMP_TIME)
|
||||
{
|
||||
MYSQL_TIME tmp;
|
||||
if (time_to_datetime_with_warn(thd, this, &tmp, flags))
|
||||
time_type= MYSQL_TIMESTAMP_NONE;
|
||||
else
|
||||
*(static_cast<MYSQL_TIME*>(this))= tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Type_std_attributes::set(const Field *field)
|
||||
{
|
||||
decimals= field->decimals();
|
||||
@@ -3523,7 +3549,55 @@ Type_handler_temporal_result::Item_func_hybrid_field_type_get_date(
|
||||
MYSQL_TIME *ltime,
|
||||
ulonglong fuzzydate) const
|
||||
{
|
||||
return item->get_date_from_date_op(ltime, fuzzydate);
|
||||
return item->date_op(ltime, fuzzydate);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
String *
|
||||
Type_handler_time_common::Item_func_hybrid_field_type_val_str(
|
||||
Item_func_hybrid_field_type *item,
|
||||
String *str) const
|
||||
{
|
||||
return item->val_str_from_time_op(str);
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
Type_handler_time_common::Item_func_hybrid_field_type_val_real(
|
||||
Item_func_hybrid_field_type *item)
|
||||
const
|
||||
{
|
||||
return item->val_real_from_time_op();
|
||||
}
|
||||
|
||||
|
||||
longlong
|
||||
Type_handler_time_common::Item_func_hybrid_field_type_val_int(
|
||||
Item_func_hybrid_field_type *item)
|
||||
const
|
||||
{
|
||||
return item->val_int_from_time_op();
|
||||
}
|
||||
|
||||
|
||||
my_decimal *
|
||||
Type_handler_time_common::Item_func_hybrid_field_type_val_decimal(
|
||||
Item_func_hybrid_field_type *item,
|
||||
my_decimal *dec) const
|
||||
{
|
||||
return item->val_decimal_from_time_op(dec);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Type_handler_time_common::Item_func_hybrid_field_type_get_date(
|
||||
Item_func_hybrid_field_type *item,
|
||||
MYSQL_TIME *ltime,
|
||||
ulonglong fuzzydate) const
|
||||
{
|
||||
return item->time_op(ltime);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user