List:Commits« Previous MessageNext Message »
From:Andrei Elkin Date:July 12 2007 2:09pm
Subject:Re: bk commit into 5.1 tree (cbell:1.2538)
View as plain text  
Chuck, hi.


Please find some comments inlined.

> ChangeSet@stripped, 2007-07-11 21:23:09-04:00, cbell@mysql_cab_desk. +12 -0
>   WL#3228 : RBR using different table defs on slave/master
>   
>   This patch adds the ability to store extra field metadata in the table
>   map event. This data can include pack_length() or field_lenght() for
>   fields such as CHAR or VARCHAR enabling developers to add code that
>   can check for compatibilty between master and slave columns. More 
>   importantly, the extra field metadata can be used to store data from the
>   master correctly should a VARCHAR field on the master be <= 255 bytes 
>   while the same field on the slave is > 255 bytes. '
>   
>   The patch also includes the needed changes to unpack to ensure that data
>   which is smaller on the master can be unpacked correctly on the slave.
>   
>   See worklog for additional details.
>
>   mysql-test/r/rpl_colSize.result@stripped, 2007-07-11 21:23:05-04:00,
> cbell@mysql_cab_desk. +0 -0
>     WL#3228 : prototype test
>
>   mysql-test/r/rpl_colSize.result@stripped, 2007-07-11 21:23:05-04:00,
> cbell@mysql_cab_desk. +0 -0
>
>   mysql-test/r/rpl_row_max_relay_size.result@stripped, 2007-07-11 21:23:00-04:00,
> cbell@mysql_cab_desk. +10 -10
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch changes the test result to coincide with changes to binlog
>     size of table map event.
>
>   mysql-test/r/rpl_slave_skip.result@stripped, 2007-07-11 21:23:00-04:00,
> cbell@mysql_cab_desk. +2 -2
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch changes the test result to coincide with changes to binlog
>     size of table map event.
>
>   mysql-test/t/rpl_colSize.test@stripped, 2007-07-11 21:23:05-04:00, cbell@mysql_cab_desk.
> +78 -0
>     WL#3228 : prototype test
>
>   mysql-test/t/rpl_colSize.test@stripped, 2007-07-11 21:23:05-04:00, cbell@mysql_cab_desk.
> +0 -0
>
>   sql/field.cc@stripped, 2007-07-11 21:23:01-04:00, cbell@mysql_cab_desk. +105 -3
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch includes updates to the unpack() methods for the variable
>     length fields. A new parameter was added (from_length) that is the
>     value stored in the field_metadata of the table map from the table_def
>     class. If the value is non-zero and less than what the field on the 
>     slave is then use the from_length else use the original value from the
>     field on the slave.
>
>   sql/field.h@stripped, 2007-07-11 21:23:01-04:00, cbell@mysql_cab_desk. +13 -1
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch includes updates to the unpack() methods for the variable
>     length fields. A new parameter was added (from_length) that is the
>     value stored in the field_metadata of the table map from the table_def
>     class. 
>
>   sql/log_event.cc@stripped, 2007-07-11 21:23:02-04:00, cbell@mysql_cab_desk. +152 -8
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch adds methods to calculate the field metadata size, prepare
>     the field metadata for writing to the binlog, and additions to the
>     Table_map_log_event::write_body method to include the field metadata 
>     in the table map that is written to the binlog.
>
>   sql/log_event.h@stripped, 2007-07-11 21:23:03-04:00, cbell@mysql_cab_desk. +8 -2
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch adds method declarations and variables needed to support
>     storing field metadata in the table map that is written to the binlog.
>
>   sql/rpl_record.cc@stripped, 2007-07-11 21:23:03-04:00, cbell@mysql_cab_desk. +15 -5
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch modifies the unpack_row() method to unpack fields passing in
>     the value from the table_def class. This value is the extra field
>     metadata stored there from the master.
>
>   sql/rpl_rli.h@stripped, 2007-07-11 21:23:04-04:00, cbell@mysql_cab_desk. +10 -0
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch adds a helper function to retrieve the table_def for a given
>     table in the RPL_TABLE_LIST structure.
>
>   sql/rpl_utility.cc@stripped, 2007-07-11 21:23:04-04:00, cbell@mysql_cab_desk. +82 -33
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch adds a helper method that retrieves the correct size 
>     parameter for the field. This method is used to compare the size as
>     sent by the master with that on the slave for all types of fields that
>     can vary in size and storage requirements. 
>
>   sql/rpl_utility.h@stripped, 2007-07-11 21:23:04-04:00, cbell@mysql_cab_desk. +80 -4
>     WL#3228 : RBR using different table defs on slave/master
>     
>     This patch changes the table_def class constructor to pass in the raw
>     data read from the table map and extract it into an array of dimension
>     size (number of fields). It also adds a method to return the field 
>     metadata for any field. The method returns the data stored in the table
>     map or 0 if no data was stored for that field.
>
> diff -Nrup a/mysql-test/r/rpl_row_max_relay_size.result
> b/mysql-test/r/rpl_row_max_relay_size.result
> --- a/mysql-test/r/rpl_row_max_relay_size.result	2007-06-11 16:15:21 -04:00
> +++ b/mysql-test/r/rpl_row_max_relay_size.result	2007-07-11 21:23:00 -04:00
> @@ -30,7 +30,7 @@ Master_User	root
>  Master_Port	MASTER_PORT
>  Connect_Retry	1
>  Master_Log_File	master-bin.000001
> -Read_Master_Log_Pos	58668
> +Read_Master_Log_Pos	59468
>  Relay_Log_File	#
>  Relay_Log_Pos	#
>  Relay_Master_Log_File	master-bin.000001
> @@ -45,7 +45,7 @@ Replicate_Wild_Ignore_Table	
>  Last_Errno	0
>  Last_Error	
>  Skip_Counter	0
> -Exec_Master_Log_Pos	58668
> +Exec_Master_Log_Pos	59468
>  Relay_Log_Space	#
>  Until_Condition	None
>  Until_Log_File	
> @@ -78,7 +78,7 @@ Master_User	root
>  Master_Port	MASTER_PORT
>  Connect_Retry	1
>  Master_Log_File	master-bin.000001
> -Read_Master_Log_Pos	58668
> +Read_Master_Log_Pos	59468
>  Relay_Log_File	#
>  Relay_Log_Pos	#
>  Relay_Master_Log_File	master-bin.000001
> @@ -93,7 +93,7 @@ Replicate_Wild_Ignore_Table	
>  Last_Errno	0
>  Last_Error	
>  Skip_Counter	0
> -Exec_Master_Log_Pos	58668
> +Exec_Master_Log_Pos	59468
>  Relay_Log_Space	#
>  Until_Condition	None
>  Until_Log_File	
> @@ -126,7 +126,7 @@ Master_User	root
>  Master_Port	MASTER_PORT
>  Connect_Retry	1
>  Master_Log_File	master-bin.000001
> -Read_Master_Log_Pos	58668
> +Read_Master_Log_Pos	59468
>  Relay_Log_File	#
>  Relay_Log_Pos	#
>  Relay_Master_Log_File	master-bin.000001
> @@ -141,7 +141,7 @@ Replicate_Wild_Ignore_Table	
>  Last_Errno	0
>  Last_Error	
>  Skip_Counter	0
> -Exec_Master_Log_Pos	58668
> +Exec_Master_Log_Pos	59468
>  Relay_Log_Space	#
>  Until_Condition	None
>  Until_Log_File	
> @@ -217,7 +217,7 @@ Master_User	root
>  Master_Port	MASTER_PORT
>  Connect_Retry	1
>  Master_Log_File	master-bin.000001
> -Read_Master_Log_Pos	58754
> +Read_Master_Log_Pos	59554
>  Relay_Log_File	#
>  Relay_Log_Pos	#
>  Relay_Master_Log_File	master-bin.000001
> @@ -232,7 +232,7 @@ Replicate_Wild_Ignore_Table	
>  Last_Errno	0
>  Last_Error	
>  Skip_Counter	0
> -Exec_Master_Log_Pos	58754
> +Exec_Master_Log_Pos	59554
>  Relay_Log_Space	#
>  Until_Condition	None
>  Until_Log_File	
> @@ -261,7 +261,7 @@ Master_User	root
>  Master_Port	MASTER_PORT
>  Connect_Retry	1
>  Master_Log_File	master-bin.000001
> -Read_Master_Log_Pos	58830
> +Read_Master_Log_Pos	59630
>  Relay_Log_File	#
>  Relay_Log_Pos	#
>  Relay_Master_Log_File	master-bin.000001
> @@ -276,7 +276,7 @@ Replicate_Wild_Ignore_Table	
>  Last_Errno	0
>  Last_Error	
>  Skip_Counter	0
> -Exec_Master_Log_Pos	58830
> +Exec_Master_Log_Pos	59630
>  Relay_Log_Space	#
>  Until_Condition	None
>  Until_Log_File	
> diff -Nrup a/mysql-test/r/rpl_slave_skip.result b/mysql-test/r/rpl_slave_skip.result
> --- a/mysql-test/r/rpl_slave_skip.result	2007-06-13 09:16:26 -04:00
> +++ b/mysql-test/r/rpl_slave_skip.result	2007-07-11 21:23:00 -04:00
> @@ -44,7 +44,7 @@ Master_User	root
>  Master_Port	MASTER_PORT
>  Connect_Retry	1
>  Master_Log_File	master-bin.000001
> -Read_Master_Log_Pos	714
> +Read_Master_Log_Pos	718
>  Relay_Log_File	#
>  Relay_Log_Pos	#
>  Relay_Master_Log_File	master-bin.000001
> @@ -59,7 +59,7 @@ Replicate_Wild_Ignore_Table	
>  Last_Errno	0
>  Last_Error	
>  Skip_Counter	0
> -Exec_Master_Log_Pos	484
> +Exec_Master_Log_Pos	486
>  Relay_Log_Space	#
>  Until_Condition	Master
>  Until_Log_File	master-bin.000001
> diff -Nrup a/mysql-test/t/rpl_colSize.test b/mysql-test/t/rpl_colSize.test
> --- /dev/null	Wed Dec 31 16:00:00 196900
> +++ b/mysql-test/t/rpl_colSize.test	2007-07-11 21:23:05 -04:00
> @@ -0,0 +1,78 @@
> +-- source include/have_binlog_format_row.inc
> +-- source include/master-slave.inc
> +
> +--disable_warnings
> +DROP TABLE IF EXISTS t1;
> +--enable_warnings
> +
> +--echo **** Testing WL#3228 changes. ****
> +
> +--echo *** On Slave ***
> +sync_slave_with_master;
> +STOP SLAVE;
> +RESET SLAVE;
> +
> +eval CREATE TABLE t1 (
> +  a float     (47),
> +  b double    (143,9),
> +  c decimal   (65,30),
> +  d numeric   (4,0),
> +  e bit       (32),
> +  f char      (21),
> +  g varchar   (1300),
> +  h binary    (33),
> +  j varbinary (200),
> +  k enum      ('0','1'),
> +  l set      
> ('1','2','3','4','5','6','7','8','9','0','11','12','13','14','15','16','17','18','19','21','22','23','24','25','26','27','28','29')
> +);
> +
> +--echo *** Create t1 on Master ***
> +connection master;
> +eval CREATE TABLE t1 (
> +  a float     (44),
> +  b double    (10,3),
> +  c decimal   (10,2),
> +  d numeric   (3,0),
> +  e bit       (20),
> +  f char      (10),
> +  g varchar   (100),
> +  h binary    (7),
> +  j varbinary (20),
> +  k enum      ('0'),
> +  l set       ('1','2','3','4','5','6','7','8','9','0')
> +);
> +
> +RESET MASTER;
> +
> +--echo *** Start Slave ***
> +connection slave;
> +START SLAVE;
> +
> +--echo *** Master Data Insert ***
> +connection master;
> +
> +INSERT INTO t1 () VALUES (
> +  17.567, 
> +  2.123, 
> +  10.20, 
> +  125,
> +  3,
> +  'TEST',
> +  'This is a test',
> +  'binary data',
> +  'more binary data',
> +  '0',
> +  '0');
> +
> +SELECT * FROM t1 ORDER BY a;
> +
> +--echo *** Select from slave ***
> +sync_slave_with_master;
> +SELECT * FROM t1 ORDER BY a;
> +
> +--echo *** Drop t1  ***
> +connection master;
> +DROP TABLE t1;
> +sync_slave_with_master;
> +
> +# END 5.1 Test Case
> diff -Nrup a/sql/field.cc b/sql/field.cc
> --- a/sql/field.cc	2007-06-21 11:12:54 -04:00
> +++ b/sql/field.cc	2007-07-11 21:23:01 -04:00
> @@ -2642,6 +2642,31 @@ uint Field_new_decimal::is_equal(Create_
>            (new_field->decimals == dec));
>  }
>  
> +const uchar *Field_new_decimal::unpack(uchar* to, const uchar *from, uint
> from_length)
> +{
> +  uint from_precision= from_length >> 8U;
> +  uint from_decimal= from_length - (from_precision << 8U);
> +  uint length=pack_length();
> +  uint from_pack_len= my_decimal_get_binary_size(from_precision, from_decimal);
> +  uint len= (from_length && (from_pack_len < length)) ?
> +            from_pack_len : length;
> +  if (from_length && (from_pack_len < length))
> +  {
> +    decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION];
> +    decimal_t dec;
> +    dec.len= from_precision;
> +    dec.buf= dec_buf;
> +    double dbl;
> +    bin2decimal((uchar*) from, &dec, from_precision, from_decimal);
> +    decimal2double(&dec, &dbl);
> +    double2decimal(dbl, &dec);
> +    decimal2bin(&dec, to, precision, decimals());
> +    printf ("%f %d.%d\n", dbl, precision, decimals());
> +  }
> +  else
> +    memcpy(to, from, len);
> +  return from+len;
> +}
>  
>  /****************************************************************************
>  ** tiny int
> @@ -6291,6 +6316,27 @@ uchar *Field_string::pack(uchar *to, con
>  }
>  
>  
> +/*
> +  When unpacking data that may be smaller in the "from" than the "to," use
> +  the from_length to unpack rather than the to's length.
> +*/
> +const uchar *Field_string::unpack(uchar *to, const uchar *from, uint from_length)
> +{
> +  uint length= 0;
> +  uint f_length= (from_length && (from_length < field_length)) ? 
> +                from_length : field_length;
> +  if (f_length > 255)
> +  {
> +    length= uint2korr(from);
> +    from+= 2;
> +  }
> +  else
> +    length= (uint) *from++;
> +  memcpy(to, from, (int) length);
> +  bfill(to+length, field_length - length, ' ');
> +  return from+length;
> +}
> +
>  const uchar *Field_string::unpack(uchar *to, const uchar *from)
>  {
>    uint length;
> @@ -6306,7 +6352,6 @@ const uchar *Field_string::unpack(uchar 
>    return from+length;
>  }
>  
> -
>  /*
>    Compare two packed keys
>  
> @@ -6783,7 +6828,34 @@ uchar *Field_varstring::pack_key_from_ke
>  
>  /*
>    unpack field packed with Field_varstring::pack()
> +
> +  When unpacking data that may be smaller in the "from" than the "to," use
> +  the from_length to unpack rather than the to's length_bytes.
>  */
> +const uchar *Field_varstring::unpack(uchar *to, const uchar *from, uint
> from_length)
> +{
> +  uint length;
> +  uint l_bytes= (from_length && (from_length < field_length)) ? 
> +                (from_length <= 255) ? 1 : 2 : length_bytes;
> +  if (l_bytes == 1)
> +    if (length_bytes == 1)
> +      length= (uint) (*to= *from++);
> +    else
> +    {
> +      to[1]= 0;
> +      to[0]= *from++;
> +      length= to[0];
> +    }
> +  else
> +  {
> +    length= uint2korr(from);
> +    to[0]= *from++;
> +    to[1]= *from++;
> +  }
> +  if (length)
> +    memcpy(to+ length_bytes, from, length);
> +  return from+length;
> +}
>  
>  const uchar *Field_varstring::unpack(uchar *to, const uchar *from)
>  {
> @@ -6801,7 +6873,6 @@ const uchar *Field_varstring::unpack(uch
>    return from+length;
>  }
>  
> -
>  int Field_varstring::pack_cmp(const uchar *a, const uchar *b,
>                                uint key_length_arg,
>                                my_bool insert_or_update)
> @@ -7476,6 +7547,14 @@ uchar *Field_blob::pack(uchar *to, const
>    return to+packlength+length;
>  }
>  
> +/*
> +  Note: from_length included to satisfy inheritance rules, but is not needed
> +  for blob fields.
> +*/
> +const uchar *Field_blob::unpack(uchar *to, const uchar *from, uint from_length)
> +{
> +  return unpack(to, from);
> +}
>  
>  const uchar *Field_blob::unpack(uchar *to, const uchar *from)
>  {
> @@ -8524,6 +8603,30 @@ uchar *Field_bit::pack(uchar *to, const 
>  }
>  
>  
> +/*
> +  When unpacking data that may be smaller in the "from" than the "to," use
> +  the from_length to unpack rather than the to's length.
> +*/
> +const uchar *Field_bit::unpack(uchar *to, const uchar *from, uint from_length)
> +{
> +  uint from_bit_len= from_length >> 8U;
> +  uint from_bytes_in_rec= from_length - (from_bit_len << 8U);
> +  if (from_bit_len > 0)
> +  {
> +    /*
> +      set_rec_bits is a macro, don't put the post-increment in the
> +      argument since that might cause strange side-effects.
> +
> +      For the choice of the second argument, see the explanation for
> +      Field_bit::pack().
> +    */
> +    set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, from_bit_len);
> +    from++;
> +  }
> +  memcpy(to, from, from_bytes_in_rec);
> +  return from + from_bytes_in_rec;
> +}
> +
>  const uchar *Field_bit::unpack(uchar *to, const uchar *from)
>  {
>    if (bit_len > 0)
> @@ -8541,7 +8644,6 @@ const uchar *Field_bit::unpack(uchar *to
>    memcpy(to, from, bytes_in_rec);
>    return from + bytes_in_rec;
>  }
> -
>  
>  void Field_bit::set_default()
>  {
> diff -Nrup a/sql/field.h b/sql/field.h
> --- a/sql/field.h	2007-06-15 13:36:14 -04:00
> +++ b/sql/field.h	2007-07-11 21:23:01 -04:00
> @@ -278,7 +278,6 @@ public:
>    inline void set_image(const uchar *buff,uint length, CHARSET_INFO *cs)
>      { memcpy(ptr,buff,length); }
>  
> -
>    /*
>      Copy a field part into an output buffer.
>  

> @@ -343,6 +342,14 @@ public:
>      memcpy(to,from,length);
>      return to+length;
>    }
> +  virtual const uchar *unpack(uchar* to, const uchar *from, uint from_length)
> +  {
> +    uint length=pack_length();
> +    uint len= (from_length && (from_length < length)) ?
> +              from_length : length;
> +    memcpy(to,from,len);
> +    return from+len;
> +  }

Shall we DBUG_ASSERT(from_lenght == 0 || from_length <= length)?
Either unpack with the basic 2-args method or when from_length is
informal it must not exceed the basic's pack_length. In other words
it's good to have a guard against overrun.


>    virtual const uchar *unpack(uchar* to, const uchar *from)
>    {
>      uint length=pack_length();
> @@ -626,6 +633,7 @@ public:
>    uint size_of() const { return sizeof(*this); } 
>    uint32 pack_length() const { return (uint32) bin_size; }
>    uint is_equal(Create_field *new_field);
> +  const uchar *unpack(uchar* to, const uchar *from, uint from_length);
>  };
>  
>  
> @@ -1162,6 +1170,7 @@ public:
>    void sort_string(uchar *buff,uint length);
>    void sql_type(String &str) const;
>    uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0);
> +  const uchar *unpack(uchar* to, const uchar *from, uint from_length);
>    const uchar *unpack(uchar* to, const uchar *from);
>    int pack_cmp(const uchar *a,const uchar *b,uint key_length,
>                 my_bool insert_or_update);
> @@ -1238,6 +1247,7 @@ public:
>    uchar *pack_key(uchar *to, const uchar *from, uint max_length);
>    uchar *pack_key_from_key_image(uchar* to, const uchar *from,
>                                   uint max_length);
> +  const uchar *unpack(uchar* to, const uchar *from, uint from_length);
>    const uchar *unpack(uchar* to, const uchar *from);
>    const uchar *unpack_key(uchar* to, const uchar *from, uint max_length);
>    int pack_cmp(const uchar *a, const uchar *b, uint key_length,
> @@ -1377,6 +1387,7 @@ public:
>    uchar *pack_key(uchar *to, const uchar *from, uint max_length);
>    uchar *pack_key_from_key_image(uchar* to, const uchar *from,
>                                   uint max_length);
> +  const uchar *unpack(uchar *to, const uchar *from, uint from_length);
>    const uchar *unpack(uchar *to, const uchar *from);
>    const uchar *unpack_key(uchar* to, const uchar *from, uint max_length);
>    int pack_cmp(const uchar *a, const uchar *b, uint key_length,
> @@ -1552,6 +1563,7 @@ public:
>    uint32 pack_length_in_rec() const { return bytes_in_rec; }
>    void sql_type(String &str) const;
>    uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0);
> +  const uchar *unpack(uchar* to, const uchar *from, uint from_length);
>    const uchar *unpack(uchar* to, const uchar *from);
>    virtual void set_default();
>  
> diff -Nrup a/sql/log_event.cc b/sql/log_event.cc
> --- a/sql/log_event.cc	2007-06-28 09:07:53 -04:00
> +++ b/sql/log_event.cc	2007-07-11 21:23:02 -04:00
> @@ -6023,11 +6023,8 @@ int Rows_log_event::do_apply_event(RELAY
>  #ifdef HAVE_QUERY_CACHE
>      query_cache.invalidate_locked_for_write(rli->tables_to_lock);
>  #endif
> -    const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
>    }
>  
> -  DBUG_ASSERT(rli->tables_to_lock == NULL && rli->tables_to_lock_count
> == 0);
> -
>    TABLE* table=
> const_cast<RELAY_LOG_INFO*>(rli)->m_table_map.get_table(m_table_id);
>  
>    if (table)
> @@ -6122,6 +6119,15 @@ int Rows_log_event::do_apply_event(RELAY
>      }
>    }
>  
> +  /*
> +    We need to delay this clear until the table def is no longer needed.
> +    The table def is needed in unpack_row().
> +  */
> +  if (rli->tables_to_lock)
> +    const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
> +
> +  DBUG_ASSERT(rli->tables_to_lock == NULL && rli->tables_to_lock_count
> == 0);
> +
>    if (error)
>    {                     /* error has occured during the transaction */
>      rli->report(ERROR_LEVEL, thd->net.last_errno,
> @@ -6370,6 +6376,112 @@ void Rows_log_event::print_helper(FILE *
>  /**************************************************************************
>  	Table_map_log_event member functions and support functions
>  **************************************************************************/
> +/**
> +  * Calculate field metadata size based on the real_type of the field.
> +  *
> +  * @returns int Size of field metadata.
> +  */
> +#if !defined(MYSQL_CLIENT)
> +int Table_map_log_event::get_field_metadata_size()
> +{
> +  DBUG_ENTER("Table_map_log_event::get_field_metadata_size");
> +  int size= 0;
> +  for (unsigned int i= 0 ; i < m_table->s->fields ; i++)
> +  {
> +    switch (m_table->s->field[i]->real_type()) {
> +    case MYSQL_TYPE_DOUBLE:
> +    case MYSQL_TYPE_FLOAT:
> +    {
> +      size++;                         // Store one byte here.
> +      break; 
> +    }
> +    case MYSQL_TYPE_NEWDECIMAL:
> +    case MYSQL_TYPE_ENUM:
> +    case MYSQL_TYPE_STRING:
> +    case MYSQL_TYPE_VARCHAR:
> +    case MYSQL_TYPE_SET:
> +    case MYSQL_TYPE_BIT:
> +    {
> +      size= size + sizeof(short int); // Store short int here.
> +      break;
> +    }
> +    default:
> +      break;
> +    }
> +  }
> +  m_field_metadata_size= size;
> +  DBUG_PRINT("info", ("Table_map_log_event: %d bytes in field metadata.",
> +                       m_field_metadata_size));
> +  DBUG_RETURN(m_field_metadata_size);
> +}
> +#endif /* !defined(MYSQL_CLIENT) */
> +
> +/**
> +  * Save the field metadata based on the real_type of the field.
> +  * The metadata saved depends on the type of the field. Some fields
> +  * store a single byte for pack_length() while others store two bytes
> +  * for field_length (max length).
> +  *
> +  * @returns int 0 = Ok.
> +  */
> +#if !defined(MYSQL_CLIENT)
> +int Table_map_log_event::get_field_metadata()
> +{
> +  DBUG_ENTER("Table_map_log_event::get_field_metadata");
> +  int index= 0;
> +  for (unsigned int i= 0 ; i < m_table->s->fields ; i++)
> +  {
> +    switch (m_table->s->field[i]->real_type()) {
> +    case MYSQL_TYPE_NEWDECIMAL:
> +    {
> +      m_field_metadata[index]= 
> +        (byte)((Field_new_decimal *)m_table->s->field[i])->precision;

> +      index++;

Imo although

   m_field_metadata[index++]

is less readable but is safer
as no chances to forget incrementing of index.

> +      m_field_metadata[index]= 
> +        (byte)((Field_new_decimal *)m_table->s->field[i])->decimals();
> +      index++;
> +      break;
> +    }
> +    case MYSQL_TYPE_DOUBLE:
> +    case MYSQL_TYPE_FLOAT:
> +    {
> +      m_field_metadata[index]= (byte)m_table->s->field[i]->pack_length();
> +      index++;
> +      break;
> +    }
> +    case MYSQL_TYPE_BIT:
> +    { 
> +      m_field_metadata[index]= 
> +        (byte)((Field_bit *)m_table->s->field[i])->bit_len;
> +      index++;
> +      m_field_metadata[index]= 
> +        (byte)((Field_bit *)m_table->s->field[i])->bytes_in_rec;
> +      index++;
> +      break;
> +    }
> +    case MYSQL_TYPE_ENUM:
> +    case MYSQL_TYPE_STRING:
> +    case MYSQL_TYPE_VARCHAR:
> +    {
> +      short int *x= (short int *)&m_field_metadata[index];
> +      int2store(x, m_table->s->field[i]->field_length);
> +      index= index + sizeof(short int);
> +      break;
> +    }
> +    case MYSQL_TYPE_SET:
> +    {
> +      short int *x= (short int *)&m_field_metadata[index];
> +      int2store(x, m_table->s->field[i]->pack_length());
> +      index= index + sizeof(short int);
> +      break;
> +    }
> +    default:
> +      break;
> +    }
> +  }
> +  DBUG_RETURN(0);
> +}
> +#endif /* !defined(MYSQL_CLIENT) */
>  
>  /*
>    Constructor used to build an event for writing to the binary log.
> @@ -6385,7 +6497,7 @@ Table_map_log_event::Table_map_log_event
>      m_dblen(m_dbnam ? tbl->s->db.length : 0),
>      m_tblnam(tbl->s->table_name.str),
>      m_tbllen(tbl->s->table_name.length),
> -    m_colcnt(tbl->s->fields), m_coltype(0),
> +    m_colcnt(tbl->s->fields), m_field_metadata(0),
>      m_table_id(tid),
>      m_flags(flags)
>  {
> @@ -6406,6 +6518,8 @@ Table_map_log_event::Table_map_log_event
>    m_data_size+= m_dblen + 2;	// Include length and terminating \0
>    m_data_size+= m_tbllen + 2;	// Include length and terminating \0
>    m_data_size+= 1 + m_colcnt;	// COLCNT and column types
> +  m_field_metadata_size= get_field_metadata_size();

> +  m_data_size+= m_field_metadata_size + 1;

Suggest to comment:  +1 is due to net_store_length-ing of
m_field_metadata_size, right?
Then it might not be enough as merely the max number of columns is more than
256 (I met a link with "MySQL: Maximum number of columns in one table - 3398").
To multiply the max on 2 or even 4 still keeps the needed size within 2 bytes.

>  
>    /* If malloc fails, catched in is_valid() */
>    if ((m_memory= (uchar*) my_malloc(m_colcnt, MYF(MY_WME))))
> @@ -6414,6 +6528,12 @@ Table_map_log_event::Table_map_log_event
>      for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
>        m_coltype[i]= m_table->field[i]->type();
>    }
> +
> +  /*
> +    Create an array for the field metadata and store it.
> +  */
> +  m_field_metadata= new byte[m_field_metadata_size];
> +  get_field_metadata();
>  }
>  #endif /* !defined(MYSQL_CLIENT) */
>  
> @@ -6429,8 +6549,10 @@ Table_map_log_event::Table_map_log_event
>  #ifndef MYSQL_CLIENT
>    m_table(NULL),
>  #endif
> -  m_memory(NULL)
> +  m_memory(NULL),
> +  m_field_metadata(0), m_field_metadata_size(0)
>  {
> +  unsigned int bytes_read= 0;
>    DBUG_ENTER("Table_map_log_event::Table_map_log_event(const char*,uint,...)");
>  
>    uint8 common_header_len= description_event->common_header_len;
> @@ -6503,12 +6625,24 @@ Table_map_log_event::Table_map_log_event
>      memcpy(m_coltype, ptr_after_colcnt, m_colcnt);
>    }
>  
> +  ptr_after_colcnt= ptr_after_colcnt + m_colcnt;
> +  bytes_read= ptr_after_colcnt - (uchar *)buf;
> +  DBUG_PRINT("info", ("Bytes read: %d.\n", bytes_read));
> +  if (bytes_read < event_len)
> +  {
> +    m_field_metadata_size= net_field_length(&ptr_after_colcnt);
> +
> +    m_field_metadata= new byte[m_field_metadata_size];
> +    memcpy(m_field_metadata, ptr_after_colcnt, m_field_metadata_size);
> +  }
> +
>    DBUG_VOID_RETURN;
>  }
>  #endif
>  
>  Table_map_log_event::~Table_map_log_event()
>  {
> +  delete[] m_field_metadata;
>    my_free(m_memory, MYF(MY_ALLOW_ZERO_PTR));
>  }
>  
> @@ -6639,7 +6773,9 @@ int Table_map_log_event::do_apply_event(
>        inside st_relay_log_info::clear_tables_to_lock() by calling the
>        table_def destructor explicitly.
>      */
> -    new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt);
> +    new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt, 
> +         m_field_metadata, m_field_metadata_size);
> +
>      table_list->m_tabledef_valid= TRUE;
>  
>      /*
> @@ -6653,7 +6789,7 @@ int Table_map_log_event::do_apply_event(
>    }
>  
>    DBUG_RETURN(error);
> -
> + 
>  err:
>    my_free(memory, MYF(MY_WME));
>    DBUG_RETURN(error);
> @@ -6711,12 +6847,20 @@ bool Table_map_log_event::write_data_bod
>    uchar *const cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
>    DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
>  
> +  /*
> +    Store the size of the field metadata.
> +  */
> +  uchar mbuf[sizeof(m_field_metadata_size)];
> +  uchar *const mbuf_end= net_store_length(mbuf, (size_t) m_field_metadata_size);
> +
>    return (my_b_safe_write(file, dbuf,      sizeof(dbuf)) ||
>            my_b_safe_write(file, (const uchar*)m_dbnam,   m_dblen+1) ||
>            my_b_safe_write(file, tbuf,      sizeof(tbuf)) ||
>            my_b_safe_write(file, (const uchar*)m_tblnam,  m_tbllen+1) ||
>            my_b_safe_write(file, cbuf, (size_t) (cbuf_end - cbuf)) ||
> -          my_b_safe_write(file, m_coltype, m_colcnt));
> +          my_b_safe_write(file, m_coltype, m_colcnt) ||
> +          my_b_safe_write(file, mbuf, (size_t) (mbuf_end - mbuf)) ||
> +          my_b_safe_write(file, m_field_metadata, m_field_metadata_size));
>   }
>  #endif
>  
> diff -Nrup a/sql/log_event.h b/sql/log_event.h
> --- a/sql/log_event.h	2007-06-04 19:15:00 -04:00
> +++ b/sql/log_event.h	2007-07-11 21:23:03 -04:00
> @@ -2049,6 +2049,8 @@ public:
>  
>    virtual int get_data_size() { return m_data_size; } 
>  #ifndef MYSQL_CLIENT
> +  virtual int get_field_metadata_size();
> +  virtual int get_field_metadata();
>    virtual bool write_data_header(IO_CACHE *file);
>    virtual bool write_data_body(IO_CACHE *file);
>    virtual const char *get_db() { return m_dbnam; }
> @@ -2079,12 +2081,16 @@ private:
>    size_t         m_tbllen;
>    ulong          m_colcnt;
>    uchar         *m_coltype;

> -

>    uchar         *m_memory;
>    ulong          m_table_id;
>    flag_set       m_flags;

> -

(and of course not to forget on consmetics: usually reviewers ask not to touch unnecessary
lines ... Could you
restore the blank lines above (and there are some places across the
patch) and remove blanks added ?)

>    size_t         m_data_size;
> +
> +  uchar          *m_field_metadata;        // buffer for field metadata
> +  /*
> +    The size of field metadata buffer set by calling get_field_metadata_size()
> +  */
> +  ulong         m_field_metadata_size;   
>  };
>  
>  
> diff -Nrup a/sql/rpl_record.cc b/sql/rpl_record.cc
> --- a/sql/rpl_record.cc	2007-06-11 16:15:28 -04:00
> +++ b/sql/rpl_record.cc	2007-07-11 21:23:03 -04:00
> @@ -17,6 +17,7 @@
>  #include "rpl_rli.h"
>  #include "rpl_record.h"
>  #include "slave.h"                  // Need to pull in slave_print_msg
> +#include "rpl_utility.h"
>  
>  /**
>     Pack a record of data for a table into a format suitable for
> @@ -124,7 +125,6 @@ pack_row(TABLE *table, MY_BITMAP const* 
>  }
>  #endif
>  
> -
>  /**
>     Unpack a row into @c table->record[0].
>  
> @@ -169,6 +169,8 @@ unpack_row(RELAY_LOG_INFO const *rli,
>             uchar const **const row_end, ulong *const master_reclength,
>             MY_BITMAP* const rw_set, Log_event_type const event_type)
>  {

> +  my_bool stop= FALSE;
> +

We spoke about `stop' that's for wl#3915 ie for me, thanks!

   <started askin before found the mail with a prototype code for wl3915>
    it's not changed anymore in the following. Why? Just for testing?

>    DBUG_ENTER("unpack_row");
>    DBUG_ASSERT(row_data);
>    size_t const master_null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
> @@ -191,10 +193,11 @@ unpack_row(RELAY_LOG_INFO const *rli,
>    unsigned int null_mask= 1U;
>    // The "current" null bits
>    unsigned int null_bits= *null_ptr++;
> -  for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)

> +  int i= 0;

   <started askin>
    Another cosmetics wrt to i counter. I'd rather moved initialization in
    increment into for (i=0,...i++) as i is incremented per each loop and
    that would designate it's not needed outside of it.

> +  table_def *tabledef=
> const_cast<RELAY_LOG_INFO*>(rli)->get_tabledef(table);
> +  for (field_ptr= begin_ptr ; field_ptr < end_ptr && !stop ;
> ++field_ptr)
>    {
>      Field *const f= *field_ptr;
> -
>      /*
>        No need to bother about columns that does not exist: they have
>        gotten default values when being emptied above.
> @@ -220,14 +223,21 @@ unpack_row(RELAY_LOG_INFO const *rli,
>          f->set_notnull();
>  
>          /*
> -          We only unpack the field if it was non-null
> +          We only unpack the field if it was non-null.
> +          Use the master's size information if available else call
> +          normal unpack operation.
>          */
> -        pack_ptr= f->unpack(f->ptr, pack_ptr);
> +        if (tabledef->field_metadata(i))
> +          pack_ptr= f->unpack(f->ptr, pack_ptr,
> tabledef->field_metadata(i));
> +        else
> +          pack_ptr= f->unpack(f->ptr, pack_ptr);
>        }
>  
>        bitmap_set_bit(rw_set, f->field_index);
>        null_mask <<= 1;
> +      i++;
>      }
> +
>    }
>  
>    /*
> diff -Nrup a/sql/rpl_rli.h b/sql/rpl_rli.h
> --- a/sql/rpl_rli.h	2007-06-11 16:15:29 -04:00
> +++ b/sql/rpl_rli.h	2007-07-11 21:23:04 -04:00
> @@ -18,6 +18,7 @@
>  
>  #include "rpl_tblmap.h"
>  #include "rpl_reporting.h"
> +#include "rpl_utility.h"
>  
>  struct RPL_TABLE_LIST;
>  

> @@ -300,6 +301,15 @@ typedef struct st_relay_log_info : publi
>    RPL_TABLE_LIST *tables_to_lock;           /* RBR: Tables to lock  */
>    uint tables_to_lock_count;        /* RBR: Count of tables to lock */
>    table_mapping m_table_map;      /* RBR: Mapping table-id to table */
> +
> +  inline table_def *get_tabledef(TABLE *tbl)
> +  {
> +    table_def *td= 0;
> +    for (TABLE_LIST *ptr= tables_to_lock; ptr && !td; ptr=
> ptr->next_global)
> +      if (ptr->table == tbl)
> +        td= &((RPL_TABLE_LIST *)ptr)->m_tabledef;
> +    return (td);
> +  }
>  

Don't have a good solution for get_tabledef which is to be called per
row. 
Computation expence grows with when number of tables. One day we
would like to optimize that...
One idea is to build a table array to fill with the list's
entries. If the list order coincide with the order of Rows_log events'
tables it'd be enough to compare the current array's index or - when all
rows are done for the current table - to switch to the next.



>    /*
>      Last charset (6 bytes) seen by slave SQL thread is cached here; it helps
> diff -Nrup a/sql/rpl_utility.cc b/sql/rpl_utility.cc
> --- a/sql/rpl_utility.cc	2007-06-11 16:15:29 -04:00
> +++ b/sql/rpl_utility.cc	2007-07-11 21:23:04 -04:00
> @@ -16,16 +16,72 @@
>  #include "rpl_utility.h"
>  #include "rpl_rli.h"
>  
> -uint32
> -field_length_from_packed(enum_field_types const field_type, 
> -                         uchar const *const data)
> +/* 
> +  This method gets the field metadata as pertaining to how the field
> +  is stored in the raw data from the master. This can be used to determine
> +  if the sizes are compatible in either max size (length) or if the
> +  packed size is compatible.
> +*/
> +uint get_field_metadata (uint32 type, int col, TABLE *table)
> +{
> +  uint field_size= 0;
> +  switch (type) {
> +  case MYSQL_TYPE_NEWDECIMAL:
> +  {
> +    field_size= (byte)table->field[col]->pack_length() << 8U;
> +    field_size= field_size + ((Field_new_decimal
> *)table->field[col])->decimals();
> +    break;
> +  }
> +  case MYSQL_TYPE_DOUBLE:
> +  case MYSQL_TYPE_FLOAT:
> +  {
> +    field_size= table->field[col]->pack_length();
> +    break;
> +  }
> +  case MYSQL_TYPE_BIT:
> +  {
> +    field_size= ((Field_bit *)table->field[col])->bit_len << 8U;
> +    field_size= field_size + ((Field_bit *)table->field[col])->bytes_in_rec;
> +    break;
> +  }
> +  case MYSQL_TYPE_SET:
> +  case MYSQL_TYPE_STRING:
> +  case MYSQL_TYPE_ENUM:
> +  case MYSQL_TYPE_VARCHAR:
> +  {
> +    field_size= table->field[col]->field_length;
> +    break;
> +  }
> +  default:
> +    field_size= 0;
> +  }
> +  return (field_size);
> +}
> +
> +/*********************************************************************
> + *                   table_def member definitions                    *
> + *********************************************************************/
> +
> +/*
> +  This function returns the field size in raw bytes based on the type
> +  and the encoded field data from the master's raw data.
> +*/
> +uint32 table_def::get_field_size(uint col, uchar *master_data)
>  {
>    uint32 length;
>  
> -  switch (field_type) {
> -  case MYSQL_TYPE_DECIMAL:
> +  switch (type(col)) {
>    case MYSQL_TYPE_NEWDECIMAL:
> -    length= ~(uint32) 0;
> +    length= my_decimal_get_binary_size(m_field_metadata[col] >> 8, 
> +             m_field_metadata[col] - ((m_field_metadata[col] >> 8) <<
> 8));
> +    break;
> +  case MYSQL_TYPE_DECIMAL:
> +  case MYSQL_TYPE_FLOAT:
> +  case MYSQL_TYPE_DOUBLE:
> +  case MYSQL_TYPE_SET:
> +  case MYSQL_TYPE_ENUM:
> +  case MYSQL_TYPE_STRING:
> +    length= m_field_metadata[col];
>      break;
>    case MYSQL_TYPE_YEAR:
>    case MYSQL_TYPE_TINY:
> @@ -45,12 +101,6 @@ field_length_from_packed(enum_field_type
>      length= 8;
>      break;
>  #endif
> -  case MYSQL_TYPE_FLOAT:
> -    length= sizeof(float);
> -    break;
> -  case MYSQL_TYPE_DOUBLE:
> -    length= sizeof(double);
> -    break;
>    case MYSQL_TYPE_NULL:
>      length= 0;
>      break;
> @@ -69,41 +119,31 @@ field_length_from_packed(enum_field_type
>    case MYSQL_TYPE_DATETIME:
>      length= 8;
>      break;
> -    break;
>    case MYSQL_TYPE_BIT:
> -    length= ~(uint32) 0;
> -    break;
> -  default:
> -    /* This case should never be chosen */
> -    DBUG_ASSERT(0);
> -    /* If something goes awfully wrong, it's better to get a string than die */
> -  case MYSQL_TYPE_STRING:
> -    length= uint2korr(data);
> +    length= (m_field_metadata[col] << 8U) >> 8U;
>      break;
> -
> -  case MYSQL_TYPE_ENUM:
> -  case MYSQL_TYPE_SET:
> -  case MYSQL_TYPE_VAR_STRING:
>    case MYSQL_TYPE_VARCHAR:
> -    length= ~(uint32) 0;                               // NYI
> +    length= m_field_metadata[col] + m_field_metadata[col] > 255 ? 2 : 1;
>      break;
> -
>    case MYSQL_TYPE_TINY_BLOB:
>    case MYSQL_TYPE_MEDIUM_BLOB:
>    case MYSQL_TYPE_LONG_BLOB:
>    case MYSQL_TYPE_BLOB:
>    case MYSQL_TYPE_GEOMETRY:
> -    length= ~(uint32) 0;                               // NYI
> +  {
> +    Field_blob *fb= new Field_blob(m_field_metadata[col], TRUE, "temp",
> system_charset_info);
> +    fb->ptr= master_data;
> +    length= fb->pack_length();
> +    delete fb;
>      break;
>    }
> -
> +  default:
> +    length= -1;
> +  }
> +  printf("Calculated field size of col %d is %d\n", col, length);
>    return length;
>  }
>  
> -/*********************************************************************
> - *                   table_def member definitions                    *
> - *********************************************************************/
> -
>  /*
>    Is the definition compatible with a table?
>  
> @@ -112,6 +152,9 @@ int
>  table_def::compatible_with(RELAY_LOG_INFO const *rli_arg, TABLE *table)
>    const
>  {
> +  uint received_size= 0;
> +  uint field_size= 0;
> +
>    /*
>      We only check the initial columns for the tables.
>    */
> @@ -138,8 +181,14 @@ table_def::compatible_with(RELAY_LOG_INF
>                  ER(ER_BINLOG_ROW_WRONG_TABLE_DEF), buf);
>    }
>  
> +  /*
> +    We now check for column type and size compatibility.
> +  */
>    for (uint col= 0 ; col < cols_to_check ; ++col)
>    {
> +    /*
> +      Checking types.
> +    */
>      if (table->field[col]->type() != type(col))
>      {
>        DBUG_ASSERT(col < size() && col < tsh->fields);
> diff -Nrup a/sql/rpl_utility.h b/sql/rpl_utility.h
> --- a/sql/rpl_utility.h	2007-05-23 18:39:21 -04:00
> +++ b/sql/rpl_utility.h	2007-07-11 21:23:04 -04:00
> @@ -25,8 +25,7 @@
>  struct st_relay_log_info;
>  typedef st_relay_log_info RELAY_LOG_INFO;
>  
> -uint32
> -field_length_from_packed(enum_field_types field_type, uchar const *data);
> +uint get_field_metadata (uint32 type, int col, TABLE *table);
>  
>  /**
>    A table definition from the master.
> @@ -58,18 +57,74 @@ public:
>      @param types Array of types
>      @param size  Number of elements in array 'types'
>     */
> -  table_def(field_type *types, ulong size)
> -    : m_size(size), m_type(new unsigned char [size])
> +  table_def(field_type *types, ulong size, byte *field_metadata, 
> +      int metadata_size)
> +    : m_size(size), m_type(new unsigned char [size]), m_field_metadata(0)
>    {
>      if (m_type)
>        memcpy(m_type, types, size);
>      else
>        m_size= 0;
> +    /*
> +      Extract the data from the table map into the field metadata array
> +      iff there is field metadata. The variable metadata_size will be
> +      0 if we are replicating from a down-level server hence no field
> +      metadata was written to the table map. This can also happen if 
> +      there were no fields in the master that needed extra metadata.
> +    */
> +    if (m_size && metadata_size)
> +    {
> +      m_field_metadata= new short int[m_size];
> +      int index= 0;
> +      for (unsigned int i= 0; i < m_size; i++)
> +      {
> +        switch (m_type[i]) {
> +        case MYSQL_TYPE_DOUBLE:
> +        case MYSQL_TYPE_FLOAT:
> +        {
> +          /*
> +            These types store a single byte.
> +          */
> +          m_field_metadata[i]= (byte)field_metadata[index];
> +          index++;
> +          break;
> +        }
> +        case MYSQL_TYPE_SET:
> +        case MYSQL_TYPE_ENUM:
> +        case MYSQL_TYPE_STRING:
> +        case MYSQL_TYPE_VARCHAR:
> +        {
> +          /*
> +            These types store two bytes.
> +          */
> +          short int *x= (short int *)&field_metadata[index];
> +          m_field_metadata[i]= sint2korr(x);
> +          index= index + sizeof(short int);
> +          break;
> +        }
> +        case MYSQL_TYPE_NEWDECIMAL:
> +        case MYSQL_TYPE_BIT:
> +        {
> +          short int x= field_metadata[index] << 8U; // bit_len
> +          index++;
> +          x = x + field_metadata[index];
> +          m_field_metadata[i]= x;
> +          index++;
> +          break;
> +        }
> +        default:
> +          m_field_metadata[i]= 0;
> +          break;
> +        }
> +      }
> +    }
>    }
>  
>    ~table_def() {
>      if (m_type)
>        delete [] m_type;
> +    if (m_field_metadata)
> +      delete [] m_field_metadata;
>  #ifndef DBUG_OFF
>      m_type= 0;
>      m_size= 0;
> @@ -99,6 +154,26 @@ public:
>      return m_type[index];
>    }
>  
> +  /*
> +    This function allows callers to get the extra field data from the
> +    table map for a given field. If there is no metadata for that field
> +    or there is no extra metadata at all, the function returns 0.
> +  */
> +  uint field_metadata(uint index) const
> +  {
> +    DBUG_ASSERT(index < m_size);
> +    if (m_field_metadata)
> +      return m_field_metadata[index];
> +    else
> +      return 0;
> +  }
> +
> +  /*
> +    This function returns the field size in raw bytes based on the type
> +    and the encoded field data from the master's raw data.
> +  */
> +  uint32 get_field_size(uint col, uchar *master_data);
> +
>    /**
>      Decide if the table definition is compatible with a table.
>  
> @@ -121,6 +196,7 @@ public:
>  private:
>    ulong m_size;           // Number of elements in the types array
>    field_type *m_type;                     // Array of type descriptors
> +  short int *m_field_metadata;
>  };
>  
>  /**
>
>

Besides the code in the patch I was thinking on emulation of old ->
new replication. 
There is a DBUG_EXECUTE_IF() examples left by Mats probably to emulate
a similar scenario when table_map event got changed.

regards,

Andrei
Thread
bk commit into 5.1 tree (cbell:1.2538)cbell12 Jul
  • Re: bk commit into 5.1 tree (cbell:1.2538)Andrei Elkin12 Jul
    • RE: bk commit into 5.1 tree (cbell:1.2538)Chuck Bell12 Jul