diff options
author | Sergei Golubchik <serg@mariadb.org> | 2017-09-19 11:18:45 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2017-09-21 22:03:21 +0200 |
commit | f4f48e06215fe6717865ccbe27ddc388a2cb86b8 (patch) | |
tree | c4128f9caa12333de890e338a609f8bbe6f897fb | |
parent | 46a2917c0fd287755d9e357a98d04ed2c8b1ba0a (diff) | |
download | mariadb-git-f4f48e06215fe6717865ccbe27ddc388a2cb86b8.tar.gz |
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).
-rw-r--r-- | mysql-test/r/old-mode.result | 23 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_temporal_format_mariadb53_to_mysql56_dst.result | 28 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56_dst.test | 37 | ||||
-rw-r--r-- | mysql-test/t/old-mode.test | 17 | ||||
-rw-r--r-- | sql/field_conv.cc | 16 |
5 files changed, 120 insertions, 1 deletions
diff --git a/mysql-test/r/old-mode.result b/mysql-test/r/old-mode.result index c2ee3324ede..398e719cf02 100644 --- a/mysql-test/r/old-mode.result +++ b/mysql-test/r/old-mode.result @@ -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 DROP TABLE t1; 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; diff --git a/mysql-test/suite/rpl/r/rpl_temporal_format_mariadb53_to_mysql56_dst.result b/mysql-test/suite/rpl/r/rpl_temporal_format_mariadb53_to_mysql56_dst.result new file mode 100644 index 00000000000..352101cb8cd --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_temporal_format_mariadb53_to_mysql56_dst.result @@ -0,0 +1,28 @@ +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 diff --git a/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56_dst.test b/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56_dst.test new file mode 100644 index 00000000000..511bdc15184 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56_dst.test @@ -0,0 +1,37 @@ +# +# 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; diff --git a/mysql-test/t/old-mode.test b/mysql-test/t/old-mode.test index 0572570d122..99c92f8093d 100644 --- a/mysql-test/t/old-mode.test +++ b/mysql-test/t/old-mode.test @@ -83,3 +83,20 @@ SELECT TO_DAYS(a), TO_DAYS(b) FROM t1; DROP TABLE t1; 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; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 7b57c7da104..74c5fb5b502 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -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) { MYSQL_TIME ltime; @@ -724,7 +736,9 @@ Copy_field::get_copy_func(Field *to,Field *from) ((to->table->in_use->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE)) && 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 */ } // Check if identical fields |