mirror of
https://github.com/MariaDB/server.git
synced 2025-07-14 13:41:20 +03:00
bugfix: copy timestamps correctly in INSERT...SELECT
don't do it via MYSQL_TIME, that conversion is lossy around DST change dates.
This commit is contained in:
@ -149,4 +149,26 @@ a unix_timestamp(a)
|
|||||||
2010-10-31 02:25:26 1288477526
|
2010-10-31 02:25:26 1288477526
|
||||||
2010-10-31 02:25:26 1288481126
|
2010-10-31 02:25:26 1288481126
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
set global mysql56_temporal_format=false;
|
||||||
|
create table t1 (a timestamp);
|
||||||
|
set timestamp=1288477526;
|
||||||
|
insert t1 values (null);
|
||||||
|
set timestamp=1288481126;
|
||||||
|
insert t1 values (null);
|
||||||
|
select a, unix_timestamp(a) from t1;
|
||||||
|
a unix_timestamp(a)
|
||||||
|
2010-10-31 02:25:26 1288477526
|
||||||
|
2010-10-31 02:25:26 1288481126
|
||||||
|
set global mysql56_temporal_format=true;
|
||||||
|
select a, unix_timestamp(a) from t1;
|
||||||
|
a unix_timestamp(a)
|
||||||
|
2010-10-31 02:25:26 1288477526
|
||||||
|
2010-10-31 02:25:26 1288481126
|
||||||
|
create table t2 (a timestamp);
|
||||||
|
insert t2 select a from t1;
|
||||||
|
select a, unix_timestamp(a) from t2;
|
||||||
|
a unix_timestamp(a)
|
||||||
|
2010-10-31 02:25:26 1288477526
|
||||||
|
2010-10-31 02:25:26 1288481126
|
||||||
|
drop table t1, t2;
|
||||||
set time_zone=DEFAULT;
|
set time_zone=DEFAULT;
|
||||||
|
@ -86,6 +86,8 @@ SET @@global.mysql56_temporal_format=DEFAULT;
|
|||||||
#
|
#
|
||||||
# MDEV-12672 Replicated TIMESTAMP fields given wrong value near DST change
|
# MDEV-12672 Replicated TIMESTAMP fields given wrong value near DST change
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# Copy_field
|
||||||
set time_zone='Europe/Moscow';
|
set time_zone='Europe/Moscow';
|
||||||
set global mysql56_temporal_format=false;
|
set global mysql56_temporal_format=false;
|
||||||
create table t1 (a timestamp);
|
create table t1 (a timestamp);
|
||||||
@ -99,4 +101,19 @@ select a, unix_timestamp(a) from t1;
|
|||||||
alter table t1 modify a timestamp;
|
alter table t1 modify a timestamp;
|
||||||
select a, unix_timestamp(a) from t1;
|
select a, unix_timestamp(a) from t1;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
# field_conv_incompatible()
|
||||||
|
set global mysql56_temporal_format=false;
|
||||||
|
create table t1 (a timestamp);
|
||||||
|
set timestamp=1288477526;
|
||||||
|
insert t1 values (null);
|
||||||
|
set timestamp=1288481126;
|
||||||
|
insert t1 values (null);
|
||||||
|
select a, unix_timestamp(a) from t1;
|
||||||
|
set global mysql56_temporal_format=true;
|
||||||
|
select a, unix_timestamp(a) from t1;
|
||||||
|
create table t2 (a timestamp);
|
||||||
|
insert t2 select a from t1;
|
||||||
|
select a, unix_timestamp(a) from t2;
|
||||||
|
drop table t1, t2;
|
||||||
set time_zone=DEFAULT;
|
set time_zone=DEFAULT;
|
||||||
|
17
sql/field.cc
17
sql/field.cc
@ -5064,6 +5064,23 @@ int Field_timestamp::store(longlong nr, bool unsigned_val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Field_timestamp::store_timestamp(Field_timestamp *from)
|
||||||
|
{
|
||||||
|
ulong sec_part;
|
||||||
|
my_time_t ts= from->get_timestamp(&sec_part);
|
||||||
|
store_TIME(ts, sec_part);
|
||||||
|
if (!ts && !sec_part && get_thd()->variables.sql_mode & MODE_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)
|
double Field_timestamp::val_real(void)
|
||||||
{
|
{
|
||||||
return (double) Field_timestamp::val_int();
|
return (double) Field_timestamp::val_int();
|
||||||
|
@ -2186,6 +2186,7 @@ public:
|
|||||||
int store(longlong nr, bool unsigned_val);
|
int store(longlong nr, bool unsigned_val);
|
||||||
int store_time_dec(MYSQL_TIME *ltime, uint dec);
|
int store_time_dec(MYSQL_TIME *ltime, uint dec);
|
||||||
int store_decimal(const my_decimal *);
|
int store_decimal(const my_decimal *);
|
||||||
|
int store_timestamp(Field_timestamp *from);
|
||||||
double val_real(void);
|
double val_real(void);
|
||||||
longlong val_int(void);
|
longlong val_int(void);
|
||||||
String *val_str(String*,String *);
|
String *val_str(String*,String *);
|
||||||
|
@ -219,6 +219,13 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int copy_timestamp_fields(Field *from, Field *to)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(from->type() == MYSQL_TYPE_TIMESTAMP);
|
||||||
|
DBUG_ASSERT(to->type() == MYSQL_TYPE_TIMESTAMP);
|
||||||
|
return ((Field_timestamp*)to)->store_timestamp((Field_timestamp*)from);
|
||||||
|
}
|
||||||
|
|
||||||
static void do_skip(Copy_field *copy __attribute__((unused)))
|
static void do_skip(Copy_field *copy __attribute__((unused)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -419,13 +426,7 @@ static void do_field_decimal(Copy_field *copy)
|
|||||||
|
|
||||||
static void do_field_timestamp(Copy_field *copy)
|
static void do_field_timestamp(Copy_field *copy)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(copy->from_field->type() == MYSQL_TYPE_TIMESTAMP);
|
copy_timestamp_fields(copy->from_field, copy->to_field);
|
||||||
DBUG_ASSERT(copy->to_field->type() == MYSQL_TYPE_TIMESTAMP);
|
|
||||||
ulong sec_part;
|
|
||||||
Field_timestamp *f= static_cast<Field_timestamp*>(copy->from_field);
|
|
||||||
Field_timestamp *t= static_cast<Field_timestamp*>(copy->to_field);
|
|
||||||
my_time_t ts= f->get_timestamp(&sec_part);
|
|
||||||
t->store_TIME(ts, sec_part);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -938,6 +939,10 @@ int field_conv_incompatible(Field *to, Field *from)
|
|||||||
my_decimal buff;
|
my_decimal buff;
|
||||||
return to->store_decimal(from->val_decimal(&buff));
|
return to->store_decimal(from->val_decimal(&buff));
|
||||||
}
|
}
|
||||||
|
if (from->type() == MYSQL_TYPE_TIMESTAMP && to->type() == MYSQL_TYPE_TIMESTAMP)
|
||||||
|
{
|
||||||
|
return copy_timestamp_fields(from, to);
|
||||||
|
}
|
||||||
if (from->cmp_type() == TIME_RESULT)
|
if (from->cmp_type() == TIME_RESULT)
|
||||||
{
|
{
|
||||||
MYSQL_TIME ltime;
|
MYSQL_TIME ltime;
|
||||||
|
Reference in New Issue
Block a user