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
|
NULL
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1292 Truncated incorrect date value: '1997-00-04 22:23:00'
|
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);
|
create table t1 (field DATE);
|
||||||
insert into t1 values ('2006-11-06');
|
insert into t1 values ('2006-11-06');
|
||||||
select * from t1 where field < '2006-11-06 04:08:36.0';
|
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)
|
String *Item_temporal_hybrid_func::val_str_ascii(String *str)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
MYSQL_TIME ltime;
|
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)))
|
(null_value= my_TIME_to_str(<ime, str, decimals)))
|
||||||
return (String *) 0;
|
return (String *) 0;
|
||||||
|
|
||||||
@ -2201,11 +2146,45 @@ bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
|
|||||||
{
|
{
|
||||||
INTERVAL interval;
|
INTERVAL interval;
|
||||||
|
|
||||||
if (args[0]->get_date(ltime,
|
if (field_type() == MYSQL_TYPE_TIME)
|
||||||
field_type() == MYSQL_TYPE_TIME ?
|
{
|
||||||
TIME_TIME_ONLY : 0) ||
|
Time t(args[0]);
|
||||||
get_interval_value(args[1], int_type, &interval))
|
if (!t.is_valid_time())
|
||||||
return (null_value=1);
|
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 &&
|
if (ltime->time_type != MYSQL_TIMESTAMP_TIME &&
|
||||||
check_date_with_warn(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE,
|
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)
|
bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
MYSQL_TIME l_time1, l_time2;
|
MYSQL_TIME l_time2;
|
||||||
bool is_time= 0;
|
|
||||||
long days, microseconds;
|
|
||||||
longlong seconds;
|
|
||||||
int l_sign= sign;
|
|
||||||
|
|
||||||
if (Item_func_add_time::field_type() == MYSQL_TYPE_DATETIME)
|
if (Item_func_add_time::field_type() == MYSQL_TYPE_DATETIME)
|
||||||
{
|
{
|
||||||
// TIMESTAMP function OR the first argument is DATE/DATETIME/TIMESTAMP
|
// TIMESTAMP function OR the first argument is DATE/DATETIME/TIMESTAMP
|
||||||
if (get_arg0_date(&l_time1, 0) ||
|
Datetime dt(current_thd, args[0], 0);
|
||||||
args[1]->get_time(&l_time2) ||
|
return (null_value= (!dt.is_valid_datetime() ||
|
||||||
l_time1.time_type == MYSQL_TIMESTAMP_TIME ||
|
args[1]->get_time(&l_time2) ||
|
||||||
l_time2.time_type != MYSQL_TIMESTAMP_TIME)
|
Sec6_add(dt.get_mysql_time(), &l_time2, sign).
|
||||||
return (null_value= 1);
|
to_datetime(ltime)));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (Item_func_add_time::field_type() == MYSQL_TYPE_TIME)
|
||||||
{
|
{
|
||||||
// ADDTIME function AND the first argument is TIME
|
// ADDTIME() and the first argument is TIME
|
||||||
if (args[0]->get_time(&l_time1) ||
|
Time t(args[0]);
|
||||||
args[1]->get_time(&l_time2) ||
|
return (null_value= (!t.is_valid_time() ||
|
||||||
l_time2.time_type != MYSQL_TIMESTAMP_TIME)
|
args[1]->get_time(&l_time2) ||
|
||||||
return (null_value= 1);
|
Sec6_add(t.get_mysql_time(), &l_time2, sign).
|
||||||
is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME);
|
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);
|
|
||||||
|
|
||||||
/*
|
// Detect a proper timestamp type based on the argument values
|
||||||
If first argument was negative and diff between arguments
|
MYSQL_TIME l_time1;
|
||||||
is non-zero we need to swap sign to get proper result.
|
if (args[0]->get_time(&l_time1) || args[1]->get_time(&l_time2))
|
||||||
*/
|
return (null_value= true);
|
||||||
if (l_time1.neg && (seconds || microseconds))
|
Sec6_add add(&l_time1, &l_time2, sign);
|
||||||
ltime->neg= 1-ltime->neg; // Swap sign of result
|
return (null_value= (l_time1.time_type == MYSQL_TIMESTAMP_TIME ?
|
||||||
|
add.to_time(ltime, decimals) : add.to_datetime(ltime)));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -620,11 +620,6 @@ public:
|
|||||||
my_decimal *val_decimal(my_decimal *decimal_value)
|
my_decimal *val_decimal(my_decimal *decimal_value)
|
||||||
{ return val_decimal_from_date(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.
|
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.
|
Class Time is designed to store valid TIME values.
|
||||||
|
|
||||||
@ -355,6 +414,17 @@ public:
|
|||||||
DBUG_ASSERT(is_valid_date_slow());
|
DBUG_ASSERT(is_valid_date_slow());
|
||||||
return this;
|
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