mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +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:
@@ -160,14 +160,17 @@ public:
|
||||
void print_args(String *str, uint from, enum_query_type query_type);
|
||||
inline bool get_arg0_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
|
||||
{
|
||||
return (null_value=args[0]->get_date_with_conversion(ltime, fuzzy_date));
|
||||
return fuzzy_date & TIME_TIME_ONLY ? get_arg0_time(ltime) :
|
||||
get_arg0_datetime(ltime, fuzzy_date);
|
||||
}
|
||||
inline bool get_arg0_datetime(MYSQL_TIME *ltime, ulonglong fuzzy_date)
|
||||
{
|
||||
Datetime dt(current_thd, args[0], fuzzy_date);
|
||||
return (null_value= dt.copy_to_mysql_time(ltime));
|
||||
}
|
||||
inline bool get_arg0_time(MYSQL_TIME *ltime)
|
||||
{
|
||||
null_value= args[0]->get_time(ltime);
|
||||
DBUG_ASSERT(null_value ||
|
||||
ltime->time_type != MYSQL_TIMESTAMP_TIME || ltime->day == 0);
|
||||
return null_value;
|
||||
return (null_value= Time(args[0]).copy_to_mysql_time(ltime));
|
||||
}
|
||||
bool is_null() {
|
||||
update_null_value();
|
||||
@@ -447,11 +450,17 @@ class Item_func_hybrid_field_type: public Item_hybrid_func
|
||||
*/
|
||||
bool date_op_with_null_check(MYSQL_TIME *ltime)
|
||||
{
|
||||
bool rc= date_op(ltime,
|
||||
field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0);
|
||||
bool rc= date_op(ltime, 0);
|
||||
DBUG_ASSERT(!rc ^ null_value);
|
||||
return rc;
|
||||
}
|
||||
bool time_op_with_null_check(MYSQL_TIME *ltime)
|
||||
{
|
||||
bool rc= time_op(ltime);
|
||||
DBUG_ASSERT(!rc ^ null_value);
|
||||
DBUG_ASSERT(rc || ltime->time_type == MYSQL_TIMESTAMP_TIME);
|
||||
return rc;
|
||||
}
|
||||
String *str_op_with_null_check(String *str)
|
||||
{
|
||||
String *res= str_op(str);
|
||||
@@ -488,32 +497,30 @@ public:
|
||||
{
|
||||
return real_op();
|
||||
}
|
||||
bool get_date_from_date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
|
||||
{
|
||||
return date_op(ltime,
|
||||
(fuzzydate |
|
||||
(field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0)));
|
||||
}
|
||||
|
||||
// Value methods that involve conversion
|
||||
String *val_str_from_decimal_op(String *str);
|
||||
String *val_str_from_real_op(String *str);
|
||||
String *val_str_from_int_op(String *str);
|
||||
String *val_str_from_date_op(String *str);
|
||||
String *val_str_from_time_op(String *str);
|
||||
|
||||
my_decimal *val_decimal_from_str_op(my_decimal *dec);
|
||||
my_decimal *val_decimal_from_real_op(my_decimal *dec);
|
||||
my_decimal *val_decimal_from_int_op(my_decimal *dec);
|
||||
my_decimal *val_decimal_from_date_op(my_decimal *dec);
|
||||
my_decimal *val_decimal_from_time_op(my_decimal *dec);
|
||||
|
||||
longlong val_int_from_str_op();
|
||||
longlong val_int_from_real_op();
|
||||
longlong val_int_from_decimal_op();
|
||||
longlong val_int_from_date_op();
|
||||
longlong val_int_from_time_op();
|
||||
|
||||
double val_real_from_str_op();
|
||||
double val_real_from_decimal_op();
|
||||
double val_real_from_date_op();
|
||||
double val_real_from_time_op();
|
||||
double val_real_from_int_op();
|
||||
|
||||
bool get_date_from_str_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
|
||||
@@ -609,11 +616,18 @@ public:
|
||||
|
||||
/**
|
||||
@brief Performs the operation that this functions implements when
|
||||
field type is a temporal type.
|
||||
field type is DATETIME or DATE.
|
||||
@return The result of the operation.
|
||||
*/
|
||||
virtual bool date_op(MYSQL_TIME *res, ulonglong fuzzy_date)= 0;
|
||||
|
||||
/**
|
||||
@brief Performs the operation that this functions implements when
|
||||
field type is TIME.
|
||||
@return The result of the operation.
|
||||
*/
|
||||
virtual bool time_op(MYSQL_TIME *res)= 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -676,6 +690,11 @@ public:
|
||||
DBUG_ASSERT(0);
|
||||
return true;
|
||||
}
|
||||
bool time_op(MYSQL_TIME *ltime)
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user