1
0
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:
Alexander Barkov
2018-02-19 23:41:01 +04:00
parent 5c3d0c6bad
commit aef530bb69
14 changed files with 527 additions and 119 deletions

View File

@ -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(&ltime, 0) :
const_item->get_date(&ltime, 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, &ltime,
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(&ltime,
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, &ltime,
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, &ltime,
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, &ltime, 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(&ltime,
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(&ltime))
if (!dt.hhmmssff_is_zero())
return new (thd->mem_root)
Item_datetime_literal_for_invalid_dates(thd, &ltime,
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(&ltime);
return new (thd->mem_root)
Item_date_literal_for_invalid_dates(thd, &ltime);
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(&ltime, 0) :
const_item->get_date(&ltime, 0))
Date d(thd, const_item, 0);
if (!d.is_valid_date())
return NULL;
datetime_to_date(&ltime);
return new (thd->mem_root) Item_date_literal(thd, &ltime);
return new (thd->mem_root) Item_date_literal(thd, d.get_mysql_time());
}
break;
}