Commit 9811802a authored by Alexander Barkov's avatar Alexander Barkov

MDEV-16939 Move TIMESTAMP truncation code to Field_timestamp::store_TIME_with_warn

parent 2085f14a
...@@ -5024,41 +5024,53 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, const Datetime *dt, ...@@ -5024,41 +5024,53 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, const Datetime *dt,
const ErrConv *str, int was_cut) const ErrConv *str, int was_cut)
{ {
ASSERT_COLUMN_MARKED_FOR_WRITE; ASSERT_COLUMN_MARKED_FOR_WRITE;
uint error = 0; static const timeval zero= {0, (uint) 0 };
if (MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) || !dt->is_valid_datetime())
// Handle totally bad values
if (!dt->is_valid_datetime())
{ {
error= 1; set_datetime_warning(WARN_DATA_TRUNCATED, str, MYSQL_TIMESTAMP_DATETIME, 1);
set_datetime_warning(WARN_DATA_TRUNCATED, store_TIMEVAL(zero);
str, MYSQL_TIMESTAMP_DATETIME, 1); return 1;
} }
else if (MYSQL_TIME_WARN_HAVE_NOTES(was_cut))
// Handle values that do not need DATETIME to TIMESTAMP conversion
if (!dt->get_mysql_time()->month)
{ {
error= 3; /*
set_datetime_warning(Sql_condition::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, Zero date is allowed by the current sql_mode. Store zero timestamp.
str, MYSQL_TIMESTAMP_DATETIME, 1); Return success or a warning about non-fatal truncation, e.g.:
INSERT INTO t1 (ts) VALUES ('0000-00-00 00:00:00 some tail');
*/
store_TIMEVAL(zero);
return store_TIME_return_code_with_warnings(was_cut, str,
MYSQL_TIMESTAMP_DATETIME);
} }
/* Only convert a correct date (not a zero date) */ // Convert DATETIME to TIMESTAMP
if (dt->is_valid_datetime() && dt->get_mysql_time()->month)
{
uint conversion_error; uint conversion_error;
const MYSQL_TIME *l_time= dt->get_mysql_time(); const MYSQL_TIME *l_time= dt->get_mysql_time();
my_time_t 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;
if (unlikely(conversion_error))
{ {
set_datetime_warning(conversion_error, set_datetime_warning(ER_WARN_DATA_OUT_OF_RANGE, str, MYSQL_TIMESTAMP_DATETIME, 1);
str, MYSQL_TIMESTAMP_DATETIME, !error); store_TIMEVAL(zero);
error= 1; return 1; // date was fine but pointed to a DST gap
} }
store_TIME(timestamp, l_time->second_part);
} // Adjust and store the value
else timeval tv= {timestamp, (uint) l_time->second_part};
my_timeval_trunc(&tv, decimals());
store_TIMEVAL(tv);
// Calculate return value and send warnings if needed
if (unlikely(conversion_error)) // e.g. DATETIME in the DST gap
{ {
store_TIME(0, 0); set_datetime_warning(conversion_error, str, MYSQL_TIMESTAMP_DATETIME, 1);
return 1;
} }
return error; return store_TIME_return_code_with_warnings(was_cut, str,
MYSQL_TIMESTAMP_DATETIME);
} }
...@@ -5367,10 +5379,10 @@ static longlong read_lowendian(const uchar *from, uint bytes) ...@@ -5367,10 +5379,10 @@ static longlong read_lowendian(const uchar *from, uint bytes)
} }
} }
void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) void Field_timestamp_hires::store_TIMEVAL(const timeval &tv)
{ {
mi_int4store(ptr, timestamp); mi_int4store(ptr, tv.tv_sec);
store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes(dec)); store_bigendian(sec_part_shift(tv.tv_usec, dec), ptr+4, sec_part_bytes(dec));
} }
my_time_t Field_timestamp_hires::get_timestamp(const uchar *pos, my_time_t Field_timestamp_hires::get_timestamp(const uchar *pos,
...@@ -5449,12 +5461,8 @@ void Field_timestamp_with_dec::make_send_field(Send_field *field) ...@@ -5449,12 +5461,8 @@ void Field_timestamp_with_dec::make_send_field(Send_field *field)
** MySQL-5.6 compatible TIMESTAMP(N) ** MySQL-5.6 compatible TIMESTAMP(N)
**************************************************************/ **************************************************************/
void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part) void Field_timestampf::store_TIMEVAL(const timeval &tm)
{ {
struct timeval tm;
tm.tv_sec= timestamp;
tm.tv_usec= sec_part;
my_timeval_trunc(&tm, dec);
my_timestamp_to_binary(&tm, ptr, dec); my_timestamp_to_binary(&tm, ptr, dec);
} }
......
...@@ -2711,6 +2711,10 @@ class Field_timestamp :public Field_temporal { ...@@ -2711,6 +2711,10 @@ class Field_timestamp :public Field_temporal {
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 *, const Datetime *, int store_TIME_with_warning(THD *, const Datetime *,
const ErrConv *, int warn); const ErrConv *, int warn);
virtual void store_TIMEVAL(const timeval &tv)
{
int4store(ptr, tv.tv_sec);
}
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,
...@@ -2750,9 +2754,11 @@ class Field_timestamp :public Field_temporal { ...@@ -2750,9 +2754,11 @@ class Field_timestamp :public Field_temporal {
{ {
return get_timestamp(ptr, sec_part); return get_timestamp(ptr, sec_part);
} }
virtual void store_TIME(my_time_t timestamp, ulong sec_part) void store_TIME(my_time_t timestamp, ulong sec_part)
{ {
int4store(ptr,timestamp); timeval tv= {timestamp, (uint) sec_part};
my_timeval_trunc(&tv, decimals());
store_TIMEVAL(tv);
} }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
uchar *pack(uchar *to, const uchar *from, uchar *pack(uchar *to, const uchar *from,
...@@ -2822,6 +2828,7 @@ class Field_timestamp_hires :public Field_timestamp_with_dec { ...@@ -2822,6 +2828,7 @@ class Field_timestamp_hires :public Field_timestamp_with_dec {
{ {
return Type_handler_timestamp::sec_part_bytes(dec); return Type_handler_timestamp::sec_part_bytes(dec);
} }
void store_TIMEVAL(const timeval &tv);
public: public:
Field_timestamp_hires(uchar *ptr_arg, Field_timestamp_hires(uchar *ptr_arg,
uchar *null_ptr_arg, uchar null_bit_arg, uchar *null_ptr_arg, uchar null_bit_arg,
...@@ -2834,7 +2841,6 @@ class Field_timestamp_hires :public Field_timestamp_with_dec { ...@@ -2834,7 +2841,6 @@ class Field_timestamp_hires :public Field_timestamp_with_dec {
DBUG_ASSERT(dec); DBUG_ASSERT(dec);
} }
my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const;
void store_TIME(my_time_t timestamp, ulong sec_part);
int cmp(const uchar *,const uchar *); int cmp(const uchar *,const uchar *);
uint32 pack_length() const { return 4 + sec_part_bytes(dec); } uint32 pack_length() const { return 4 + sec_part_bytes(dec); }
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
...@@ -2850,6 +2856,7 @@ class Field_timestampf :public Field_timestamp_with_dec { ...@@ -2850,6 +2856,7 @@ class Field_timestampf :public Field_timestamp_with_dec {
*metadata_ptr= (uchar) decimals(); *metadata_ptr= (uchar) decimals();
return 1; return 1;
} }
void store_TIMEVAL(const timeval &tv);
public: public:
Field_timestampf(uchar *ptr_arg, Field_timestampf(uchar *ptr_arg,
uchar *null_ptr_arg, uchar null_bit_arg, uchar *null_ptr_arg, uchar null_bit_arg,
...@@ -2878,7 +2885,6 @@ class Field_timestampf :public Field_timestamp_with_dec { ...@@ -2878,7 +2885,6 @@ class Field_timestampf :public Field_timestamp_with_dec {
} }
void set_max(); void set_max();
bool is_max(); bool is_max();
void store_TIME(my_time_t timestamp, ulong sec_part);
my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const;
my_time_t get_timestamp(ulong *sec_part) const my_time_t get_timestamp(ulong *sec_part) const
{ {
......
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