Skip to content

Commit

Permalink
bugfix: copy timestamps correctly in INSERT...SELECT
Browse files Browse the repository at this point in the history
Implement Field_timestamp::save_in_field(timestamp_field)
that stores timestamp values without converting them to MYSQL_TIME
and back, because this conversion is lossy around DST change time.
This fixes main.old-mode test.

This is 10.2 version of f8a800b
  • Loading branch information
vuvova committed Sep 22, 2017
1 parent a5e1f60 commit 68d1a59
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 20 deletions.
67 changes: 52 additions & 15 deletions sql/field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,33 @@ int Field::store(const char *to, uint length, CHARSET_INFO *cs,
}


static int timestamp_to_TIME(THD *thd, MYSQL_TIME *ltime, my_time_t ts,
ulong sec_part, ulonglong fuzzydate)
{
thd->time_zone_used= 1;
if (ts == 0 && sec_part == 0)
{
if (fuzzydate & TIME_NO_ZERO_DATE)
return 1;
set_zero_time(ltime, MYSQL_TIMESTAMP_DATETIME);
}
else
{
thd->variables.time_zone->gmt_sec_to_TIME(ltime, ts);
ltime->second_part= sec_part;
}
return 0;
}


int Field::store_timestamp(my_time_t ts, ulong sec_part)
{
MYSQL_TIME ltime;
THD *thd= get_thd();
timestamp_to_TIME(thd, &ltime, ts, sec_part, 0);
return store_time_dec(&ltime, decimals());
}

/**
Pack the field into a format suitable for storage and transfer.
Expand Down Expand Up @@ -4966,6 +4993,13 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
}


int Field_timestamp::save_in_field(Field *to)
{
ulong sec_part;
my_time_t ts= get_timestamp(&sec_part);
return to->store_timestamp(ts, sec_part);
}

my_time_t Field_timestamp::get_timestamp(const uchar *pos,
ulong *sec_part) const
{
Expand Down Expand Up @@ -5092,6 +5126,22 @@ int Field_timestamp::store(longlong nr, bool unsigned_val)
}


int Field_timestamp::store_timestamp(my_time_t ts, ulong sec_part)
{
store_TIME(ts, sec_part);
if (ts == 0 && sec_part == 0 &&
get_thd()->variables.sql_mode & TIME_NO_ZERO_DATE)
{
ErrConvString s(
STRING_WITH_LEN("0000-00-00 00:00:00.000000") - (decimals() ? 6 - decimals() : 7),
system_charset_info);
set_datetime_warning(WARN_DATA_TRUNCATED, &s, MYSQL_TIMESTAMP_DATETIME, 1);
return 1;
}
return 0;
}


double Field_timestamp::val_real(void)
{
return (double) Field_timestamp::val_int();
Expand Down Expand Up @@ -5195,22 +5245,9 @@ Field_timestamp::validate_value_in_record(THD *thd, const uchar *record) const

bool Field_timestamp::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
THD *thd= get_thd();
thd->time_zone_used= 1;
ulong sec_part;
my_time_t temp= get_timestamp(&sec_part);
if (temp == 0 && sec_part == 0)
{ /* Zero time is "000000" */
if (fuzzydate & TIME_NO_ZERO_DATE)
return 1;
set_zero_time(ltime, MYSQL_TIMESTAMP_DATETIME);
}
else
{
thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp);
ltime->second_part= sec_part;
}
return 0;
my_time_t ts= get_timestamp(&sec_part);
return timestamp_to_TIME(get_thd(), ltime, ts, sec_part, fuzzydate);
}


Expand Down
3 changes: 3 additions & 0 deletions sql/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,7 @@ class Field: public Value_source
virtual int store(longlong nr, bool unsigned_val)=0;
virtual int store_decimal(const my_decimal *d)=0;
virtual int store_time_dec(MYSQL_TIME *ltime, uint dec);
virtual int store_timestamp(my_time_t timestamp, ulong sec_part);
int store_time(MYSQL_TIME *ltime)
{ return store_time_dec(ltime, TIME_SECOND_PART_DIGITS); }
int store(const char *to, uint length, CHARSET_INFO *cs,
Expand Down Expand Up @@ -2395,6 +2396,8 @@ class Field_timestamp :public Field_temporal {
int store(longlong nr, bool unsigned_val);
int store_time_dec(MYSQL_TIME *ltime, uint dec);
int store_decimal(const my_decimal *);
int store_timestamp(my_time_t timestamp, ulong sec_part);
int save_in_field(Field *to);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
Expand Down
7 changes: 2 additions & 5 deletions sql/field_conv.cc
Original file line number Diff line number Diff line change
Expand Up @@ -419,11 +419,8 @@ void Field::do_field_decimal(Copy_field *copy)

void Field::do_field_timestamp(Copy_field *copy)
{
Field_timestamp *f= static_cast<Field_timestamp*>(copy->from_field);
Field_timestamp *t= static_cast<Field_timestamp*>(copy->to_field);
ulong sec_part;
my_time_t ts= f->get_timestamp(&sec_part);
t->store_TIME(ts, sec_part);
// XXX why couldn't we do it everywhere?
copy->from_field->save_in_field(copy->to_field);
}


Expand Down

0 comments on commit 68d1a59

Please sign in to comment.