From 1f4f425a2007c51eeee35f911a787fc7d82d977c Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 6 Dec 2013 19:02:55 +0400 Subject: [PATCH] MDEV-5297 TIME(0), TIMESTAMP(0) and DATETIME(0) are self-incompatible during replication (upstream) Fixed. --- .../mysql050614_temporal0.MYD | Bin 0 -> 13 bytes .../mysql050614_temporal0.MYI | Bin 0 -> 1024 bytes .../mysql050614_temporal0.frm | Bin 0 -> 8602 bytes .../mysql050614_temporal1.MYD | 0 .../mysql050614_temporal1.MYI | Bin 0 -> 1024 bytes .../mysql050614_temporal1.frm | Bin 0 -> 8602 bytes .../r/rpl_temporal_mysql56_to_mariadb.result | 36 +++++++++++ .../t/rpl_temporal_mysql56_to_mariadb.test | 42 +++++++++++++ sql/rpl_utility.cc | 58 ++++++++++++++---- 9 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 mysql-test/std_data/temporal_upgrade/mysql050614_temporal0.MYD create mode 100644 mysql-test/std_data/temporal_upgrade/mysql050614_temporal0.MYI create mode 100644 mysql-test/std_data/temporal_upgrade/mysql050614_temporal0.frm create mode 100644 mysql-test/std_data/temporal_upgrade/mysql050614_temporal1.MYD create mode 100644 mysql-test/std_data/temporal_upgrade/mysql050614_temporal1.MYI create mode 100644 mysql-test/std_data/temporal_upgrade/mysql050614_temporal1.frm create mode 100644 mysql-test/suite/rpl/r/rpl_temporal_mysql56_to_mariadb.result create mode 100644 mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb.test diff --git a/mysql-test/std_data/temporal_upgrade/mysql050614_temporal0.MYD b/mysql-test/std_data/temporal_upgrade/mysql050614_temporal0.MYD new file mode 100644 index 0000000000000000000000000000000000000000..c04784cf1d45b533349c5d2ceb29c2d4caf8733b GIT binary patch literal 13 Ucmey_z`!^&y@`R*%KtJa6!;I}F#zRJ0ONlsfQYidBza*B+%#7mP)-Rd4>vcc z^#ePy9xQwVR6TGzk+orCgWQCSMSy&;W;SNHa)@`~TrdObHfAO;j}>Ac(YB(RHOd1p=5QX7iBU#A80mlkXlR~X4`354T3q!ysuyhJ{?$fvoIY@4hYh^QQA=N2u z@&>`MuUN#_?)ypR^Awf|Y<=;-G*(c+ES`N2v-I`#4KHKRG*FKRZ3##~0uqpb1SB8< z2}nQ!5|DrdZdSku)4zo?_%}|@{JG`VXNn$^TFQkzv79fK#OGI5w%Exu;hki=*?ACO!f16mIM;j>ZS^4SX%@t%U06;GoI5 zgtR?P+U6Ufchm0&Kx%-cHv0II7%|XuV{O}V)7Kj?>w-K7=G}lT1t>rP3Q&Lo6rcbF zC_n)UP=EqID`;IL6rcbFC_n)UP=Epypa2CZ@Gk-v z^Zv{KUrznKa~cF#W2FnGuUih-VFGz>vPKxlcrpL55JF15Ga(fsNR3dE#I1C0bhVMY dP9a&QQ#iR`s6pfc{i<>_Q(&NhEp26Miw7Ek8SnrA literal 0 HcmV?d00001 diff --git a/mysql-test/suite/rpl/r/rpl_temporal_mysql56_to_mariadb.result b/mysql-test/suite/rpl/r/rpl_temporal_mysql56_to_mariadb.result new file mode 100644 index 00000000000..ecc95481f2d --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_temporal_mysql56_to_mariadb.result @@ -0,0 +1,36 @@ +include/master-slave.inc +[connection master] +# +# Testing replication from MariaDB-10.0 master +# started over MySQL-5.6 data directory +# to MariaDB-10.0 slave running with natively created tables +# +SET TIME_ZONE='+00:00'; +SHOW CREATE TABLE mysql050614_temporal0; +Table Create Table +mysql050614_temporal0 CREATE TABLE `mysql050614_temporal0` ( + `a` time DEFAULT NULL, + `b` datetime DEFAULT NULL, + `c` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE mysql050614_temporal1; +Table Create Table +mysql050614_temporal1 CREATE TABLE `mysql050614_temporal1` ( + `a` time(1) DEFAULT NULL, + `b` datetime(1) DEFAULT NULL, + `c` timestamp(1) NOT NULL DEFAULT CURRENT_TIMESTAMP(1) ON UPDATE CURRENT_TIMESTAMP(1) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SET TIME_ZONE='+00:00'; +CREATE TABLE mysql050614_temporal0 (a time(0), b datetime(0), c timestamp(0)) engine=myisam; +CREATE TABLE mysql050614_temporal1 (a time(1), b datetime(1), c timestamp(1)) engine=myisam; +INSERT INTO mysql050614_temporal0 VALUES ('00:00:02','2001-01-01 00:00:02','2001-01-01 00:00:02'); +INSERT INTO mysql050614_temporal1 VALUES ('00:00:02.1','2001-01-01 00:00:02.2','2001-01-01 00:00:02.3'); +SELECT * FROM mysql050614_temporal0; +a b c +00:00:02 2001-01-01 00:00:02 2001-01-01 00:00:02 +SELECT * FROM mysql050614_temporal1; +a b c +00:00:02.1 2001-01-01 00:00:02.2 2001-01-01 00:00:02.3 +DROP TABLE mysql050614_temporal0; +DROP TABLE mysql050614_temporal1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb.test b/mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb.test new file mode 100644 index 00000000000..46c51a5e465 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb.test @@ -0,0 +1,42 @@ +--source include/master-slave.inc + + +--echo # +--echo # Testing replication from MariaDB-10.0 master +--echo # started over MySQL-5.6 data directory +--echo # to MariaDB-10.0 slave running with natively created tables +--echo # + +connection master; +SET TIME_ZONE='+00:00'; +let $MYSQLD_MASTER_DATADIR= `select @@datadir`; + +--copy_file std_data/temporal_upgrade/mysql050614_temporal0.frm $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal0.frm +--copy_file std_data/temporal_upgrade/mysql050614_temporal0.MYD $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal0.MYD +--copy_file std_data/temporal_upgrade/mysql050614_temporal0.MYI $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal0.MYI + +--copy_file std_data/temporal_upgrade/mysql050614_temporal1.frm $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal1.frm +--copy_file std_data/temporal_upgrade/mysql050614_temporal1.MYD $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal1.MYD +--copy_file std_data/temporal_upgrade/mysql050614_temporal1.MYI $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal1.MYI +SHOW CREATE TABLE mysql050614_temporal0; +SHOW CREATE TABLE mysql050614_temporal1; + +connection slave; +SET TIME_ZONE='+00:00'; +CREATE TABLE mysql050614_temporal0 (a time(0), b datetime(0), c timestamp(0)) engine=myisam; +CREATE TABLE mysql050614_temporal1 (a time(1), b datetime(1), c timestamp(1)) engine=myisam; + +connection master; +INSERT INTO mysql050614_temporal0 VALUES ('00:00:02','2001-01-01 00:00:02','2001-01-01 00:00:02'); +INSERT INTO mysql050614_temporal1 VALUES ('00:00:02.1','2001-01-01 00:00:02.2','2001-01-01 00:00:02.3'); +sync_slave_with_master; + +connection slave; +SELECT * FROM mysql050614_temporal0; +SELECT * FROM mysql050614_temporal1; + +connection master; +DROP TABLE mysql050614_temporal0; +DROP TABLE mysql050614_temporal1; + +--source include/rpl_end.inc diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 590a5ae06ac..1f67dd6ee8f 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -46,6 +46,19 @@ uint32 uint_max(int bits) { } +/** + Calculate display length for MySQL56 temporal data types from their metadata. + It contains fractional precision in the low 16-bit word. +*/ +static uint32 +max_display_length_for_temporal2_field(uint32 int_display_length, + unsigned int metadata) +{ + metadata&= 0x00ff; + return int_display_length + metadata + (metadata ? 1 : 0); +} + + /** Compute the maximum display length of a field. @@ -109,17 +122,23 @@ max_display_length_for_field(enum_field_types sql_type, unsigned int metadata) case MYSQL_TYPE_DATE: case MYSQL_TYPE_TIME: - case MYSQL_TYPE_TIME2: return 3; + case MYSQL_TYPE_TIME2: + return max_display_length_for_temporal2_field(MIN_TIME_WIDTH, metadata); + case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_TIMESTAMP2: return 4; + case MYSQL_TYPE_TIMESTAMP2: + return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata); + case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_DATETIME2: return 8; + case MYSQL_TYPE_DATETIME2: + return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata); + case MYSQL_TYPE_BIT: /* Decode the size of the bit field from the master. @@ -630,19 +649,32 @@ can_convert_field_to(Field *field, else DBUG_RETURN(false); } - else if (metadata == 0 && - ((field->real_type() == MYSQL_TYPE_TIMESTAMP2 && - source_type == MYSQL_TYPE_TIMESTAMP) || - (field->real_type() == MYSQL_TYPE_TIME2 && - source_type == MYSQL_TYPE_TIME) || - (field->real_type() == MYSQL_TYPE_DATETIME2 && - source_type == MYSQL_TYPE_DATETIME))) + else if ( + /* + Conversion from MariaDB TIMESTAMP(0), TIME(0), DATETIME(0) + to the corresponding MySQL56 types is non-lossy. + */ + (metadata == 0 && + ((field->real_type() == MYSQL_TYPE_TIMESTAMP2 && + source_type == MYSQL_TYPE_TIMESTAMP) || + (field->real_type() == MYSQL_TYPE_TIME2 && + source_type == MYSQL_TYPE_TIME) || + (field->real_type() == MYSQL_TYPE_DATETIME2 && + source_type == MYSQL_TYPE_DATETIME))) || + /* + Conversion from MySQL56 TIMESTAMP(N), TIME(N), DATETIME(N) + to the corresponding MariaDB or MySQL55 types is non-lossy. + */ + (metadata == field->decimals() && + ((field->real_type() == MYSQL_TYPE_TIMESTAMP && + source_type == MYSQL_TYPE_TIMESTAMP2) || + (field->real_type() == MYSQL_TYPE_TIME && + source_type == MYSQL_TYPE_TIME2) || + (field->real_type() == MYSQL_TYPE_DATETIME && + source_type == MYSQL_TYPE_DATETIME2)))) { /* TS-TODO: conversion from FSP1>FSP2. - Can do non-lossy conversion - from old TIME, TIMESTAMP, DATETIME - to MySQL56 TIME(0), TIMESTAMP(0), DATETIME(0). */ *order_var= -1; DBUG_RETURN(true);