List:Commits« Previous MessageNext Message »
From:Mats Kindahl Date:October 29 2010 12:28pm
Subject:Re: bzr commit into mysql-trunk-bugfixing branch (luis.soares:3288)
Bug#53386
View as plain text  
Hi Luis,

I would the test extended to insert a string that is really more than
255 *bytes* long and see that it actually replicates correctly. Apart
from that, I have nothing that prevents it from being approved. You can
read my comments below anyway.

/Matz

On 10/29/2010 02:08 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-29
>       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.
>      @ sql/rpl_record.cc
>         Added assertion so that calc_field_size always matches the
>         size returned by field->unpack.
>      @ sql/rpl_utility.cc
>         Changed calc_field_size so that either one or two bytes are
>         taken into account, depending on the maximum field size.
>         
>         Additionally, fixed one wrong assertion that was deployed
>         when calculating the field size of a varchar type.
>
>     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_record.cc
>       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-29 12:08:34 +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 ();
>   

What about a row with a string that is longer than 255 bytes here? Is it
skipped correctly?

> +-- 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-29 12:08:34
> +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-29 12:08:34
> +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_record.cc'
> --- a/sql/rpl_record.cc	2010-07-24 13:47:42 +0000
> +++ b/sql/rpl_record.cc	2010-10-29 12:08:34 +0000
> @@ -324,6 +324,13 @@ unpack_row(Relay_log_info const *rli,
>                               f->field_name, metadata,
>                               (ulong) old_pack_ptr, (ulong) pack_ptr,
>                               (int) (pack_ptr - old_pack_ptr)));
> +
> +        /*
> +          The raw size of the field, as calculated in calc_field_size,
> +          should match the one reported by Field_*::unpack.
> +         */
> +        DBUG_ASSERT(tabledef->calc_field_size(i, (uchar *) old_pack_ptr) == 
> +                    (pack_ptr - old_pack_ptr));
>   

Nice assertion. :)

>        }
>  
>        /*
>
> === 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-29 12:08:34 +0000
> @@ -225,9 +225,12 @@ 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;
> +      length= max_display_length_for_field(MYSQL_TYPE_STRING, m_field_metadata[col])
> > 255 ? 2 : 1;
> +
> +      /* As in Field_string::unpack */
> +      length+= ((length == 1) ? *master_data : uint2korr(master_data));
>        DBUG_ASSERT(length != 0);
>      }
>      break;
> @@ -284,8 +287,8 @@ uint32 table_def::calc_field_size(uint c
>    case MYSQL_TYPE_VARCHAR:
>    {
>      length= m_field_metadata[col] > 255 ? 2 : 1; // c&p of
> Field_varstring::data_length()
> -    DBUG_ASSERT(uint2korr(master_data) > 0);
>      length+= length == 1 ? (uint32) *master_data : uint2korr(master_data);
> +    DBUG_ASSERT(length != 0);
>   

Assertions are meant to state that something is required for the code to
function correctly: either that the input parameter is correct (the code
has assumptions on the input which, if violated, lead to incorrect
results or a crash) or that the output parameter is correct. This
assertion seems to not be needed, since length is guaranteed to be 1 or
2 plus an unsigned number: hence it cannot even by mistake be 0.

Maybe it is something else that you want to assert?

>      break;
>    }
>    case MYSQL_TYPE_TINY_BLOB:
>
>   
>
>
>
>   

Thread
bzr commit into mysql-trunk-bugfixing branch (luis.soares:3288) Bug#53386Luis Soares29 Oct
  • Re: bzr commit into mysql-trunk-bugfixing branch (luis.soares:3288)Bug#53386Mats Kindahl29 Oct
    • Re: bzr commit into mysql-trunk-bugfixing branch (luis.soares:3288)Bug#53386Luís Soares29 Oct