Commit d2bba4ce authored by Alexander Barkov's avatar Alexander Barkov

MDEV-16928 Move MYSQL_TIME initialization from Field_xxx::store_time_dec() to...

MDEV-16928 Move MYSQL_TIME initialization from Field_xxx::store_time_dec() to new constructors Time() and Datetime()
parent ffdae1a9
...@@ -5021,15 +5021,12 @@ my_time_t Field_timestamp::get_timestamp(const uchar *pos, ...@@ -5021,15 +5021,12 @@ my_time_t Field_timestamp::get_timestamp(const uchar *pos,
int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time,
const ErrConv *str, const ErrConv *str, int was_cut)
int was_cut,
bool have_smth_to_conv)
{ {
ASSERT_COLUMN_MARKED_FOR_WRITE; ASSERT_COLUMN_MARKED_FOR_WRITE;
uint error = 0; uint error = 0;
my_time_t timestamp;
if (MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) || !have_smth_to_conv) if (MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) || !l_time)
{ {
error= 1; error= 1;
set_datetime_warning(WARN_DATA_TRUNCATED, set_datetime_warning(WARN_DATA_TRUNCATED,
...@@ -5042,10 +5039,10 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, ...@@ -5042,10 +5039,10 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time,
str, MYSQL_TIMESTAMP_DATETIME, 1); str, MYSQL_TIMESTAMP_DATETIME, 1);
} }
/* Only convert a correct date (not a zero date) */ /* Only convert a correct date (not a zero date) */
if (have_smth_to_conv && l_time->month) if (l_time && l_time->month)
{ {
uint conversion_error; uint conversion_error;
timestamp= TIME_to_timestamp(thd, l_time, &conversion_error); my_time_t timestamp= TIME_to_timestamp(thd, l_time, &conversion_error);
if (timestamp == 0 && l_time->second_part == 0) if (timestamp == 0 && l_time->second_part == 0)
conversion_error= ER_WARN_DATA_OUT_OF_RANGE; conversion_error= ER_WARN_DATA_OUT_OF_RANGE;
if (unlikely(conversion_error)) if (unlikely(conversion_error))
...@@ -5054,27 +5051,16 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, ...@@ -5054,27 +5051,16 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time,
str, MYSQL_TIMESTAMP_DATETIME, !error); str, MYSQL_TIMESTAMP_DATETIME, !error);
error= 1; error= 1;
} }
store_TIME(timestamp, l_time->second_part);
} }
else else
{ {
timestamp= 0; store_TIME(0, 0);
l_time->second_part= 0;
} }
store_TIME(timestamp, l_time->second_part);
return error; return error;
} }
static bool
copy_or_convert_to_datetime(THD *thd, const MYSQL_TIME *from, MYSQL_TIME *to)
{
if (from->time_type == MYSQL_TIMESTAMP_TIME)
return time_to_datetime(thd, from, to);
*to= *from;
return false;
}
sql_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const sql_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const
{ {
// We don't want to store invalid or fuzzy datetime values in TIMESTAMP // We don't want to store invalid or fuzzy datetime values in TIMESTAMP
...@@ -5084,14 +5070,13 @@ sql_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const ...@@ -5084,14 +5070,13 @@ sql_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const
int Field_timestamp::store_time_dec(const MYSQL_TIME *ltime, uint dec) int Field_timestamp::store_time_dec(const MYSQL_TIME *ltime, uint dec)
{ {
int unused; int warn;
ErrConvTime str(ltime); ErrConvTime str(ltime);
THD *thd= get_thd(); THD *thd= get_thd();
MYSQL_TIME l_time; Datetime dt(thd, &warn, ltime, sql_mode_for_timestamp(thd));
bool valid= !copy_or_convert_to_datetime(thd, ltime, &l_time) && ltime= dt.is_valid_datetime() ? dt.get_mysql_time() : NULL;
!check_date(&l_time, pack_time(&l_time) != 0, return store_TIME_with_warning(thd, const_cast<MYSQL_TIME*>(ltime),
sql_mode_for_timestamp(thd), &unused); &str, warn);
return store_TIME_with_warning(thd, &l_time, &str, false, valid);
} }
...@@ -5099,14 +5084,12 @@ int Field_timestamp::store(const char *from,size_t len,CHARSET_INFO *cs) ...@@ -5099,14 +5084,12 @@ int Field_timestamp::store(const char *from,size_t len,CHARSET_INFO *cs)
{ {
MYSQL_TIME l_time; MYSQL_TIME l_time;
MYSQL_TIME_STATUS status; MYSQL_TIME_STATUS status;
bool have_smth_to_conv;
ErrConvString str(from, len, cs); ErrConvString str(from, len, cs);
THD *thd= get_thd(); THD *thd= get_thd();
bool rc= str_to_datetime(cs, from, len, &l_time,
have_smth_to_conv= !str_to_datetime(cs, from, len, &l_time, sql_mode_for_timestamp(thd), &status);
sql_mode_for_timestamp(thd), &status); return store_TIME_with_warning(thd, rc ? NULL : &l_time, &str,
return store_TIME_with_warning(thd, &l_time, &str, status.warnings);
status.warnings, have_smth_to_conv);
} }
...@@ -5117,7 +5100,7 @@ int Field_timestamp::store(double nr) ...@@ -5117,7 +5100,7 @@ int Field_timestamp::store(double nr)
ErrConvDouble str(nr); ErrConvDouble str(nr);
THD *thd= get_thd(); THD *thd= get_thd();
bool rc= Sec6(nr).to_datetime(&l_time, sql_mode_for_timestamp(thd), &error); bool rc= Sec6(nr).to_datetime(&l_time, sql_mode_for_timestamp(thd), &error);
return store_TIME_with_warning(thd, &l_time, &str, error, !rc); return store_TIME_with_warning(thd, rc ? NULL : &l_time, &str, error);
} }
...@@ -5130,7 +5113,7 @@ int Field_timestamp::store(longlong nr, bool unsigned_val) ...@@ -5130,7 +5113,7 @@ int Field_timestamp::store(longlong nr, bool unsigned_val)
bool rc= Sec6(nr, unsigned_val).to_datetime(&l_time, bool rc= Sec6(nr, unsigned_val).to_datetime(&l_time,
sql_mode_for_timestamp(thd), sql_mode_for_timestamp(thd),
&error); &error);
return store_TIME_with_warning(thd, &l_time, &str, error, !rc); return store_TIME_with_warning(thd, rc ? NULL : &l_time, &str, error);
} }
...@@ -5431,7 +5414,7 @@ int Field_timestamp::store_decimal(const my_decimal *d) ...@@ -5431,7 +5414,7 @@ int Field_timestamp::store_decimal(const my_decimal *d)
THD *thd= get_thd(); THD *thd= get_thd();
ErrConvDecimal str(d); ErrConvDecimal str(d);
bool rc= Sec6(d).to_datetime(&ltime, sql_mode_for_timestamp(thd), &error); bool rc= Sec6(d).to_datetime(&ltime, sql_mode_for_timestamp(thd), &error);
return store_TIME_with_warning(thd, &ltime, &str, error, !rc); return store_TIME_with_warning(thd, rc ? NULL : &ltime, &str, error);
} }
int Field_timestamp_with_dec::set_time() int Field_timestamp_with_dec::set_time()
...@@ -5557,22 +5540,23 @@ void Field_temporal::set_warnings(Sql_condition::enum_warning_level trunc_level, ...@@ -5557,22 +5540,23 @@ void Field_temporal::set_warnings(Sql_condition::enum_warning_level trunc_level,
*/ */
int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime, int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime,
const ErrConv *str, const ErrConv *str,
int was_cut, int was_cut)
int have_smth_to_conv)
{ {
Sql_condition::enum_warning_level trunc_level= Sql_condition::WARN_LEVEL_WARN; Sql_condition::enum_warning_level trunc_level= Sql_condition::WARN_LEVEL_WARN;
int ret= 2; int ret;
ASSERT_COLUMN_MARKED_FOR_WRITE; ASSERT_COLUMN_MARKED_FOR_WRITE;
if (was_cut == 0 && have_smth_to_conv == 0) // special case: zero date if (was_cut == 0 && !ltime) // special case: zero date
{ {
was_cut= MYSQL_TIME_WARN_OUT_OF_RANGE; was_cut= MYSQL_TIME_WARN_OUT_OF_RANGE;
store_TIME(const_cast<MYSQL_TIME*>(Datetime().get_mysql_time()));
ret= 2;
} }
else if (!have_smth_to_conv) else if (!ltime)
{ {
bzero(ltime, sizeof(*ltime));
was_cut= MYSQL_TIME_WARN_TRUNCATED; was_cut= MYSQL_TIME_WARN_TRUNCATED;
store_TIME(const_cast<MYSQL_TIME*>(Datetime().get_mysql_time()));
ret= 1; ret= 1;
} }
else if (!MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) && else if (!MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) &&
...@@ -5582,12 +5566,17 @@ int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime, ...@@ -5582,12 +5566,17 @@ int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime,
{ {
trunc_level= Sql_condition::WARN_LEVEL_NOTE; trunc_level= Sql_condition::WARN_LEVEL_NOTE;
was_cut|= MYSQL_TIME_WARN_TRUNCATED; was_cut|= MYSQL_TIME_WARN_TRUNCATED;
store_TIME(ltime);
ret= 3; ret= 3;
} }
else
{
store_TIME(ltime);
ret= was_cut ? 2 : 0;
}
set_warnings(trunc_level, str, was_cut, set_warnings(trunc_level, str, was_cut,
type_handler()->mysql_timestamp_type()); type_handler()->mysql_timestamp_type());
store_TIME(ltime); return ret;
return was_cut ? ret : 0;
} }
...@@ -5597,10 +5586,9 @@ int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO * ...@@ -5597,10 +5586,9 @@ int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *
MYSQL_TIME_STATUS status; MYSQL_TIME_STATUS status;
THD *thd= get_thd(); THD *thd= get_thd();
ErrConvString str(from, len, cs); ErrConvString str(from, len, cs);
bool func_res= !str_to_datetime(cs, from, len, &ltime, bool rc= str_to_datetime(cs, from, len, &ltime, sql_mode_for_dates(thd),
sql_mode_for_dates(thd), &status);
&status); return store_TIME_with_warning(rc ? NULL : &ltime, &str, status.warnings);
return store_TIME_with_warning(&ltime, &str, status.warnings, func_res);
} }
...@@ -5611,7 +5599,7 @@ int Field_temporal_with_date::store(double nr) ...@@ -5611,7 +5599,7 @@ int Field_temporal_with_date::store(double nr)
THD *thd= get_thd(); THD *thd= get_thd();
ErrConvDouble str(nr); ErrConvDouble str(nr);
bool rc= Sec6(nr).to_datetime(&ltime, sql_mode_for_dates(thd), &error); bool rc= Sec6(nr).to_datetime(&ltime, sql_mode_for_dates(thd), &error);
return store_TIME_with_warning(&ltime, &str, error, !rc); return store_TIME_with_warning(rc ? NULL : &ltime, &str, error);
} }
...@@ -5623,35 +5611,18 @@ int Field_temporal_with_date::store(longlong nr, bool unsigned_val) ...@@ -5623,35 +5611,18 @@ int Field_temporal_with_date::store(longlong nr, bool unsigned_val)
ErrConvInteger str(nr, unsigned_val); ErrConvInteger str(nr, unsigned_val);
bool rc= Sec6(nr, unsigned_val).to_datetime(&ltime, sql_mode_for_dates(thd), bool rc= Sec6(nr, unsigned_val).to_datetime(&ltime, sql_mode_for_dates(thd),
&error); &error);
return store_TIME_with_warning(&ltime, &str, error, !rc); return store_TIME_with_warning(rc ? NULL : &ltime, &str, error);
} }
int Field_temporal_with_date::store_time_dec(const MYSQL_TIME *ltime, uint dec) int Field_temporal_with_date::store_time_dec(const MYSQL_TIME *ltime, uint dec)
{ {
int error= 0, have_smth_to_conv= 1; int error;
ErrConvTime str(ltime); ErrConvTime str(ltime);
MYSQL_TIME l_time; THD *thd= get_thd();
Datetime dt(thd, &error, ltime, sql_mode_for_dates(thd));
if (copy_or_convert_to_datetime(get_thd(), ltime, &l_time)) ltime= dt.is_valid_datetime() ? dt.get_mysql_time() : NULL;
{ return store_TIME_with_warning(const_cast<MYSQL_TIME*>(ltime), &str, error);
/*
Set have_smth_to_conv and error in a way to have
store_TIME_with_warning do bzero().
*/
have_smth_to_conv= false;
error= MYSQL_TIME_WARN_OUT_OF_RANGE;
}
else
{
/*
We don't perform range checking here since values stored in TIME
structure always fit into DATETIME range.
*/
have_smth_to_conv= !check_date(&l_time, pack_time(&l_time) != 0,
sql_mode_for_dates(get_thd()), &error);
}
return store_TIME_with_warning(&l_time, &str, error, have_smth_to_conv);
} }
...@@ -5738,16 +5709,14 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd, ...@@ -5738,16 +5709,14 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd,
** Stored as a 3 byte unsigned int ** Stored as a 3 byte unsigned int
****************************************************************************/ ****************************************************************************/
int Field_time::store_TIME_with_warning(MYSQL_TIME *ltime, int Field_time::store_TIME_with_warning(MYSQL_TIME *ltime,
const ErrConv *str, const ErrConv *str, int was_cut)
int was_cut,
int have_smth_to_conv)
{ {
ASSERT_COLUMN_MARKED_FOR_WRITE; ASSERT_COLUMN_MARKED_FOR_WRITE;
if (!have_smth_to_conv) if (!ltime)
{ {
bzero(ltime, sizeof(*ltime)); Datetime tmp;
store_TIME(ltime); store_TIME(const_cast<MYSQL_TIME*>(tmp.get_mysql_time()));
set_warnings(Sql_condition::WARN_LEVEL_WARN, str, MYSQL_TIME_WARN_TRUNCATED); set_warnings(Sql_condition::WARN_LEVEL_WARN, str, MYSQL_TIME_WARN_TRUNCATED);
return 1; return 1;
} }
...@@ -5786,54 +5755,19 @@ int Field_time::store(const char *from,size_t len,CHARSET_INFO *cs) ...@@ -5786,54 +5755,19 @@ int Field_time::store(const char *from,size_t len,CHARSET_INFO *cs)
MYSQL_TIME ltime; MYSQL_TIME ltime;
MYSQL_TIME_STATUS status; MYSQL_TIME_STATUS status;
ErrConvString str(from, len, cs); ErrConvString str(from, len, cs);
bool have_smth_to_conv= bool rc= str_to_time(cs, from, len, &ltime, sql_mode_for_dates(get_thd()),
!str_to_time(cs, from, len, &ltime, sql_mode_for_dates(get_thd()), &status);
&status); return store_TIME_with_warning(rc ? NULL : &ltime, &str, status.warnings);
return store_TIME_with_warning(&ltime, &str,
status.warnings, have_smth_to_conv);
}
/**
subtract a given number of days from DATETIME, return TIME
optimized version of calc_time_diff()
@note it might generate TIME values outside of the valid TIME range!
*/
static void calc_datetime_days_diff(MYSQL_TIME *ltime, long days)
{
long daydiff= calc_daynr(ltime->year, ltime->month, ltime->day) - days;
ltime->year= ltime->month= 0;
if (daydiff >=0 )
{
ltime->day= daydiff;
ltime->time_type= MYSQL_TIMESTAMP_TIME;
}
else
{
longlong timediff= ((((daydiff * 24LL +
ltime->hour) * 60LL +
ltime->minute) * 60LL +
ltime->second) * 1000000LL +
ltime->second_part);
unpack_time(timediff, ltime, MYSQL_TIMESTAMP_TIME);
}
} }
int Field_time::store_time_dec(const MYSQL_TIME *ltime, uint dec) int Field_time::store_time_dec(const MYSQL_TIME *ltime, uint dec)
{ {
MYSQL_TIME l_time= *ltime;
ErrConvTime str(ltime); ErrConvTime str(ltime);
int was_cut= 0; int warn;
Time tm(&warn, ltime, curdays);
if (curdays && l_time.time_type != MYSQL_TIMESTAMP_TIME) ltime= tm.is_valid_time() ? tm.get_mysql_time() : NULL;
calc_datetime_days_diff(&l_time, curdays); return store_TIME_with_warning(const_cast<MYSQL_TIME *>(ltime), &str, warn);
int have_smth_to_conv= !check_time_range(&l_time, decimals(), &was_cut);
return store_TIME_with_warning(&l_time, &str, was_cut, have_smth_to_conv);
} }
...@@ -5843,7 +5777,7 @@ int Field_time::store(double nr) ...@@ -5843,7 +5777,7 @@ int Field_time::store(double nr)
ErrConvDouble str(nr); ErrConvDouble str(nr);
int was_cut; int was_cut;
bool rc= Sec6(nr).to_time(&ltime, &was_cut); bool rc= Sec6(nr).to_time(&ltime, &was_cut);
return store_TIME_with_warning(&ltime, &str, was_cut, !rc); return store_TIME_with_warning(rc ? NULL : &ltime, &str, was_cut);
} }
...@@ -5853,7 +5787,7 @@ int Field_time::store(longlong nr, bool unsigned_val) ...@@ -5853,7 +5787,7 @@ int Field_time::store(longlong nr, bool unsigned_val)
ErrConvInteger str(nr, unsigned_val); ErrConvInteger str(nr, unsigned_val);
int was_cut; int was_cut;
bool rc= Sec6(nr, unsigned_val).to_time(&ltime, &was_cut); bool rc= Sec6(nr, unsigned_val).to_time(&ltime, &was_cut);
return store_TIME_with_warning(&ltime, &str, was_cut, !rc); return store_TIME_with_warning(rc ? NULL : &ltime, &str, was_cut);
} }
...@@ -6012,7 +5946,7 @@ int Field_time::store_decimal(const my_decimal *d) ...@@ -6012,7 +5946,7 @@ int Field_time::store_decimal(const my_decimal *d)
MYSQL_TIME ltime; MYSQL_TIME ltime;
int was_cut; int was_cut;
bool rc= Sec6(d).to_time(&ltime, &was_cut); bool rc= Sec6(d).to_time(&ltime, &was_cut);
return store_TIME_with_warning(&ltime, &str, was_cut, !rc); return store_TIME_with_warning(rc ? NULL : &ltime, &str, was_cut);
} }
...@@ -6735,7 +6669,7 @@ int Field_temporal_with_date::store_decimal(const my_decimal *d) ...@@ -6735,7 +6669,7 @@ int Field_temporal_with_date::store_decimal(const my_decimal *d)
THD *thd= get_thd(); THD *thd= get_thd();
ErrConvDecimal str(d); ErrConvDecimal str(d);
bool rc= Sec6(d).to_datetime(&ltime, sql_mode_for_dates(thd), &error); bool rc= Sec6(d).to_datetime(&ltime, sql_mode_for_dates(thd), &error);
return store_TIME_with_warning(&ltime, &str, error, !rc); return store_TIME_with_warning(rc ? NULL : &ltime, &str, error);
} }
bool Field_datetime_with_dec::send_binary(Protocol *protocol) bool Field_datetime_with_dec::send_binary(Protocol *protocol)
......
...@@ -2661,7 +2661,7 @@ class Field_temporal: public Field { ...@@ -2661,7 +2661,7 @@ class Field_temporal: public Field {
class Field_temporal_with_date: public Field_temporal { class Field_temporal_with_date: public Field_temporal {
protected: protected:
int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str,
int was_cut, int have_smth_to_conv); int was_cut);
virtual void store_TIME(MYSQL_TIME *ltime) = 0; virtual void store_TIME(MYSQL_TIME *ltime) = 0;
virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos,
ulonglong fuzzydate) const = 0; ulonglong fuzzydate) const = 0;
...@@ -2694,8 +2694,7 @@ class Field_temporal_with_date: public Field_temporal { ...@@ -2694,8 +2694,7 @@ class Field_temporal_with_date: public Field_temporal {
class Field_timestamp :public Field_temporal { class Field_timestamp :public Field_temporal {
protected: protected:
sql_mode_t sql_mode_for_timestamp(THD *thd) const; sql_mode_t sql_mode_for_timestamp(THD *thd) const;
int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *, int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *, int warn);
int warnings, bool have_smth_to_conv);
public: public:
Field_timestamp(uchar *ptr_arg, uint32 len_arg, Field_timestamp(uchar *ptr_arg, uint32 len_arg,
uchar *null_ptr_arg, uchar null_bit_arg, uchar *null_ptr_arg, uchar null_bit_arg,
...@@ -3020,8 +3019,7 @@ class Field_time :public Field_temporal { ...@@ -3020,8 +3019,7 @@ class Field_time :public Field_temporal {
long curdays; long curdays;
protected: protected:
virtual void store_TIME(const MYSQL_TIME *ltime); virtual void store_TIME(const MYSQL_TIME *ltime);
int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, int warn);
int was_cut, int have_smth_to_conv);
void set_warnings(Sql_condition::enum_warning_level level, void set_warnings(Sql_condition::enum_warning_level level,
const ErrConv *str, int was_cut) const ErrConv *str, int was_cut)
{ {
......
...@@ -368,6 +368,105 @@ void Time::make_from_item(Item *item, const Options opt) ...@@ -368,6 +368,105 @@ void Time::make_from_item(Item *item, const Options opt)
} }
/**
Create from a DATETIME by subtracting a given number of days,
implementing an optimized version of calc_time_diff().
*/
void Time::make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from,
long days)
{
*warn= 0;
DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATETIME ||
from->time_type == MYSQL_TIMESTAMP_DATE);
long daynr= calc_daynr(from->year, from->month, from->day);
long daydiff= daynr - days;
if (!daynr) // Zero date
{
set_zero_time(this, MYSQL_TIMESTAMP_TIME);
neg= true;
hour= TIME_MAX_HOUR + 1; // to report "out of range" in "warn"
}
else if (daydiff >=0)
{
neg= false;
year= month= day= 0;
hhmmssff_copy(from);
hour+= daydiff * 24;
time_type= MYSQL_TIMESTAMP_TIME;
}
else
{
longlong timediff= ((((daydiff * 24LL +
from->hour) * 60LL +
from->minute) * 60LL +
from->second) * 1000000LL +
from->second_part);
unpack_time(timediff, this, MYSQL_TIMESTAMP_TIME);
}
// The above code can generate TIME values outside of the valid TIME range.
adjust_time_range_or_invalidate(warn);
}
void Time::make_from_datetime_move_day_to_hour(int *warn,
const MYSQL_TIME *from)
{
*warn= 0;
DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE ||
from->time_type == MYSQL_TIMESTAMP_DATETIME);
time_type= MYSQL_TIMESTAMP_TIME;
neg= false;
year= month= day= 0;
hhmmssff_copy(from);
datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(warn, from->year,
from->month, from->day);
adjust_time_range_or_invalidate(warn);
}
void Time::make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays)
{
if (!curdays)
make_from_datetime_move_day_to_hour(warn, from);
else
make_from_datetime_with_days_diff(warn, from, curdays);
}
void Time::make_from_time(int *warn, const MYSQL_TIME *from)
{
DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
if (from->year || from->month)
make_from_out_of_range(warn);
else
{
*warn= 0;
DBUG_ASSERT(from->day == 0);
*(static_cast<MYSQL_TIME*>(this))= *from;
adjust_time_range_or_invalidate(warn);
}
}
Time::Time(int *warn, const MYSQL_TIME *from, long curdays)
{
switch (from->time_type) {
case MYSQL_TIMESTAMP_NONE:
case MYSQL_TIMESTAMP_ERROR:
make_from_out_of_range(warn);
break;
case MYSQL_TIMESTAMP_DATE:
case MYSQL_TIMESTAMP_DATETIME:
make_from_datetime(warn, from, curdays);
break;
case MYSQL_TIMESTAMP_TIME:
make_from_time(warn, from);
break;
}
DBUG_ASSERT(is_valid_value_slow());
}
void Temporal_with_date::make_from_item(THD *thd, Item *item, sql_mode_t flags) void Temporal_with_date::make_from_item(THD *thd, Item *item, sql_mode_t flags)
{ {
flags&= ~TIME_TIME_ONLY; flags&= ~TIME_TIME_ONLY;
...@@ -400,6 +499,65 @@ void Temporal_with_date::make_from_item(THD *thd, Item *item) ...@@ -400,6 +499,65 @@ void Temporal_with_date::make_from_item(THD *thd, Item *item)
} }
void Temporal_with_date::check_date_or_invalidate(int *warn, sql_mode_t flags)
{
if (check_date(this, pack_time(this) != 0, flags, warn))
time_type= MYSQL_TIMESTAMP_NONE;
}
void Datetime::make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
sql_mode_t flags)
{
DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
if (time_to_datetime(thd, from, this))
make_from_out_of_range(warn);
else
{
*warn= 0;
check_date_or_invalidate(warn, flags);
}
}
void Datetime::make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
sql_mode_t flags)
{
DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE ||
from->time_type == MYSQL_TIMESTAMP_DATETIME);
if (from->neg || check_datetime_range(from))
make_from_out_of_range(warn);
else
{
*warn= 0;
*(static_cast<MYSQL_TIME*>(this))= *from;
date_to_datetime(this);
check_date_or_invalidate(warn, flags);
}
}
Datetime::Datetime(THD *thd, int *warn, const MYSQL_TIME *from,
sql_mode_t flags)
{
DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0);
switch (from->time_type) {
case MYSQL_TIMESTAMP_ERROR:
case MYSQL_TIMESTAMP_NONE:
make_from_out_of_range(warn);
break;
case MYSQL_TIMESTAMP_TIME:
make_from_time(thd, warn, from, flags);
break;
case MYSQL_TIMESTAMP_DATETIME:
case MYSQL_TIMESTAMP_DATE:
make_from_datetime(thd, warn, from, flags);
break;
}
DBUG_ASSERT(is_valid_value_slow());
}
uint Type_std_attributes::count_max_decimals(Item **item, uint nitems) uint Type_std_attributes::count_max_decimals(Item **item, uint nitems)
{ {
uint res= 0; uint res= 0;
......
...@@ -460,6 +460,11 @@ class Temporal: protected MYSQL_TIME ...@@ -460,6 +460,11 @@ class Temporal: protected MYSQL_TIME
return negate ? -d : d; return negate ? -d : d;
} }
longlong to_packed() const { return ::pack_time(this); } longlong to_packed() const { return ::pack_time(this); }
void make_from_out_of_range(int *warn)
{
*warn= MYSQL_TIME_WARN_OUT_OF_RANGE;
time_type= MYSQL_TIMESTAMP_NONE;
}
public: public:
}; };
...@@ -574,7 +579,23 @@ class Time: private Temporal ...@@ -574,7 +579,23 @@ class Time: private Temporal
second <= TIME_MAX_SECOND && second <= TIME_MAX_SECOND &&
second_part <= TIME_MAX_SECOND_PART; second_part <= TIME_MAX_SECOND_PART;
} }
void hhmmssff_copy(const MYSQL_TIME *from)
{
hour= from->hour;
minute= from->minute;
second= from->second;
second_part= from->second_part;
}
void datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(int *warn,
uint from_year,
uint from_month,
uint from_day)
{
if (from_year != 0 || from_month != 0)
*warn|= MYSQL_TIME_NOTE_TRUNCATED;
else
hour+= from_day * 24;
}
/* /*
Convert a valid DATE or DATETIME to TIME. Convert a valid DATE or DATETIME to TIME.
Before this call, "this" must be a valid DATE or DATETIME value, Before this call, "this" must be a valid DATE or DATETIME value,
...@@ -635,11 +656,23 @@ class Time: private Temporal ...@@ -635,11 +656,23 @@ class Time: private Temporal
break; break;
} }
} }
void adjust_time_range_or_invalidate(int *warn)
{
if (check_time_range(this, TIME_SECOND_PART_DIGITS, warn))
time_type= MYSQL_TIMESTAMP_NONE;
DBUG_ASSERT(is_valid_value_slow());
}
void make_from_datetime_move_day_to_hour(int *warn, const MYSQL_TIME *from);
void make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from,
long curdays);
void make_from_time(int *warn, const MYSQL_TIME *from);
void make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays);
void make_from_item(class Item *item, const Options opt); void make_from_item(class Item *item, const Options opt);
public: public:
Time() { time_type= MYSQL_TIMESTAMP_NONE; } Time() { time_type= MYSQL_TIMESTAMP_NONE; }
Time(Item *item) { make_from_item(item, Options()); } Time(Item *item) { make_from_item(item, Options()); }
Time(Item *item, const Options opt) { make_from_item(item, opt); } Time(Item *item, const Options opt) { make_from_item(item, opt); }
Time(int *warn, const MYSQL_TIME *from, long curdays);
static sql_mode_t flags_for_get_date() static sql_mode_t flags_for_get_date()
{ return TIME_TIME_ONLY | TIME_INVALID_DATES; } { return TIME_TIME_ONLY | TIME_INVALID_DATES; }
static sql_mode_t comparison_flags_for_get_date() static sql_mode_t comparison_flags_for_get_date()
...@@ -744,8 +777,13 @@ class Time: private Temporal ...@@ -744,8 +777,13 @@ class Time: private Temporal
class Temporal_with_date: protected Temporal class Temporal_with_date: protected Temporal
{ {
protected: protected:
void check_date_or_invalidate(int *warn, sql_mode_t flags);
void make_from_item(THD *thd, Item *item, sql_mode_t flags); void make_from_item(THD *thd, Item *item, sql_mode_t flags);
void make_from_item(THD *thd, Item *item); void make_from_item(THD *thd, Item *item);
Temporal_with_date()
{
time_type= MYSQL_TIMESTAMP_NONE;
}
Temporal_with_date(THD *thd, Item *item, sql_mode_t flags) Temporal_with_date(THD *thd, Item *item, sql_mode_t flags)
{ {
make_from_item(thd, item, flags); make_from_item(thd, item, flags);
...@@ -878,6 +916,10 @@ class Datetime: public Temporal_with_date ...@@ -878,6 +916,10 @@ class Datetime: public Temporal_with_date
DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATETIME); DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATETIME);
return !check_datetime_range(this); return !check_datetime_range(this);
} }
void make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
sql_mode_t flags);
void make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
sql_mode_t flags);
public: public:
Datetime(THD *thd, Item *item, sql_mode_t flags) Datetime(THD *thd, Item *item, sql_mode_t flags)
:Temporal_with_date(thd, item, flags) :Temporal_with_date(thd, item, flags)
...@@ -900,6 +942,11 @@ class Datetime: public Temporal_with_date ...@@ -900,6 +942,11 @@ class Datetime: public Temporal_with_date
date_to_datetime(this); date_to_datetime(this);
DBUG_ASSERT(is_valid_value_slow()); DBUG_ASSERT(is_valid_value_slow());
} }
Datetime(THD *thd, int *warn, const MYSQL_TIME *from, sql_mode_t flags);
Datetime()
{
set_zero_time(this, MYSQL_TIMESTAMP_DATETIME);
}
bool is_valid_datetime() const bool is_valid_datetime() const
{ {
/* /*
...@@ -974,6 +1021,7 @@ class Datetime: public Temporal_with_date ...@@ -974,6 +1021,7 @@ class Datetime: public Temporal_with_date
} }
}; };
/* /*
Flags for collation aggregation modes, used in TDCollation::agg(): Flags for collation aggregation modes, used in TDCollation::agg():
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment