List:Commits« Previous MessageNext Message »
From:tomas Date:July 27 2007 8:06pm
Subject:bk commit into 5.1 tree (tomas:1.2594)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of tomas. When tomas does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-07-27 22:06:29+02:00, tomas@stripped +6 -0
  Merge whalegate.ndb.mysql.com:/home/tomas/mysql-5.1-new-ndb
  into  whalegate.ndb.mysql.com:/home/tomas/mysql-5.1-telco-6.2
  MERGE: 1.2506.1.63

  mysql-test/r/rpl_ndb_log.result@stripped, 2007-07-27 22:03:23+02:00, tomas@stripped +0 -0
    Auto merged
    MERGE: 1.18.1.9

  mysql-test/t/disabled.def@stripped, 2007-07-27 22:03:23+02:00, tomas@stripped +0 -0
    Auto merged
    MERGE: 1.243.1.16

  sql/field.cc@stripped, 2007-07-27 22:03:23+02:00, tomas@stripped +0 -0
    Auto merged
    MERGE: 1.393.1.2

  sql/field.h@stripped, 2007-07-27 22:03:23+02:00, tomas@stripped +0 -0
    Auto merged
    MERGE: 1.225.1.3

  sql/ha_ndbcluster.cc@stripped, 2007-07-27 22:03:24+02:00, tomas@stripped +0 -0
    Auto merged
    MERGE: 1.408.1.55

  sql/log_event.cc@stripped, 2007-07-27 22:06:26+02:00, tomas@stripped +0 -0
    manual merge
    MERGE: 1.271.1.11

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	tomas
# Host:	whalegate.ndb.mysql.com
# Root:	/home/tomas/mysql-5.1-telco-6.2/RESYNC

--- 1.395/sql/field.cc	2007-07-06 22:30:40 +02:00
+++ 1.396/sql/field.cc	2007-07-27 22:03:23 +02:00
@@ -1358,6 +1358,49 @@
 }
 
 
+/**
+   Unpack a field from row data.
+
+   This method is used to unpack a field from a master whose size 
+   of the field is less than that of the slave.
+  
+   @param   to         Destination of the data
+   @param   from       Source of the data
+   @param   param_data Pack length of the field data
+
+   @return  New pointer into memory based on from + length of the data
+*/
+const char *Field::unpack(char* to, const char *from, uint param_data)
+{
+  uint length=pack_length();
+  int from_type= 0;
+  /*
+    If from length is > 255, it has encoded data in the upper bits. Need
+    to mask it out.
+  */
+  if (param_data > 255)
+  {
+    from_type= (param_data & 0xff00) >> 8U;  // real_type.
+    param_data= param_data & 0x00ff;        // length.
+  }
+  uint len= (param_data && (param_data < length)) ?
+            param_data : length;
+  /*
+    If the length is the same, use old unpack method.
+    If the param_data is 0, use the old unpack method.
+      This is possible if the table map was generated from a down-level
+      master or if the data was not available on the master.
+    If the real_types are not the same, use the old unpack method.
+  */
+  if ((length == param_data) ||
+      (param_data == 0) ||
+      (from_type != real_type()))
+    return(unpack(to, from));
+  memcpy(to, from, param_data > length ? length : len);
+  return from+len;
+}
+
+
 my_decimal *Field::val_decimal(my_decimal *decimal)
 {
   /* This never have to be called */
@@ -2635,6 +2678,51 @@
           (new_field->decimals == dec));
 }
 
+/**
+   Unpack a decimal field from row data.
+
+   This method is used to unpack a decimal or numeric field from a master
+   whose size of the field is less than that of the slave.
+  
+   @param   to         Destination of the data
+   @param   from       Source of the data
+   @param   param_data Precision (upper) and decimal (lower) values
+
+   @return  New pointer into memory based on from + length of the data
+*/
+const char *Field_new_decimal::unpack(char* to, 
+                                      const char *from, 
+                                      uint param_data)
+{
+  uint from_precision= (param_data & 0xff00) >> 8U;
+  uint from_decimal= param_data & 0x00ff;
+  uint length=pack_length();
+  uint from_pack_len= my_decimal_get_binary_size(from_precision, from_decimal);
+  uint len= (param_data && (from_pack_len < length)) ?
+            from_pack_len : length;
+  if (from_pack_len && (from_pack_len < length))
+  {
+    /*
+      If the master's data is smaller than the slave, we need to convert
+      the binary to decimal then resize the decimal converting it back to
+      a decimal and write that to the raw data buffer.
+    */
+    decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION];
+    decimal_t dec;
+    dec.len= from_precision;
+    dec.buf= dec_buf;
+    /*
+      Note: bin2decimal does not change the length of the field. So it is
+      just the first step the resizing operation. The second step does the
+      resizing using the precision and decimals from the slave.
+    */
+    bin2decimal((char *)from, &dec, from_precision, from_decimal);
+    decimal2bin(&dec, to, precision, decimals());
+  }
+  else
+    memcpy(to, from, len); // Sizes are the same, just copy the data.
+  return from+len;
+}
 
 /****************************************************************************
 ** tiny int
@@ -6294,6 +6382,37 @@
 }
 
 
+/**
+   Unpack a string field from row data.
+
+   This method is used to unpack a string field from a master whose size 
+   of the field is less than that of the slave. Note that there can be a
+   variety of field types represented with this class. Certain types like
+   ENUM or SET are processed differently. Hence, the upper byte of the 
+   @c param_data argument contains the result of field->real_type() from
+   the master.
+
+   @param   to         Destination of the data
+   @param   from       Source of the data
+   @param   param_data Real type (upper) and length (lower) values
+
+   @return  New pointer into memory based on from + length of the data
+*/
+const char *Field_string::unpack(char *to,
+                                 const char *from,
+                                 uint param_data)
+{
+  uint from_len= param_data & 0x00ff;                 // length.
+  uint length= 0;
+  uint f_length= (from_len < field_length) ? from_len : field_length;
+  DBUG_ASSERT(f_length <= 255);
+  length= (uint) *from++;
+  bitmap_set_bit(table->write_set,field_index);
+  store(from, length, system_charset_info);
+  return from+length;
+}
+
+
 const char *Field_string::unpack(char *to, const char *from)
 {
   uint length;
@@ -6787,6 +6906,44 @@
 }
 
 
+/**
+   Unpack a varstring field from row data.
+
+   This method is used to unpack a varstring field from a master
+   whose size of the field is less than that of the slave.
+  
+   @param   to         Destination of the data
+   @param   from       Source of the data
+   @param   param_data Length bytes from the master's field data
+
+   @return  New pointer into memory based on from + length of the data
+*/
+const char *Field_varstring::unpack(char *to, 
+                                    const char *from,
+                                    uint param_data)
+{
+  uint length;
+  uint l_bytes= (param_data && (param_data < field_length)) ? 
+                (param_data <= 255) ? 1 : 2 : length_bytes;
+  if (l_bytes == 1)
+  {
+    to[0]= *from++;
+    length= to[0];
+    if (length_bytes == 2)
+      to[1]= 0;
+  }
+  else
+  {
+    length= uint2korr(from);
+    to[0]= *from++;
+    to[1]= *from++;
+  }
+  if (length)
+    memcpy(to+ length_bytes, from, length);
+  return from+length;
+}
+
+
 /*
   unpack field packed with Field_varstring::pack()
 */
@@ -7478,6 +7635,29 @@
 }
 
 
+/**
+   Unpack a blob field from row data.
+
+   This method is used to unpack a blob field from a master whose size of 
+   the field is less than that of the slave. Note: This method is included
+   to satisfy inheritance rules, but is not needed for blob fields. It
+   simply is used as a pass-through to the original unpack() method for
+   blob fields.
+
+   @param   to         Destination of the data
+   @param   from       Source of the data
+   @param   param_data <not used>
+
+   @return  New pointer into memory based on from + length of the data
+*/
+const char *Field_blob::unpack(char *to, 
+                               const char *from,
+                               uint param_data)
+{
+  return unpack(to, from);
+}
+
+
 const char *Field_blob::unpack(char *to, const char *from)
 {
   memcpy(to,from,packlength);
@@ -8512,6 +8692,58 @@
   length= min(bytes_in_rec, max_length - (bit_len > 0));
   memcpy(to, from, length);
   return to + length;
+}
+
+
+/**
+   Unpack a bit field from row data.
+
+   This method is used to unpack a bit field from a master whose size 
+   of the field is less than that of the slave.
+  
+   @param   to         Destination of the data
+   @param   from       Source of the data
+   @param   param_data Bit length (upper) and length (lower) values
+
+   @return  New pointer into memory based on from + length of the data
+*/
+const char *Field_bit::unpack(char *to,
+                              const char *from,
+                              uint param_data)
+{
+  uint const from_len= (param_data >> 8U) & 0x00ff;
+  uint const from_bit_len= param_data & 0x00ff;
+  /*
+    If the master and slave have the same sizes, then use the old
+    unpack() method.
+  */
+  if ((from_bit_len == bit_len) &&
+      (from_len == bytes_in_rec)) 
+    return(unpack(to, from));
+  /*
+    We are converting a smaller bit field to a larger one here.
+    To do that, we first need to construct a raw value for the original
+    bit value stored in the from buffer. Then that needs to be converted
+    to the larger field then sent to store() for writing to the field.
+    Lastly the odd bits need to be masked out if the bytes_in_rec > 0.
+    Otherwise stray bits can cause spurious values.
+  */
+  uint new_len= (field_length + 7) / 8;
+  char *value= (char *)my_alloca(new_len);
+  bzero(value, new_len);
+  uint len= from_len + ((from_bit_len > 0) ? 1 : 0);
+  memcpy(value + (new_len - len), from, len);
+  /*
+    Mask out the unused bits in the partial byte. 
+    TODO: Add code to the master to always mask these bits and remove
+          the following.
+  */
+  if ((from_bit_len > 0) && (from_len > 0))
+    value[new_len - len]= value[new_len - len] & ((1U << from_bit_len) - 1);
+  bitmap_set_bit(table->write_set,field_index);
+  store(value, new_len, system_charset_info);
+  my_afree(value);
+  return from + len;
 }
 
 

--- 1.228/sql/field.h	2007-07-06 22:30:41 +02:00
+++ 1.229/sql/field.h	2007-07-27 22:03:23 +02:00
@@ -349,6 +349,7 @@
     memcpy(to,from,length);
     return to+length;
   }
+  virtual const char *unpack(char* to, const char *from, uint param_data);
   virtual const char *unpack(char* to, const char *from)
   {
     uint length=pack_length();
@@ -632,6 +633,7 @@
   uint size_of() const { return sizeof(*this); } 
   uint32 pack_length() const { return (uint32) bin_size; }
   uint is_equal(create_field *new_field);
+  virtual const char *unpack(char* to, const char *from, uint param_data);
 };
 
 
@@ -1173,6 +1175,7 @@
   void sort_string(char *buff,uint length);
   void sql_type(String &str) const;
   char *pack(char *to, const char *from, uint max_length=~(uint) 0);
+  virtual const char *unpack(char* to, const char *from, uint param_data);
   const char *unpack(char* to, const char *from);
   int pack_cmp(const char *a,const char *b,uint key_length,
                my_bool insert_or_update);
@@ -1243,6 +1246,7 @@
   char *pack(char *to, const char *from, uint max_length=~(uint) 0);
   char *pack_key(char *to, const char *from, uint max_length);
   char *pack_key_from_key_image(char* to, const char *from, uint max_length);
+  virtual const char *unpack(char* to, const char *from, uint param_data);
   const char *unpack(char* to, const char *from);
   const char *unpack_key(char* to, const char *from, uint max_length);
   int pack_cmp(const char *a, const char *b, uint key_length,
@@ -1299,6 +1303,9 @@
                   l_char_length <= 16777215 ? 3 : 4;
     }
   }
+  Field_blob(uint32 packlength_arg)
+    :Field_longstr((char*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info),
+    packlength(packlength_arg) {}
   enum_field_types type() const { return MYSQL_TYPE_BLOB;}
   enum ha_base_keytype key_type() const
     { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; }
@@ -1320,6 +1327,17 @@
   void sort_string(char *buff,uint length);
   uint32 pack_length() const
   { return (uint32) (packlength+table->s->blob_ptr_size); }
+
+  /**
+     Return the packed length without the pointer size added. 
+
+     This is used to determine the size of the actual data in the row
+     buffer.
+
+     @retval The length of the raw data itself without the pointer.
+  */
+  uint32 pack_length_no_ptr() const
+  { return (uint32) (packlength); }
   uint32 sort_length() const;
   inline uint32 max_data_length() const
   {
@@ -1336,6 +1354,17 @@
     store_length(ptr, packlength, number);
   }
 
+  /**
+     Return the packed length plus the length of the data. 
+
+     This is used to determine the size of the data plus the 
+     packed length portion in the row data.
+
+     @retval The length in the row plus the size of the data.
+  */
+  uint32 get_packed_size(const uchar *ptr)
+    {return packlength + get_length((uint)ptr);}
+
   inline uint32 get_length(uint row_offset=0)
   { return get_length(ptr+row_offset); }
   uint32 get_length(const char *ptr);
@@ -1380,6 +1409,7 @@
   char *pack(char *to, const char *from, uint max_length= ~(uint) 0);
   char *pack_key(char *to, const char *from, uint max_length);
   char *pack_key_from_key_image(char* to, const char *from, uint max_length);
+  virtual const char *unpack(char *to, const char *from, uint param_data);
   const char *unpack(char *to, const char *from);
   const char *unpack_key(char* to, const char *from, uint max_length);
   int pack_cmp(const char *a, const char *b, uint key_length,
@@ -1554,6 +1584,7 @@
   uint32 pack_length_in_rec() const { return bytes_in_rec; }
   void sql_type(String &str) const;
   char *pack(char *to, const char *from, uint max_length=~(uint) 0);
+  virtual const char *unpack(char *to, const char *from, uint param_data);
   const char *unpack(char* to, const char *from);
   virtual void set_default();
 

--- 1.280/sql/log_event.cc	2007-07-11 14:37:59 +02:00
+++ 1.281/sql/log_event.cc	2007-07-27 22:06:26 +02:00
@@ -5976,11 +5976,8 @@
 #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)
@@ -6082,6 +6079,13 @@
     }
   }
 
+  /*
+    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 && get_flags(STMT_END_F))
+    const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
+
   /* reset OPTION_ALLOW_BATCH as not affect later events */
   thd->options&= ~OPTION_ALLOW_BATCH;
 
@@ -6323,6 +6327,163 @@
 	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)
+const int Table_map_log_event::calc_field_metadata_size()
+{
+  DBUG_ENTER("Table_map_log_event::calc_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_TINY_BLOB:
+    case MYSQL_TYPE_BLOB:
+    case MYSQL_TYPE_MEDIUM_BLOB:
+    case MYSQL_TYPE_LONG_BLOB:
+    case MYSQL_TYPE_DOUBLE:
+    case MYSQL_TYPE_FLOAT:
+    {
+      size++;                         // Store one byte here.
+      break; 
+    }
+    case MYSQL_TYPE_BIT:
+    case MYSQL_TYPE_NEWDECIMAL:
+    case MYSQL_TYPE_ENUM:
+    case MYSQL_TYPE_STRING:
+    case MYSQL_TYPE_VARCHAR:
+    case MYSQL_TYPE_SET:
+    {
+      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.",
+                       (int)m_field_metadata_size));
+  DBUG_RETURN(m_field_metadata_size);
+}
+#endif /* !defined(MYSQL_CLIENT) */
+
+/**
+  @page How replication of field metadata works.
+  
+  When a table map is created, the master first calls 
+  Table_map_log_event::get_field_metadata_size() which calculates how many 
+  values will be in the field metadata. Only those fields that require the 
+  extra data are added (see table above). The master then loops through all
+  of the fields in the table calling the method 
+  Table_map_log_event::get_field_metadata() which returns the values for the 
+  field that will be saved in the metadata and replicated to the slave. Once 
+  all fields have been processed, the table map is written to the binlog 
+  adding the size of the field metadata and the field metadata to the end of 
+  the body of the table map.
+  
+  When a table map is read on the slave, the field metadata is read from the 
+  table map and passed to the table_def class constructor which saves the 
+  field metadata from the table map into an array based on the type of the 
+  field. Field metadata values not present (those fields that do not use extra 
+  data) in the table map are initialized as zero (0). The array size is the 
+  same as the columns for the table on the slave.
+
+*/
+
+/**
+  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).
+  
+  @retval 0 Ok.
+
+  TODO: We may want to consider changing the encoding of the information.
+  Currently, the code attempts to minimize the number of bytes written to 
+  the tablemap. There are at least two other alternatives; 1) using 
+  net_store_length() to store the data allowing it to choose the number of
+  bytes that are appropriate thereby making the code much easier to 
+  maintain (only 1 place to change the encoding), or 2) use a fixed number
+  of bytes for each field. The problem with option 1 is that net_store_length()
+  will use one byte if the value < 251, but 3 bytes if it is > 250. Thus,
+  for fields like CHAR which can be no larger than 255 characters, the method
+  will use 3 bytes when the value is > 250. Further, every value that is
+  encoded using 2 parts (e.g., pack_length, field_length) will be numerically
+  > 250 therefore will use 3 bytes for eah value. The problem with option 2
+  is less wasteful for space but does waste 1 byte for every field that does
+  not encode 2 parts. 
+*/
+#if !defined(MYSQL_CLIENT)
+int Table_map_log_event::save_field_metadata()
+{
+  DBUG_ENTER("Table_map_log_event::save_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++]= 
+        (uchar)((Field_new_decimal *)m_table->s->field[i])->precision;
+      m_field_metadata[index++]= 
+        (uchar)((Field_new_decimal *)m_table->s->field[i])->decimals();
+      break;
+    }
+    case MYSQL_TYPE_TINY_BLOB:
+    case MYSQL_TYPE_BLOB:
+    case MYSQL_TYPE_MEDIUM_BLOB:
+    case MYSQL_TYPE_LONG_BLOB:
+    {
+      m_field_metadata[index++]= 
+       (uchar)((Field_blob *)m_table->s->field[i])->pack_length_no_ptr();
+      break;
+    }
+    case MYSQL_TYPE_DOUBLE:
+    case MYSQL_TYPE_FLOAT:
+    {
+      m_field_metadata[index++]= (uchar)m_table->s->field[i]->pack_length();
+      break;
+    }
+    case MYSQL_TYPE_BIT:
+    { 
+      m_field_metadata[index++]= 
+        (uchar)((Field_bit *)m_table->s->field[i])->bit_len;
+      m_field_metadata[index++]= 
+        (uchar)((Field_bit *)m_table->s->field[i])->bytes_in_rec;
+      break;
+    }
+    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_STRING:
+    {
+      m_field_metadata[index++]= (uchar)m_table->s->field[i]->real_type();
+      m_field_metadata[index++]= m_table->s->field[i]->field_length;
+      break;
+    }
+    case MYSQL_TYPE_ENUM:
+    case MYSQL_TYPE_SET:
+    {
+      m_field_metadata[index++]= (uchar)m_table->s->field[i]->real_type();
+      m_field_metadata[index++]= m_table->s->field[i]->pack_length();
+      break;
+    }
+    default:
+      break;
+    }
+  }
+  DBUG_RETURN(0);
+}
+#endif /* !defined(MYSQL_CLIENT) */
+
 /*
   Constructor used to build an event for writing to the binary log.
   Mats says tbl->s lives longer than this event so it's ok to copy pointers
@@ -6337,9 +6498,8 @@
     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_table_id(tid),
-    m_flags(flags)
+    m_colcnt(tbl->s->fields), m_field_metadata(0),
+    m_table_id(tid), m_null_bits(0), m_flags(flags)
 {
   DBUG_ASSERT(m_table_id != ~0UL);
   /*
@@ -6358,6 +6518,16 @@
   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= calc_field_metadata_size();
+
+  /*
+    Now set the size of the data to the size of the field metadata array
+    plus one or two bytes for number of elements in the field metadata array.
+  */
+  if (m_field_metadata_size > 255)
+    m_data_size+= m_field_metadata_size + 2; 
+  else
+    m_data_size+= m_field_metadata_size + 1; 
 
   /* If malloc fails, catched in is_valid() */
   if ((m_memory= my_malloc(m_colcnt, MYF(MY_WME))))
@@ -6366,6 +6536,28 @@
     for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
       m_coltype[i]= m_table->field[i]->type();
   }
+
+  /*
+    Calculate a bitmap for the results of maybe_null() for all columns.
+    The bitmap is used to determine when there is a column from the master
+    that is not on the slave and is null and thus not in the row data during
+    replication.
+  */
+  uint num_null_bytes= (m_table->s->fields + 7) / 8;
+  m_data_size+= num_null_bytes;
+  m_meta_memory= my_multi_malloc(MYF(MY_WME),
+                                 &m_null_bits, num_null_bytes,
+                                 &m_field_metadata, m_field_metadata_size,
+                                 NULL);
+  bzero(m_null_bits, num_null_bytes);
+  for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+    if (m_table->field[i]->maybe_null())
+      m_null_bits[(i / 8)]+= 1 << (i % 8);
+
+  /*
+    Create an array for the field metadata and store it.
+  */
+  save_field_metadata();
 }
 #endif /* !defined(MYSQL_CLIENT) */
 
@@ -6381,8 +6573,10 @@
 #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;
@@ -6453,6 +6647,22 @@
     strncpy(const_cast<char*>(m_dbnam), (const char*)ptr_dblen  + 1, m_dblen + 1);
     strncpy(const_cast<char*>(m_tblnam), (const char*)ptr_tbllen + 1, m_tbllen + 1);
     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);
+      uint num_null_bytes= (m_colcnt + 7) / 8;
+      m_meta_memory= my_multi_malloc(MYF(MY_WME),
+                                     &m_null_bits, num_null_bytes,
+                                     &m_field_metadata, m_field_metadata_size,
+                                     NULL);
+      memcpy(m_field_metadata, ptr_after_colcnt, m_field_metadata_size);
+      ptr_after_colcnt= (uchar*)ptr_after_colcnt + m_field_metadata_size;
+      memcpy(m_null_bits, ptr_after_colcnt, num_null_bytes);
+    }
   }
 
   DBUG_VOID_RETURN;
@@ -6461,6 +6671,7 @@
 
 Table_map_log_event::~Table_map_log_event()
 {
+  my_free(m_meta_memory, MYF(MY_ALLOW_ZERO_PTR));
   my_free(m_memory, MYF(MY_ALLOW_ZERO_PTR));
 }
 
@@ -6594,7 +6805,8 @@
       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, m_null_bits);
     table_list->m_tabledef_valid= TRUE;
 
     /*
@@ -6653,13 +6865,22 @@
   char *const cbuf_end= net_store_length((char*) cbuf, (uint) m_colcnt);
   DBUG_ASSERT(static_cast<my_size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
 
+  /*
+    Store the size of the field metadata.
+  */
+  char mbuf[sizeof(m_field_metadata_size)];
+  char *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 byte*)m_dbnam,   m_dblen+1) ||
           my_b_safe_write(file, tbuf,      sizeof(tbuf)) ||
           my_b_safe_write(file, (const byte*)m_tblnam,  m_tbllen+1) ||
           my_b_safe_write(file, reinterpret_cast<byte*>(cbuf),
                           cbuf_end - (char*) cbuf) ||
-          my_b_safe_write(file, reinterpret_cast<byte*>(m_coltype), m_colcnt));
+          my_b_safe_write(file, reinterpret_cast<byte*>(m_coltype), m_colcnt) ||
+          my_b_safe_write(file, reinterpret_cast<byte*>(mbuf), (size_t) (mbuf_end - mbuf)) ||
+          my_b_safe_write(file, reinterpret_cast<byte*>(m_field_metadata), m_field_metadata_size),
+          my_b_safe_write(file, reinterpret_cast<byte*>(m_null_bits), (m_colcnt + 7) / 8));
  }
 #endif
 
@@ -6855,6 +7076,7 @@
                          my_size_t master_reclength,
                          my_ptrdiff_t master_fields)
 {
+  DBUG_ENTER("copy_extra_record_fields(table, master_reclen, master_fields)");
   DBUG_PRINT("info", ("Copying to 0x%lx "
                       "from field %lu at offset %lu "
                       "to field %d at offset %lu",
@@ -6865,6 +7087,10 @@
     Copying the extra fields of the slave that does not exist on
     master into record[0] (which are basically the default values).
   */
+
+  if (table->s->fields < (uint) master_fields)
+    DBUG_RETURN(0);
+
   DBUG_ASSERT(master_reclength <= table->s->reclength);
   if (master_reclength < table->s->reclength)
     bmove_align(table->record[0] + master_reclength,
@@ -6922,7 +7148,7 @@
       }
     }
   }
-  return 0;                                     // All OK
+  DBUG_RETURN(0);                                     // All OK
 }
 
 #define DBUG_PRINT_BITSET(N,FRM,BS)                \
@@ -7527,12 +7753,6 @@
 {
   int error;
   DBUG_ASSERT(row_start && row_end);
-  /*
-    This assertion actually checks that there is at least as many
-    columns on the slave as on the master.
-  */
-  DBUG_ASSERT(table->s->fields >= m_width);
-
   error= unpack_row(rli, table, m_width, row_start, &m_cols, row_end,
                     &m_master_reclength, table->read_set, DELETE_ROWS_EVENT);
   /*
@@ -7701,12 +7921,6 @@
 {
   int error;
   DBUG_ASSERT(row_start && row_end);
-  /*
-    This assertion actually checks that there is at least as many
-    columns on the slave as on the master.
-  */
-  DBUG_ASSERT(table->s->fields >= m_width);
-
   /*
     We need to perform some juggling below since unpack_row() always
     unpacks into table->record[0]. For more information, see the

--- 1.23/mysql-test/r/rpl_ndb_log.result	2007-04-23 20:45:22 +02:00
+++ 1.24/mysql-test/r/rpl_ndb_log.result	2007-07-27 22:03:23 +02:00
@@ -88,12 +88,12 @@
 master-bin.000002	#	Query	1	#	COMMIT
 show binary logs;
 Log_name	File_size
-master-bin.000001	1775
-master-bin.000002	617
+master-bin.000001	1789
+master-bin.000002	623
 start slave;
 show binary logs;
 Log_name	File_size
-slave-bin.000001	1870
+slave-bin.000001	1884
 slave-bin.000002	202
 show binlog events in 'slave-bin.000001' from 4;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
@@ -126,9 +126,41 @@
 slave-bin.000002	#	Write_rows	2	#	table_id: #
 slave-bin.000002	#	Write_rows	1	#	table_id: # flags: STMT_END_F
 slave-bin.000002	#	Query	2	#	COMMIT
-show slave status;
-Slave_IO_State	Master_Host	Master_User	Master_Port	Connect_Retry	Master_Log_File	Read_Master_Log_Pos	Relay_Log_File	Relay_Log_Pos	Relay_Master_Log_File	Slave_IO_Running	Slave_SQL_Running	Replicate_Do_DB	Replicate_Ignore_DB	Replicate_Do_Table	Replicate_Ignore_Table	Replicate_Wild_Do_Table	Replicate_Wild_Ignore_Table	Last_Errno	Last_Error	Skip_Counter	Exec_Master_Log_Pos	Relay_Log_Space	Until_Condition	Until_Log_File	Until_Log_Pos	Master_SSL_Allowed	Master_SSL_CA_File	Master_SSL_CA_Path	Master_SSL_Cert	Master_SSL_Cipher	Master_SSL_Key	Seconds_Behind_Master	Master_SSL_Verify_Server_Cert
-#	127.0.0.1	root	MASTER_PORT	1	master-bin.000002	617	#	#	master-bin.000002	Yes	Yes				#			0		0	617	#	None		0	No						#	No
+show slave status;;
+Slave_IO_State	#
+Master_Host	127.0.0.1
+Master_User	root
+Master_Port	MASTER_PORT
+Connect_Retry	1
+Master_Log_File	master-bin.000002
+Read_Master_Log_Pos	623
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000002
+Slave_IO_Running	Yes
+Slave_SQL_Running	Yes
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	#
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	0
+Last_Error	
+Skip_Counter	0
+Exec_Master_Log_Pos	623
+Relay_Log_Space	#
+Until_Condition	None
+Until_Log_File	
+Until_Log_Pos	0
+Master_SSL_Allowed	No
+Master_SSL_CA_File	
+Master_SSL_CA_Path	
+Master_SSL_Cert	
+Master_SSL_Cipher	
+Master_SSL_Key	
+Seconds_Behind_Master	#
+Master_SSL_Verify_Server_Cert	No
 show binlog events in 'slave-bin.000005' from 4;
 ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log
 DROP TABLE t1;

--- 1.261/mysql-test/t/disabled.def	2007-07-23 09:33:19 +02:00
+++ 1.262/mysql-test/t/disabled.def	2007-07-27 22:03:23 +02:00
@@ -32,7 +32,8 @@
 rpl_ndb_myisam2ndb       : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue
 rpl_row_blob_innodb      : BUG#18980 2006-04-10 kent    Test fails randomly
 synchronization          : Bug#24529  	Test 'synchronization' fails on Mac pushbuild; Also on Linux 64 bit.
-rpl_ndb_ctype_ucs2_def   : BUG#27404 util thd mysql_parse sig11 when mysqld default multibyte charset
+rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported.
+rpl_ndb_ctype_ucs2_def   : BUG#29562, BUG#29563 and BUG#29564
 
 # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open
 #ndb_binlog_ddl_multi     : BUG#18976 2006-04-10 kent    CRBR: multiple binlog, second binlog may miss schema log events

--- 1.485/sql/ha_ndbcluster.cc	2007-07-25 07:30:38 +02:00
+++ 1.486/sql/ha_ndbcluster.cc	2007-07-27 22:03:24 +02:00
@@ -4503,6 +4503,8 @@
     DBUG_PRINT("info", ("HA_STATUS_AUTO"));
     if (m_table && table->found_next_number_field)
     {
+      if ((my_errno= check_ndb_connection()))
+        DBUG_RETURN(my_errno);
       Ndb *ndb= get_ndb();
       Ndb_tuple_id_range_guard g(m_share);
       
Thread
bk commit into 5.1 tree (tomas:1.2594)tomas27 Jul