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

ChangeSet@stripped, 2007-05-21 21:23:19+02:00, rafal@quant.(none) +9 -0
  BUG#21842 (Cluster fails to replicate to innodb or myisam with err 134 
  using TPC-B):
  
  This patch implements solution b described in the bug report with some
  modifications. Main modifications are:
  
  - make replace_record() function a method of Rows_log_event as an 
    instance of this class contains most of the data needed by the function.
  - make similar modifications to find_and_fetch_row() function. Also in
    this case row data is unpacked inside the function.
  - make modified versions of rpl_ndb_2xxx tests so that they work in
    the current tree and test that modified code correctly handles 
    ndb->other replication.

  mysql-test/extra/rpl_tests/rpl_ndb_2multi_basic.test@stripped, 2007-05-21 21:23:16+02:00,
rafal@quant.(none) +74 -0
    Version of rpl_ndb_2multi test which doesnt test partitions (the full
    version doesn't work right now - when it works, it can replace this 
    test).

  mysql-test/extra/rpl_tests/rpl_ndb_2multi_basic.test@stripped, 2007-05-21 21:23:16+02:00,
rafal@quant.(none) +0 -0

  mysql-test/include/rpl_multi_engine.inc@stripped, 2007-05-21 21:23:15+02:00,
rafal@quant.(none) +17 -0
    Added documentation.

  mysql-test/include/rpl_multi_engine3.inc@stripped, 2007-05-21 21:23:15+02:00,
rafal@quant.(none) +20 -2
    - Added documentation.
    - Removed DELETE statement causing failure (see BUG#28538). 
    Note: this breaks old rpl_ndb2xxx tests which include this file, but 
    these tests are disabled anyway.

  mysql-test/r/rpl_ndb_2innodb_basic.result@stripped, 2007-05-21 21:23:16+02:00,
rafal@quant.(none) +162 -0
    Basic version of rpl_ndb_2innodb test.

  mysql-test/r/rpl_ndb_2innodb_basic.result@stripped, 2007-05-21 21:23:16+02:00,
rafal@quant.(none) +0 -0

  mysql-test/r/rpl_ndb_2myisam_basic.result@stripped, 2007-05-21 21:23:16+02:00,
rafal@quant.(none) +159 -0
    Basic version of rpl_ndb_2myisam test.

  mysql-test/r/rpl_ndb_2myisam_basic.result@stripped, 2007-05-21 21:23:16+02:00,
rafal@quant.(none) +0 -0

  mysql-test/t/rpl_ndb_2innodb_basic.test@stripped, 2007-05-21 21:23:15+02:00,
rafal@quant.(none) +18 -0
    Basic version of rpl_ndb_2myisam test.

  mysql-test/t/rpl_ndb_2innodb_basic.test@stripped, 2007-05-21 21:23:15+02:00,
rafal@quant.(none) +0 -0

  mysql-test/t/rpl_ndb_2myisam_basic.test@stripped, 2007-05-21 21:23:15+02:00,
rafal@quant.(none) +11 -0
    Basic version of rpl_ndb_2myisam test.

  mysql-test/t/rpl_ndb_2myisam_basic.test@stripped, 2007-05-21 21:23:15+02:00,
rafal@quant.(none) +0 -0

  sql/log_event.cc@stripped, 2007-05-21 21:23:15+02:00, rafal@quant.(none) +474 -428
    - In Rows_log_event::do_apply_event():
     -- Set and use COMPLETE_ROWS_F flag for optimization.
     -- Before, table->read_set was the same as table->write_set, but now
        we use complete read_set since we want to read all columns (also 
        the missing ones).
    
    - Changes in find_and_fetch_row():
     -- it becomes a member of Rows_log_event,
     -- the row to be located is taken from event's row data buffer 
        (pointed by m_curr_row) not from table->record[0] as before,
     -- the row is unpacked inside this function,
     -- one of three methods to locate the row is choosen explicitely - 
        a switch statement is used to execute correct method,
     -- table->record[0] is used consequently as a buffer for the record
        being located,
     -- if key is used to locate the record, key data is fetched from row
        inside this function (not in do_prepare_row() as before),
     -- code handling null bytes is removed as now the canonical row
        format is used,
     -- more debug messages added,
     -- file->print_error() is used when reporting errors comming from
        storage engine.
    
    - Changes in insert_row() (formely replace_record()):
     -- it is a member of Rows_log_event,
     -- the row to be located is taken from event's row data buffer 
        (pointed by m_curr_row) not from table->record[0] as before,
     -- the row is unpacked inside this function,
     -- more debug messages added,
     -- file->print_error() is used when reporting errors comming from
        storage engine.
    
    - Remove do_prepare_row() methods which now do nothing (no row 
      unpacking needed).
    - m_after_image no longer used. Only m_key buffer is allocated.
    - Changes in Update_rows_log_event::do_exec_row() to use new semantics
      of function's.
    

  sql/log_event.h@stripped, 2007-05-21 21:23:15+02:00, rafal@quant.(none) +78 -55
    - Added COMPLETE_ROWS_F flag for Rows_log_event.
    - Changed order of member declarations.
    - Added m_key member (previously declared in subclasses).
    - Turned find_and_fetch_row() into a member of Rows_log_event class.
    - Changed replace_record() into Rows_log_event::insert_row() member function.
    - Added unpack_row() member function to Rows_log_event.
    - Added default definitions for do_xxx() members (except do_exec_row())
      so that derived classes don't have to define them if they don't need
      them. The methods become protected.
    - Removed m_memory and m_after_image members which
      are no longer used.
    - Classes derived from Rows_log_event don't need do_prepare_row() 
      method because row unpacking happes inside insert_row() or 
      find_and_fetch_row(). 
      

# 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:	rafal
# Host:	quant.(none)
# Root:	/ext/mysql/bk/mysql-5.1-bug21842

--- 1.279/sql/log_event.cc	2007-05-21 21:23:25 +02:00
+++ 1.280/sql/log_event.cc	2007-05-21 21:23:25 +02:00
@@ -32,7 +32,6 @@
 #include <base64.h>
 #include <my_bitmap.h>
 
-
 #define log_cs	&my_charset_latin1
 
 #define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
@@ -5588,7 +5587,7 @@
     m_width(tbl_arg ? tbl_arg->s->fields : 1),
     m_rows_buf(0), m_rows_cur(0), m_rows_end(0),
     m_curr_row(NULL), m_curr_row_end(NULL),
-    m_flags(0)
+    m_flags(0), m_key(NULL)
 {
   /*
     We allow a special form of dummy event when the table, and cols
@@ -5628,7 +5627,8 @@
   : Log_event(buf, description_event),
     m_row_count(0),
     m_rows_buf(0), m_rows_cur(0), m_rows_end(0),
-    m_curr_row(NULL), m_curr_row_end(NULL)
+    m_curr_row(NULL), m_curr_row_end(NULL),
+    m_key(NULL)
 {
   DBUG_ENTER("Rows_log_event::Rows_log_event(const char*,...)");
   uint8 const common_header_len= description_event->common_header_len;
@@ -5715,8 +5715,8 @@
   if (likely((bool)m_rows_buf))
   {
     m_curr_row= m_rows_buf;
-    m_rows_end= m_rows_buf + data_size;
-    m_rows_cur= m_rows_end;
+    m_rows_cur= m_rows_buf + data_size;
+    m_rows_end= m_rows_cur;
     memcpy(m_rows_buf, ptr_rows_data, data_size);
   }
   else
@@ -5894,6 +5894,7 @@
         thd->options|= OPTION_RELAXED_UNIQUE_CHECKS;
     else
         thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS;
+
     /* A small test to verify that objects have consistent types */
     DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
 
@@ -5908,6 +5909,9 @@
      */
     const_cast<RELAY_LOG_INFO*>(rli)->set_flag(RELAY_LOG_INFO::IN_STMT);
 
+     if ( m_width == table->s->fields && bitmap_is_set_all(&m_cols))
+      set_flags(COMPLETE_ROWS_F);
+
     /* 
       Initialize table's write and read sets. Extra columns are included
       as they will be filled with default values.
@@ -5918,22 +5922,30 @@
       N = number of columns on master (m_witdth)
       M = number of columns on slave 
       X = bits from the row's column set (m_cols)      
-     */
 
-    // TODO: consider doing this inside Table_map event
+      We set all bits in read_set since we want to retreive all columns even
+      when the row is not complete.
+      
+      TODO: consider doing this inside Table_map event
+     */
 
     bitmap_set_all(table->write_set);
+    bitmap_set_all(table->read_set);
 
-    // Note: I (Rafal) couldn't find any bitmap function which would
-    // copy bits from m_cols to a prefix of write_set.
-
-    for (uint bit=0 ; bit < m_width ; ++bit)
-     if (!bitmap_is_set(&m_cols,bit))
-      bitmap_clear_bit(table->write_set,bit);
+    /* 
+      Note: I (Rafal) couldn't find any bitmap function which would
+      copy bits from m_cols to a prefix of write_set. This is why I use
+      simple loop below.
+     */
+    if (!get_flags(COMPLETE_ROWS_F)) 
+      for (uint bit=0 ; bit < m_width ; ++bit)
+         if (!bitmap_is_set(&m_cols,bit))
+            bitmap_clear_bit(table->write_set,bit);
 
-    bitmap_copy(table->read_set, table->write_set); 
+    // Do event specific preparations 
 
-    error= do_before_row_operations(thd);
+    if (!error) 
+      error= do_before_row_operations(thd);
 
     // row processing loop
 
@@ -5959,9 +5971,9 @@
       case HA_ERR_RECORD_CHANGED:
       case HA_ERR_KEY_NOT_FOUND:	/* Idempotency support: OK if
                                            tuple does not exist */
-	error= 0;
+	      error= 0;
       case 0:
-	break;
+	      break;
 
       default:
       	slave_print_msg(ERROR_LEVEL, rli, thd->net.last_errno,
@@ -5971,10 +5983,21 @@
       	break;
       }
 
+      /*
+        If m_curr_row_end  was not set during event execution (e.g., because
+        of errors) we can't proceed to the next row. If the error is transient
+        (i.e., error==0 at this point) we must call unpack_row() to set 
+        m_curr_row_end.
+       */ 
+
+      if (!m_curr_row_end && !error)
+        unpack_row();
+
+      DBUG_ASSERT(error || m_curr_row_end != NULL); 
+
       // at this moment m_curr_row_end should be set
-      DBUG_ASSERT(m_curr_row_end != NULL); 
-      DBUG_ASSERT(m_curr_row < m_curr_row_end);
-      DBUG_ASSERT(m_curr_row_end <= (const char*)m_rows_end);
+      DBUG_ASSERT(error || m_curr_row < m_curr_row_end);
+      DBUG_ASSERT(error || m_curr_row_end <= (const char*)m_rows_end);
 
       m_curr_row= m_curr_row_end;
 
@@ -6367,7 +6390,7 @@
 }
 #endif
 
-
+/**** helper functions/methods ****/
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 
@@ -6375,7 +6398,7 @@
   Check if there are more UNIQUE keys after the given key.
 */
 static int
-last_uniq_key(TABLE *table, uint keyno)
+last_uniq_key(const TABLE *const table, uint keyno)
 {
   while (++keyno < table->s->keys)
     if (table->key_info[keyno].flags & HA_NOSAME)
@@ -6413,6 +6436,7 @@
 
 }
 
+
 /*
   Copy "extra" columns from record[1] to record[0].
 
@@ -6511,6 +6535,7 @@
   return 0;                                     // All OK
 }
 
+
 #define DBUG_PRINT_BITSET(N,FRM,BS)                \
   do {                                             \
     char buf[256];                                 \
@@ -6535,7 +6560,7 @@
    otherwise.
  */
 bool
-is_duplicate_key_error(int errcode)
+is_duplicate_key_error(const int errcode)
 {
   switch (errcode)
   {
@@ -6551,6 +6576,12 @@
   Compares table->record[0] and table->record[1]
 
   Returns TRUE if different.
+
+  TODO: Consider changing this method to handle incomplete rows:
+   1. make it Rows_log_event method like find_and_fetch_row() and insert_row(). 
+      It will compare the current row with table->record[0]
+   2. iterate over columns whose values are given in the row and check
+      that they have the same values in record[0].
 */
 static bool record_compare(TABLE *table)
 {
@@ -6625,49 +6656,79 @@
   return result;
 }
 
+/**
+  Locate the current row in @c m_table.
 
-/*
-  Find the row given by 'key', if the table has keys, or else use a table scan
-  to find (and fetch) the row.
+  The current row is stored in event's row buffer, pointed by @c m_curr_row 
+  member. Member @c m_width tells how many colums are there in the row (this 
+  number can be smaller than the number of columns in the table). It is assumend 
+  that event's table is already open and pointed by @c m_table.
+
+  If a corresponding record is found in the table it is stored in 
+  @c m_table->record[0]. Note that when record is located based on a primary 
+  key, it is possible that the record found differs from the row being located.
+
+  If no key is specified or table does not have keys, a table scan is used to 
+  find the row. In taht case the row should be complete and contain values for
+  all columns. However, it can still be shorter than the table, i.e. the table 
+  can contain extra columns not present in the row. 
+
+  @returns Error code on failure, 0 on success. If success @c m_table->record[0] 
+  contains the recorord found. Also, the internal "cursor" of the table is 
+  positioned at the record found.
 
-  If the engine allows random access of the records, a combination of
-  position() and rnd_pos() will be used.
+  @note If the engine allows random access of the records, a combination of
+  position() and rnd_pos() will be used. 
+ */
 
-  @param table Pointer to table to search
-  @param key   Pointer to key to use for search, if table has key
+int Rows_log_event::find_and_fetch_row()
+{
+  DBUG_ENTER("find_and_fetch_row");
 
-  @pre <code>table->record[0]</code> shall contain the row to locate
-  and <code>key</code> shall contain a key to use for searching, if
-  the engine has a key.
-
-  @post If the return value is zero, <code>table->record[1]</code>
-  will contain the fetched row and the internal "cursor" will refer to
-  the row. If the return value is non-zero,
-  <code>table->record[1]</code> is undefined.  In either case,
-  <code>table->record[0]</code> is undefined.
+  DBUG_ASSERT(m_table && m_table->in_use != NULL);
 
-  @return Zero if the row was successfully fetched into
-  <code>table->record[1]</code>, error code otherwise.
- */
+  int error;
 
-static int find_and_fetch_row(TABLE *table, byte *key)
-{
-  DBUG_ENTER("find_and_fetch_row(TABLE *table, byte *key, byte *record)");
-  DBUG_PRINT("enter", ("table: 0x%lx, key: 0x%lx  record: 0x%lx",
-           (long) table, (long) key, (long) table->record[1]));
+  /* unpack row - missing fields get default values */
+
+  prepare_record(m_table,m_width,FALSE /* don't check errors */); // TODO: shall we check
and reprot errors here?
+  error= unpack_row(); 
+
+  DBUG_PRINT("info",("looking for the following record"));
+  DBUG_DUMP("record[0]", m_table->record[0], m_table->s->reclength);
+
+  /* Select best method for locating the row based on handler capabilities */
+
+  enum { TABLE_SCAN, INDEX, POSITION } method= TABLE_SCAN;
 
-  DBUG_ASSERT(table->in_use != NULL);
+  if ((m_table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION)
&&
+      m_table->s->primary_key < MAX_KEY)
+   method= POSITION;
+  else if (m_table->s->keys > 0)
+   method= INDEX;
 
-  DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+  if (method != POSITION)
+  { 
+    m_table->use_all_columns();
 
-  if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION)
&&
-      table->s->primary_key < MAX_KEY)
+    /*
+      Save unpacked row in record[1] for comparisons during scans if they happen.
+      Note: missing columns are filled with default values and these will be used
+      in comparisons. TODO: better handling of missing columns in comparisons.
+     */ 
+    store_record(m_table,record[1]); 
+  }
+
+  /* Locate row using selected method. The record found is stored in record[0] */
+
+  switch (method) {
+
+  case POSITION:
   {
+    DBUG_PRINT("info",("locating record using primary key (position)"));
     /*
-      Use a more efficient method to fetch the record given by
-      table->record[0] if the engine allows it.  We first compute a
-      row reference using the position() member function (it will be
-      stored in table->file->ref) and the use rnd_pos() to position
+      We compute a row reference using the position() member function 
+      (it    will be stored in table->file->ref) and the use rnd_pos() to position
       the "cursor" (i.e., record[0] in this case) at the correct row.
 
       TODO: Add a check that the correct record has been fetched by
@@ -6679,63 +6740,54 @@
               int error= table->file->rnd_pos(table->record[0],
table->file->ref);
       ADD>>>  DBUG_ASSERT(memcmp(table->record[1], table->record[0],
                                  table->s->reclength) == 0);
-
     */
-    table->file->position(table->record[0]);
-    int error= table->file->rnd_pos(table->record[0], table->file->ref);
-    /*
-      rnd_pos() returns the record in table->record[0], so we have to
-      move it to table->record[1].
-     */
-    bmove_align(table->record[1], table->record[0], table->s->reclength);
-    DBUG_RETURN(error);
+    m_table->file->position(m_table->record[0]);
+    if ((error= m_table->file->rnd_pos(m_table->record[0],
m_table->file->ref)))
+      goto handler_error;
+
+    break;
   }
 
-  /* We need to retrieve all fields */
-  /* TODO: Move this out from this function to main loop */
-  table->use_all_columns();
-
-  if (table->s->keys > 0)
-  {
-    int error;
-    /* We have a key: search the table using the index */
-    if (!table->file->inited && (error= table->file->ha_index_init(0,
FALSE)))
-      DBUG_RETURN(error);
+  case INDEX:    
+  {  
+    DBUG_PRINT("info",("locating record using primary key (index_read)"));
+
+    /* Initialize primary key index (key #0) */
+
+    if (!m_table->file->inited && (error=
m_table->file->ha_index_init(0, FALSE)))
+      goto handler_error;
+
+    /* Fill key data for the row */
+
+    DBUG_ASSERT(m_key);
+    key_copy(m_key, m_table->record[0], m_table->key_info, 0);
 
-  /*
-    Don't print debug messages when running valgrind since they can
-    trigger false warnings.
-   */
 #ifndef HAVE_purify
-    DBUG_DUMP("table->record[0]", (const char *)table->record[0],
table->s->reclength);
-    DBUG_DUMP("table->record[1]", (const char *)table->record[1],
table->s->reclength);
+    /*
+      Don't print debug messages when running valgrind since they can
+      trigger false warnings.
+     */
+    DBUG_DUMP("key data", m_key, m_table->key_info->key_length);
 #endif
 
-    /*
-      We need to set the null bytes to ensure that the filler bit are
-      all set when returning.  There are storage engines that just set
-      the necessary bits on the bytes and don't set the filler bits
-      correctly.
-    */
-    my_ptrdiff_t const pos=
-      table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0;
-    table->record[1][pos]= 0xFF;
-    if ((error= table->file->index_read(table->record[1], key, HA_WHOLE_KEY,
-                                        HA_READ_KEY_EXACT)))
+    if ((error= m_table->file->index_read(m_table->record[0], m_key, 
+                                          HA_WHOLE_KEY,
+                                          HA_READ_KEY_EXACT)))
     {
-      table->file->print_error(error, MYF(0));
-      table->file->ha_index_end();
-      DBUG_RETURN(error);
+      DBUG_PRINT("info",("no record matching the key found in the table"));
+      m_table->file->ha_index_end();
+      goto handler_error;
     }
 
-  /*
-    Don't print debug messages when running valgrind since they can
-    trigger false warnings.
-   */
 #ifndef HAVE_purify
-    DBUG_DUMP("table->record[0]", (const char *)table->record[0],
table->s->reclength);
-    DBUG_DUMP("table->record[1]", (const char *)table->record[1],
table->s->reclength);
+    /*
+      Don't print debug messages when running valgrind since they can
+      trigger false warnings.
+     */
+    DBUG_PRINT("info",("found first matching record")); 
+    DBUG_DUMP("record[0]", (const char *)m_table->record[0],
m_table->s->reclength);
 #endif
+
     /*
       Below is a minor "optimization".  If the key (i.e., key number
       0) has the HA_NOSAME flag set, we know that we have found the
@@ -6750,150 +6802,232 @@
       found.  I can see no scenario where it would be incorrect to
       chose the row to change only using a PK or an UNNI.
     */
-    if (table->key_info->flags & HA_NOSAME)
+    if (!(m_table->key_info->flags & HA_NOSAME))
     {
-      table->file->ha_index_end();
-      DBUG_RETURN(0);
-    }
+      /*
+        In case key is not unique, we still have to iterate over records found
+        and find the one which is identical to the row given. The row is unpacked
+        in record[1] where missing columns are filled with default values.
+       */ 
+      DBUG_PRINT("info",("non-unique index, scanning it to find matching record")); 
 
-    while (record_compare(table))
-    {
-      int error;
+      while (record_compare(m_table))
+      {  
+        /*
+          Note: During tests I (Rafal) discovered that index_next (for NDB)
+          always places next record found in table->record[0] ignoring the buffer
+          passed as a parameter. This violates specifications given in the 
+          internals manual (!).
+
+          Because of that the code below is written so that record[0] is always
+          used as a buffer. 
+         */ 
+        if ((error= m_table->file->index_next(m_table->record[0])))
+        {
+          DBUG_PRINT("info",("no record matching the given row found"));
+          m_table->file->ha_index_end();
+          goto handler_error;
+        }
 
-      /*
-        We need to set the null bytes to ensure that the filler bit
-        are all set when returning.  There are storage engines that
-        just set the necessary bits on the bytes and don't set the
-        filler bits correctly.
+#ifndef HAVE_purify
+        /*
+          Don't print debug messages when running valgrind since they can
+          trigger false warnings.
+         */
+        DBUG_PRINT("info",("found next record")); 
+        DBUG_DUMP("record[0]", (const char *)m_table->record[0],
m_table->s->reclength);
+#endif
+      } // index scan loop
 
-        TODO[record format ndb]: Remove this code once NDB returns the
-        correct record format.
-      */
-      if (table->s->null_bytes > 0)
-      {
-        table->record[1][table->s->null_bytes - 1]|=
-          256U - (1U << table->s->last_null_bit_pos);
-      }
+    } // if !<unique_index>
 
-      if ((error= table->file->index_next(table->record[1])))
-      {
-  table->file->print_error(error, MYF(0));
-        table->file->ha_index_end();
-  DBUG_RETURN(error);
-      }
-    }
+    m_table->file->ha_index_end();
 
-    /*
-      Have to restart the scan to be able to fetch the next row.
-    */
-    table->file->ha_index_end();
+    break;
   }
-  else
-  {
+
+  case TABLE_SCAN:    
+  {    
+    DBUG_PRINT("info",("locating record using table scan (rnd_next)"));
+
     int restart_count= 0; // Number of times scanning has restarted from top
-    int error;
 
-    /* We don't have a key: search the table using rnd_next() */
-    if ((error= table->file->ha_rnd_init(1)))
-      return error;
+    if ((error= m_table->file->ha_rnd_init(1)))
+    {
+      DBUG_PRINT("info",("error initializing table scan (ha_rnd_init)"));
+      m_table->file->ha_index_end();
+      goto handler_error;
+    }
 
     /* Continue until we find the right record or have made a full loop */
+    /*
+      TODO: record_compare() below will take into account all fields in 
+      table->record[1] - some of them might be not present in the row given and are
+      filled with default values. Eventually, only the fields present in the row
+      should be used to determine if a record was found or not.
+
+      Idea: change signature of record_compare to use row data for comparison. 
+      I.e., function should check if columns present in the row have the same
+      value in table->record[0].  
+     */ 
     do
     {
-      error= table->file->rnd_next(table->record[1]);
+      error= m_table->file->rnd_next(m_table->record[0]);
 
-      DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
-      DBUG_DUMP("record[1]", table->record[1], table->s->reclength);
+      switch (error) {
 
-      switch (error)
-      {
       case 0:
-      case HA_ERR_RECORD_DELETED:
-  break;
+        DBUG_DUMP("record found", m_table->record[0], m_table->s->reclength);
+
+      case HA_ERR_RECORD_DELETED: 
+        break;
 
       case HA_ERR_END_OF_FILE:
-  if (++restart_count < 2)
-    table->file->ha_rnd_init(1);
-  break;
+        if (++restart_count < 2)
+          m_table->file->ha_rnd_init(1); // TODO: handle error...
+        break;
 
       default:
-  table->file->print_error(error, MYF(0));
-        DBUG_PRINT("info", ("Record not found"));
-        table->file->ha_rnd_end();
-  DBUG_RETURN(error);
+        DBUG_PRINT("info", ("Failed to get next record (rnd_next)"));
+        m_table->file->ha_rnd_end();
+        goto handler_error;
       }
     }
-    while (restart_count < 2 && record_compare(table));
+    while (restart_count < 2 && record_compare(m_table));
 
-    /*
-      Have to restart the scan to be able to fetch the next row.
-    */
-    DBUG_PRINT("info", ("Record %sfound", restart_count == 2 ? "not " : ""));
-    table->file->ha_rnd_end();
+    m_table->file->ha_rnd_end();
 
     DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0);
-    DBUG_RETURN(error);
+
+    if (error || restart_count == 2)
+    {
+      DBUG_PRINT("info",("Record not found"));  
+      error= error? error: HA_ERR_END_OF_FILE;
+      goto error; 
+    }
+
+    break;
   }
 
-  DBUG_RETURN(0);
+  default: DBUG_ASSERT(FALSE);
+
+  } // switch (method)
+
+  if (error)
+  {
+    DBUG_PRINT("info", ("Record not found"));
+    goto error;
+  }
+
+  /*
+    We have located the row in the table - it is stored in record[0].
+   */ 
+
+  DBUG_PRINT("info", ("Record found"));
+
+#ifndef HAVE_purify
+  /*
+    Don't print debug messages when running valgrind since they can
+    trigger false warnings.
+   */
+  DBUG_DUMP("record found", (const char *)m_table->record[0],
m_table->s->reclength);
+#endif
+
+  goto error;
+
+ handler_error:
+
+  if (error)
+    m_table->file->print_error(error, MYF(0));
+
+ error:
+
+  DBUG_RETURN(error);
+
 }
 
+/**
+  Insert the current row into @c m_table.
 
-/*
-  Write a record to a table, replacing old record if it already exists there
-  (i.e. a record with the same primary key value is replaced by the new record).
+  The row is located in the row buffer, pointed by @c m_curr_row member.
+  Number of columns of the row is stored in @c m_width member (it can be smaller
+  than the number of columns in the table to which we insert). Bitmap @c m_cols
+  indicates which colums are present in the row. It is assumend that event's 
+  table is already open and pointed by @c m_table.
+
+  If the same record already exists in the table it can be either overwritten 
+  or an error is reported depending on the value of @c overwrite flag 
+  (error reporting not yet implemented). Note that the matching record can be
+  different from the row we insert if we use primary keys to identify records in
+  the table.
+
+  The row to be inserted can contain values only for selected columns. The 
+  missing columns are filled with default values using @c prepare_record() 
+  function. If a matching record is found in the table and overwritten, the 
+  missing columns are taken from it.
+
+  @param  thd   Thread context for writing the record.
+  @param  overwrite  Shall we overwrite if the row already exists or signal 
+                error (currently ignored).
+
+  @returns Error code on failure, 0 on success.
+
+  This method, if successful, sets @c m_curr_row_end pointer to point at the
+  next row in the rows buffer. This is done when unpacking the row to be 
+  inserted.
 
-  SYNOPSIS
-      replace_record()
-      thd    Thread context for writing the record.
-      table  Table to which record should be written.
-      table->record[0]
-             The record to be written.
-      table->write_set
-             Set of columns in record[0] to be updated on replace.
-      master_reclength
-             Offset to first column that is not present on the master,
-             alternatively the length of the record on master.
+  @note If a matching record is found, it is either updated using 
+  @c ha_update_row() function or first deleted and then new record written.
 
-  RETURN VALUE
-      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,
-               ulong const master_reclength,
-               uint const master_fields)
+int
+Rows_log_event::insert_row(THD *const thd, const my_bool overwrite)
 {
-  DBUG_ENTER("replace_record");
-  DBUG_ASSERT(table != NULL && thd != NULL);
+  DBUG_ENTER("insert_row");
+  DBUG_ASSERT(m_table != NULL && thd != NULL);
 
   int error;
   int keynum;
   auto_afree_ptr<char> key(NULL);
 
+  /* fill m_table->record[0] with default values */
+
+  if ((error= prepare_record(m_table,m_width,
+                             TRUE /* check if columns have def. values */)))
+    goto error; 
+
+  /* unpack row into m_table->record[0] */
+  error= unpack_row(); // TODO: how to handle errors?
+
 #ifndef DBUG_OFF
-  DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
-  DBUG_PRINT_BITSET("debug", "write_set = %s", table->write_set);
-  DBUG_PRINT_BITSET("debug", "read_set = %s", table->read_set);
+  DBUG_DUMP("record[0]", m_table->record[0], m_table->s->reclength);
+  DBUG_PRINT_BITSET("debug", "write_set = %s", m_table->write_set);
+  DBUG_PRINT_BITSET("debug", "read_set = %s", m_table->read_set);
 #endif
 
-  while ((error= table->file->ha_write_row(table->record[0])))
+  /* 
+    Try to write record. If a corresponding record already exists in the table,
+    we try to change it using ha_update_row() if possible. Otherwise we delete
+    it and jump here to try writing again. 
+
+    TODO: Add safety measures against infinite looping. 
+   */
+
+ write_row:
+
+  if ((error= m_table->file->ha_write_row(m_table->record[0])))
   {
+    DBUG_PRINT("info",("ha_write_row() returned error %d",error));
+
     if (error == HA_ERR_LOCK_DEADLOCK || error == HA_ERR_LOCK_WAIT_TIMEOUT)
+      goto handler_error;
+
+    if ((keynum= m_table->file->get_dup_key(error)) < 0)
     {
-      table->file->print_error(error, MYF(0)); /* to check at exec_relay_log_event
*/
-      DBUG_RETURN(error);
-    }
-    if ((keynum= table->file->get_dup_key(error)) < 0)
-    {
-      /* We failed to retrieve the duplicate key */
-      DBUG_RETURN(error);
+      DBUG_PRINT("info",("Can't locate duplicate key (get_dup_key returns %d)",keynum));
+      goto handler_error;
     }
-
     /*
        We need to retrieve the old row into record[1] to be able to
        either update or delete the offending record.  We either:
@@ -6904,55 +7038,71 @@
        - use index_read_idx() with the key that is duplicated, to
          retrieve the offending row.
      */
-    if (table->file->ha_table_flags() & HA_DUPLICATE_POS)
+    if (m_table->file->ha_table_flags() & HA_DUPLICATE_POS)
     {
-      error= table->file->rnd_pos(table->record[1], table->file->dup_ref);
-      if (error)
+      DBUG_PRINT("info",("Locationg offending record using rnd_pos()"));
+
+      if ((error= m_table->file->rnd_pos(m_table->record[1], 
+                                         m_table->file->dup_ref)))
       {
-        table->file->print_error(error, MYF(0));
-        DBUG_RETURN(error);
+        DBUG_PRINT("info",("rnd_pos() returns error %d",error));
+        goto handler_error;
       }
     }
     else
     {
-      if (table->file->extra(HA_EXTRA_FLUSH_CACHE))
-      {
-        DBUG_RETURN(my_errno);
+      DBUG_PRINT("info",("Locationg offending record using index_read_idx()"));
+
+      if (m_table->file->extra(HA_EXTRA_FLUSH_CACHE))
+      { 
+        DBUG_PRINT("info",("Error when setting HA_EXTRA_FLUSH_CACHE"));
+        error= my_errno;
+        goto error;
       }
 
       if (key.get() == NULL)
       {
-       
key.assign(static_cast<char*>(my_alloca(table->s->max_unique_length)));
+       
key.assign(static_cast<char*>(my_alloca(m_table->s->max_unique_length)));
         if (key.get() == NULL)
-          DBUG_RETURN(ENOMEM);
+        {
+          DBUG_PRINT("info",("Can't allocate key buffer"));
+          error= ENOMEM;
+          goto error;
+        }
       }
 
-      key_copy((byte*)key.get(), table->record[0], table->key_info + keynum, 0);
-      error= table->file->index_read_idx(table->record[1], keynum,
-                                         (const byte*)key.get(),
-                                         HA_WHOLE_KEY,
-                                         HA_READ_KEY_EXACT);
-      if (error)
-      {
-        table->file->print_error(error, MYF(0));
-        DBUG_RETURN(error);
+      key_copy((byte*)key.get(), m_table->record[0], m_table->key_info + keynum,
0);
+      if ((error= m_table->file->index_read_idx(m_table->record[1], keynum,
+                                                (const byte*)key.get(),
+                                                HA_WHOLE_KEY,
+                                                HA_READ_KEY_EXACT)))
+      { 
+        DBUG_PRINT("info",("index_read_idx() returns error %d",error)); 
+        goto handler_error;
       }
     }
 
     /*
-       Now, table->record[1] should contain the offending row.  That
+       Now, record[1] should contain the offending row.  That
        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.
+    /*
+      If row is incomplete we will use the record found to fill 
+      missing columns.  
     */
-    copy_extra_record_fields(table, master_reclength, master_fields);
+    if (!get_flags(COMPLETE_ROWS_F))
+    {
+      restore_record(m_table,record[1]);
+      error= unpack_row();
+    }
+
 
 #ifndef DBUG_OFF
     DBUG_PRINT("debug",("preparing for update: before and after image"));
-    DBUG_DUMP("record[1] (before)", table->record[1], table->s->reclength);
-    DBUG_DUMP("record[0] (after)", table->record[0], table->s->reclength);
+    DBUG_DUMP("record[1] (before)", m_table->record[1], m_table->s->reclength);
+    DBUG_DUMP("record[0] (after)", m_table->record[0], m_table->s->reclength);
 #endif
 
     /*
@@ -6970,26 +7120,45 @@
        fail, so we're better off just deleting the row and inserting
        the correct row.
      */
-    if (last_uniq_key(table, keynum) &&
-        !table->file->referenced_by_foreign_key())
+    if (last_uniq_key(m_table, keynum) &&
+        !m_table->file->referenced_by_foreign_key())
     {
-      error=table->file->ha_update_row(table->record[1],
-                                       table->record[0]);
-      if (error)
-        table->file->print_error(error, MYF(0));
-      DBUG_RETURN(error);
+      DBUG_PRINT("info",("Updating row using ha_update_row()"));
+      if ((error= m_table->file->ha_update_row(m_table->record[1],
+                                               m_table->record[0])))
+      {
+        DBUG_PRINT("info",("ha_update_row() returns error %d",error));
+        goto handler_error;
+      }
     }
     else
     {
-      if ((error= table->file->ha_delete_row(table->record[1])))
-      {
-        table->file->print_error(error, MYF(0));
-        DBUG_RETURN(error);
+      DBUG_PRINT("info",("Deleting offending row and trying to write new one again"));
+      if ((error= m_table->file->ha_delete_row(m_table->record[1])))
+      { 
+        DBUG_PRINT("info",("ha_delete_row() returns error %d",error));
+        goto handler_error;
       }
-      /* Will retry ha_write_row() with the offending row removed. */
+
+      /* try to write the row again */
+      goto write_row;
     }
-  }
 
+ } // if (ha_write_row()) 
+
+#ifndef DBUG_OFF
+ if (error)
+   DBUG_PRINT("info",("Failed to insert row (error=%d)",error));
+#endif
+
+ goto error;
+
+ handler_error:
+
+ if (error)
+    m_table->file->print_error(error, MYF(0));
+
+ error:
   DBUG_RETURN(error);
 }
 
@@ -7388,8 +7557,7 @@
                                            MY_BITMAP const *cols,
                                            bool is_transactional)
   : Rows_log_event(thd_arg, tbl_arg, tid_arg, cols, is_transactional)
-{
-}
+{}
 #endif
 
 /*
@@ -7400,14 +7568,13 @@
                                            const Format_description_log_event
                                            *description_event)
 : Rows_log_event(buf, event_len, WRITE_ROWS_EVENT, description_event)
-{
-}
+{}
 #endif
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 int Write_rows_log_event::do_before_row_operations(THD *thd)
 {
-  int error= 0;
+  int error= Rows_log_event::do_before_row_operations(thd);
 
   /*
     We are using REPLACE semantics and not INSERT IGNORE semantics
@@ -7457,26 +7624,14 @@
 {
   if (error == 0)
     error= m_table->file->ha_end_bulk_insert();
-  return error;
+  return Rows_log_event::do_after_row_operations(thd,error);
 }
 
-int Write_rows_log_event::do_prepare_row(THD *thd)
-{
-  DBUG_ASSERT(m_table != NULL);
-
-  int error1, error2;
-  error1= prepare_record(m_table,m_width,TRUE);
-  error2= unpack_row(m_table, m_width, m_curr_row, &m_cols, 
-                     (const char**)&m_curr_row_end, &m_master_reclength);
-
-  return error2 ? error2 : error1;
-}
 
 int Write_rows_log_event::do_exec_row(THD *thd)
 {
   DBUG_ASSERT(m_table != NULL);
-  int error= replace_record(thd, m_table, m_master_reclength, m_width);
-  return error;
+  return insert_row(thd, TRUE /* overwrite */); 
 }
 #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
 
@@ -7500,11 +7655,7 @@
                                              ulong tid, MY_BITMAP const *cols,
                                              bool is_transactional)
   : Rows_log_event(thd_arg, tbl_arg, tid, cols, is_transactional)
-#ifdef HAVE_REPLICATION
-  ,m_memory(NULL), m_key(NULL), m_after_image(NULL)
-#endif
-{
-}
+{}
 #endif /* #if !defined(MYSQL_CLIENT) */
 
 /*
@@ -7514,89 +7665,45 @@
 Delete_rows_log_event::Delete_rows_log_event(const char *buf, uint event_len,
                                              const Format_description_log_event
                                              *description_event)
-#if defined(MYSQL_CLIENT)
   : Rows_log_event(buf, event_len, DELETE_ROWS_EVENT, description_event)
-#else
-  : Rows_log_event(buf, event_len, DELETE_ROWS_EVENT, description_event),
-    m_memory(NULL), m_key(NULL), m_after_image(NULL)
-#endif
-{
-}
+{}
 #endif
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 int Delete_rows_log_event::do_before_row_operations(THD *thd)
 {
-  DBUG_ASSERT(m_memory == NULL);
+  int error= Rows_log_event::do_before_row_operations(thd);
 
-  if ((m_table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION)
&&
+  if (error || 
+      (m_table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION)
&&
       m_table->s->primary_key < MAX_KEY)
   {
     /*
       We don't need to allocate any memory for m_after_image and
       m_key since they are not used.
     */
-    return 0;
+    return error;
   }
 
-  int error= 0;
-
   if (m_table->s->keys > 0)
   {
-    m_memory=
-      my_multi_malloc(MYF(MY_WME),
-		      &m_after_image, m_table->s->reclength,
-		      &m_key, m_table->key_info->key_length,
-		      NULL);
+    // Allocate buffer for key searches
+    m_key= (byte*)my_malloc(m_table->key_info->key_length, MYF(MY_WME));
+   if (!m_key)
+     return HA_ERR_OUT_OF_MEM;
   }
-  else
-  {
-    m_after_image= (byte*)my_malloc(m_table->s->reclength, MYF(MY_WME));
-    m_memory= (gptr)m_after_image;
-    m_key= NULL;
-  }
-  if (!m_memory)
-    return HA_ERR_OUT_OF_MEM;
 
-  return error;
+  return 0;
 }
 
 int Delete_rows_log_event::do_after_row_operations(THD *thd, int error)
 {
   /*error= ToDo:find out what this should really be, this triggers close_scan in nbd,
returning error?*/
   m_table->file->ha_index_or_rnd_end();
-  my_free(m_memory, MYF(MY_ALLOW_ZERO_PTR)); // Free for multi_malloc
-  m_memory= NULL;
-  m_after_image= NULL;
+  my_free(m_key, MYF(MY_ALLOW_ZERO_PTR));
   m_key= NULL;
 
-  return error;
-}
-
-int Delete_rows_log_event::do_prepare_row(THD *thd)
-{
-  int error;
-  /*
-    This assertion actually checks that there is at least as many
-    columns on the slave as on the master.
-  */
-  DBUG_ASSERT(m_table->s->fields >= m_width);
-
-  prepare_record(m_table,m_width);
-  error= unpack_row(m_table, m_width, m_curr_row, &m_cols, 
-                    (const char**)&m_curr_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.
-   */
-  if (m_key)
-  {
-    KEY *const key_info= m_table->key_info;
-
-    key_copy(m_key, m_table->record[0], key_info, 0);
-  }
-
-  return error;
+  return Rows_log_event::do_after_row_operations(thd,error);
 }
 
 int Delete_rows_log_event::do_exec_row(THD *thd)
@@ -7604,12 +7711,10 @@
   int error;
   DBUG_ASSERT(m_table != NULL);
 
-  if (!(error= find_and_fetch_row(m_table, m_key)))
+  if (!(error= find_and_fetch_row())) 
   { 
     /*
-      Now we should have the right row to delete.  We are using
-      record[0] since it is guaranteed to point to a record with the
-      correct value.
+      Delete the record found, located in record[0]
     */
     error= m_table->file->ha_delete_row(m_table->record[0]);
   }
@@ -7635,16 +7740,13 @@
   Constructor used to build an event for writing to the binary log.
  */
 #if !defined(MYSQL_CLIENT)
+
 Update_rows_log_event::Update_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
                                              ulong tid,
                                              MY_BITMAP const *cols_bi,
                                              MY_BITMAP const *cols_ai,
                                              bool is_transactional)
 : Rows_log_event(thd_arg, tbl_arg, tid, cols_bi, is_transactional)
-#ifdef HAVE_REPLICATION
-  , m_memory(NULL), m_key(NULL)
-
-#endif
 {
   init(cols_ai);
 }
@@ -7654,9 +7756,6 @@
                                              MY_BITMAP const *cols,
                                              bool is_transactional)
 : Rows_log_event(thd_arg, tbl_arg, tid, cols, is_transactional)
-#ifdef HAVE_REPLICATION
-  , m_memory(NULL), m_key(NULL)
-#endif
 {
   init(cols);
 }
@@ -7674,14 +7773,15 @@
       memcpy(m_cols_ai.bitmap, cols->bitmap, no_bytes_in_map(cols));
   }
 }
+
 #endif /* !defined(MYSQL_CLIENT) */
 
 
 Update_rows_log_event::~Update_rows_log_event()
 {
   if (m_cols_ai.bitmap == m_bitbuf_ai) // no my_malloc happened
-    m_cols_ai.bitmap= 0; // so no my_free in bitmap_free
-  bitmap_free(&m_cols_ai); // To pair with bitmap_init().
+    m_cols_ai.bitmap= 0;               // so no my_free in bitmap_free
+  bitmap_free(&m_cols_ai);             // To pair with bitmap_init().
 }
 
 
@@ -7689,45 +7789,31 @@
   Constructor used by slave to read the event from the binary log.
  */
 #ifdef HAVE_REPLICATION
+
 Update_rows_log_event::Update_rows_log_event(const char *buf, uint event_len,
                                              const
                                              Format_description_log_event
                                              *description_event)
-#if defined(MYSQL_CLIENT)
   : Rows_log_event(buf, event_len, UPDATE_ROWS_EVENT, description_event)
-#else
-  : Rows_log_event(buf, event_len, UPDATE_ROWS_EVENT, description_event),
-    m_memory(NULL), m_key(NULL)
-#endif
-{
-}
+{}
+
 #endif
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+
 int Update_rows_log_event::do_before_row_operations(THD *thd)
 {
-  DBUG_ASSERT(m_memory == NULL);
+  int error= Rows_log_event::do_before_row_operations(thd);
 
-  int error= 0;
+  m_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
 
   if (m_table->s->keys > 0)
   {
-    m_memory=
-      my_multi_malloc(MYF(MY_WME),
-		      &m_after_image, m_table->s->reclength,
-		      &m_key, m_table->key_info->key_length,
-		      NULL);
+    // Allocate buffer for key searches
+    m_key= (byte*)my_malloc(m_table->key_info->key_length, MYF(MY_WME));
+   if (!m_key)
+     return HA_ERR_OUT_OF_MEM;
   }
-  else
-  {
-    m_after_image= (byte*)my_malloc(m_table->s->reclength, MYF(MY_WME));
-    m_memory= (gptr)m_after_image;
-    m_key= NULL;
-  }
-  if (!m_memory)
-    return HA_ERR_OUT_OF_MEM;
-
-  m_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
 
   return error;
 }
@@ -7736,111 +7822,71 @@
 {
   /*error= ToDo:find out what this should really be, this triggers close_scan in nbd,
returning error?*/
   m_table->file->ha_index_or_rnd_end();
-  my_free(m_memory, MYF(MY_ALLOW_ZERO_PTR));
-  m_memory= NULL;
-  m_after_image= NULL;
+  my_free(m_key, MYF(MY_ALLOW_ZERO_PTR)); // Free for multi_malloc
   m_key= NULL;
 
-  return error;
+  return Rows_log_event::do_after_row_operations(thd,error);
 }
 
-int Update_rows_log_event::do_prepare_row(THD *thd)
+int Update_rows_log_event::do_exec_row(THD *thd)
 {
-  int error;
-  /*
-    This assertion actually checks that there is at least as many
-    columns on the slave as on the master.
-  */
+  DBUG_ASSERT(m_table != NULL);
   DBUG_ASSERT(m_table->s->fields >= m_width);
 
-  /*
-    We need to perform some juggling below since unpack_row() always
-    unpacks into m_table->record[0]. For more information, see the
-    comments for unpack_row().
-  */
-
-  /* record[0] is the before image for the update */
-  prepare_record(m_table,m_width);
-  error= unpack_row(m_table, m_width, m_curr_row, &m_cols, 
-                    (const char**)&m_curr_row_end, &m_master_reclength);
-  store_record(m_table, record[1]);
-
-  char const *next_start = m_curr_row_end;
-
-  prepare_record(m_table,m_width);
-  error= unpack_row(m_table, m_width, next_start, &m_cols_ai, 
-                    (const char**)&m_curr_row_end, &m_master_reclength);
-
-  /* m_after_image is the after image for the update */
-  bmove_align(m_after_image, m_table->record[0], m_table->s->reclength);
-  restore_record(m_table, record[1]);
-
-  /*
-    Don't print debug messages when running valgrind since they can
-    trigger false warnings.
-   */
-#ifndef HAVE_purify
-  DBUG_DUMP("record[0]", (const char *)m_table->record[0],
m_table->s->reclength);
-  DBUG_DUMP("m_after_image", (const char *)m_after_image, m_table->s->reclength);
-#endif
+  int error= find_and_fetch_row(); 
+  if (error)
+    return error;
 
   /*
-    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.
-   */
-  if (m_key)
-  {
-    KEY *const key_info= m_table->key_info;
+    This is the situation after locating BI:
 
-    key_copy(m_key, m_table->record[0], key_info, 0);
-  }
+    ===|=== before image ====|=== after image ===|===
+       ^                     ^
+       m_curr_row            m_curr_row_end
 
-  return error;
-}
-
-int Update_rows_log_event::do_exec_row(THD *thd)
-{
-  DBUG_ASSERT(m_table != NULL);
+    BI found in the table is stored in record[0]. We copy it to record[1]
+    and unpack AI to record[0].
+   */
 
-  int error= find_and_fetch_row(m_table, m_key);
-  if (error)
-    return error;
+  store_record(m_table,record[1]);
 
-  /*
-    We have to ensure that the new record (i.e., the after image) is
-    in record[0] and the old record (i.e., the before image) is in
-    record[1].  This since some storage engines require this (for
-    example, the partition engine).
-
-    Since find_and_fetch_row() puts the fetched record (i.e., the old
-    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(m_table->record[0], m_after_image, m_table->s->reclength);
-  copy_extra_record_fields(m_table, m_master_reclength, m_width);
+  m_curr_row= m_curr_row_end;
+  error= unpack_row(); // this also updates m_curr_row_end
 
   /*
     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.
+    looking for) is in record[1] and the new row is in record[0].
   */
+#ifndef HAVE_purify
+  /*
+    Don't print debug messages when running valgrind since they can
+    trigger false warnings.
+   */
+  DBUG_PRINT("info",("Updating row in table"));
+  DBUG_DUMP("old record", (const char *)m_table->record[1],
m_table->s->reclength);
+  DBUG_DUMP("new values", (const char *)m_table->record[0],
m_table->s->reclength);
+#endif
+
   error= m_table->file->ha_update_row(m_table->record[1],
m_table->record[0]);
 
   return error;
 }
+
 #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
 
 #ifdef MYSQL_CLIENT
+
 void Update_rows_log_event::print(FILE *file,
 				  PRINT_EVENT_INFO* print_event_info)
 {
   Rows_log_event::print_helper(file, print_event_info, "Update_rows");
 }
+
 #endif
+
+/**************************************************************************
+  Incident_log_event member functions
+**************************************************************************/
 
 
 Incident_log_event::Incident_log_event(const char *buf, uint event_len,

--- 1.145/sql/log_event.h	2007-05-21 21:23:26 +02:00
+++ 1.146/sql/log_event.h	2007-05-21 21:23:26 +02:00
@@ -23,6 +23,7 @@
 
 #include <my_bitmap.h>
 #include "rpl_constants.h"
+#include "rpl_record.h"
 
 #define LOG_READ_EOF    -1
 #define LOG_READ_BOGUS  -2
@@ -2104,6 +2105,7 @@
 class Rows_log_event : public Log_event
 {
 public:
+
   /**
      Enumeration of the errors that can be returned.
    */
@@ -2133,7 +2135,13 @@
     NO_FOREIGN_KEY_CHECKS_F = (1U << 1),
 
     /* Value of the OPTION_RELAXED_UNIQUE_CHECKS flag in thd->options */
-    RELAXED_UNIQUE_CHECKS_F = (1U << 2)
+    RELAXED_UNIQUE_CHECKS_F = (1U << 2),
+
+    /* 
+      Indicates that rows in this event are complete, that is contain
+      values for all columns of the table.
+     */
+    COMPLETE_ROWS_F = (1U << 3)
   };
 
   typedef uint16 flag_set;
@@ -2178,6 +2186,7 @@
   virtual bool write_data_body(IO_CACHE *file);
   virtual const char *get_db() { return m_table->s->db.str; }
 #endif
+
   /*
     Check that malloc() succeeded in allocating memory for the rows
     buffer and the COLS vector. Checking that an Update_rows_log_event
@@ -2192,6 +2201,42 @@
   uint     m_row_count;         /* The number of rows added to the event */
 
 protected:
+
+#ifndef MYSQL_CLIENT
+  TABLE *m_table;   /* The table the rows belong to */
+#endif
+  ulong       m_table_id; /* Table ID */
+  ulong       m_width;    /* Number of columns in a row (as it is on master) */
+  ulong       m_master_reclength; /* Length of record on master side */
+
+  MY_BITMAP   m_cols;     /* Bitmap denoting columns available */
+  /*
+    Bitmap for columns available in the after image, if present. These
+    fields are only available for Update_rows events. Observe that the
+    width of both the before image COLS vector and the after image
+    COLS vector is the same: the number of columns of the table on the
+    master.
+
+    TODO: this should be a member of Update_rows_log_event class.
+  */
+  MY_BITMAP   m_cols_ai;
+
+  /* Bit buffers in the same memory as the class */
+  uint32    m_bitbuf[128/(sizeof(uint32)*8)];
+  uint32    m_bitbuf_ai[128/(sizeof(uint32)*8)];
+
+  /* Pointers to the row buffer area */
+
+  byte       *m_rows_buf;    /* The rows in packed format */
+  byte       *m_rows_cur;    /* One-after the end of the data */
+  const byte *m_rows_end;    /* One-after the end of the allocated space */
+
+  const byte *m_curr_row;     /* Start of the row being processed */
+  const byte *m_curr_row_end; /* One-after the end of the current row */
+
+  flag_set m_flags; /* Flags for row-level events */
+  byte *m_key;      /* Buffer to keep key value during searches */
+
   /* 
      The constructors are protected since you're supposed to inherit
      this class, not create instances of this class.
@@ -2212,37 +2257,17 @@
   virtual int do_add_row_data(byte *data, my_size_t length);
 #endif
 
-#ifndef MYSQL_CLIENT
-  TABLE *m_table;		/* The table the rows belong to */
-#endif
-  ulong       m_table_id;	/* Table ID */
-  MY_BITMAP   m_cols;		/* Bitmap denoting columns available */
-  ulong       m_width;          /* The width of the columns bitmap */
-  /*
-    Bitmap for columns available in the after image, if present. These
-    fields are only available for Update_rows events. Observe that the
-    width of both the before image COLS vector and the after image
-    COLS vector is the same: the number of columns of the table on the
-    master.
-  */
-  MY_BITMAP   m_cols_ai;
-
-  ulong       m_master_reclength; /* Length of record on master side */
-
-  /* Bit buffers in the same memory as the class */
-  uint32    m_bitbuf[128/(sizeof(uint32)*8)];
-  uint32    m_bitbuf_ai[128/(sizeof(uint32)*8)];
-
-  byte    *m_rows_buf;		/* The rows in packed format */
-  byte    *m_rows_cur;		/* One-after the end of the data */
-  byte    *m_rows_end;		/* One-after the end of the allocated space */
-
-  byte    *m_curr_row;     /* Start of the row being processed */
-  byte    *m_curr_row_end; /* One-after the end of the current row */
+  /* helper functions */
 
-  flag_set m_flags;		/* Flags for row-level events */
+  int find_and_fetch_row();
+  int insert_row(THD *const, const my_bool);
 
-private:
+  // Unpack the current row into m_table->record[0]
+  int unpack_row()
+  { 
+    return ::unpack_row(m_table, m_width, m_curr_row, &m_cols, 
+                        &m_curr_row_end, &m_master_reclength);
+  }
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 
@@ -2271,28 +2296,30 @@
       The member function will return 0 if all went OK, or a non-zero
       error code otherwise.
   */
-  virtual int do_before_row_operations(THD*) = 0;
+  virtual int do_before_row_operations(THD*)
+  { return 0; }
 
   /*
     Primitive to clean up after a sequence of row executions.
 
     DESCRIPTION
-    
+
       After doing a sequence of do_prepare_row() and do_exec_row(),
       this member function should be called to clean up and release
       any allocated buffers.
-      
+
       The error argument, if non-zero, indicates error which happened
       while processing rows (or in the do_before_row_operations() function)
       before calling this function. In that case this function should return
       non-zero error code (the same error which was passed as an argument
       if no errors were encountered here).
   */
-  virtual int do_after_row_operations(THD*,int error) = 0;
+  virtual int do_after_row_operations(THD*,int error)
+  { return error; }
 
   /*
     Primitive to prepare for handling one row in a row-level event.
-    
+
     DESCRIPTION 
 
       The member function prepares for execution of operations needed for one
@@ -2304,11 +2331,14 @@
     RETURN VALUE
       Error code, if something went wrong, 0 otherwise.
    */
-   
+
    // TODO: consider not passing the THD struct to discourage doing parts of
    // row execution here
-   
-  virtual int do_prepare_row(THD*) =0;
+
+  virtual int do_prepare_row(THD*)
+  { return 0; }
+
+private:
 
   /*
     Primitive to do the actual execution necessary for a row.
@@ -2318,10 +2348,10 @@
       The row is located at m_curr_row. When the function returns, 
       m_curr_row_end should point at the next row (one byte after the end
       of the current row).    
-         
+
     RETURN VALUE
       0 if execution succeeded, 1 if execution failed.
-      
+
   */
   virtual int do_exec_row(THD*) = 0;
 
@@ -2351,10 +2381,12 @@
   Write_rows_log_event(THD*, TABLE*, ulong table_id, 
 		       MY_BITMAP const *cols, bool is_transactional);
 #endif
+
 #ifdef HAVE_REPLICATION
   Write_rows_log_event(const char *buf, uint event_len, 
                        const Format_description_log_event *description_event);
 #endif
+
 #if !defined(MYSQL_CLIENT) 
   static bool binlog_row_logging_function(THD *thd, TABLE *table,
                                           bool is_transactional,
@@ -2370,6 +2402,7 @@
 #endif
 
 private:
+
   virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
 
 #ifdef MYSQL_CLIENT
@@ -2377,14 +2410,11 @@
 #endif
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-  gptr  m_memory;
-  byte *m_after_image;
-
   virtual int do_before_row_operations(THD*);
   virtual int do_after_row_operations(THD*,int error);
-  virtual int do_prepare_row(THD*);
   virtual int do_exec_row(THD*);
 #endif
+
 };
 
 
@@ -2442,12 +2472,15 @@
   }
 #endif
 
+/*
   virtual bool is_valid() const
   {
     return Rows_log_event::is_valid() && m_cols_ai.bitmap;
   }
+*/
 
 protected:
+
   virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
 
 #ifdef MYSQL_CLIENT
@@ -2455,13 +2488,8 @@
 #endif
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-  gptr  m_memory;
-  byte *m_key;
-  byte *m_after_image;
-
   virtual int do_before_row_operations(THD*);
   virtual int do_after_row_operations(THD*,int error);
-  virtual int do_prepare_row(THD*);
   virtual int do_exec_row(THD*);
 #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
 };
@@ -2516,7 +2544,7 @@
                                   cols, fields, before_record);
   }
 #endif
-  
+
 protected:
   virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
 
@@ -2525,13 +2553,8 @@
 #endif
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-  gptr  m_memory;
-  byte *m_key;
-  byte *m_after_image;
-
   virtual int do_before_row_operations(THD*);
   virtual int do_after_row_operations(THD*,int error);
-  virtual int do_prepare_row(THD*);
   virtual int do_exec_row(THD*);
 #endif
 };

--- 1.5/mysql-test/include/rpl_multi_engine3.inc	2007-05-21 21:23:26 +02:00
+++ 1.6/mysql-test/include/rpl_multi_engine3.inc	2007-05-21 21:23:26 +02:00
@@ -2,9 +2,24 @@
 # Author: JBM
 # Date: 2006-02-23
 # Purpose: To reuse through out test and make maint easier
+#
+# Structure of t1:
+#
+# CREATE TABLE t1 (
+#  id MEDIUMINT, 
+#  b1 BIT(8), 
+#  vc VARCHAR(255), 
+#  bc CHAR(255),
+#  d DECIMAL(10,4), 
+#  f FLOAT DEFAULT 0, 
+#  total BIGINT UNSIGNED, 
+#  y YEAR, 
+#  t DATE
+# );
+#
 #############################################################
 connection master;
---echo "--- Insert into t1 --" as "";
+--echo --- Insert into t1 --;
 
 --disable_query_log
 INSERT INTO t1 VALUES(42,1,'Testing MySQL databases is a cool ',
@@ -57,5 +72,8 @@
 --echo --- Show current count on slave for t1 --- 
 SELECT COUNT(*) FROM t1;
 
+# DELETE FROM t1 statement makes ndb->myisam replication fail, see
+# BUG#28538. This must be fixed to make rpl_ndb_2xxx tests work.
+#
 connection master;
-DELETE FROM t1;
+#DELETE FROM t1;

--- 1.1/mysql-test/include/rpl_multi_engine.inc	2007-05-21 21:23:26 +02:00
+++ 1.2/mysql-test/include/rpl_multi_engine.inc	2007-05-21 21:23:26 +02:00
@@ -1,3 +1,20 @@
+################################################################
+#
+# Statements below assume table t1 with the following structure
+# (see extra/rpl_tests/rpl_ndb_2multi_eng.test)
+#
+# CREATE TABLE t1 (
+#  id MEDIUMINT, 
+#  b1 BIT(8), 
+#  vc VARCHAR(255), 
+#  bc CHAR(255),
+#  d DECIMAL(10,4), 
+#  f FLOAT DEFAULT 0, 
+#  total BIGINT UNSIGNED, 
+#  y YEAR, 
+#  t DATE
+# );
+################################################################
 connection master;
 INSERT INTO t1 VALUES(42,1,'Testing MySQL databases is a cool ', 'Must make it bug free
for the customer',654321.4321,15.21,0,1965,"2005-11-14");
 select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
--- New file ---
+++ mysql-test/extra/rpl_tests/rpl_ndb_2multi_basic.test	07/05/21 21:23:16
#######################################
# Author: Rafal                       #
# Date: 2007-05-19		      #
#                                     #
# Based on rpl_ndb_2multi_eng.test,   #
# without partition testing	      #
#				      #
#######################################

--echo --- Doing pre test cleanup --- 

connection master;
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_query_log

#################################################################

--echo --- Start test 1: replication with primary key ---
--echo --- Create Table Section ---


CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), 
                 bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, 
                 f FLOAT DEFAULT 0, total BIGINT UNSIGNED, 
                 y YEAR, t DATE, PRIMARY KEY(id));

--echo --- Show table on master ---

SHOW CREATE TABLE t1;

--echo --- Show table on slave ---

sync_slave_with_master;
SHOW CREATE TABLE t1;

--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---

connection master;
--source include/rpl_multi_engine3.inc

DROP TABLE IF EXISTS t1;
sync_slave_with_master;

#################################################################

--echo --- Start test 2: replication without key ---
--echo --- Create Table Section ---

connection master;

CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), 
                 bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, 
                 f FLOAT DEFAULT 0, total BIGINT UNSIGNED, 
                 y YEAR, t DATE);

--echo --- Show table on master ---

SHOW CREATE TABLE t1;

--echo --- Show table on slave ---

sync_slave_with_master;
SHOW CREATE TABLE t1;

--echo --- Perform basic operation on master ---
--echo --- and ensure replicated correctly ---

--source include/rpl_multi_engine3.inc

DROP TABLE IF EXISTS t1;

# End of 5.1 test case

--- New file ---
+++ mysql-test/r/rpl_ndb_2innodb_basic.result	07/05/21 21:23:16
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 storage_engine=innodb;
START SLAVE;
SET storage_engine=ndb;
--- Doing pre test cleanup --- 
DROP TABLE IF EXISTS t1;
--- Start test 1: replication with primary key ---
--- Create Table Section ---
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), 
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, 
f FLOAT DEFAULT 0, total BIGINT UNSIGNED, 
y YEAR, t DATE, PRIMARY KEY(id));
--- Show table on master ---
SHOW CREATE TABLE t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `id` mediumint(9) NOT NULL,
  `b1` bit(8) DEFAULT NULL,
  `vc` varchar(255) DEFAULT NULL,
  `bc` char(255) DEFAULT NULL,
  `d` decimal(10,4) DEFAULT '0.0000',
  `f` float DEFAULT '0',
  `total` bigint(20) unsigned DEFAULT NULL,
  `y` year(4) DEFAULT NULL,
  `t` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
--- Show table on slave ---
SHOW CREATE TABLE t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `id` mediumint(9) NOT NULL,
  `b1` bit(8) DEFAULT NULL,
  `vc` varchar(255) DEFAULT NULL,
  `bc` char(255) DEFAULT NULL,
  `d` decimal(10,4) DEFAULT '0.0000',
  `f` float DEFAULT '0',
  `total` bigint(20) unsigned DEFAULT NULL,
  `y` year(4) DEFAULT NULL,
  `t` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
--- Perform basic operation on master ---
--- and ensure replicated correctly ---
--- Insert into t1 --;
--- Select from t1 on master --- 
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
id	hex(b1)	vc	bc	d	f	total	y	t
2	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1965-11-14
4	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1985-11-14
42	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1905-11-14
142	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1995-11-14
412	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2005-11-14
--- Select from t1 on slave ---
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
id	hex(b1)	vc	bc	d	f	total	y	t
2	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1965-11-14
4	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1985-11-14
42	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1905-11-14
142	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1995-11-14
412	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2005-11-14
--- Update t1 on master --
UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
--- Check the update on master --- 
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
id	hex(b1)	vc	bc	d	f	total	y	t
412	0	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2006-02-22
--- Check Update on slave ---
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
id	hex(b1)	vc	bc	d	f	total	y	t
412	0	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2006-02-22
--- Remove a record from t1 on master ---
DELETE FROM t1 WHERE id = 42;
--- Show current count on master for t1 ---
SELECT COUNT(*) FROM t1;
COUNT(*)
4
--- Show current count on slave for t1 --- 
SELECT COUNT(*) FROM t1;
COUNT(*)
4
DROP TABLE IF EXISTS t1;
--- Start test 2: replication without key ---
--- Create Table Section ---
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), 
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, 
f FLOAT DEFAULT 0, total BIGINT UNSIGNED, 
y YEAR, t DATE);
--- Show table on master ---
SHOW CREATE TABLE t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `id` mediumint(9) NOT NULL,
  `b1` bit(8) DEFAULT NULL,
  `vc` varchar(255) DEFAULT NULL,
  `bc` char(255) DEFAULT NULL,
  `d` decimal(10,4) DEFAULT '0.0000',
  `f` float DEFAULT '0',
  `total` bigint(20) unsigned DEFAULT NULL,
  `y` year(4) DEFAULT NULL,
  `t` date DEFAULT NULL
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
--- Show table on slave ---
SHOW CREATE TABLE t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `id` mediumint(9) NOT NULL,
  `b1` bit(8) DEFAULT NULL,
  `vc` varchar(255) DEFAULT NULL,
  `bc` char(255) DEFAULT NULL,
  `d` decimal(10,4) DEFAULT '0.0000',
  `f` float DEFAULT '0',
  `total` bigint(20) unsigned DEFAULT NULL,
  `y` year(4) DEFAULT NULL,
  `t` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
--- Perform basic operation on master ---
--- and ensure replicated correctly ---
--- Insert into t1 --;
--- Select from t1 on master --- 
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
id	hex(b1)	vc	bc	d	f	total	y	t
2	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1965-11-14
4	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1985-11-14
42	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1905-11-14
142	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1995-11-14
412	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2005-11-14
--- Select from t1 on slave ---
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
id	hex(b1)	vc	bc	d	f	total	y	t
2	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1965-11-14
4	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1985-11-14
42	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1905-11-14
142	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1995-11-14
412	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2005-11-14
--- Update t1 on master --
UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
--- Check the update on master --- 
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
id	hex(b1)	vc	bc	d	f	total	y	t
412	0	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2006-02-22
--- Check Update on slave ---
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
id	hex(b1)	vc	bc	d	f	total	y	t
412	0	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2006-02-22
--- Remove a record from t1 on master ---
DELETE FROM t1 WHERE id = 42;
--- Show current count on master for t1 ---
SELECT COUNT(*) FROM t1;
COUNT(*)
4
--- Show current count on slave for t1 --- 
SELECT COUNT(*) FROM t1;
COUNT(*)
4
DROP TABLE IF EXISTS t1;

--- New file ---
+++ mysql-test/r/rpl_ndb_2myisam_basic.result	07/05/21 21:23:16
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;
SET storage_engine=ndb;
--- Doing pre test cleanup --- 
DROP TABLE IF EXISTS t1;
--- Start test 1: replication with primary key ---
--- Create Table Section ---
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), 
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, 
f FLOAT DEFAULT 0, total BIGINT UNSIGNED, 
y YEAR, t DATE, PRIMARY KEY(id));
--- Show table on master ---
SHOW CREATE TABLE t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `id` mediumint(9) NOT NULL,
  `b1` bit(8) DEFAULT NULL,
  `vc` varchar(255) DEFAULT NULL,
  `bc` char(255) DEFAULT NULL,
  `d` decimal(10,4) DEFAULT '0.0000',
  `f` float DEFAULT '0',
  `total` bigint(20) unsigned DEFAULT NULL,
  `y` year(4) DEFAULT NULL,
  `t` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
--- Show table on slave ---
SHOW CREATE TABLE t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `id` mediumint(9) NOT NULL,
  `b1` bit(8) DEFAULT NULL,
  `vc` varchar(255) DEFAULT NULL,
  `bc` char(255) DEFAULT NULL,
  `d` decimal(10,4) DEFAULT '0.0000',
  `f` float DEFAULT '0',
  `total` bigint(20) unsigned DEFAULT NULL,
  `y` year(4) DEFAULT NULL,
  `t` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
--- Perform basic operation on master ---
--- and ensure replicated correctly ---
--- Insert into t1 --;
--- Select from t1 on master --- 
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
id	hex(b1)	vc	bc	d	f	total	y	t
2	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1965-11-14
4	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1985-11-14
42	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1905-11-14
142	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1995-11-14
412	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2005-11-14
--- Select from t1 on slave ---
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
id	hex(b1)	vc	bc	d	f	total	y	t
2	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1965-11-14
4	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1985-11-14
42	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1905-11-14
142	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1995-11-14
412	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2005-11-14
--- Update t1 on master --
UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
--- Check the update on master --- 
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
id	hex(b1)	vc	bc	d	f	total	y	t
412	0	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2006-02-22
--- Check Update on slave ---
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
id	hex(b1)	vc	bc	d	f	total	y	t
412	0	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2006-02-22
--- Remove a record from t1 on master ---
DELETE FROM t1 WHERE id = 42;
--- Show current count on master for t1 ---
SELECT COUNT(*) FROM t1;
COUNT(*)
4
--- Show current count on slave for t1 --- 
SELECT COUNT(*) FROM t1;
COUNT(*)
4
DROP TABLE IF EXISTS t1;
--- Start test 2: replication without key ---
--- Create Table Section ---
CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), 
bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, 
f FLOAT DEFAULT 0, total BIGINT UNSIGNED, 
y YEAR, t DATE);
--- Show table on master ---
SHOW CREATE TABLE t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `id` mediumint(9) NOT NULL,
  `b1` bit(8) DEFAULT NULL,
  `vc` varchar(255) DEFAULT NULL,
  `bc` char(255) DEFAULT NULL,
  `d` decimal(10,4) DEFAULT '0.0000',
  `f` float DEFAULT '0',
  `total` bigint(20) unsigned DEFAULT NULL,
  `y` year(4) DEFAULT NULL,
  `t` date DEFAULT NULL
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
--- Show table on slave ---
SHOW CREATE TABLE t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `id` mediumint(9) NOT NULL,
  `b1` bit(8) DEFAULT NULL,
  `vc` varchar(255) DEFAULT NULL,
  `bc` char(255) DEFAULT NULL,
  `d` decimal(10,4) DEFAULT '0.0000',
  `f` float DEFAULT '0',
  `total` bigint(20) unsigned DEFAULT NULL,
  `y` year(4) DEFAULT NULL,
  `t` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
--- Perform basic operation on master ---
--- and ensure replicated correctly ---
--- Insert into t1 --;
--- Select from t1 on master --- 
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
id	hex(b1)	vc	bc	d	f	total	y	t
2	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1965-11-14
4	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1985-11-14
42	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1905-11-14
142	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1995-11-14
412	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2005-11-14
--- Select from t1 on slave ---
select id,hex(b1),vc,bc,d,f,total,y,t from t1 order by id;
id	hex(b1)	vc	bc	d	f	total	y	t
2	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1965-11-14
4	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1985-11-14
42	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1905-11-14
142	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	1995-11-14
412	1	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2005-11-14
--- Update t1 on master --
UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412;
--- Check the update on master --- 
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
id	hex(b1)	vc	bc	d	f	total	y	t
412	0	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2006-02-22
--- Check Update on slave ---
SELECT id,hex(b1),vc,bc,d,f,total,y,t FROM t1 WHERE id = 412;
id	hex(b1)	vc	bc	d	f	total	y	t
412	0	Testing MySQL databases is a cool 	Must make it bug free for the
customer	654321.4321	15.21	0	1965	2006-02-22
--- Remove a record from t1 on master ---
DELETE FROM t1 WHERE id = 42;
--- Show current count on master for t1 ---
SELECT COUNT(*) FROM t1;
COUNT(*)
4
--- Show current count on slave for t1 --- 
SELECT COUNT(*) FROM t1;
COUNT(*)
4
DROP TABLE IF EXISTS t1;

--- New file ---
+++ mysql-test/t/rpl_ndb_2innodb_basic.test	07/05/21 21:23:15
#############################################################
# Author: Rafal
# Date: 2007-05-19
# Purpose: Trying to test ability to replicate from cluster
# to innodb, or myisam, or replicate from innodb/myisam to
# cluster slave. 
##############################################################
-- source include/have_ndb.inc
-- source include/master-slave.inc
connection slave;
STOP SLAVE;
-- source include/have_innodb.inc
SET GLOBAL storage_engine=innodb;
START SLAVE;

connection master;
SET storage_engine=ndb;
--source extra/rpl_tests/rpl_ndb_2multi_basic.test

--- New file ---
+++ mysql-test/t/rpl_ndb_2myisam_basic.test	07/05/21 21:23:15
#############################################################
# Author: Rafal
# Date: 2007-05-19
# Purpose: Trying to test ability to replicate from cluster
# to innodb, or myisam, or replicate from innodb/myisam to
# cluster slave.
##############################################################
-- source include/have_ndb.inc
-- source include/master-slave.inc
SET storage_engine=ndb;
--source extra/rpl_tests/rpl_ndb_2multi_basic.test

Thread
bk commit into 5.1 tree (rafal:1.2577) BUG#21842rsomla21 May