On 10/20/2010 04:45 PM, Luis Soares wrote:
> #At file:///home/lsoares/Workspace/bzr/work/bugfixing/53386/mysql-trunk-bugfixing/
> based on revid:alfranio.correia@stripped
>
> 3288 Luis Soares 2010-10-20
> BUG#53386: HA_ERR_CORRUPT_EVENT or debug assertion with different
> table on slave
>
> When the number of raw bytes used for a CHAR field exceeds 255
> two bytes are actually used while packing the length of the
> field. CHAR fields can exceed the raw 255 byte length, for
> instance, if using multi-byte character sets.
>
> The problem is that when calculating the raw length of the field,
> at unpacking time, only one byte was assumed to be used
> always. Therefore, the number of bytes used would not add up,
> triggering the assertion.
>
> We fix this, by making the member function that calculates the
> raw byte length for a given field to take into account the actual
> number of bytes used while packing the field length.
> @ mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test
> Extended the test case with one based on the bug report entry.
>
> modified:
> mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test
> mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result
> mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result
> sql/rpl_utility.cc
> === modified file 'mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test'
> --- a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test 2010-06-22 09:34:59 +0000
> +++ b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test 2010-10-20 14:45:31 +0000
> @@ -1029,4 +1029,34 @@ sync_slave_with_master;
>
> # END of 5.1 tests case
>
> +#
> +# BUG#53386: HA_ERR_CORRUPT_EVENT or debug assertion with different table on slave
> +#
> +
> +-- connection master
> +-- source include/master-slave-reset.inc
> +-- connection master
> +
> +# CREATE Different tables on master and slave
> +SET SQL_LOG_BIN=0;
> +-- eval CREATE TABLE t1 (c1 INT NOT NULL, c2 CHAR(255) CHARACTER SET UTF8 NOT NULL)
> ENGINE=$engine_type
> +SET SQL_LOG_BIN=1;
> +-- connection slave
> +-- eval CREATE TABLE t1 (c1 INT) ENGINE=$engine_type
> +
> +# insert empty row (c2 gets an empty string)
> +-- connection master
> +
> +-- disable_warnings
> +INSERT INTO t1 VALUES ();
> +-- enable_warnings
> +
> +SELECT * FROM t1;
> +-- sync_slave_with_master
> +SELECT * FROM t1;
> +
> +# clean up
> +-- connection master
> +DROP TABLE t1;
> +-- sync_slave_with_master
>
>
> === modified file 'mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result'
> --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result 2010-06-22 09:34:59
> +0000
> +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result 2010-10-20 14:45:31
> +0000
> @@ -876,3 +876,21 @@ c1 hex(c4) c5
> 3 6231623162316231 QA
> DROP TABLE t5;
>
> +stop slave;
> +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
> +reset master;
> +reset slave;
> +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
> +start slave;
> +SET SQL_LOG_BIN=0;
> +CREATE TABLE t1 (c1 INT NOT NULL, c2 CHAR(255) CHARACTER SET UTF8 NOT NULL)
> ENGINE='InnoDB';
> +SET SQL_LOG_BIN=1;
> +CREATE TABLE t1 (c1 INT) ENGINE='InnoDB';
> +INSERT INTO t1 VALUES ();
> +SELECT * FROM t1;
> +c1 c2
> +0
> +SELECT * FROM t1;
> +c1
> +0
> +DROP TABLE t1;
>
> === modified file 'mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result'
> --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result 2010-06-22 09:34:59
> +0000
> +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result 2010-10-20 14:45:31
> +0000
> @@ -876,3 +876,21 @@ c1 hex(c4) c5
> 3 6231623162316231 QA
> DROP TABLE t5;
>
> +stop slave;
> +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
> +reset master;
> +reset slave;
> +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
> +start slave;
> +SET SQL_LOG_BIN=0;
> +CREATE TABLE t1 (c1 INT NOT NULL, c2 CHAR(255) CHARACTER SET UTF8 NOT NULL)
> ENGINE='MyISAM';
> +SET SQL_LOG_BIN=1;
> +CREATE TABLE t1 (c1 INT) ENGINE='MyISAM';
> +INSERT INTO t1 VALUES ();
> +SELECT * FROM t1;
> +c1 c2
> +0
> +SELECT * FROM t1;
> +c1
> +0
> +DROP TABLE t1;
>
> === modified file 'sql/rpl_utility.cc'
> --- a/sql/rpl_utility.cc 2010-07-16 21:00:50 +0000
> +++ b/sql/rpl_utility.cc 2010-10-20 14:45:31 +0000
> @@ -225,9 +225,10 @@ uint32 table_def::calc_field_size(uint c
> /*
> We are reading the actual size from the master_data record
> because this field has the actual lengh stored in the first
> - byte.
> + one or two bytes.
> */
> - length= (uint) *master_data + 1;
> + uint32 max_length= max_display_length_for_field(MYSQL_TYPE_STRING,
> m_field_metadata[col]);
> + length= (uint) (max_length > 255 ? 2 : 1) + *master_data;
>
If two bytes are used to represent the length, I think you need to read
two bytes from the master data to compute the length... but you're just
reading one.
Shouldn't it be:
if (max_length > 255)
length= *master_data + *(master_data + 1) << 8 + 2;
else
length = *master_data + 1;
or
length = *master_data + (max_length > 255 ? 2 + *(master_data + 1)
<< 8 : 1)
whichever you prefer.
Just my few cents,
Mats Kindahl
> DBUG_ASSERT(length != 0);
> }
> break;
>
>
>
>
>
>