mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +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:
50
sql/field.cc
50
sql/field.cc
@ -5655,30 +5655,28 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd,
|
||||
const_item->field_type() != MYSQL_TYPE_TIMESTAMP) ||
|
||||
const_item->decimals != decimals())
|
||||
{
|
||||
MYSQL_TIME ltime;
|
||||
if (const_item->field_type() == MYSQL_TYPE_TIME ?
|
||||
const_item->get_date_with_conversion(<ime, 0) :
|
||||
const_item->get_date(<ime, 0))
|
||||
Datetime dt(thd, const_item, 0);
|
||||
if (!dt.is_valid_datetime())
|
||||
return NULL;
|
||||
/*
|
||||
See comments about truncation in the same place in
|
||||
Field_time::get_equal_const_item().
|
||||
*/
|
||||
return new (thd->mem_root) Item_datetime_literal(thd, <ime,
|
||||
return new (thd->mem_root) Item_datetime_literal(thd,
|
||||
dt.get_mysql_time(),
|
||||
decimals());
|
||||
}
|
||||
break;
|
||||
case ANY_SUBST:
|
||||
if (!is_temporal_type_with_date(const_item->field_type()))
|
||||
{
|
||||
MYSQL_TIME ltime;
|
||||
if (const_item->get_date_with_conversion(<ime,
|
||||
TIME_FUZZY_DATES |
|
||||
TIME_INVALID_DATES))
|
||||
Datetime dt(thd, const_item, TIME_FUZZY_DATES | TIME_INVALID_DATES);
|
||||
if (!dt.is_valid_datetime())
|
||||
return NULL;
|
||||
return new (thd->mem_root)
|
||||
Item_datetime_literal_for_invalid_dates(thd, <ime,
|
||||
ltime.second_part ?
|
||||
Item_datetime_literal_for_invalid_dates(thd, dt.get_mysql_time(),
|
||||
dt.get_mysql_time()->
|
||||
second_part ?
|
||||
TIME_SECOND_PART_DIGITS : 0);
|
||||
}
|
||||
break;
|
||||
@ -6030,10 +6028,8 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx,
|
||||
{
|
||||
MYSQL_TIME ltime;
|
||||
// Get the value of const_item with conversion from DATETIME to TIME
|
||||
if (const_item->get_time_with_conversion(thd, <ime,
|
||||
TIME_TIME_ONLY |
|
||||
TIME_FUZZY_DATES |
|
||||
TIME_INVALID_DATES))
|
||||
ulonglong fuzzydate= Time::comparison_flags_for_get_date();
|
||||
if (const_item->get_time_with_conversion(thd, <ime, fuzzydate))
|
||||
return NULL;
|
||||
/*
|
||||
Replace a DATE/DATETIME constant to a TIME constant:
|
||||
@ -6506,10 +6502,9 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx,
|
||||
case ANY_SUBST:
|
||||
if (!is_temporal_type_with_date(const_item->field_type()))
|
||||
{
|
||||
MYSQL_TIME ltime;
|
||||
// Get the value of const_item with conversion from TIME to DATETIME
|
||||
if (const_item->get_date_with_conversion(<ime,
|
||||
TIME_FUZZY_DATES | TIME_INVALID_DATES))
|
||||
Datetime dt(thd, const_item, TIME_FUZZY_DATES | TIME_INVALID_DATES);
|
||||
if (!dt.is_valid_datetime())
|
||||
return NULL;
|
||||
/*
|
||||
Replace the constant to a DATE or DATETIME constant.
|
||||
@ -6522,26 +6517,23 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx,
|
||||
|
||||
(assuming CURRENT_DATE is '2015-08-30'
|
||||
*/
|
||||
if (non_zero_hhmmssuu(<ime))
|
||||
if (!dt.hhmmssff_is_zero())
|
||||
return new (thd->mem_root)
|
||||
Item_datetime_literal_for_invalid_dates(thd, <ime,
|
||||
ltime.second_part ?
|
||||
Item_datetime_literal_for_invalid_dates(thd, dt.get_mysql_time(),
|
||||
dt.get_mysql_time()->
|
||||
second_part ?
|
||||
TIME_SECOND_PART_DIGITS : 0);
|
||||
datetime_to_date(<ime);
|
||||
return new (thd->mem_root)
|
||||
Item_date_literal_for_invalid_dates(thd, <ime);
|
||||
Item_date_literal_for_invalid_dates(thd, Date(&dt).get_mysql_time());
|
||||
}
|
||||
break;
|
||||
case IDENTITY_SUBST:
|
||||
if (const_item->field_type() != MYSQL_TYPE_DATE)
|
||||
{
|
||||
MYSQL_TIME ltime;
|
||||
if (const_item->field_type() == MYSQL_TYPE_TIME ?
|
||||
const_item->get_date_with_conversion(<ime, 0) :
|
||||
const_item->get_date(<ime, 0))
|
||||
Date d(thd, const_item, 0);
|
||||
if (!d.is_valid_date())
|
||||
return NULL;
|
||||
datetime_to_date(<ime);
|
||||
return new (thd->mem_root) Item_date_literal(thd, <ime);
|
||||
return new (thd->mem_root) Item_date_literal(thd, d.get_mysql_time());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user