List:Commits« Previous MessageNext Message »
From:Andrei Elkin Date:September 7 2006 11:31am
Subject:bk commit into 5.1 tree (aelkin:1.2255)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of elkin. When elkin 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-09-07 14:31:49+03:00, aelkin@stripped +15 -0
  Cset include: mats@romeo.(none)|ChangeSet|20060822083611|06817
  Cset include: mats@stripped|ChangeSet|20060508180525|50617
  Cset include: mats@stripped|ChangeSet|20060503130038|00318

  mysql-test/extra/rpl_tests/rpl_row_tabledefs.test@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  mysql-test/r/rpl_row_tabledefs_2myisam.result@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  mysql-test/r/rpl_row_tabledefs_3innodb.result@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  mysql-test/r/rpl_row_tabledefs_7ndb.result@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  mysql-test/t/disabled.def@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  mysql-test/t/rpl_row_tabledefs_2myisam.test@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  mysql-test/t/rpl_row_tabledefs_3innodb.test@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  sql/Makefile.am@stripped, 2006-09-07 14:31:46+03:00, aelkin@stripped +0 -0
    Include

  sql/field.cc@stripped, 2006-09-07 14:31:46+03:00, aelkin@stripped +0 -0
    Include

  sql/field.h@stripped, 2006-09-07 14:31:46+03:00, aelkin@stripped +0 -0
    Include

  sql/log_event.cc@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  sql/log_event.h@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  sql/mysql_priv.h@stripped, 2006-09-07 14:31:47+03:00, aelkin@stripped +0 -0
    Include

  sql/rpl_utility.cc@stripped, 2006-09-07 14:31:48+03:00, aelkin@stripped +0 -0
    Include

  sql/rpl_utility.h@stripped, 2006-09-07 14:31:48+03:00, aelkin@stripped +0 -0
    Include

# 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:	aelkin
# Host:	dsl-hkigw8-fe00f800-98.dhcp.inet.fi
# Root:	/home/elkin/MySQL/TEAM/BARE/mysql-5.1-new-rpl

--- 1.148/sql/Makefile.am	2006-09-07 14:31:57 +03:00
+++ 1.149/sql/Makefile.am	2006-09-07 14:31:57 +03:00
@@ -53,7 +53,7 @@ noinst_HEADERS =	item.h item_func.h item
 			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 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
 			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.330/sql/field.cc	2006-09-07 14:31:57 +03:00
+++ 1.331/sql/field.cc	2006-09-07 14:31:57 +03:00
@@ -1255,6 +1255,15 @@ void Field::hash(ulong *nr, ulong *nr2)
     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;
+}
+
 
 void Field::copy_from_tmp(int row_offset)
 {
@@ -8166,6 +8175,30 @@ Field_bit::Field_bit(char *ptr_arg, uint
 }
 
 
+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,
@@ -8416,6 +8449,14 @@ const char *Field_bit::unpack(char *to, 
   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.187/sql/field.h	2006-09-07 14:31:57 +03:00
+++ 1.188/sql/field.h	2006-09-07 14:31:57 +03:00
@@ -207,6 +207,19 @@ public:
     { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; }
   inline bool maybe_null(void) { return null_ptr != 0 || table->maybe_null; }
   inline bool real_maybe_null(void) { return null_ptr != 0; }
+
+  /*
+    Return a pointer to the last byte of the null bytes where the
+    field conceptually is placed.  In the case that the field does not
+    use any bits of the null bytes, a null pointer is returned.
+   */
+  my_size_t last_null_byte() const {
+    my_size_t bytes= do_last_null_byte();
+    DBUG_PRINT("debug", ("last_null_byte() ==> %d", bytes));
+    DBUG_ASSERT(bytes <= table->s->null_bytes);
+    return bytes;
+  }
+
   virtual void make_field(Send_field *);
   virtual void sort_string(char *buff,uint length)=0;
   virtual bool optimize_range(uint idx, uint part);
@@ -369,6 +382,9 @@ public:
   friend class Item_sum_min;
   friend class Item_sum_max;
   friend class Item_func_group_concat;
+
+private:
+  virtual my_size_t do_last_null_byte() const;
 };
 
 
@@ -1384,6 +1400,8 @@ public:
   void sql_type(String &str) const;
   char *pack(char *to, const char *from, uint max_length=~(uint) 0);
   const char *unpack(char* to, const char *from);
+  virtual void set_default();
+
   Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
                        char *new_ptr, uchar *new_null_ptr,
                        uint new_null_bit);
@@ -1404,6 +1422,9 @@ public:
     Field::move_field_offset(ptr_diff);
     bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*);
   }
+
+private:
+  virtual my_size_t do_last_null_byte() const;
 };
 
 

--- 1.240/sql/log_event.cc	2006-09-07 14:31:57 +03:00
+++ 1.241/sql/log_event.cc	2006-09-07 14:31:57 +03: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,36 +5291,114 @@ int Rows_log_event::do_add_row_data(byte
 
 #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
-  record are left alone.
+  Unpack a row into a record.
+  
+  SYNOPSIS
+    unpack_row()
+    rli     Relay log info
+    table   Table to unpack into
+    colcnt  Number of columns to read from record
+    record  Record where the data should be unpacked
+    row     Packed row data
+    cols    Pointer to columns data to fill in
+    row_end Pointer to variable that will hold the value of the
+            one-after-end position for the row
+    master_reclength
+            Pointer to variable that will hold the length of the
+            record on the master side
+    rw_set  Pointer to bitmap that holds either the read_set or the
+            write_set of the table
+
+  DESCRIPTION
+
+      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,
+           MY_BITMAP* const rw_set)
 {
   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(rw_set);
 
-  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;
-      --colcnt;
+    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...::unpack() cannot return 0 */
-      ptr= f->unpack(f->ptr + offset, ptr);
+      Field *const f= *field_ptr;
+
+      if (bitmap_is_set(cols, field_ptr -  begin_ptr))
+      {
+        ptr= f->unpack(f->ptr + offset, ptr);
+        /* Field...::unpack() cannot return 0 */
+        DBUG_ASSERT(ptr != NULL);
+      }
+      else
+        bitmap_clear_bit(rw_set, field_ptr - begin_ptr);
+    }
+
+    *row_end = ptr;
+    if (master_reclength)
+    {
+      if (*field_ptr)
+        *master_reclength = (*field_ptr)->ptr - table->record[0];
+      else
+        *master_reclength = table->s->reclength;
+    }
+  }
+
+  /*
+    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))
+    {
+      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
+      (*field_ptr)->set_default();
   }
-  return ptr;
+
+  return error;
 }
 
 int Rows_log_event::exec_event(st_relay_log_info *rli)
@@ -5475,7 +5554,11 @@ int Rows_log_event::exec_event(st_relay_
     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);
 
@@ -5680,7 +5763,7 @@ void Rows_log_event::pack_info(Protocol 
 #endif
 
 /**************************************************************************
-	Table_map_log_event member functions
+	Table_map_log_event member functions and support functions
 **************************************************************************/
 
 /*
@@ -5922,71 +6005,9 @@ int Table_map_log_event::exec_event(st_r
     */
     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))
     {
-      /*
-        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;
@@ -6100,8 +6121,6 @@ void Table_map_log_event::print(FILE *fi
 }
 #endif
 
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-#endif
 /**************************************************************************
 	Write_rows_log_event member functions
 **************************************************************************/
@@ -6187,19 +6206,21 @@ int Write_rows_log_event::do_after_row_o
   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,
+                    table->write_set);
+  bitmap_copy(table->read_set, table->write_set);
+  return error;
 }
 
 /*
@@ -6246,21 +6267,104 @@ namespace {
 
 
 /*
+  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
-  try to do a <code>ha_write_row()</code> and of that fails due to
-  duplicated keys (or indices), we do an <code>ha_update_row()</code>
-  or a <code>ha_delete_row()</code> instead.
+  SYNOPSIS
+      replace_record()
+      thd    Thread context for writing the record.
+      table  Table to which record should be written.
+      master_reclength
+             Offset to first column that is not present on the master,
+             alternatively the length of the record on the master
+             side.
 
-  @param thd    Thread context for writing the record.
-  @param table  Table to which record should be written.
+  RETURN VALUE
+      Error code on failure, 0 on success.
 
-  @return Error code on failure, 0 on success.
+  DESCRIPTION
+      Similar to how it is done in mysql_insert(), we first try to do
+      a ha_write_row() and of that fails due to duplicated keys (or
+      indices), we do an ha_update_row() or a ha_delete_row() instead.
  */
 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;
@@ -6272,7 +6376,7 @@ replace_record(THD *thd, TABLE *table)
     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);
     }
 
     /*
@@ -6289,20 +6393,20 @@ replace_record(THD *thd, TABLE *table)
     {
       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);
@@ -6311,7 +6415,7 @@ replace_record(THD *thd, TABLE *table)
                                          table->key_info[keynum].key_length,
                                          HA_READ_KEY_EXACT);
       if (error)
-        return error;
+        DBUG_RETURN(error);
     }
 
     /*
@@ -6319,6 +6423,12 @@ replace_record(THD *thd, TABLE *table)
        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.
@@ -6338,22 +6448,22 @@ replace_record(THD *thd, TABLE *table)
     {
       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) */
@@ -6639,20 +6749,23 @@ int Delete_rows_log_event::do_after_row_
   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,
+                    table->read_set);
   /*
     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.
@@ -6664,7 +6777,7 @@ char const *Delete_rows_log_event::do_pr
     key_copy(m_key, table->record[0], key_info, 0);
   }
 
-  return ptr;
+  return error;
 }
 
 int Delete_rows_log_event::do_exec_row(TABLE *table)
@@ -6778,11 +6891,13 @@ int Update_rows_log_event::do_after_row_
   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.
@@ -6790,10 +6905,16 @@ char const *Update_rows_log_event::do_pr
   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,
+                    table->read_set);
+  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,
+                    table->write_set);
 
   /*
     If we will access rows using the random access method, m_key will
@@ -6806,7 +6927,7 @@ char const *Update_rows_log_event::do_pr
     key_copy(m_key, table->record[0], key_info, 0);
   }
 
-  return ptr;
+  return error;
 }
 
 int Update_rows_log_event::do_exec_row(TABLE *table)
@@ -6824,17 +6945,20 @@ int Update_rows_log_event::do_exec_row(T
     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.136/sql/log_event.h	2006-09-07 14:31:57 +03:00
+++ 1.137/sql/log_event.h	2006-09-07 14:31:57 +03:00
@@ -1874,6 +1874,7 @@ protected:
   ulong       m_table_id;	/* Table ID */
   MY_BITMAP   m_cols;		/* Bitmap denoting columns available */
   ulong       m_width;          /* The width of the columns bitmap */
+  ulong       m_master_reclength; /* Length of record on master side */
 
   /* Bit buffer in the same memory as the class */
   uint32    m_bitbuf[128/(sizeof(uint32)*8)];
@@ -1927,12 +1928,15 @@ private:
       since SQL thread specific data is not available: that data is made
       available for the do_exec function.
 
-    RETURN VALUE
       A pointer to the start of the next row, or NULL if the preparation
       failed. Currently, preparation cannot fail, but don't rely on this
       behavior. 
+
+    RETURN VALUE
+      Error code, if something went wrong, 0 otherwise.
    */
-  virtual char const *do_prepare_row(THD*, TABLE*, char const *row_start) = 0;
+  virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
+                             char const *row_start, char const **row_end) = 0;
 
   /*
     Primitive to do the actual execution necessary for a row.
@@ -2000,10 +2004,11 @@ private:
   gptr  m_memory;
   byte *m_after_image;
 
-  virtual int         do_before_row_operations(TABLE *table);
-  virtual int         do_after_row_operations(TABLE *table, int error);
-  virtual char const *do_prepare_row(THD*, TABLE*, char const *row_start);
-  virtual int         do_exec_row(TABLE *table);
+  virtual int do_before_row_operations(TABLE *table);
+  virtual int do_after_row_operations(TABLE *table, int error);
+  virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
+                             char const *row_start, char const **row_end);
+  virtual int do_exec_row(TABLE *table);
 #endif
 };
 
@@ -2064,10 +2069,11 @@ private:
   byte *m_key;
   byte *m_after_image;
 
-  virtual int         do_before_row_operations(TABLE *table);
-  virtual int         do_after_row_operations(TABLE *table, int error);
-  virtual char const *do_prepare_row(THD*, TABLE*, char const *row_start);
-  virtual int         do_exec_row(TABLE *table);
+  virtual int do_before_row_operations(TABLE *table);
+  virtual int do_after_row_operations(TABLE *table, int error);
+  virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
+                             char const *row_start, char const **row_end);
+  virtual int do_exec_row(TABLE *table);
 #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
 };
 
@@ -2134,10 +2140,11 @@ private:
   byte *m_key;
   byte *m_after_image;
 
-  virtual int         do_before_row_operations(TABLE *table);
-  virtual int         do_after_row_operations(TABLE *table, int error);
-  virtual char const *do_prepare_row(THD*, TABLE*, char const *row_start);
-  virtual int         do_exec_row(TABLE *table);
+  virtual int do_before_row_operations(TABLE *table);
+  virtual int do_after_row_operations(TABLE *table, int error);
+  virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
+                             char const *row_start, char const **row_end);
+  virtual int do_exec_row(TABLE *table);
 #endif
 };
 

--- 1.424/sql/mysql_priv.h	2006-09-07 14:31:57 +03:00
+++ 1.425/sql/mysql_priv.h	2006-09-07 14:31:57 +03: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 @@ bool schema_table_store_record(THD *thd,
 
 #endif /* MYSQL_SERVER */
 #endif /* MYSQL_CLIENT */
+
+#endif /* MYSQL_PRIV_H */

--- 1.185/mysql-test/t/disabled.def	2006-09-07 14:31:57 +03:00
+++ 1.186/mysql-test/t/disabled.def	2006-09-07 14:31:57 +03:00
@@ -36,6 +36,7 @@ rpl_row_blob_innodb      : BUG#18980 200
 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-08-22 mats    Bug appear to be fixed
 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

--- 1.4/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test	2006-09-07 14:31:57 +03:00
+++ 1.5/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test	2006-09-07 14:31:57 +03:00
@@ -3,11 +3,23 @@
 
 # Consider making these part of the basic RBR tests.
 
--- source include/have_binlog_format_row.inc
--- source include/master-slave.inc
+connection master;
+--disable_warnings
+--disable_query_log
+DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef;
+DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t9;
+--enable_query_log
+--enable_warnings
+sync_slave_with_master;
+STOP SLAVE;
+SET GLOBAL SQL_MODE='STRICT_ALL_TABLES';
+START SLAVE;
 
 connection master;
-eval CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=$engine_type;
+eval CREATE TABLE t1_int (a INT PRIMARY KEY, b INT) ENGINE=$engine_type;
+eval CREATE TABLE t1_bit (a INT PRIMARY KEY, b INT) ENGINE=$engine_type;
+eval CREATE TABLE t1_char (a INT PRIMARY KEY, b INT) ENGINE=$engine_type;
+eval CREATE TABLE t1_nodef (a INT PRIMARY KEY, b INT) ENGINE=$engine_type;
 eval CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=$engine_type;
 eval CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=$engine_type;
 eval CREATE TABLE t4 (a INT) ENGINE=$engine_type;
@@ -15,15 +27,25 @@ eval CREATE TABLE t5 (a INT, b INT, c IN
 eval CREATE TABLE t6 (a INT, b INT, c INT) ENGINE=$engine_type;
 
 # Table used to detect that slave is running
-eval CREATE TABLE t9 (a INT PRIMARY KEY) ENGINE=$engine_type;
+eval CREATE TABLE t9 (a INT) ENGINE=$engine_type;
 
 sync_slave_with_master;
-# On the slave, we add one column last in table 't1',
-ALTER TABLE t1 ADD x INT DEFAULT 42;
-# ... add one column in the middle of table 't2', and
-ALTER TABLE t2 ADD x INT DEFAULT 42 AFTER a;
-# ... add one column first in table 't3'.
-ALTER TABLE t3 ADD x INT DEFAULT 42 FIRST;
+
+# On the slave, we add one INT column last in table 't1_int',
+ALTER TABLE t1_int ADD x INT DEFAULT 42;
+# ... and add BIT columns last in table 't1_bit' to ensure that we
+# have at least one extra null byte on the slave,
+ALTER TABLE t1_bit
+  ADD x BIT(3) DEFAULT b'011',
+  ADD y BIT(5) DEFAULT b'10101',
+  ADD z BIT(2) DEFAULT b'10';
+# ... and add one CHAR column last in table 't1_char',
+ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test';
+# ... and add one non-nullable INT column last in table 't1_text'
+#     with no default,
+ALTER TABLE t1_nodef ADD x INT NOT NULL;
+# ... and remove the last column in t2
+ALTER TABLE t2 DROP b;
 # ... change the type of the single column in table 't4'
 ALTER TABLE t4 MODIFY a FLOAT;
 # ... change the type of the middle column of table 't5'
@@ -31,49 +53,70 @@ ALTER TABLE t5 MODIFY b FLOAT;
 # ... change the type of the last column of table 't6'
 ALTER TABLE t6 MODIFY c FLOAT;
 
+# Insert some values for tables on slave side. These should not be
+# modified when the row from the master is applied.
+INSERT INTO t1_int  VALUES (2, 4, 4711);
+INSERT INTO t1_char VALUES (2, 4, 'Foo is a bar');
+INSERT INTO t1_bit  VALUES (2, 4, b'101', b'11100', b'01');
+
+--echo **** On Master ****
+connection master;
+INSERT INTO t1_int VALUES (1,2);
+INSERT INTO t1_int VALUES (2,5);
+INSERT INTO t1_bit VALUES (1,2);
+INSERT INTO t1_bit VALUES (2,5);
+INSERT INTO t1_char VALUES (1,2);
+INSERT INTO t1_char VALUES (2,5);
+SELECT * FROM t1_int;
+SELECT * FROM t1_bit;
+SELECT * FROM t1_char;
+--echo **** On Slave ****
+sync_slave_with_master;
+SELECT a,b,x FROM t1_int;
+SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit;
+SELECT a,b,x FROM t1_char;
+
+--echo **** On Master ****
+connection master;
+UPDATE t1_int  SET b=2*b WHERE a=2;
+UPDATE t1_char SET b=2*b WHERE a=2;
+UPDATE t1_bit  SET b=2*b WHERE a=2;
+SELECT * FROM t1_int;
+SELECT * FROM t1_bit;
+SELECT * FROM t1_char;
+--echo **** On Slave ****
+sync_slave_with_master;
+SELECT a,b,x FROM t1_int;
+SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit;
+SELECT a,b,x FROM t1_char;
+
 # Each of these should generate an error and stop the slave
-connection master;
-INSERT INTO t9 VALUES (1);
-sync_slave_with_master;
-# Now slave is guaranteed to be running
-connection master;
-INSERT INTO t1 VALUES (1,2);
-connection slave;
-wait_for_slave_to_stop;
---replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 23 # 33 #
---vertical_results
-SHOW SLAVE STATUS;
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
-START SLAVE;
 
 connection master;
 INSERT INTO t9 VALUES (2);
 sync_slave_with_master;
 # Now slave is guaranteed to be running
 connection master;
-INSERT INTO t2 VALUES (2,4);
+INSERT INTO t1_nodef VALUES (1,2);
 connection slave;
 wait_for_slave_to_stop;
 --replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 23 # 33 #
---vertical_results
-SHOW SLAVE STATUS;
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
 START SLAVE;
 
 connection master;
-INSERT INTO t9 VALUES (3);
+INSERT INTO t9 VALUES (2);
 sync_slave_with_master;
 # Now slave is guaranteed to be running
 connection master;
-INSERT INTO t3 VALUES (3,6);
+INSERT INTO t2 VALUES (2,4);
 connection slave;
 wait_for_slave_to_stop;
 --replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 23 # 33 #
---vertical_results
-SHOW SLAVE STATUS;
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
 START SLAVE;
 
@@ -86,9 +129,8 @@ INSERT INTO t4 VALUES (4);
 connection slave;
 wait_for_slave_to_stop;
 --replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 23 # 33 #
---vertical_results
-SHOW SLAVE STATUS;
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
 START SLAVE;
 
@@ -101,9 +143,8 @@ INSERT INTO t5 VALUES (5,10,25);
 connection slave;
 wait_for_slave_to_stop;
 --replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 23 # 33 #
---vertical_results
-SHOW SLAVE STATUS;
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
 START SLAVE;
 
@@ -116,14 +157,14 @@ INSERT INTO t6 VALUES (6,12,36);
 connection slave;
 wait_for_slave_to_stop;
 --replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 23 # 33 #
---vertical_results
-SHOW SLAVE STATUS;
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
 START SLAVE;
 
 connection master;
 --disable_warnings
-DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t9;
+DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef;
+DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t9;
 --enable_warnings
 sync_slave_with_master;

--- 1.5/mysql-test/r/rpl_row_tabledefs_2myisam.result	2006-09-07 14:31:57 +03:00
+++ 1.6/mysql-test/r/rpl_row_tabledefs_2myisam.result	2006-09-07 14:31:57 +03:00
@@ -4,21 +4,96 @@ reset master;
 reset slave;
 drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
 start slave;
-CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
-CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
-CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
-CREATE TABLE t4 (a INT) ENGINE=myisam;
-CREATE TABLE t5 (a INT, b INT, c INT) ENGINE=myisam;
-CREATE TABLE t6 (a INT, b INT, c INT) ENGINE=myisam;
-CREATE TABLE t9 (a INT PRIMARY KEY) ENGINE=myisam;
-ALTER TABLE t1 ADD x INT DEFAULT 42;
-ALTER TABLE t2 ADD x INT DEFAULT 42 AFTER a;
-ALTER TABLE t3 ADD x INT DEFAULT 42 FIRST;
+STOP SLAVE;
+SET GLOBAL SQL_MODE='STRICT_ALL_TABLES';
+START SLAVE;
+CREATE TABLE t1_int (a INT PRIMARY KEY, b INT) ENGINE='MyISAM';
+CREATE TABLE t1_bit (a INT PRIMARY KEY, b INT) ENGINE='MyISAM';
+CREATE TABLE t1_char (a INT PRIMARY KEY, b INT) ENGINE='MyISAM';
+CREATE TABLE t1_nodef (a INT PRIMARY KEY, b INT) ENGINE='MyISAM';
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE='MyISAM';
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE='MyISAM';
+CREATE TABLE t4 (a INT) ENGINE='MyISAM';
+CREATE TABLE t5 (a INT, b INT, c INT) ENGINE='MyISAM';
+CREATE TABLE t6 (a INT, b INT, c INT) ENGINE='MyISAM';
+CREATE TABLE t9 (a INT) ENGINE='MyISAM';
+ALTER TABLE t1_int ADD x INT DEFAULT 42;
+ALTER TABLE t1_bit
+ADD x BIT(3) DEFAULT b'011',
+ADD y BIT(5) DEFAULT b'10101',
+ADD z BIT(2) DEFAULT b'10';
+ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test';
+ALTER TABLE t1_nodef ADD x INT NOT NULL;
+ALTER TABLE t2 DROP b;
 ALTER TABLE t4 MODIFY a FLOAT;
 ALTER TABLE t5 MODIFY b FLOAT;
 ALTER TABLE t6 MODIFY c FLOAT;
-INSERT INTO t9 VALUES (1);
-INSERT INTO t1 VALUES (1,2);
+INSERT INTO t1_int  VALUES (2, 4, 4711);
+INSERT INTO t1_char VALUES (2, 4, 'Foo is a bar');
+INSERT INTO t1_bit  VALUES (2, 4, b'101', b'11100', b'01');
+**** On Master ****
+INSERT INTO t1_int VALUES (1,2);
+INSERT INTO t1_int VALUES (2,5);
+INSERT INTO t1_bit VALUES (1,2);
+INSERT INTO t1_bit VALUES (2,5);
+INSERT INTO t1_char VALUES (1,2);
+INSERT INTO t1_char VALUES (2,5);
+SELECT * FROM t1_int;
+a	b
+1	2
+2	5
+SELECT * FROM t1_bit;
+a	b
+1	2
+2	5
+SELECT * FROM t1_char;
+a	b
+1	2
+2	5
+**** On Slave ****
+SELECT a,b,x FROM t1_int;
+a	b	x
+2	5	4711
+1	2	42
+SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit;
+a	b	HEX(x)	HEX(y)	HEX(z)
+2	5	5	1C	1
+1	2	3	15	2
+SELECT a,b,x FROM t1_char;
+a	b	x
+2	5	Foo is a bar
+1	2	Just a test
+**** On Master ****
+UPDATE t1_int  SET b=2*b WHERE a=2;
+UPDATE t1_char SET b=2*b WHERE a=2;
+UPDATE t1_bit  SET b=2*b WHERE a=2;
+SELECT * FROM t1_int;
+a	b
+1	2
+2	10
+SELECT * FROM t1_bit;
+a	b
+1	2
+2	10
+SELECT * FROM t1_char;
+a	b
+1	2
+2	10
+**** On Slave ****
+SELECT a,b,x FROM t1_int;
+a	b	x
+2	10	4711
+1	2	42
+SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit;
+a	b	HEX(x)	HEX(y)	HEX(z)
+2	10	5	1C	1
+1	2	3	15	2
+SELECT a,b,x FROM t1_char;
+a	b	x
+2	10	Foo is a bar
+1	2	Just a test
+INSERT INTO t9 VALUES (2);
+INSERT INTO t1_nodef VALUES (1,2);
 SHOW SLAVE STATUS;
 Slave_IO_State	#
 Master_Host	127.0.0.1
@@ -26,7 +101,7 @@ Master_User	root
 Master_Port	MASTER_PORT
 Connect_Retry	1
 Master_Log_File	master-bin.000001
-Read_Master_Log_Pos	1042
+Read_Master_Log_Pos	#
 Relay_Log_File	#
 Relay_Log_Pos	#
 Relay_Master_Log_File	master-bin.000001
@@ -38,10 +113,10 @@ Replicate_Do_Table	
 Replicate_Ignore_Table	
 Replicate_Wild_Do_Table	
 Replicate_Wild_Ignore_Table	
-Last_Errno	1454
-Last_Error	Table width mismatch - received 2 columns, test.t1 has 3 columns
+Last_Errno	1364
+Last_Error	Error in Write_rows event: error during transaction execution on table test.t1_nodef
 Skip_Counter	0
-Exec_Master_Log_Pos	968
+Exec_Master_Log_Pos	#
 Relay_Log_Space	#
 Until_Condition	None
 Until_Log_File	
@@ -64,45 +139,7 @@ Master_User	root
 Master_Port	MASTER_PORT
 Connect_Retry	1
 Master_Log_File	master-bin.000001
-Read_Master_Log_Pos	1185
-Relay_Log_File	#
-Relay_Log_Pos	#
-Relay_Master_Log_File	master-bin.000001
-Slave_IO_Running	Yes
-Slave_SQL_Running	No
-Replicate_Do_DB	
-Replicate_Ignore_DB	
-Replicate_Do_Table	
-Replicate_Ignore_Table	
-Replicate_Wild_Do_Table	
-Replicate_Wild_Ignore_Table	
-Last_Errno	1454
-Last_Error	Table width mismatch - received 2 columns, test.t2 has 3 columns
-Skip_Counter	0
-Exec_Master_Log_Pos	1111
-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	#
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
-START SLAVE;
-INSERT INTO t9 VALUES (3);
-INSERT INTO t3 VALUES (3,6);
-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.000001
-Read_Master_Log_Pos	1328
+Read_Master_Log_Pos	#
 Relay_Log_File	#
 Relay_Log_Pos	#
 Relay_Master_Log_File	master-bin.000001
@@ -114,10 +151,10 @@ Replicate_Do_Table	
 Replicate_Ignore_Table	
 Replicate_Wild_Do_Table	
 Replicate_Wild_Ignore_Table	
-Last_Errno	1454
-Last_Error	Table width mismatch - received 2 columns, test.t3 has 3 columns
+Last_Errno	1514
+Last_Error	Table width mismatch - received 2 columns, test.t2 has 1 columns
 Skip_Counter	0
-Exec_Master_Log_Pos	1254
+Exec_Master_Log_Pos	#
 Relay_Log_Space	#
 Until_Condition	None
 Until_Log_File	
@@ -140,7 +177,7 @@ Master_User	root
 Master_Port	MASTER_PORT
 Connect_Retry	1
 Master_Log_File	master-bin.000001
-Read_Master_Log_Pos	1466
+Read_Master_Log_Pos	#
 Relay_Log_File	#
 Relay_Log_Pos	#
 Relay_Master_Log_File	master-bin.000001
@@ -152,10 +189,10 @@ Replicate_Do_Table	
 Replicate_Ignore_Table	
 Replicate_Wild_Do_Table	
 Replicate_Wild_Ignore_Table	
-Last_Errno	1454
+Last_Errno	1514
 Last_Error	Column 0 type mismatch - received type 3, test.t4 has type 4
 Skip_Counter	0
-Exec_Master_Log_Pos	1397
+Exec_Master_Log_Pos	#
 Relay_Log_Space	#
 Until_Condition	None
 Until_Log_File	
@@ -178,7 +215,7 @@ Master_User	root
 Master_Port	MASTER_PORT
 Connect_Retry	1
 Master_Log_File	master-bin.000001
-Read_Master_Log_Pos	1614
+Read_Master_Log_Pos	#
 Relay_Log_File	#
 Relay_Log_Pos	#
 Relay_Master_Log_File	master-bin.000001
@@ -190,10 +227,10 @@ Replicate_Do_Table	
 Replicate_Ignore_Table	
 Replicate_Wild_Do_Table	
 Replicate_Wild_Ignore_Table	
-Last_Errno	1454
+Last_Errno	1514
 Last_Error	Column 1 type mismatch - received type 3, test.t5 has type 4
 Skip_Counter	0
-Exec_Master_Log_Pos	1535
+Exec_Master_Log_Pos	#
 Relay_Log_Space	#
 Until_Condition	None
 Until_Log_File	
@@ -216,7 +253,7 @@ Master_User	root
 Master_Port	MASTER_PORT
 Connect_Retry	1
 Master_Log_File	master-bin.000001
-Read_Master_Log_Pos	1762
+Read_Master_Log_Pos	#
 Relay_Log_File	#
 Relay_Log_Pos	#
 Relay_Master_Log_File	master-bin.000001
@@ -228,10 +265,10 @@ Replicate_Do_Table	
 Replicate_Ignore_Table	
 Replicate_Wild_Do_Table	
 Replicate_Wild_Ignore_Table	
-Last_Errno	1454
+Last_Errno	1514
 Last_Error	Column 2 type mismatch - received type 3, test.t6 has type 4
 Skip_Counter	0
-Exec_Master_Log_Pos	1683
+Exec_Master_Log_Pos	#
 Relay_Log_Space	#
 Until_Condition	None
 Until_Log_File	
@@ -245,4 +282,5 @@ Master_SSL_Key	
 Seconds_Behind_Master	#
 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
 START SLAVE;
-DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t9;
+DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef;
+DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t9;

--- 1.3/mysql-test/r/rpl_row_tabledefs_3innodb.result	2006-09-07 14:31:57 +03:00
+++ 1.4/mysql-test/r/rpl_row_tabledefs_3innodb.result	2006-09-07 14:31:57 +03:00
@@ -0,0 +1,286 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+STOP SLAVE;
+SET GLOBAL SQL_MODE='STRICT_ALL_TABLES';
+START SLAVE;
+CREATE TABLE t1_int (a INT PRIMARY KEY, b INT) ENGINE='InnoDB';
+CREATE TABLE t1_bit (a INT PRIMARY KEY, b INT) ENGINE='InnoDB';
+CREATE TABLE t1_char (a INT PRIMARY KEY, b INT) ENGINE='InnoDB';
+CREATE TABLE t1_nodef (a INT PRIMARY KEY, b INT) ENGINE='InnoDB';
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE='InnoDB';
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE='InnoDB';
+CREATE TABLE t4 (a INT) ENGINE='InnoDB';
+CREATE TABLE t5 (a INT, b INT, c INT) ENGINE='InnoDB';
+CREATE TABLE t6 (a INT, b INT, c INT) ENGINE='InnoDB';
+CREATE TABLE t9 (a INT) ENGINE='InnoDB';
+ALTER TABLE t1_int ADD x INT DEFAULT 42;
+ALTER TABLE t1_bit
+ADD x BIT(3) DEFAULT b'011',
+ADD y BIT(5) DEFAULT b'10101',
+ADD z BIT(2) DEFAULT b'10';
+ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test';
+ALTER TABLE t1_nodef ADD x INT NOT NULL;
+ALTER TABLE t2 DROP b;
+ALTER TABLE t4 MODIFY a FLOAT;
+ALTER TABLE t5 MODIFY b FLOAT;
+ALTER TABLE t6 MODIFY c FLOAT;
+INSERT INTO t1_int  VALUES (2, 4, 4711);
+INSERT INTO t1_char VALUES (2, 4, 'Foo is a bar');
+INSERT INTO t1_bit  VALUES (2, 4, b'101', b'11100', b'01');
+**** On Master ****
+INSERT INTO t1_int VALUES (1,2);
+INSERT INTO t1_int VALUES (2,5);
+INSERT INTO t1_bit VALUES (1,2);
+INSERT INTO t1_bit VALUES (2,5);
+INSERT INTO t1_char VALUES (1,2);
+INSERT INTO t1_char VALUES (2,5);
+SELECT * FROM t1_int;
+a	b
+1	2
+2	5
+SELECT * FROM t1_bit;
+a	b
+1	2
+2	5
+SELECT * FROM t1_char;
+a	b
+1	2
+2	5
+**** On Slave ****
+SELECT a,b,x FROM t1_int;
+a	b	x
+2	5	4711
+1	2	42
+SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit;
+a	b	HEX(x)	HEX(y)	HEX(z)
+2	5	5	1C	1
+1	2	3	15	2
+SELECT a,b,x FROM t1_char;
+a	b	x
+2	5	Foo is a bar
+1	2	Just a test
+**** On Master ****
+UPDATE t1_int  SET b=2*b WHERE a=2;
+UPDATE t1_char SET b=2*b WHERE a=2;
+UPDATE t1_bit  SET b=2*b WHERE a=2;
+SELECT * FROM t1_int;
+a	b
+1	2
+2	10
+SELECT * FROM t1_bit;
+a	b
+1	2
+2	10
+SELECT * FROM t1_char;
+a	b
+1	2
+2	10
+**** On Slave ****
+SELECT a,b,x FROM t1_int;
+a	b	x
+2	10	4711
+1	2	42
+SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit;
+a	b	HEX(x)	HEX(y)	HEX(z)
+2	10	5	1C	1
+1	2	3	15	2
+SELECT a,b,x FROM t1_char;
+a	b	x
+2	10	Foo is a bar
+1	2	Just a test
+INSERT INTO t9 VALUES (2);
+INSERT INTO t1_nodef VALUES (1,2);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1364
+Last_Error	Error in Write_rows event: error during transaction execution on table test.t1_nodef
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+INSERT INTO t9 VALUES (2);
+INSERT INTO t2 VALUES (2,4);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1522
+Last_Error	Table width mismatch - received 2 columns, test.t2 has 1 columns
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+INSERT INTO t9 VALUES (4);
+INSERT INTO t4 VALUES (4);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1522
+Last_Error	Column 0 type mismatch - received type 3, test.t4 has type 4
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+INSERT INTO t9 VALUES (5);
+INSERT INTO t5 VALUES (5,10,25);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1522
+Last_Error	Column 1 type mismatch - received type 3, test.t5 has type 4
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+INSERT INTO t9 VALUES (6);
+INSERT INTO t6 VALUES (6,12,36);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1522
+Last_Error	Column 2 type mismatch - received type 3, test.t6 has type 4
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef;
+DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t9;

--- 1.2/mysql-test/r/rpl_row_tabledefs_7ndb.result	2006-09-07 14:31:57 +03:00
+++ 1.3/mysql-test/r/rpl_row_tabledefs_7ndb.result	2006-09-07 14:31:57 +03:00
@@ -0,0 +1,286 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+STOP SLAVE;
+SET GLOBAL SQL_MODE='STRICT_ALL_TABLES';
+START SLAVE;
+CREATE TABLE t1_int (a INT PRIMARY KEY, b INT) ENGINE='NDB';
+CREATE TABLE t1_bit (a INT PRIMARY KEY, b INT) ENGINE='NDB';
+CREATE TABLE t1_char (a INT PRIMARY KEY, b INT) ENGINE='NDB';
+CREATE TABLE t1_nodef (a INT PRIMARY KEY, b INT) ENGINE='NDB';
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE='NDB';
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE='NDB';
+CREATE TABLE t4 (a INT) ENGINE='NDB';
+CREATE TABLE t5 (a INT, b INT, c INT) ENGINE='NDB';
+CREATE TABLE t6 (a INT, b INT, c INT) ENGINE='NDB';
+CREATE TABLE t9 (a INT) ENGINE='NDB';
+ALTER TABLE t1_int ADD x INT DEFAULT 42;
+ALTER TABLE t1_bit
+ADD x BIT(3) DEFAULT b'011',
+ADD y BIT(5) DEFAULT b'10101',
+ADD z BIT(2) DEFAULT b'10';
+ALTER TABLE t1_char ADD x CHAR(20) DEFAULT 'Just a test';
+ALTER TABLE t1_nodef ADD x INT NOT NULL;
+ALTER TABLE t2 DROP b;
+ALTER TABLE t4 MODIFY a FLOAT;
+ALTER TABLE t5 MODIFY b FLOAT;
+ALTER TABLE t6 MODIFY c FLOAT;
+INSERT INTO t1_int  VALUES (2, 4, 4711);
+INSERT INTO t1_char VALUES (2, 4, 'Foo is a bar');
+INSERT INTO t1_bit  VALUES (2, 4, b'101', b'11100', b'01');
+**** On Master ****
+INSERT INTO t1_int VALUES (1,2);
+INSERT INTO t1_int VALUES (2,5);
+INSERT INTO t1_bit VALUES (1,2);
+INSERT INTO t1_bit VALUES (2,5);
+INSERT INTO t1_char VALUES (1,2);
+INSERT INTO t1_char VALUES (2,5);
+SELECT * FROM t1_int;
+a	b
+1	2
+2	5
+SELECT * FROM t1_bit;
+a	b
+1	2
+2	5
+SELECT * FROM t1_char;
+a	b
+1	2
+2	5
+**** On Slave ****
+SELECT a,b,x FROM t1_int;
+a	b	x
+1	2	42
+2	5	42
+SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit;
+a	b	HEX(x)	HEX(y)	HEX(z)
+1	2	3	15	2
+2	5	3	15	2
+SELECT a,b,x FROM t1_char;
+a	b	x
+1	2	Just a test
+2	5	Just a test
+**** On Master ****
+UPDATE t1_int  SET b=2*b WHERE a=2;
+UPDATE t1_char SET b=2*b WHERE a=2;
+UPDATE t1_bit  SET b=2*b WHERE a=2;
+SELECT * FROM t1_int;
+a	b
+1	2
+2	10
+SELECT * FROM t1_bit;
+a	b
+1	2
+2	10
+SELECT * FROM t1_char;
+a	b
+1	2
+2	10
+**** On Slave ****
+SELECT a,b,x FROM t1_int;
+a	b	x
+1	2	42
+2	10	42
+SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit;
+a	b	HEX(x)	HEX(y)	HEX(z)
+1	2	3	15	2
+2	10	3	15	2
+SELECT a,b,x FROM t1_char;
+a	b	x
+1	2	Just a test
+2	10	Just a test
+INSERT INTO t9 VALUES (2);
+INSERT INTO t1_nodef VALUES (1,2);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1364
+Last_Error	Error in Write_rows event: error during transaction execution on table test.t1_nodef
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+INSERT INTO t9 VALUES (2);
+INSERT INTO t2 VALUES (2,4);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1514
+Last_Error	Table width mismatch - received 2 columns, test.t2 has 1 columns
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+INSERT INTO t9 VALUES (4);
+INSERT INTO t4 VALUES (4);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1514
+Last_Error	Column 0 type mismatch - received type 3, test.t4 has type 4
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+INSERT INTO t9 VALUES (5);
+INSERT INTO t5 VALUES (5,10,25);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1514
+Last_Error	Column 1 type mismatch - received type 3, test.t5 has type 4
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+INSERT INTO t9 VALUES (6);
+INSERT INTO t6 VALUES (6,12,36);
+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.000001
+Read_Master_Log_Pos	#
+Relay_Log_File	#
+Relay_Log_Pos	#
+Relay_Master_Log_File	master-bin.000001
+Slave_IO_Running	Yes
+Slave_SQL_Running	No
+Replicate_Do_DB	
+Replicate_Ignore_DB	
+Replicate_Do_Table	
+Replicate_Ignore_Table	
+Replicate_Wild_Do_Table	
+Replicate_Wild_Ignore_Table	
+Last_Errno	1514
+Last_Error	Column 2 type mismatch - received type 3, test.t6 has type 4
+Skip_Counter	0
+Exec_Master_Log_Pos	#
+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	#
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef;
+DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t9;

--- 1.3/mysql-test/t/rpl_row_tabledefs_2myisam.test	2006-09-07 14:31:57 +03:00
+++ 1.4/mysql-test/t/rpl_row_tabledefs_2myisam.test	2006-09-07 14:31:57 +03:00
@@ -0,0 +1,8 @@
+
+-- source include/have_binlog_format_row.inc
+-- source include/master-slave.inc
+
+let $engine_type = 'MyISAM';
+-- source extra/rpl_tests/rpl_row_tabledefs.test
+
+

--- 1.2/mysql-test/t/rpl_row_tabledefs_3innodb.test	2006-09-07 14:31:57 +03:00
+++ 1.3/mysql-test/t/rpl_row_tabledefs_3innodb.test	2006-09-07 14:31:57 +03:00
@@ -0,0 +1,9 @@
+
+-- source include/have_binlog_format_row.inc
+-- source include/have_innodb.inc
+-- source include/master-slave.inc
+
+let $engine_type = 'InnoDB';
+-- source extra/rpl_tests/rpl_row_tabledefs.test
+
+

--- 1.2/sql/rpl_utility.cc	2006-09-07 14:31:57 +03:00
+++ 1.3/sql/rpl_utility.cc	2006-09-07 14:31:57 +03:00
@@ -0,0 +1,156 @@
+/* Copyright 2006 MySQL AB. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include "rpl_utility.h"
+
+uint32
+field_length_from_packed(enum_field_types const field_type, 
+                         byte const *const data)
+{
+  uint32 length;
+
+  switch (field_type) {
+  case MYSQL_TYPE_DECIMAL:
+  case MYSQL_TYPE_NEWDECIMAL:
+    length= ~0UL;
+    break;
+  case MYSQL_TYPE_YEAR:
+  case MYSQL_TYPE_TINY:
+    length= 1;
+    break;
+  case MYSQL_TYPE_SHORT:
+    length= 2;
+    break;
+  case MYSQL_TYPE_INT24:
+    length= 3;
+    break;
+  case MYSQL_TYPE_LONG:
+    length= 4;
+    break;
+#ifdef HAVE_LONG_LONG
+  case MYSQL_TYPE_LONGLONG:
+    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;
+  case MYSQL_TYPE_NEWDATE:
+    length= 3;
+    break;
+  case MYSQL_TYPE_DATE:
+    length= 4;
+    break;
+  case MYSQL_TYPE_TIME:
+    length= 3;
+    break;
+  case MYSQL_TYPE_TIMESTAMP:
+    length= 4;
+    break;
+  case MYSQL_TYPE_DATETIME:
+    length= 8;
+    break;
+    break;
+  case MYSQL_TYPE_BIT:
+    length= ~0UL;
+    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);
+    break;
+
+  case MYSQL_TYPE_ENUM:
+  case MYSQL_TYPE_SET:
+  case MYSQL_TYPE_VAR_STRING:
+  case MYSQL_TYPE_VARCHAR:
+    length= ~0UL;                               // NYI
+    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= ~0UL;                               // NYI
+    break;
+  }
+}
+
+/*********************************************************************
+ *                   table_def member definitions                    *
+ *********************************************************************/
+
+/*
+  Is the definition compatible with a table?
+
+  Compare the definition with a table to see if it is compatible with
+  it.  A table definition is compatible with a table if
+  - the columns types of the table definition is a (not necessarily
+    proper) prefix of the column type of the table, or
+  - the other way around
+*/
+int
+table_def::compatible_with(RELAY_LOG_INFO *rli, TABLE *table)
+  const
+{
+  /*
+    We only check the initial columns for the tables.
+  */
+  uint const cols_to_check= min(table->s->fields, size());
+  int error= 0;
+
+  TABLE_SHARE const *const tsh= table->s;
+
+  /*
+    To get proper error reporting for all columns of the table, we
+    both check the width and iterate over all columns.
+  */
+  if (tsh->fields < size())
+  {
+    DBUG_ASSERT(tsh->db.str && tsh->table_name.str);
+    error= 1;
+    slave_print_msg(ERROR_LEVEL, rli, ER_BINLOG_ROW_WRONG_TABLE_DEF,
+                    "Table width mismatch - "
+                    "received %u columns, %s.%s has %u columns",
+                    size(), tsh->db.str, tsh->table_name.str, tsh->fields);
+  }
+
+  for (uint col= 0 ; col < cols_to_check ; ++col)
+  {
+    if (table->field[col]->type() != type(col))
+    {
+      DBUG_ASSERT(col < size() && col < tsh->fields);
+      DBUG_ASSERT(tsh->db.str && tsh->table_name.str);
+      error= 1;
+      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, type(col), tsh->db.str, tsh->table_name.str,
+                      table->field[col]->type());
+    }
+  }
+
+  return error;
+}

--- 1.2/sql/rpl_utility.h	2006-09-07 14:31:57 +03:00
+++ 1.3/sql/rpl_utility.h	2006-09-07 14:31:57 +03:00
@@ -0,0 +1,60 @@
+/* Copyright 2006 MySQL AB. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef RPL_UTILITY_H
+#define RPL_UTILITY_H
+
+#ifndef __cplusplus
+#error "Don't include this C++ header file from a non-C++ file!"
+#endif
+
+#include "mysql_priv.h"
+
+uint32
+field_length_from_packed(enum_field_types const field_type, 
+                         byte const *const data);
+
+/*
+  A table definition from the master.
+
+  RESPONSIBILITIES
+
+  - Extract table definition data from the table map event
+  - Check if table definition in table map is compatible with table
+    definition on slave
+ */
+
+class table_def
+{
+public:
+  typedef unsigned char field_type;
+
+  table_def(field_type *t, my_size_t s)
+    : m_type(t), m_size(s)
+  {
+  }
+
+  my_size_t size() const { return m_size; }
+  field_type type(my_ptrdiff_t i) const { return m_type[i]; }
+
+  int compatible_with(RELAY_LOG_INFO *rli, TABLE *table) const;
+
+private:
+  my_size_t m_size;
+  field_type *m_type;
+};
+
+#endif /* RPL_UTILITY_H */
Thread
bk commit into 5.1 tree (aelkin:1.2255)Andrei Elkin7 Sep