List:Commits« Previous MessageNext Message »
From:He Zhenxing Date:June 27 2008 11:09am
Subject:Re: bzr commit into mysql-5.1 branch (mats:2667) Bug#37426
View as plain text  
Hi, Mats

Nice work! Approved!

Mats Kindahl wrote:
> #At file:///home/bzr/b37426-mysql-5.1-bugteam/
> 
>  2667 Mats Kindahl	2008-06-25
>       BUG#37426: RBR breaks for CHAR() UTF-8 fields > 85 chars
>       
>       In order to handle CHAR() fields, 8 bits were reserved for
>       the size of the CHAR field. However, instead of denoting the
>       number of characters in the field, field_length was used which
>       denotes the number of bytes in the field.
>       
>       Since UTF-8 fields can have three bytes per character (and
>       has been extended to have four bytes per character in 6.0),
>       an extra two bits have been encoded in the field metadata
>       work for fields of type Field_string (i.e., CHAR fields).
>       
>       Since the metadata word is filled, the extra bits have been
>       encoded in the upper 4 bits of the real type (the most 
>       significant byte of the metadata word) by computing the
>       bitwise xor of the extra two bits. Since the upper 4 bits
>       of the real type always is 1111 for Field_string, this 
>       means that for fields of length <256, the encoding is
>       identical to the encoding used in pre-5.1.26 servers, but
>       for lengths of 256 or more, an unrecognized type is formed,
>       causing an old slave (that does not handle lengths of 256
>       or more) to stop.
> added:
>   mysql-test/suite/bugs/r/rpl_bug37426.result
>   mysql-test/suite/bugs/t/rpl_bug37426.test
> modified:
>   mysql-test/extra/rpl_tests/rpl_row_basic.test
>   mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
>   mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
>   sql/field.cc
>   sql/field.h
> 
> per-file messages:
>   mysql-test/extra/rpl_tests/rpl_row_basic.test
>     Adding test cases for replicating UTF-8 fields of lengths
>     of 256 or more (bytes).
>   mysql-test/suite/bugs/r/rpl_bug37426.result
>     Result file change.
>   mysql-test/suite/bugs/t/rpl_bug37426.test
>     Added test for reported bug.
>   mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
>     Result file change.
>   mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
>     Result file change.
>   sql/field.cc
>     Encoding an extra two bits in the most significant nibble (4 bits)
>     of the metadata word. Adding assertions to ensure that no attempt
>     is made to use lengths longer than supported.
>   sql/field.h
>     Field length is now computed from most significant 4 bits
>     of metadata word, or is equal to the row pack length if
>     there is no metadata.
> === modified file 'mysql-test/extra/rpl_tests/rpl_row_basic.test'
> --- a/mysql-test/extra/rpl_tests/rpl_row_basic.test	2007-12-12 19:12:29 +0000
> +++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test	2008-06-25 19:16:37 +0000
> @@ -259,7 +259,7 @@ DELETE FROM t1;
>  query_vertical SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
>  sync_slave_with_master;
>  set @@global.slave_exec_mode= default;
> -let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
> +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
>  disable_query_log;
>  eval SELECT "$last_error" AS Last_SQL_Error;
>  enable_query_log;
> @@ -272,3 +272,150 @@ query_vertical SELECT COUNT(*) FROM t1 O
>  connection master;
>  DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8;
>  sync_slave_with_master;
> +
> +#
> +# BUG#37426: RBR breaks for CHAR() UTF8 fields > 85 chars
> +#
> +
> +# We have 4 combinations to test with respect to the field length
> +# (i.e., the number of bytes) of the CHAR fields:
> +#
> +# 1. Replicating from CHAR<256 to CHAR<256 
> +# 2. Replicating from CHAR<256 to CHAR>255
> +# 3. Replicating from CHAR>255 to CHAR<256
> +# 4. Replicating from CHAR>255 to CHAR>255
> +
> +# We also make a special case of using the max size of a field on the
> +# master, i.e. CHAR(255) in UTF-8, giving another three cases.
> +#
> +# 5. Replicating UTF-8 CHAR(255) to CHAR(<256)
> +# 6. Replicating UTF-8 CHAR(255) to CHAR(>255)
> +# 7. Replicating UTF-8 CHAR(255) to CHAR(255) UTF-8
> +
> +connection master;
> +CREATE TABLE t1 (i INT NOT NULL,
> +                 c CHAR(16) CHARACTER SET utf8 NOT NULL,
> +                 j INT NOT NULL);
> +
> +CREATE TABLE t2 (i INT NOT NULL,
> +                 c CHAR(16) CHARACTER SET utf8 NOT NULL,
> +                 j INT NOT NULL);
> +
> +sync_slave_with_master;
> +ALTER TABLE t2 MODIFY c CHAR(128) CHARACTER SET utf8 NOT NULL;
> +
> +connection master;
> +CREATE TABLE t3 (i INT NOT NULL,
> +                 c CHAR(128) CHARACTER SET utf8 NOT NULL,
> +                 j INT NOT NULL);
> +sync_slave_with_master;
> +ALTER TABLE t3 MODIFY c CHAR(16) CHARACTER SET utf8 NOT NULL;
> +
> +connection master;
> +CREATE TABLE t4 (i INT NOT NULL,
> +                 c CHAR(128) CHARACTER SET utf8 NOT NULL,
> +                 j INT NOT NULL);
> +
> +CREATE TABLE t5 (i INT NOT NULL,
> +                 c CHAR(255) CHARACTER SET utf8 NOT NULL,
> +                 j INT NOT NULL);
> +sync_slave_with_master;
> +ALTER TABLE t5 MODIFY c CHAR(16) CHARACTER SET utf8 NOT NULL;
> +
> +connection master;
> +CREATE TABLE t6 (i INT NOT NULL,
> +                 c CHAR(255) CHARACTER SET utf8 NOT NULL,
> +                 j INT NOT NULL);
> +sync_slave_with_master;
> +ALTER TABLE t6 MODIFY c CHAR(128) CHARACTER SET utf8 NOT NULL;
> +
> +connection master;
> +CREATE TABLE t7 (i INT NOT NULL,
> +                 c CHAR(255) CHARACTER SET utf8 NOT NULL,
> +                 j INT NOT NULL);
> +
> +--echo [expecting slave to replicate correctly]
> +connection master;
> +INSERT INTO t1 VALUES (1, "", 1);
> +INSERT INTO t1 VALUES (2, repeat(_utf8'a', 16), 2);
> +
> +let $diff_table_1=master:test.t1;
> +let $diff_table_2=slave:test.t1;
> +source include/diff_tables.inc;
> +
> +--echo [expecting slave to replicate correctly]
> +connection master;
> +INSERT INTO t2 VALUES (1, "", 1);
> +INSERT INTO t2 VALUES (2, repeat(_utf8'a', 16), 2);
> +
> +let $diff_table_1=master:test.t2;
> +let $diff_table_2=slave:test.t2;
> +source include/diff_tables.inc;
> +
> +--echo [expecting slave to stop]
> +connection master;
> +INSERT INTO t3 VALUES (1, "", 1);
> +INSERT INTO t3 VALUES (2, repeat(_utf8'a', 128), 2);
> +
> +connection slave;
> +source include/wait_for_slave_sql_to_stop.inc;
> +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
> +disable_query_log;
> +eval SELECT "$last_error" AS Last_SQL_Error;
> +enable_query_log;
> +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
> +START SLAVE;
> +source include/wait_for_slave_to_start.inc;
> +
> +--echo [expecting slave to replicate correctly]
> +connection master;
> +INSERT INTO t4 VALUES (1, "", 1);
> +INSERT INTO t4 VALUES (2, repeat(_utf8'a', 128), 2);
> +
> +let $diff_table_1=master:test.t4;
> +let $diff_table_2=slave:test.t4;
> +source include/diff_tables.inc;
> +
> +--echo [expecting slave to stop]
> +connection master;
> +INSERT INTO t5 VALUES (1, "", 1);
> +INSERT INTO t5 VALUES (2, repeat(_utf8'a', 255), 2);
> +
> +connection slave;
> +source include/wait_for_slave_sql_to_stop.inc;
> +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
> +disable_query_log;
> +eval SELECT "$last_error" AS Last_SQL_Error;
> +enable_query_log;
> +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
> +START SLAVE;
> +source include/wait_for_slave_to_start.inc;
> +
> +--echo [expecting slave to stop]
> +connection master;
> +INSERT INTO t6 VALUES (1, "", 1);
> +INSERT INTO t6 VALUES (2, repeat(_utf8'a', 255), 2);
> +
> +connection slave;
> +source include/wait_for_slave_sql_to_stop.inc;
> +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
> +disable_query_log;
> +eval SELECT "$last_error" AS Last_SQL_Error;
> +enable_query_log;
> +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
> +START SLAVE;
> +source include/wait_for_slave_to_start.inc;
> +
> +--echo [expecting slave to replicate correctly]
> +connection master;
> +INSERT INTO t7 VALUES (1, "", 1);
> +INSERT INTO t7 VALUES (2, repeat(_utf8'a', 255), 2);
> +
> +let $diff_table_1=master:test.t7;
> +let $diff_table_2=slave:test.t7;
> +source include/diff_tables.inc;
> +
> +connection master;
> +drop table t1, t2, t3, t4, t5, t6, t7;
> +sync_slave_with_master;
> +
> 
> === added file 'mysql-test/suite/bugs/r/rpl_bug37426.result'
> --- a/mysql-test/suite/bugs/r/rpl_bug37426.result	1970-01-01 00:00:00 +0000
> +++ b/mysql-test/suite/bugs/r/rpl_bug37426.result	2008-06-25 19:16:37 +0000
> @@ -0,0 +1,17 @@
> +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;
> +CREATE TABLE char128_utf8 ( 
> +i1 INT NOT NULL, 
> +c CHAR(128) CHARACTER SET utf8 NOT NULL, 
> +i2 INT NOT NULL);
> +INSERT INTO char128_utf8 VALUES ( 1, "123", 1 );
> +SELECT * FROM char128_utf8;
> +i1	c	i2
> +1	123	1
> +SELECT * FROM char128_utf8;
> +i1	c	i2
> +1	123	1
> 
> === added file 'mysql-test/suite/bugs/t/rpl_bug37426.test'
> --- a/mysql-test/suite/bugs/t/rpl_bug37426.test	1970-01-01 00:00:00 +0000
> +++ b/mysql-test/suite/bugs/t/rpl_bug37426.test	2008-06-25 19:16:37 +0000
> @@ -0,0 +1,22 @@
> +#############################################################
> +# Author: Mats Kindahl <mats@stripped>
> +# Date:   2008-06-18
> +# Purpose: Test for BUG#37426
> +#   RBR breaks for CHAR() UTF8 fields > 85 chars
> +#############################################################
> +
> +source include/master-slave.inc;
> +source include/have_binlog_format_row.inc;
> +
> +connection master;
> +CREATE TABLE char128_utf8 ( 
> +    i1 INT NOT NULL, 
> +    c CHAR(128) CHARACTER SET utf8 NOT NULL, 
> +    i2 INT NOT NULL);
> +
> +INSERT INTO char128_utf8 VALUES ( 1, "123", 1 );
> +
> +SELECT * FROM char128_utf8;
> +sync_slave_with_master;
> +
> +SELECT * FROM char128_utf8;
> 
> === modified file 'mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result'
> --- a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result	2007-12-12 19:12:29 +0000
> +++ b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result	2008-06-25 19:16:37 +0000
> @@ -437,7 +437,70 @@ SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
>  COUNT(*)	0
>  set @@global.slave_exec_mode= default;
>  Last_SQL_Error
> -0
> +
>  SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
>  COUNT(*)	0
>  DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8;
> +CREATE TABLE t1 (i INT NOT NULL,
> +c CHAR(16) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +CREATE TABLE t2 (i INT NOT NULL,
> +c CHAR(16) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +ALTER TABLE t2 MODIFY c CHAR(128) CHARACTER SET utf8 NOT NULL;
> +CREATE TABLE t3 (i INT NOT NULL,
> +c CHAR(128) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +ALTER TABLE t3 MODIFY c CHAR(16) CHARACTER SET utf8 NOT NULL;
> +CREATE TABLE t4 (i INT NOT NULL,
> +c CHAR(128) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +CREATE TABLE t5 (i INT NOT NULL,
> +c CHAR(255) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +ALTER TABLE t5 MODIFY c CHAR(16) CHARACTER SET utf8 NOT NULL;
> +CREATE TABLE t6 (i INT NOT NULL,
> +c CHAR(255) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +ALTER TABLE t6 MODIFY c CHAR(128) CHARACTER SET utf8 NOT NULL;
> +CREATE TABLE t7 (i INT NOT NULL,
> +c CHAR(255) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +[expecting slave to replicate correctly]
> +INSERT INTO t1 VALUES (1, "", 1);
> +INSERT INTO t1 VALUES (2, repeat(_utf8'a', 16), 2);
> +Comparing tables master:test.t1 and slave:test.t1
> +[expecting slave to replicate correctly]
> +INSERT INTO t2 VALUES (1, "", 1);
> +INSERT INTO t2 VALUES (2, repeat(_utf8'a', 16), 2);
> +Comparing tables master:test.t2 and slave:test.t2
> +[expecting slave to stop]
> +INSERT INTO t3 VALUES (1, "", 1);
> +INSERT INTO t3 VALUES (2, repeat(_utf8'a', 128), 2);
> +Last_SQL_Error
> +Table definition on master and slave does not match: Column 1 size mismatch - master
> has size 384, test.t3 on slave has size 49. Master's column size should be <= the
> slave's column size.
> +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
> +START SLAVE;
> +[expecting slave to replicate correctly]
> +INSERT INTO t4 VALUES (1, "", 1);
> +INSERT INTO t4 VALUES (2, repeat(_utf8'a', 128), 2);
> +Comparing tables master:test.t4 and slave:test.t4
> +[expecting slave to stop]
> +INSERT INTO t5 VALUES (1, "", 1);
> +INSERT INTO t5 VALUES (2, repeat(_utf8'a', 255), 2);
> +Last_SQL_Error
> +Table definition on master and slave does not match: Column 1 size mismatch - master
> has size 765, test.t5 on slave has size 49. Master's column size should be <= the
> slave's column size.
> +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
> +START SLAVE;
> +[expecting slave to stop]
> +INSERT INTO t6 VALUES (1, "", 1);
> +INSERT INTO t6 VALUES (2, repeat(_utf8'a', 255), 2);
> +Last_SQL_Error
> +Table definition on master and slave does not match: Column 1 size mismatch - master
> has size 765, test.t6 on slave has size 385. Master's column size should be <= the
> slave's column size.
> +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
> +START SLAVE;
> +[expecting slave to replicate correctly]
> +INSERT INTO t7 VALUES (1, "", 1);
> +INSERT INTO t7 VALUES (2, repeat(_utf8'a', 255), 2);
> +Comparing tables master:test.t7 and slave:test.t7
> +drop table t1, t2, t3, t4, t5, t6, t7;
> 
> === modified file 'mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result'
> --- a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result	2007-12-12 19:12:29 +0000
> +++ b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result	2008-06-25 19:16:37 +0000
> @@ -437,7 +437,70 @@ SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
>  COUNT(*)	0
>  set @@global.slave_exec_mode= default;
>  Last_SQL_Error
> -0
> +
>  SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
>  COUNT(*)	0
>  DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8;
> +CREATE TABLE t1 (i INT NOT NULL,
> +c CHAR(16) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +CREATE TABLE t2 (i INT NOT NULL,
> +c CHAR(16) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +ALTER TABLE t2 MODIFY c CHAR(128) CHARACTER SET utf8 NOT NULL;
> +CREATE TABLE t3 (i INT NOT NULL,
> +c CHAR(128) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +ALTER TABLE t3 MODIFY c CHAR(16) CHARACTER SET utf8 NOT NULL;
> +CREATE TABLE t4 (i INT NOT NULL,
> +c CHAR(128) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +CREATE TABLE t5 (i INT NOT NULL,
> +c CHAR(255) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +ALTER TABLE t5 MODIFY c CHAR(16) CHARACTER SET utf8 NOT NULL;
> +CREATE TABLE t6 (i INT NOT NULL,
> +c CHAR(255) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +ALTER TABLE t6 MODIFY c CHAR(128) CHARACTER SET utf8 NOT NULL;
> +CREATE TABLE t7 (i INT NOT NULL,
> +c CHAR(255) CHARACTER SET utf8 NOT NULL,
> +j INT NOT NULL);
> +[expecting slave to replicate correctly]
> +INSERT INTO t1 VALUES (1, "", 1);
> +INSERT INTO t1 VALUES (2, repeat(_utf8'a', 16), 2);
> +Comparing tables master:test.t1 and slave:test.t1
> +[expecting slave to replicate correctly]
> +INSERT INTO t2 VALUES (1, "", 1);
> +INSERT INTO t2 VALUES (2, repeat(_utf8'a', 16), 2);
> +Comparing tables master:test.t2 and slave:test.t2
> +[expecting slave to stop]
> +INSERT INTO t3 VALUES (1, "", 1);
> +INSERT INTO t3 VALUES (2, repeat(_utf8'a', 128), 2);
> +Last_SQL_Error
> +Table definition on master and slave does not match: Column 1 size mismatch - master
> has size 384, test.t3 on slave has size 49. Master's column size should be <= the
> slave's column size.
> +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
> +START SLAVE;
> +[expecting slave to replicate correctly]
> +INSERT INTO t4 VALUES (1, "", 1);
> +INSERT INTO t4 VALUES (2, repeat(_utf8'a', 128), 2);
> +Comparing tables master:test.t4 and slave:test.t4
> +[expecting slave to stop]
> +INSERT INTO t5 VALUES (1, "", 1);
> +INSERT INTO t5 VALUES (2, repeat(_utf8'a', 255), 2);
> +Last_SQL_Error
> +Table definition on master and slave does not match: Column 1 size mismatch - master
> has size 765, test.t5 on slave has size 49. Master's column size should be <= the
> slave's column size.
> +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
> +START SLAVE;
> +[expecting slave to stop]
> +INSERT INTO t6 VALUES (1, "", 1);
> +INSERT INTO t6 VALUES (2, repeat(_utf8'a', 255), 2);
> +Last_SQL_Error
> +Table definition on master and slave does not match: Column 1 size mismatch - master
> has size 765, test.t6 on slave has size 385. Master's column size should be <= the
> slave's column size.
> +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
> +START SLAVE;
> +[expecting slave to replicate correctly]
> +INSERT INTO t7 VALUES (1, "", 1);
> +INSERT INTO t7 VALUES (2, repeat(_utf8'a', 255), 2);
> +Comparing tables master:test.t7 and slave:test.t7
> +drop table t1, t2, t3, t4, t5, t6, t7;
> 
> === modified file 'sql/field.cc'
> --- a/sql/field.cc	2008-05-13 12:01:02 +0000
> +++ b/sql/field.cc	2008-06-25 19:16:37 +0000
> @@ -4037,7 +4037,6 @@ Field_real::pack(uchar *to, const uchar 
>  {
>    DBUG_ENTER("Field_real::pack");
>    DBUG_ASSERT(max_length >= pack_length());
> -  DBUG_PRINT("debug", ("pack_length(): %u", pack_length()));
>  #ifdef WORDS_BIGENDIAN
>    if (low_byte_first != table->s->db_low_byte_first)
>    {
> @@ -4056,7 +4055,6 @@ Field_real::unpack(uchar *to, const ucha
>                     uint param_data, bool low_byte_first)
>  {
>    DBUG_ENTER("Field_real::unpack");
> -  DBUG_PRINT("debug", ("pack_length(): %u", pack_length()));
>  #ifdef WORDS_BIGENDIAN
>    if (low_byte_first != table->s->db_low_byte_first)
>    {
> @@ -6724,6 +6722,25 @@ uchar *Field_string::pack(uchar *to, con
>     @c param_data argument contains the result of field->real_type() from
>     the master.
>  
> +   @note In order to be able to handle lengths exceeding 255 and be
> +   backwards-compatible with pre-5.1.26 servers, an extra two bits of
> +   the length has been added to the metadata in such a way that if
> +   they are set, a new unrecognized type is generated.  This will
> +   cause pre-5.1-26 servers to stop due to a field type mismatch,
> +   while new servers will be able to extract the extra bits. If the
> +   length is <256, there will be no difference and both a new and an
> +   old server will be able to handle it.
> +
> +   @note The extra two bits are added to bits 13 and 14 of the
> +   parameter data (with 1 being the least siginficant bit and 16 the
> +   most significant bit of the word) by xoring the extra length bits
> +   with the real type.  Since all allowable types have 0xF as most
> +   significant bits, lengths <256 will not affect the real type at
> +   all, while all other values will result in a non-existant type in
> +   the range 17-244.
> +
> +   @see Field_string::do_save_field_metadata
> +
>     @param   to         Destination of the data
>     @param   from       Source of the data
>     @param   param_data Real type (upper) and length (lower) values
> @@ -6736,10 +6753,24 @@ Field_string::unpack(uchar *to,
>                       uint param_data,
>                       bool low_byte_first __attribute__((unused)))
>  {
> -  uint from_length=
> -    param_data ? min(param_data & 0x00ff, field_length) : field_length;
> -  uint length;
> +  uint from_length, length;
> +
> +  /*
> +    Compute the declared length of the field on the master. This is
> +    used to decide if one or two bytes should be read as length.
> +   */
> +  if (param_data)
> +    from_length= (((param_data >> 4) & 0x300) ^ 0x300) + (param_data &
> 0x00ff);
> +  else
> +    from_length= field_length;
>  
> +  DBUG_PRINT("debug",
> +             ("param_data: 0x%x, field_length: %u, from_length: %u",
> +              param_data, field_length, from_length));
> +  /*
> +    Compute the actual length of the data by reading one or two bits
> +    (depending on the declared field length on the master).
> +   */
>    if (from_length > 255)
>    {
>      length= uint2korr(from);
> @@ -6762,14 +6793,37 @@ Field_string::unpack(uchar *to,
>     second byte of the field metadata array at index of *metadata_ptr and
>     *(metadata_ptr + 1).
>  
> +   @note In order to be able to handle lengths exceeding 255 and be
> +   backwards-compatible with pre-5.1.26 servers, an extra two bits of
> +   the length has been added to the metadata in such a way that if
> +   they are set, a new unrecognized type is generated.  This will
> +   cause pre-5.1-26 servers to stop due to a field type mismatch,
> +   while new servers will be able to extract the extra bits. If the
> +   length is <256, there will be no difference and both a new and an
> +   old server will be able to handle it.
> +
> +   @note The extra two bits are added to bits 13 and 14 of the
> +   parameter data (with 1 being the least siginficant bit and 16 the
> +   most significant bit of the word) by xoring the extra length bits
> +   with the real type.  Since all allowable types have 0xF as most
> +   significant bits of the metadata word, lengths <256 will not affect
> +   the real type at all, while all other values will result in a
> +   non-existant type in the range 17-244.
> +
> +   @see Field_string::unpack
> +
>     @param   metadata_ptr   First byte of field metadata
>  
>     @returns number of bytes written to metadata_ptr
>  */
>  int Field_string::do_save_field_metadata(uchar *metadata_ptr)
>  {
> -  *metadata_ptr= real_type();
> -  *(metadata_ptr + 1)= field_length;
> +  DBUG_ASSERT(field_length < 1024);
> +  DBUG_ASSERT((real_type() & 0xF0) == 0xF0);
> +  DBUG_PRINT("debug", ("field_length: %u, real_type: %u",
> +                       field_length, real_type()));
> +  *metadata_ptr= (real_type() ^ ((field_length & 0x300) >> 4));
> +  *(metadata_ptr + 1)= field_length & 0xFF;
>    return 2;
>  }
>  
> 
> === modified file 'sql/field.h'
> --- a/sql/field.h	2008-05-13 12:01:02 +0000
> +++ b/sql/field.h	2008-06-25 19:16:37 +0000
> @@ -1425,7 +1425,12 @@ public:
>    virtual const uchar *unpack(uchar* to, const uchar *from,
>                                uint param_data, bool low_byte_first);
>    uint pack_length_from_metadata(uint field_metadata)
> -  { return (field_metadata & 0x00ff); }
> +  {
> +    DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata));
> +    if (field_metadata == 0)
> +      return row_pack_length();
> +    return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata
> & 0x00ff);
> +  }
>    uint row_pack_length() { return (field_length + 1); }
>    int pack_cmp(const uchar *a,const uchar *b,uint key_length,
>                 my_bool insert_or_update);
> 


Thread
bzr commit into mysql-5.1 branch (mats:2667) Bug#37426Mats Kindahl25 Jun
  • Re: bzr commit into mysql-5.1 branch (mats:2667) Bug#37426He Zhenxing27 Jun