List:Commits« Previous MessageNext Message »
From:Mats Kindahl Date:August 21 2006 10:54am
Subject:bk commit into 5.1 tree (mats:1.2251)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of mats. When mats 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, 2006-08-21 10:54:41+02:00, mats@romeo.(none) +7 -0
  Merge romeo.(none):/home/bkroot/mysql-5.1-wl3228
  into  romeo.(none):/home/bk/w3259-mysql-5.1-new-rpl
  MERGE: 1.2119.522.3

  mysql-test/t/disabled.def@stripped, 2006-08-21 10:52:45+02:00, mats@romeo.(none) +34 -24
    MERGE: 1.133.2.1

  sql/Makefile.am@stripped, 2006-08-21 10:54:38+02:00, mats@romeo.(none) +0 -0
    Merge patch for worklog 3259 into mysql-5.1-rpl
    MERGE: 1.135.1.1

  sql/field.cc@stripped, 2006-08-21 10:54:38+02:00, mats@romeo.(none) +0 -2
    Merge patch for worklog 3259 into mysql-5.1-rpl
    MERGE: 1.308.1.4

  sql/field.h@stripped, 2006-08-21 10:51:37+02:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.183.1.10

  sql/log_event.cc@stripped, 2006-08-21 10:54:38+02:00, mats@romeo.(none) +0 -3
    Merge patch for worklog 3259 into mysql-5.1-rpl
    MERGE: 1.219.1.3

  sql/log_event.h@stripped, 2006-08-21 10:51:37+02:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.133.1.3

  sql/mysql_priv.h@stripped, 2006-08-21 10:51:37+02:00, mats@romeo.(none) +0 -0
    Auto merged
    MERGE: 1.391.2.1

# 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:	mats
# Host:	romeo.(none)
# Root:	/home/bk/w3259-mysql-5.1-new-rpl/RESYNC

--- 1.146/sql/Makefile.am	2006-08-21 10:54:48 +02:00
+++ 1.147/sql/Makefile.am	2006-08-21 10:54:48 +02:00
@@ -53,7 +53,7 @@
 			ha_innodb.h  ha_berkeley.h ha_federated.h \
 			ha_ndbcluster.h ha_ndbcluster_binlog.h \
 			ha_ndbcluster_tables.h \
-			opt_range.h protocol.h rpl_tblmap.h \
+			opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \
 			log.h sql_show.h rpl_rli.h \
 			sql_select.h structs.h table.h sql_udf.h hash_filo.h \
 			lex.h lex_symbol.h sql_acl.h sql_crypt.h  \
@@ -95,7 +95,7 @@
 			sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
 			sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
 			slave.cc sql_repl.cc rpl_filter.cc rpl_tblmap.cc \
-			rpl_injector.cc \
+			rpl_utility.cc rpl_injector.cc \
                         sql_union.cc sql_derived.cc \
 			client.c sql_client.cc mini_client_errors.c pack.c\
 			stacktrace.c repl_failsafe.h repl_failsafe.cc \

--- 1.327/sql/field.cc	2006-08-21 10:54:48 +02:00
+++ 1.328/sql/field.cc	2006-08-21 10:54:48 +02:00
@@ -1255,6 +1255,12 @@
     CHARSET_INFO *cs= charset();
     cs->coll->hash_sort(cs, (uchar*) ptr, len, nr, nr2);
   }
+
+my_size_t
+Field::do_last_null_byte() const
+{
+  DBUG_ASSERT(null_ptr == NULL || (byte*) null_ptr >= table->record[0]);
+  return null_ptr ? (byte*) null_ptr - table->record[0] + 1 : 0;
 }
 
 
@@ -8168,6 +8174,30 @@
 }
 
 
+my_size_t
+Field_bit::do_last_null_byte() const
+{
+  /*
+    Code elsewhere is assuming that bytes are 8 bits, so I'm using
+    that value instead of the correct one: CHAR_BIT.
+
+    REFACTOR SUGGESTION (Matz): Change to use the correct number of
+    bits. On systems with CHAR_BIT > 8 (not very common), the storage
+    will lose the extra bits.
+  */
+  DBUG_PRINT("debug", ("bit_ofs=%d, bit_len=%d, bit_ptr=%p",
+                       bit_ofs, bit_len, bit_ptr));
+  uchar *result;
+  if (bit_len == 0)
+    result= null_ptr;
+  else if (bit_ofs + bit_len > 8)
+    result= bit_ptr + 1;
+  else
+    result= bit_ptr;
+
+  return result ? (byte*) result - table->record[0] + 1 : 0;
+}
+
 Field *Field_bit::new_key_field(MEM_ROOT *root,
                                 struct st_table *new_table,
                                 char *new_ptr, uchar *new_null_ptr,
@@ -8418,6 +8448,14 @@
   return from + bytes_in_rec;
 }
 
+
+void Field_bit::set_default()
+{
+  my_ptrdiff_t const offset= table->s->default_values - table->record[0];
+  uchar bits= get_rec_bits(bit_ptr + offset, bit_ofs, bit_len);
+  set_rec_bits(bits, bit_ptr, bit_ofs, bit_len);
+  Field::set_default();
+}
 
 /*
   Bit field support for non-MyISAM tables.

--- 1.185/sql/field.h	2006-08-21 10:54:48 +02:00
+++ 1.186/sql/field.h	2006-08-21 10:54:48 +02:00
@@ -62,10 +62,9 @@
   struct st_table *orig_table;		// Pointer to original table
   const char	**table_name, *field_name;
   LEX_STRING	comment;
-  query_id_t	query_id;		// For quick test of used fields
-  bool          add_index;              // For check if field will be indexed
   /* Field is part of the following keys */
-  key_map	key_start,part_of_key,part_of_sortkey;
+  key_map	key_start, part_of_key, part_of_key_not_clustered;
+  key_map       part_of_sortkey;
   /* 
     We use three additional unireg types for TIMESTAMP to overcome limitation 
     of current binary format of .frm file. We'd like to be able to support 
@@ -88,12 +87,8 @@
 
   utype		unireg_check;
   uint32	field_length;		// Length of field
-  uint          field_index;            // field number in fields array
   uint32	flags;
-  /* fieldnr is the id of the field (first field = 1) as is also
-     used in key_part.
-  */
-  uint16        fieldnr;
+  uint16        field_index;            // field number in fields array
   uchar		null_bit;		// Bit used to test null bit
 
   Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uchar null_bit_arg,
@@ -129,7 +124,7 @@
   static bool type_can_have_key_part(enum_field_types);
   static enum_field_types field_type_merge(enum_field_types, enum_field_types);
   static Item_result result_merge_type(enum_field_types);
-  bool eq(Field *field)
+  virtual bool eq(Field *field)
   {
     return (ptr == field->ptr && null_ptr == field->null_ptr &&
             null_bit == field->null_bit);
@@ -237,7 +232,8 @@
   */
   virtual bool can_be_compared_as_longlong() const { return FALSE; }
   virtual void free() {}
-  virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table);
+  virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table,
+                           bool keep_type);
   virtual Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
                                char *new_ptr, uchar *new_null_ptr,
                                uint new_null_bit);
@@ -369,6 +365,8 @@
     return field_length / charset()->mbmaxlen;
   }
 
+  /* Hash value */
+  virtual void hash(ulong *nr, ulong *nr2);
   friend bool reopen_table(THD *,struct st_table *,bool);
   friend int cre_myisam(my_string name, register TABLE *form, uint options,
 			ulonglong auto_increment_value);
@@ -535,6 +533,7 @@
   uint32 max_length() { return field_length; }
   uint size_of() const { return sizeof(*this); } 
   uint32 pack_length() const { return (uint32) bin_size; }
+  uint is_equal(create_field *new_field);
 };
 
 
@@ -843,7 +842,7 @@
     if ((*null_value= is_null()))
       return 0;
 #ifdef WORDS_BIGENDIAN
-    if (table->s->db_low_byte_first)
+    if (table && table->s->db_low_byte_first)
       return sint4korr(ptr);
 #endif
     long tmp;
@@ -1063,7 +1062,7 @@
   enum_field_types real_type() const { return FIELD_TYPE_STRING; }
   bool has_charset(void) const
   { return charset() == &my_charset_bin ? FALSE : TRUE; }
-  Field *new_field(MEM_ROOT *root, struct st_table *new_table);
+  Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
 };
 
 
@@ -1136,11 +1135,12 @@
   enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; }
   bool has_charset(void) const
   { return charset() == &my_charset_bin ? FALSE : TRUE; }
-  Field *new_field(MEM_ROOT *root, struct st_table *new_table);
+  Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
   Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
                        char *new_ptr, uchar *new_null_ptr,
                        uint new_null_bit);
   uint is_equal(create_field *new_field);
+  void hash(ulong *nr, ulong *nr2);
 };
 
 
@@ -1409,6 +1409,13 @@
   {
     bit_ptr= bit_ptr_arg;
     bit_ofs= bit_ofs_arg;
+  }
+  bool eq(Field *field)
+  {
+    return (Field::eq(field) &&
+            field->type() == type() &&
+            bit_ptr == ((Field_bit *)field)->bit_ptr &&
+            bit_ofs == ((Field_bit *)field)->bit_ofs);
   }
   void move_field_offset(my_ptrdiff_t ptr_diff)
   {

--- 1.237/sql/log_event.cc	2006-08-21 10:54:48 +02:00
+++ 1.238/sql/log_event.cc	2006-08-21 10:54:48 +02:00
@@ -24,6 +24,7 @@
 #include "mysql_priv.h"
 #include "slave.h"
 #include "rpl_filter.h"
+#include "rpl_utility.h"
 #include <my_dir.h>
 #endif /* MYSQL_CLIENT */
 #include <base64.h>
@@ -5290,38 +5291,95 @@
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 /*
-  Unpack a row into a record. The row is assumed to only consist of the fields
-  for which the bitset represented by 'arr' and 'bits'; the other parts of the
+  Unpack a row into a record.
+  
+  The row is assumed to only consist of the fields for which the
+  bitset represented by 'arr' and 'bits'; the other parts of the
   record are left alone.
+
+  At most 'colcnt' columns are read: if the table is larger than that,
+  the remaining fields are not filled in.
  */
-static char const *unpack_row(TABLE *table,
-                              byte *record, char const *row,
-                              MY_BITMAP const *cols)
+static int
+unpack_row(RELAY_LOG_INFO *rli,
+           TABLE *table, uint const colcnt, byte *record,
+           char const *row, MY_BITMAP const *cols,
+           char const **row_end, ulong *master_reclength)
 {
   DBUG_ASSERT(record && row);
-
   MY_BITMAP *write_set= table->write_set;
-  my_size_t const n_null_bytes= table->s->null_bytes;
   my_ptrdiff_t const offset= record - (byte*) table->record[0];
+  my_size_t master_null_bytes= table->s->null_bytes;
+
+  if (colcnt != table->s->fields)
+  {
+    Field **fptr= &table->field[colcnt-1];
+    do
+      master_null_bytes= (*fptr)->last_null_byte();
+    while (master_null_bytes == 0 && fptr-- > table->field);
 
-  memcpy(record, row, n_null_bytes);
-  char const *ptr= row + n_null_bytes;
+    if (master_null_bytes == 0)
+      master_null_bytes= table->s->null_bytes;
+  }
+
+  DBUG_ASSERT(master_null_bytes <= table->s->null_bytes);
+  memcpy(record, row, master_null_bytes);            // [1]
+  int error= 0;
 
   bitmap_set_all(write_set);
+
   Field **const begin_ptr = table->field;
-  for (Field **field_ptr= begin_ptr ; *field_ptr ; ++field_ptr)
+  Field **field_ptr;
   {
-    Field *const f= *field_ptr;
+    char const *ptr= row + master_null_bytes;
+    Field **const end_ptr= begin_ptr + colcnt;
+    for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)
+    {
+      Field *const f= *field_ptr;
+
+      if (bitmap_is_set(cols, field_ptr -  begin_ptr))
+      {
+        /* Field...::unpack() cannot return 0 */
+        ptr= f->unpack(f->ptr + offset, ptr);
+      }
+      else
+        bitmap_clear_bit(write_set, (field_ptr - begin_ptr) + 1);
+    }
+
+    *row_end = ptr;
+    if (master_reclength)
+    {
+      if (*field_ptr)
+        *master_reclength = (*field_ptr)->ptr - table->record[0];
+      else
+        *master_reclength = table->s->reclength;
+    }
+  }
 
-    if (bitmap_is_set(cols, (uint) (field_ptr -  begin_ptr)))
+  /*
+    Set properties for remaining columns, if there are any. We let the
+    corresponding bit in the write_set be set, to write the value if
+    it was not there already. We iterate over all remaining columns,
+    even if there were an error, to get as many error messages as
+    possible.  We are still able to return a pointer to the next row,
+    so wedo that.
+   */
+  for ( ; *field_ptr ; ++field_ptr)
+  {
+    if ((*field_ptr)->flags & (NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG))
     {
-      /* Field...::unpack() cannot return 0 */
-      ptr= f->unpack(f->ptr + offset, ptr);
+      slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD, 
+                      "Field `%s` of table `%s`.`%s` "
+                      "has no default value and cannot be NULL",
+                      (*field_ptr)->field_name, table->s->db.str, 
+                      table->s->table_name.str);
+      error = ER_NO_DEFAULT_FOR_FIELD;
     }
     else
-      bitmap_clear_bit(write_set, (uint) (field_ptr - begin_ptr));
+      (*field_ptr)->set_default();
   }
-  return ptr;
+
+  return error;
 }
 
 int Rows_log_event::exec_event(st_relay_log_info *rli)
@@ -5477,7 +5535,11 @@
     error= do_before_row_operations(table);
     while (error == 0 && row_start < (const char*) m_rows_end)
     {
-      char const *row_end= do_prepare_row(thd, table, row_start);
+      char const *row_end= NULL;
+      if ((error= do_prepare_row(thd, rli, table, row_start, &row_end)))
+        break; // We should to the after-row operation even in the
+               // case of error
+      
       DBUG_ASSERT(row_end != NULL); // cannot happen
       DBUG_ASSERT(row_end <= (const char*)m_rows_end);
 
@@ -5682,7 +5744,7 @@
 #endif
 
 /**************************************************************************
-	Table_map_log_event member functions
+	Table_map_log_event member functions and support functions
 **************************************************************************/
 
 /*
@@ -5924,72 +5986,9 @@
     */
     DBUG_ASSERT(m_table->in_use);
 
-    /*
-      Check that the number of columns and the field types in the
-      event match the number of columns and field types in the opened
-      table.
-     */
-    uint col= m_table->s->fields;
-
-    if (col == m_colcnt)
-    {
-      while (col-- > 0)
-        if (m_table->field[col]->type() != m_coltype[col])
-          break;
-    }
-
-    TABLE_SHARE const *const tsh= m_table->s;
-
-    /*
-      Check the following termination conditions:
-
-      (col == m_table->s->fields)
-          ==> (m_table->s->fields != m_colcnt)
-      (0 <= col < m_table->s->fields)
-          ==> (m_table->field[col]->type() != m_coltype[col])
-
-      Logically, A ==> B is equivalent to !A || B
-
-      Since col is unsigned, is suffices to check that col <=
-      tsh->fields.  If col wrapped (by decreasing col when it is 0),
-      the number will be UINT_MAX, which is greater than tsh->fields.
-    */
-    DBUG_ASSERT(!(col == tsh->fields) || tsh->fields != m_colcnt);
-    DBUG_ASSERT(!(col < tsh->fields) ||
-                (m_table->field[col]->type() != m_coltype[col]));
-
-    if (col <= tsh->fields)
+    table_def const def(m_coltype, m_colcnt);
+    if (def.compatible_with(rli, m_table))
     {
-      /* purecov: begin inspected */
-      /*
-        If we get here, the number of columns in the event didn't
-        match the number of columns in the table on the slave, *or*
-        there were a column in the table on the slave that did not
-        have the same type as given in the event.
-
-        If 'col' has the value that was assigned to it, it was a
-        mismatch between the number of columns on the master and the
-        slave.
-       */
-      if (col == tsh->fields)
-      {
-        DBUG_ASSERT(tsh->db.str && tsh->table_name.str);
-        slave_print_msg(ERROR_LEVEL, rli, ER_BINLOG_ROW_WRONG_TABLE_DEF,
-                        "Table width mismatch - "
-                        "received %u columns, %s.%s has %u columns",
-                        m_colcnt, tsh->db.str, tsh->table_name.str,
tsh->fields);
-      }
-      else
-      {
-        DBUG_ASSERT(col < m_colcnt && col < tsh->fields);
-        DBUG_ASSERT(tsh->db.str && tsh->table_name.str);
-        slave_print_msg(ERROR_LEVEL, rli, ER_BINLOG_ROW_WRONG_TABLE_DEF,
-                        "Column %d type mismatch - "
-                        "received type %d, %s.%s has type %d",
-                        col, m_coltype[col], tsh->db.str, tsh->table_name.str,
-                        m_table->field[col]->type());
-      }
-
       thd->query_error= 1;
       error= ERR_BAD_TABLE_DEF;
       goto err;
@@ -6103,6 +6102,27 @@
 }
 #endif
 
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+#ifndef DBUG_OFF
+static void
+print_column_values(char const *text, THD *thd, TABLE *table)
+{
+  THD *old_thd= table->in_use;
+  if (table->in_use == NULL)
+    table->in_use= thd;
+  for (Field **fptr= table->field ; *fptr ; ++fptr)
+  {
+    char buf[MAX_FIELD_WIDTH];
+    String str(buf, sizeof(buf), system_charset_info);
+    (*fptr)->val_str(&str);
+    DBUG_PRINT("info", ("%s for column %d is '%s'", 
+                        text, fptr - table->field, str.c_ptr()));
+  }
+  table->in_use= old_thd;
+}
+#endif
+#endif
+
 /**************************************************************************
 	Write_rows_log_event member functions
 **************************************************************************/
@@ -6188,19 +6208,22 @@
   return error;
 }
 
-char const *Write_rows_log_event::do_prepare_row(THD *thd, TABLE *table,
-                                                 char const *row_start)
+int Write_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
+                                         TABLE *table,
+                                         char const *row_start,
+                                         char const **row_end)
 {
-  char const *ptr= row_start;
   DBUG_ASSERT(table != NULL);
-  /*
-    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);
-  DBUG_ASSERT(ptr);
-  ptr= unpack_row(table, (byte*)table->record[0], ptr, &m_cols);
-  return ptr;
+  DBUG_ASSERT(row_start && row_end);
+
+  int error;
+  error= unpack_row(rli,
+                    table, m_width, table->record[0],
+                    row_start, &m_cols, row_end, &m_master_reclength);
+#ifndef DBUG_OFF
+  print_column_values("Unpacked value", thd, table);
+#endif
+  return error;
 }
 
 /*
@@ -6247,6 +6270,79 @@
 
 
 /*
+  Copy "extra" columns from record[1] to record[0].
+
+  Copy the extra fields that are not present on the master but are
+  present on the slave from record[1] to record[0].  This is used
+  after fetching a record that are to be updated, either inside
+  replace_record() or as part of executing an update_row().
+ */
+static int
+copy_extra_record_fields(TABLE *table,
+                         my_size_t master_reclength,
+                         my_ptrdiff_t master_fields)
+{
+  DBUG_PRINT("info", ("Copying to %p from field %d at offset %u to field %d at offset
%u", 
+                      table->record[0], 
+                      master_fields, master_reclength,
+                      table->s->fields, table->s->reclength));
+  if (master_reclength < table->s->reclength)
+    bmove_align(table->record[0] + master_reclength,
+                table->record[1] + master_reclength,
+                table->s->reclength - master_reclength);
+    
+  /*
+    Bit columns are special.  We iterate over all the remaining
+    columns and copy the "extra" bits to the new record.  This is
+    not a very good solution: it should be refactored on
+    opportunity.
+
+    REFACTORING SUGGESTION (Matz).  Introduce a member function
+    similar to move_field_offset() called copy_field_offset() to
+    copy field values and implement it for all Field subclasses. Use
+    this function to copy data from the found record to the record
+    that are going to be inserted.
+
+    The copy_field_offset() function need to be a virtual function,
+    which in this case will prevent copying an entire range of
+    fields efficiently.
+  */
+  {
+    Field **field_ptr= table->field + master_fields;
+    for ( ; *field_ptr ; ++field_ptr)
+    {
+      /*
+        Set the null bit according to the values in record[1]
+       */
+      if ((*field_ptr)->maybe_null() &&
+         
(*field_ptr)->is_null_in_record(reinterpret_cast<uchar*>(table->record[1])))
+        (*field_ptr)->set_null();
+      else
+        (*field_ptr)->set_notnull();
+
+      /*
+        Do the extra work for special columns.
+       */
+      switch ((*field_ptr)->real_type())
+      {
+      default:
+        /* Nothing to do */
+        break;
+
+      case FIELD_TYPE_BIT:
+        Field_bit *f= static_cast<Field_bit*>(*field_ptr);
+        my_ptrdiff_t const offset= table->record[1] - table->record[0];
+        uchar const bits=
+          get_rec_bits(f->bit_ptr + offset, f->bit_ofs, f->bit_len);
+        set_rec_bits(bits, f->bit_ptr, f->bit_ofs, f->bit_len);
+        break;
+      }
+    }
+  }
+  return 0;                                     // All OK
+}
+
+/*
   Replace the provided record in the database.
 
   Similar to how it is done in <code>mysql_insert()</code>, we first
@@ -6256,24 +6352,33 @@
 
   @param thd    Thread context for writing the record.
   @param table  Table to which record should be written.
-
+  @param master_reclength
+         Offset to first column that is not present on the master,
+         alternatively the length of the record on the master side.
   @return Error code on failure, 0 on success.
  */
 static int
-replace_record(THD *thd, TABLE *table)
+replace_record(THD *thd, TABLE *table,
+               ulong const master_reclength,
+               uint const master_fields)
 {
+  DBUG_ENTER("replace_record");
   DBUG_ASSERT(table != NULL && thd != NULL);
 
   int error;
   int keynum;
   auto_afree_ptr<char> key(NULL);
 
+#ifndef DBUG_OFF
+  print_column_values("Starting write value", thd, table);
+#endif
+
   while ((error= table->file->ha_write_row(table->record[0])))
   {
     if ((keynum= table->file->get_dup_key(error)) < 0)
     {
       /* We failed to retrieve the duplicate key */
-      return HA_ERR_FOUND_DUPP_KEY;
+      DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY);
     }
 
     /*
@@ -6290,20 +6395,20 @@
     {
       error= table->file->rnd_pos(table->record[1], table->file->dup_ref);
       if (error)
-        return error;
+        DBUG_RETURN(error);
     }
     else
     {
       if (table->file->extra(HA_EXTRA_FLUSH_CACHE))
       {
-        return my_errno;
+        DBUG_RETURN(my_errno);
       }
 
       if (key.get() == NULL)
       {
        
key.assign(static_cast<char*>(my_alloca(table->s->max_unique_length)));
         if (key.get() == NULL)
-          return ENOMEM;
+          DBUG_RETURN(ENOMEM);
       }
 
       key_copy((byte*)key.get(), table->record[0], table->key_info + keynum, 0);
@@ -6312,7 +6417,7 @@
                                          table->key_info[keynum].key_length,
                                          HA_READ_KEY_EXACT);
       if (error)
-        return error;
+        DBUG_RETURN(error);
     }
 
     /*
@@ -6320,6 +6425,12 @@
        will enable us to update it or, alternatively, delete it (so
        that we can insert the new row afterwards).
 
+       First we copy the columns into table->record[0] that are not
+       present on the master from table->record[1], if there are any.
+    */
+    copy_extra_record_fields(table, master_reclength, master_fields);
+    
+    /*
        REPLACE is defined as either INSERT or DELETE + INSERT.  If
        possible, we can replace it with an UPDATE, but that will not
        work on InnoDB if FOREIGN KEY checks are necessary.
@@ -6339,22 +6450,22 @@
     {
       error=table->file->ha_update_row(table->record[1],
                                        table->record[0]);
-      return error;
+      DBUG_RETURN(error);
     }
     else
     {
       if ((error= table->file->ha_delete_row(table->record[1])))
-        return error;
+        DBUG_RETURN(error);
       /* Will retry ha_write_row() with the offending row removed. */
     }
   }
-  return error;
+  DBUG_RETURN(error);
 }
 
 int Write_rows_log_event::do_exec_row(TABLE *table)
 {
   DBUG_ASSERT(table != NULL);
-  int error= replace_record(thd, table);
+  int error= replace_record(thd, table, m_master_reclength, m_width);
   return error;
 }
 #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
@@ -6640,20 +6751,22 @@
   return error;
 }
 
-char const *Delete_rows_log_event::do_prepare_row(THD *thd, TABLE *table,
-                                                  char const *row_start)
+int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
+                                          TABLE *table,
+                                          char const *row_start,
+                                          char const **row_end)
 {
-  char const *ptr= row_start;
-  DBUG_ASSERT(ptr);
+  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);
 
-  DBUG_ASSERT(ptr != NULL);
-  ptr= unpack_row(table, table->record[0], ptr, &m_cols);
-
+  error= unpack_row(rli,
+                    table, m_width, table->record[0], 
+                    row_start, &m_cols, row_end, &m_master_reclength);
   /*
     If we will access rows using the random access method, m_key will
     be set to NULL, so we do not need to make a key copy in that case.
@@ -6665,7 +6778,7 @@
     key_copy(m_key, table->record[0], key_info, 0);
   }
 
-  return ptr;
+  return error;
 }
 
 int Delete_rows_log_event::do_exec_row(TABLE *table)
@@ -6779,11 +6892,13 @@
   return error;
 }
 
-char const *Update_rows_log_event::do_prepare_row(THD *thd, TABLE *table,
-                                                  char const *row_start)
+int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
+                                          TABLE *table,
+                                          char const *row_start,
+                                          char const **row_end)
 {
-  char const *ptr= row_start;
-  DBUG_ASSERT(ptr);
+  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.
@@ -6791,10 +6906,14 @@
   DBUG_ASSERT(table->s->fields >= m_width);
 
   /* record[0] is the before image for the update */
-  ptr= unpack_row(table, table->record[0], ptr, &m_cols);
-  DBUG_ASSERT(ptr != NULL);
+  error= unpack_row(rli,
+                    table, m_width, table->record[0],
+                    row_start, &m_cols, row_end, &m_master_reclength);
+  row_start = *row_end;
   /* m_after_image is the after image for the update */
-  ptr= unpack_row(table, m_after_image, ptr, &m_cols);
+  error= unpack_row(rli,
+                    table, m_width, m_after_image,
+                    row_start, &m_cols, row_end, &m_master_reclength);
 
   /*
     If we will access rows using the random access method, m_key will
@@ -6807,7 +6926,7 @@
     key_copy(m_key, table->record[0], key_info, 0);
   }
 
-  return ptr;
+  return error;
 }
 
 int Update_rows_log_event::do_exec_row(TABLE *table)
@@ -6825,17 +6944,20 @@
     example, the partition engine).
 
     Since find_and_fetch_row() puts the fetched record (i.e., the old
-    record) in record[0], we have to move it out of the way and into
-    record[1]. After that, we can put the new record (i.e., the after
-    image) into record[0].
+    record) in record[1], we can keep it there. We put the new record
+    (i.e., the after image) into record[0], and copy the fields that
+    are on the slave (i.e., in record[1]) into record[0], effectively
+    overwriting the default values that where put there by the
+    unpack_row() function.
   */
-  bmove_align(table->record[1], table->record[0], table->s->reclength);
   bmove_align(table->record[0], m_after_image, table->s->reclength);
+  copy_extra_record_fields(table, m_master_reclength, m_width);
 
   /*
-    Now we should have the right row to update.  The old row (the one
-    we're looking for) has to be in record[1] and the new row has to
-    be in record[0] for all storage engines to work correctly.
+    Now we have the right row to update.  The old row (the one we're
+    looking for) is in record[1] and the new row has is in record[0].
+    We also have copied the original values already in the slave's
+    database into the after image delivered from the master.
   */
   error= table->file->ha_update_row(table->record[1], table->record[0]);
 

--- 1.134/sql/log_event.h	2006-08-21 10:54:48 +02:00
+++ 1.135/sql/log_event.h	2006-08-21 10:54:48 +02:00
@@ -470,7 +470,7 @@
 
 #ifndef MYSQL_CLIENT
 class String;
-class MYSQL_LOG;
+class MYSQL_BIN_LOG;
 class THD;
 #endif
 
@@ -808,6 +808,7 @@
   void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
 #endif
 
+  Query_log_event();
   Query_log_event(const char* buf, uint event_len,
                   const Format_description_log_event *description_event,
                   Log_event_type event_type);
@@ -831,6 +832,26 @@
   /* Writes derived event-specific part of post header. */
 };
 
+
+/*****************************************************************************
+
+  Muted Query Log Event class
+
+  Pretends to Log SQL queries, but doesn't actually do so.
+
+ ****************************************************************************/
+class Muted_query_log_event: public Query_log_event
+{
+public:
+#ifndef MYSQL_CLIENT
+  Muted_query_log_event();
+
+  bool write(IO_CACHE* file) { return(false); };
+  virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
+#endif
+};
+
+
 #ifdef HAVE_REPLICATION
 
 /*****************************************************************************
@@ -1221,9 +1242,6 @@
   bool write(IO_CACHE* file);
 #endif
   bool is_valid() const { return 1; }
-#if !defined(DBUG_OFF) && !defined(MYSQL_CLIENT)
-  static my_bool show_xid;
-#endif
 };
 
 /*****************************************************************************
@@ -1635,6 +1653,8 @@
 #endif
 char *str_to_hex(char *to, const char *from, uint len);
 
+#ifdef HAVE_ROW_BASED_REPLICATION
+
 /*****************************************************************************
 
   Table map log event class
@@ -1643,7 +1663,6 @@
   identifier (an integer number).
 
  ****************************************************************************/
-
 class Table_map_log_event : public Log_event
 {
 public:
@@ -1750,6 +1769,7 @@
 
  ****************************************************************************/
 
+
 class Rows_log_event : public Log_event
 {
 public:
@@ -2128,5 +2148,6 @@
 #endif
 };
 
+#endif /* HAVE_ROW_BASED_REPLICATION */
 
 #endif /* _log_event_h */

--- 1.422/sql/mysql_priv.h	2006-08-21 10:54:48 +02:00
+++ 1.423/sql/mysql_priv.h	2006-08-21 10:54:48 +02:00
@@ -21,6 +21,9 @@
   except the part which must be in the server and in the client.
 */
 
+#ifndef MYSQL_PRIV_H
+#define MYSQL_PRIV_H
+
 #ifndef MYSQL_CLIENT
 
 #include <my_global.h>
@@ -2019,3 +2022,5 @@
 
 #endif /* MYSQL_SERVER */
 #endif /* MYSQL_CLIENT */
+
+#endif /* MYSQL_PRIV_H */

--- 1.182/mysql-test/t/disabled.def	2006-08-21 10:54:48 +02:00
+++ 1.183/mysql-test/t/disabled.def	2006-08-21 10:54:48 +02:00
@@ -9,37 +9,48 @@
 #  Do not use any TAB characters for whitespace.
 #
 ##############################################################################
-#events_bugs              : BUG#17619 2006-02-21 andrey  Race conditions
-#events_stress            : BUG#17619 2006-02-21 andrey  Race conditions
-#events                   : BUG#17619 2006-02-21 andrey  Race conditions
-#events_scheduling        : BUG#19170 2006-04-26 andrey  Test case of 19170 fails on some
platforms. Has to be checked.
-#im_instance_conf          : Bug#20294 2006-06-06 monty   Instance manager test
im_instance_conf fails randomly
-im_options                : Bug#20294 2006-07-24 stewart   Instance manager test
im_instance_conf fails randomly
-#im_life_cycle             : Bug#20368 2006-06-10 alik    im_life_cycle test fails
+events_bugs              : BUG#17619 2006-02-21 andrey  Race conditions
+events_stress            : BUG#17619 2006-02-21 andrey  Race conditions
+events                   : BUG#17619 2006-02-21 andrey  Race conditions
+events_scheduling        : BUG#18958 2006-04-13 andrey  Test case unstable
+events_logs_tests        : BUG#18953 2006-04-12 kent    Test is randomly failing
 ndb_autodiscover         : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog
 ndb_autodiscover2        : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog
-ndb_binlog_ignore_db     : BUG#21279 2006-07-25 ingo    Randomly throws a warning
-ndb_load                 : BUG#17233 2006-05-04 tomas failed load data from infile causes
mysqld dbug_assert, binlog not flushed
-ndb_restore_compat       : BUG#21283 2006-07-26 ingo    Test fails randomly
+ndb_cache2               : BUG#18597 2006-03-28 brian simultaneous drop table and ndb
statistics update triggers node failure
+ndb_cache_multi2         : BUG#18597 2006-04-10 kent  simultaneous drop table and ndb
statistics update triggers node failure
 partition_03ndb          : BUG#16385 2006-03-24 mikael Partitions: crash when updating a
range partitioned NDB table
 ps_7ndb                  : BUG#18950 2006-02-16 jmiller create table like does not obtain
LOCK_open
-rpl_ndb_2innodb          : BUG#19227 2006-04-20 pekka pk delete apparently not replicated
-rpl_ndb_2myisam          : BUG#19227 Seems to pass currently
-#rpl_ndb_commit_afterflush : BUG#19328 2006-05-04 tomas Slave timeout with
COM_REGISTER_SLAVE error causing stop
-rpl_ndb_dd_partitions    : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD
-rpl_ndb_ddl              : BUG#18946 result file needs update + test needs to checked
-rpl_ndb_innodb2ndb       : Bug #19710  Cluster replication to partition table fails on
DELETE FROM statement
-#rpl_ndb_log              : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create
table and insert (on different table) not determ
-rpl_ndb_myisam2ndb       : Bug #19710  Cluster replication to partition table fails on
DELETE FROM statement
+rpl_deadlock_innodb      : BUG#16920 2006-04-12 kent    fails in show slave status
(randomly)
+rpl_ndb_2innodb          : BUG#19004 2006-03-22 tomas ndb: partition by range and update
hangs
+rpl_ndb_2myisam          : BUG#19004 2006-03-22 tomas ndb: partition by range and update
hangs
+rpl_ndb_auto_inc         : BUG#17086 2006-02-16 jmiller CR: auto_increment_increment and
auto_increment_offset produce duplicate key er
+rpl_ndb_commit_afterflush : LOCK TABLES cases hang in ndb injector thread
+rpl_ndb_ddl              : result file needs update + test needs to checked
+rpl_ndb_innodb2ndb       : BUG#18094 2006-03-16 mats Slave caches invalid table
definition after atlters causes select failure
+rpl_ndb_log              : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create
table and insert (on different table) not determ
+rpl_ndb_myisam2ndb       : BUG#18094 2006-03-16 mats   Slave caches invalid table
definition after atlters causes select failure
+rpl_ndb_relay_space      : BUG#16993 2006-02-16 jmiller RBR: ALTER TABLE ZEROFILL
AUTO_INCREMENT is not replicated correctly
+rpl_switch_stm_row_mixed : BUG#18590 2006-03-28 brian
+rpl_row_basic_7ndb       : BUG#17400 2006-04-09 brian   Cluster Replication: delete &
update of rows in table without pk fails on slave.
 rpl_row_blob_innodb      : BUG#18980 2006-04-10 kent    Test fails randomly
-rpl_row_func003          : BUG#19074 2006-13-04 andrei  test failed
+rpl_row_func003		 : BUG#19074 2006-13-04 andrei  test failed
+rpl_row_inexist_tbl      : BUG#18948 2006-03-09 mats    Disabled since patch makes this
test wait forever
 rpl_sp                   : BUG#16456 2006-02-16 jmiller
-rpl_sp_effects           : BUG#19862 2006-06-15 mkindahl
+rpl_until                : BUG#15886 2006-02-16 jmiller Unstable test case
+sp-goto                  : BUG#18949 2006-02-16 jmiller GOTO is currently is disabled -
will be fixed in the future
+mysqldump                : BUG#18078 2006-03-10 lars
+udf                      : BUG#18564 2006-03-27 ian     (Permission by Brian)
 
 # 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
-rpl_ndb_idempotent       : BUG#21298 2006-07-27 msvensson
-rpl_row_basic_7ndb       : BUG#21298 2006-07-27 msvensson
-rpl_truncate_7ndb        : BUG#21298 2006-07-27 msvensson
 
-rpl_ndb_dd_advance       : BUG#18679 2006-07-28 jimw (Test fails randomly)
+# the below ndb failures have not been objerved for > 5 push builds, close bugs
+#ndb_gis                  : BUG#18600 2006-03-28 brian ndb_gis test failure
+#ndb_load                 : BUG#17233 2006-02-16 jmiller failed load data from infile
causes mysqld dbug_assert, binlog not flushed
+#rpl_ndb_basic            : BUG#18592 2006-03-28 brian rpl_ndb_basic failure
+#rpl_ndb_dd_advance       : BUG#18924 2006-04-09 brian rpl_ndb_dd_advance failure
+#rpl_ndb_dd_basic         : BUG#18569 2006-03-28 brian rpl_ndb_dd_basic failure
+#rpl_ndb_insert_ignore    : BUG#18567 2006-03-28 brian rpl_ndb_insert_ignore failure
+#rpl_ndb_multi_update2    : BUG#18928 2006-04-09 brian   rpl_ndb_multi_update2 failed
+#rpl_ndb_multi_update3    : BUG#18627 2006-03-29 monty   Cluster Replication:
rpl_ndb_multi_update3 fails on Intel 64 bit
+#rpl_ndb_trig004          : BUG#18977 2006-04-10 kent    Test fails randomly
Thread
bk commit into 5.1 tree (mats:1.2251)Mats Kindahl21 Aug