Commit f4f48e06 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-12672 Replicated TIMESTAMP fields given wrong value near DST change

Implement a special Copy_field method for timestamps, that copies
timestamps without converting them to MYSQL_TIME (the conversion
is lossy around DST change dates).
parent 46a2917c
...@@ -127,3 +127,26 @@ Warning 1264 Out of range value for column 'a' at row 1 ...@@ -127,3 +127,26 @@ Warning 1264 Out of range value for column 'a' at row 1
Warning 1264 Out of range value for column 'b' at row 1 Warning 1264 Out of range value for column 'b' at row 1
DROP TABLE t1; DROP TABLE t1;
SET @@global.mysql56_temporal_format=DEFAULT; SET @@global.mysql56_temporal_format=DEFAULT;
set time_zone='Europe/Moscow';
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
alter table t1 modify a timestamp;
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
drop table t1;
set time_zone=DEFAULT;
include/master-slave.inc
[connection master]
set global time_zone='Europe/Moscow';
set time_zone='UTC';
stop slave;
start slave;
set global mysql56_temporal_format=false;
set global time_zone='Europe/Moscow';
set time_zone='UTC';
create table t1 (pk int primary key, t timestamp not null);
set timestamp = 1288477526;
insert into t1 values (1,null);
set timestamp = 1288481126;
insert into t1 values (2,null);
select pk, t, unix_timestamp(t) from t1;
pk t unix_timestamp(t)
1 2010-10-30 22:25:26 1288477526
2 2010-10-30 23:25:26 1288481126
set time_zone=default;
select pk, t, unix_timestamp(t) from t1;
pk t unix_timestamp(t)
1 2010-10-31 02:25:26 1288477526
2 2010-10-31 02:25:26 1288481126
set global time_zone=default;
drop table t1;
set global time_zone=default;
set global mysql56_temporal_format=default;
include/rpl_end.inc
#
# MDEV-12672 Replicated TIMESTAMP fields given wrong value near DST change
#
source include/have_binlog_format_row.inc;
source include/master-slave.inc;
connection slave;
set global time_zone='Europe/Moscow';
set time_zone='UTC';
stop slave;
start slave;
connection master;
set global mysql56_temporal_format=false;
set global time_zone='Europe/Moscow';
set time_zone='UTC';
create table t1 (pk int primary key, t timestamp not null);
set timestamp = 1288477526;
insert into t1 values (1,null);
set timestamp = 1288481126;
insert into t1 values (2,null);
sync_slave_with_master;
select pk, t, unix_timestamp(t) from t1;
set time_zone=default;
select pk, t, unix_timestamp(t) from t1;
set global time_zone=default;
connection master;
drop table t1;
set global time_zone=default;
set global mysql56_temporal_format=default;
source include/rpl_end.inc;
...@@ -83,3 +83,20 @@ SELECT TO_DAYS(a), TO_DAYS(b) FROM t1; ...@@ -83,3 +83,20 @@ SELECT TO_DAYS(a), TO_DAYS(b) FROM t1;
DROP TABLE t1; DROP TABLE t1;
SET @@global.mysql56_temporal_format=DEFAULT; SET @@global.mysql56_temporal_format=DEFAULT;
#
# MDEV-12672 Replicated TIMESTAMP fields given wrong value near DST change
#
set time_zone='Europe/Moscow';
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;
alter table t1 modify a timestamp;
select a, unix_timestamp(a) from t1;
drop table t1;
set time_zone=DEFAULT;
...@@ -417,6 +417,18 @@ static void do_field_decimal(Copy_field *copy) ...@@ -417,6 +417,18 @@ static void do_field_decimal(Copy_field *copy)
} }
static void do_field_timestamp(Copy_field *copy)
{
DBUG_ASSERT(copy->from_field->type() == MYSQL_TYPE_TIMESTAMP);
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);
}
static void do_field_temporal(Copy_field *copy) static void do_field_temporal(Copy_field *copy)
{ {
MYSQL_TIME ltime; MYSQL_TIME ltime;
...@@ -724,7 +736,9 @@ Copy_field::get_copy_func(Field *to,Field *from) ...@@ -724,7 +736,9 @@ Copy_field::get_copy_func(Field *to,Field *from)
((to->table->in_use->variables.sql_mode & ((to->table->in_use->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE)) && (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE)) &&
mysql_type_to_time_type(to->type()) != MYSQL_TIMESTAMP_TIME)) mysql_type_to_time_type(to->type()) != MYSQL_TIMESTAMP_TIME))
return do_field_temporal; return (from->type() == MYSQL_TYPE_TIMESTAMP &&
to->type() == MYSQL_TYPE_TIMESTAMP)
? do_field_timestamp : do_field_temporal;
/* Do binary copy */ /* Do binary copy */
} }
// Check if identical fields // Check if identical fields
......
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