mirror of
https://github.com/MariaDB/server.git
synced 2025-07-16 00:42:55 +03:00
MDEV-16852 Get rid of Item_temporal_hybrid_func::fix_temporal_type()
- Implementing the task according to the MDEV description. - Adding a helper class Sec6_add to share the code in type-specific branches in Item_func_add_time::get_date().
This commit is contained in:
@ -1230,7 +1230,7 @@ str_to_date("1997-00-04 22:23:00","%Y-%m-%D") + interval 10 minute
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1292 Truncated incorrect date value: '1997-00-04 22:23:00'
|
||||
Warning 1292 Incorrect datetime value: '1997-00-04'
|
||||
Warning 1292 Incorrect datetime value: '1997-00-04 00:00:00'
|
||||
create table t1 (field DATE);
|
||||
insert into t1 values ('2006-11-06');
|
||||
select * from t1 where field < '2006-11-06 04:08:36.0';
|
||||
|
@ -1482,67 +1482,12 @@ String *Item_temporal_func::val_str(String *str)
|
||||
}
|
||||
|
||||
|
||||
bool Item_temporal_hybrid_func::fix_temporal_type(MYSQL_TIME *ltime)
|
||||
{
|
||||
if (ltime->time_type < 0) /* MYSQL_TIMESTAMP_NONE, MYSQL_TIMESTAMP_ERROR */
|
||||
return false;
|
||||
|
||||
if (ltime->time_type != MYSQL_TIMESTAMP_TIME)
|
||||
goto date_or_datetime_value;
|
||||
|
||||
/* Convert TIME to DATE or DATETIME */
|
||||
switch (field_type())
|
||||
{
|
||||
case MYSQL_TYPE_DATE:
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
{
|
||||
MYSQL_TIME tmp;
|
||||
if (time_to_datetime_with_warn(current_thd, ltime, &tmp, 0))
|
||||
return (null_value= true);
|
||||
*ltime= tmp;
|
||||
if (field_type() == MYSQL_TYPE_DATE)
|
||||
datetime_to_date(ltime);
|
||||
return false;
|
||||
}
|
||||
case MYSQL_TYPE_TIME:
|
||||
case MYSQL_TYPE_STRING: /* DATE_ADD, ADDTIME can return VARCHAR */
|
||||
return false;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
return (null_value= true);
|
||||
}
|
||||
|
||||
date_or_datetime_value:
|
||||
/* Convert DATE or DATETIME to TIME, DATE, or DATETIME */
|
||||
switch (field_type())
|
||||
{
|
||||
case MYSQL_TYPE_TIME:
|
||||
datetime_to_time(ltime);
|
||||
return false;
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
date_to_datetime(ltime);
|
||||
return false;
|
||||
case MYSQL_TYPE_DATE:
|
||||
datetime_to_date(ltime);
|
||||
return false;
|
||||
case MYSQL_TYPE_STRING: /* DATE_ADD, ADDTIME can return VARCHAR */
|
||||
return false;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
return (null_value= true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
String *Item_temporal_hybrid_func::val_str_ascii(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
MYSQL_TIME ltime;
|
||||
|
||||
if (get_date(<ime, 0) || fix_temporal_type(<ime) ||
|
||||
if (get_date(<ime, 0) ||
|
||||
(null_value= my_TIME_to_str(<ime, str, decimals)))
|
||||
return (String *) 0;
|
||||
|
||||
@ -2201,11 +2146,45 @@ bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
|
||||
{
|
||||
INTERVAL interval;
|
||||
|
||||
if (args[0]->get_date(ltime,
|
||||
field_type() == MYSQL_TYPE_TIME ?
|
||||
TIME_TIME_ONLY : 0) ||
|
||||
get_interval_value(args[1], int_type, &interval))
|
||||
return (null_value=1);
|
||||
if (field_type() == MYSQL_TYPE_TIME)
|
||||
{
|
||||
Time t(args[0]);
|
||||
if (!t.is_valid_time())
|
||||
return (null_value= true);
|
||||
t.copy_to_mysql_time(ltime);
|
||||
}
|
||||
else if (field_type() == MYSQL_TYPE_DATETIME)
|
||||
{
|
||||
THD *thd= current_thd;
|
||||
if (args[0]->field_type() == MYSQL_TYPE_TIME)
|
||||
{
|
||||
// time_expr + INTERVAL {YEAR|QUARTER|MONTH|WEEK|YEAR_MONTH}
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_DATETIME_FUNCTION_OVERFLOW,
|
||||
ER_THD(thd, ER_DATETIME_FUNCTION_OVERFLOW),
|
||||
"time");
|
||||
return (null_value= true);
|
||||
}
|
||||
Datetime dt(thd, args[0], 0);
|
||||
if (!dt.is_valid_datetime())
|
||||
return (null_value= true);
|
||||
dt.copy_to_mysql_time(ltime);
|
||||
}
|
||||
else if (field_type() == MYSQL_TYPE_DATE)
|
||||
{
|
||||
Date d(current_thd, args[0], 0);
|
||||
if (!d.is_valid_date())
|
||||
return (null_value= true);
|
||||
d.copy_to_mysql_time(ltime);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args[0]->get_date(ltime, 0))
|
||||
return (null_value=true);
|
||||
}
|
||||
|
||||
if (get_interval_value(args[1], int_type, &interval))
|
||||
return (null_value= true);
|
||||
|
||||
if (ltime->time_type != MYSQL_TIMESTAMP_TIME &&
|
||||
check_date_with_warn(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE,
|
||||
@ -2756,64 +2735,35 @@ bool Item_func_add_time::fix_length_and_dec()
|
||||
bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
MYSQL_TIME l_time1, l_time2;
|
||||
bool is_time= 0;
|
||||
long days, microseconds;
|
||||
longlong seconds;
|
||||
int l_sign= sign;
|
||||
MYSQL_TIME l_time2;
|
||||
|
||||
if (Item_func_add_time::field_type() == MYSQL_TYPE_DATETIME)
|
||||
{
|
||||
// TIMESTAMP function OR the first argument is DATE/DATETIME/TIMESTAMP
|
||||
if (get_arg0_date(&l_time1, 0) ||
|
||||
args[1]->get_time(&l_time2) ||
|
||||
l_time1.time_type == MYSQL_TIMESTAMP_TIME ||
|
||||
l_time2.time_type != MYSQL_TIMESTAMP_TIME)
|
||||
return (null_value= 1);
|
||||
Datetime dt(current_thd, args[0], 0);
|
||||
return (null_value= (!dt.is_valid_datetime() ||
|
||||
args[1]->get_time(&l_time2) ||
|
||||
Sec6_add(dt.get_mysql_time(), &l_time2, sign).
|
||||
to_datetime(ltime)));
|
||||
}
|
||||
else
|
||||
|
||||
if (Item_func_add_time::field_type() == MYSQL_TYPE_TIME)
|
||||
{
|
||||
// ADDTIME function AND the first argument is TIME
|
||||
if (args[0]->get_time(&l_time1) ||
|
||||
args[1]->get_time(&l_time2) ||
|
||||
l_time2.time_type != MYSQL_TIMESTAMP_TIME)
|
||||
return (null_value= 1);
|
||||
is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME);
|
||||
// ADDTIME() and the first argument is TIME
|
||||
Time t(args[0]);
|
||||
return (null_value= (!t.is_valid_time() ||
|
||||
args[1]->get_time(&l_time2) ||
|
||||
Sec6_add(t.get_mysql_time(), &l_time2, sign).
|
||||
to_time(ltime, decimals)));
|
||||
}
|
||||
if (l_time1.neg != l_time2.neg)
|
||||
l_sign= -l_sign;
|
||||
|
||||
bzero(ltime, sizeof(*ltime));
|
||||
|
||||
ltime->neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
|
||||
&seconds, µseconds);
|
||||
|
||||
/*
|
||||
If first argument was negative and diff between arguments
|
||||
is non-zero we need to swap sign to get proper result.
|
||||
*/
|
||||
if (l_time1.neg && (seconds || microseconds))
|
||||
ltime->neg= 1-ltime->neg; // Swap sign of result
|
||||
|
||||
if (!is_time && ltime->neg)
|
||||
return (null_value= 1);
|
||||
|
||||
days= (long) (seconds / SECONDS_IN_24H);
|
||||
|
||||
calc_time_from_sec(ltime, (long)(seconds % SECONDS_IN_24H), microseconds);
|
||||
|
||||
ltime->time_type= is_time ? MYSQL_TIMESTAMP_TIME : MYSQL_TIMESTAMP_DATETIME;
|
||||
|
||||
if (!is_time)
|
||||
{
|
||||
if (get_date_from_daynr(days,<ime->year,<ime->month,<ime->day) ||
|
||||
!ltime->day)
|
||||
return (null_value= 1);
|
||||
return (null_value= 0);
|
||||
}
|
||||
|
||||
ltime->hour+= days*24;
|
||||
return (null_value= adjust_time_range_with_warn(ltime, decimals));
|
||||
// Detect a proper timestamp type based on the argument values
|
||||
MYSQL_TIME l_time1;
|
||||
if (args[0]->get_time(&l_time1) || args[1]->get_time(&l_time2))
|
||||
return (null_value= true);
|
||||
Sec6_add add(&l_time1, &l_time2, sign);
|
||||
return (null_value= (l_time1.time_type == MYSQL_TIMESTAMP_TIME ?
|
||||
add.to_time(ltime, decimals) : add.to_datetime(ltime)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -620,11 +620,6 @@ public:
|
||||
my_decimal *val_decimal(my_decimal *decimal_value)
|
||||
{ return val_decimal_from_date(decimal_value); }
|
||||
|
||||
/**
|
||||
Fix the returned timestamp to match field_type(),
|
||||
which is important for val_str().
|
||||
*/
|
||||
bool fix_temporal_type(MYSQL_TIME *ltime);
|
||||
/**
|
||||
Return string value in ASCII character set.
|
||||
*/
|
||||
|
@ -89,6 +89,65 @@ enum scalar_comparison_op
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
A heler class to perform additive operations between
|
||||
two MYSQL_TIME structures and return the result as a
|
||||
combination of seconds, microseconds and sign.
|
||||
*/
|
||||
class Sec6_add
|
||||
{
|
||||
longlong m_sec; // number of seconds
|
||||
long m_usec; // number of microseconds
|
||||
bool m_neg; // false if positive, true if negative
|
||||
bool m_error; // false if the value is OK, true otherwise
|
||||
void to_hh24mmssff(MYSQL_TIME *ltime, timestamp_type tstype) const
|
||||
{
|
||||
bzero(ltime, sizeof(*ltime));
|
||||
ltime->neg= m_neg;
|
||||
calc_time_from_sec(ltime, (long) (m_sec % SECONDS_IN_24H), m_usec);
|
||||
ltime->time_type= tstype;
|
||||
}
|
||||
public:
|
||||
/*
|
||||
@param ltime1 - the first value to add (must be a valid DATE,TIME,DATETIME)
|
||||
@param ltime2 - the second value to add (must be a valid TIME)
|
||||
@param sign - the sign of the operation
|
||||
(+1 for addition, -1 for subtraction)
|
||||
*/
|
||||
Sec6_add(const MYSQL_TIME *ltime1, const MYSQL_TIME *ltime2, int sign)
|
||||
{
|
||||
DBUG_ASSERT(sign == -1 || sign == 1);
|
||||
DBUG_ASSERT(!ltime1->neg || ltime1->time_type == MYSQL_TIMESTAMP_TIME);
|
||||
if (!(m_error= (ltime2->time_type != MYSQL_TIMESTAMP_TIME)))
|
||||
{
|
||||
if (ltime1->neg != ltime2->neg)
|
||||
sign= -sign;
|
||||
m_neg= calc_time_diff(ltime1, ltime2, -sign, &m_sec, &m_usec);
|
||||
if (ltime1->neg && (m_sec || m_usec))
|
||||
m_neg= !m_neg; // Swap sign
|
||||
}
|
||||
}
|
||||
bool to_time(MYSQL_TIME *ltime, uint decimals) const
|
||||
{
|
||||
if (m_error)
|
||||
return true;
|
||||
to_hh24mmssff(ltime, MYSQL_TIMESTAMP_TIME);
|
||||
ltime->hour+= to_days_abs() * 24;
|
||||
return adjust_time_range_with_warn(ltime, decimals);
|
||||
}
|
||||
bool to_datetime(MYSQL_TIME *ltime) const
|
||||
{
|
||||
if (m_error || m_neg)
|
||||
return true;
|
||||
to_hh24mmssff(ltime, MYSQL_TIMESTAMP_DATETIME);
|
||||
return get_date_from_daynr(to_days_abs(),
|
||||
<ime->year, <ime->month, <ime->day) ||
|
||||
!ltime->day;
|
||||
}
|
||||
long to_days_abs() const { return (long) (m_sec / SECONDS_IN_24H); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Class Time is designed to store valid TIME values.
|
||||
|
||||
@ -355,6 +414,17 @@ public:
|
||||
DBUG_ASSERT(is_valid_date_slow());
|
||||
return this;
|
||||
}
|
||||
bool copy_to_mysql_time(MYSQL_TIME *ltime) const
|
||||
{
|
||||
if (time_type == MYSQL_TIMESTAMP_NONE)
|
||||
{
|
||||
ltime->time_type= MYSQL_TIMESTAMP_NONE;
|
||||
return true;
|
||||
}
|
||||
DBUG_ASSERT(is_valid_date_slow());
|
||||
*ltime= *this;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user