From 7a5f3f12bc45f7f1db9ba97be0337dfd256b96d3 Mon Sep 17 00:00:00 2001
From: unknown <mats@kindahl-laptop.dnsalias.net>
Date: Wed, 5 Dec 2007 20:00:14 +0100
Subject: [PATCH] BUG#31583 (5.1-telco-6.1 -> 5.1.22. Slave returns Error in
 unknown event):

In the patch for BUG#21842, the code for handling old rows events were
refactored.  There were a bug in the refactored code (possibly introduced
after the patch for BUG#21842) that caused caused the refactored old events
to read a columns bitmap after image even though there is no such bitmap
for old events. As a result, the reading got out of sync, and started reading
invalid data.

This patch removes all trace of the after image column bitmap from the refactored
old events and removes functions that are no longer needed because they are empty.


sql/log_event.cc:
  Adding debug printouts and adding old rows events names to output
  so that they are not printed as unknown events.
sql/log_event_old.cc:
  Adding debug printouts to see how the old events are partitioned
  when being decoded.  Removing all traces of the column bitmap for
  the after image in the old events since there is none.

  Removing the following functions since they are no longer needed:
  - Update_rows_log_event_old::init()
  - Update_rows_log_event_old::~Update_rows_log_event_old()

  Removing unused local variable.
sql/log_event_old.h:
  Removing all traces of the column bitmap for the after image in
  the old events since there is none.

  Removing the following functions since they are no longer needed:
  - Update_rows_log_event_old::init()
  - Update_rows_log_event_old::is_valid()
  - Update_rows_log_event_old::~Update_rows_log_event_old()

  Removing unused local variable.
mysql-test/suite/bugs/r/rpl_bug31583.result:
  New BitKeeper file ``mysql-test/suite/bugs/r/rpl_bug31583.result''
mysql-test/suite/bugs/t/rpl_bug31583.test:
  New BitKeeper file ``mysql-test/suite/bugs/t/rpl_bug31583.test''
---
 mysql-test/suite/bugs/r/rpl_bug31583.result | 15 ++++
 mysql-test/suite/bugs/t/rpl_bug31583.test   | 21 ++++++
 sql/log_event.cc                            |  5 ++
 sql/log_event_old.cc                        | 76 +--------------------
 sql/log_event_old.h                         | 17 -----
 5 files changed, 44 insertions(+), 90 deletions(-)
 create mode 100644 mysql-test/suite/bugs/r/rpl_bug31583.result
 create mode 100644 mysql-test/suite/bugs/t/rpl_bug31583.test

diff --git a/mysql-test/suite/bugs/r/rpl_bug31583.result b/mysql-test/suite/bugs/r/rpl_bug31583.result
new file mode 100644
index 00000000000..a5e38e9b2d8
--- /dev/null
+++ b/mysql-test/suite/bugs/r/rpl_bug31583.result
@@ -0,0 +1,15 @@
+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;
+CREATE TABLE t1 ( a INT, b INT DEFAULT -3 );
+INSERT INTO t1 VALUES (1, DEFAULT);
+UPDATE t1 SET a = 3;
+SELECT * FROM t1 ORDER BY a;
+a	b
+3	-3
+SELECT * FROM t1 ORDER BY a;
+a	b
+3	-3
diff --git a/mysql-test/suite/bugs/t/rpl_bug31583.test b/mysql-test/suite/bugs/t/rpl_bug31583.test
new file mode 100644
index 00000000000..a8f4a5538ca
--- /dev/null
+++ b/mysql-test/suite/bugs/t/rpl_bug31583.test
@@ -0,0 +1,21 @@
+#
+# BUG#31583: 5.1-telco-6.1 -> 5.1.22. Slave returns Error in unknown event
+
+# This is a problem for any update statement replicating from an old
+# server to a new server. The bug consisted of a new slave trying to
+# read two column bitmaps, but there is only one available in the old
+# format.
+
+# This test case should be executed replicating from an old server to
+# a new server, so make sure you have one handy.
+
+source include/master-slave.inc;
+
+CREATE TABLE t1 ( a INT, b INT DEFAULT -3 );
+
+INSERT INTO t1 VALUES (1, DEFAULT);
+UPDATE t1 SET a = 3;
+SELECT * FROM t1 ORDER BY a;
+sync_slave_with_master;
+SELECT * FROM t1 ORDER BY a;
+
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d3b0f7ed3b4..c7963fe803a 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -490,6 +490,9 @@ const char* Log_event::get_type_str()
   case USER_VAR_EVENT: return "User var";
   case FORMAT_DESCRIPTION_EVENT: return "Format_desc";
   case TABLE_MAP_EVENT: return "Table_map";
+  case PRE_GA_WRITE_ROWS_EVENT: return "Write_rows_event_old";
+  case PRE_GA_UPDATE_ROWS_EVENT: return "Update_rows_event_old";
+  case PRE_GA_DELETE_ROWS_EVENT: return "Delete_rows_event_old";
   case WRITE_ROWS_EVENT: return "Write_rows";
   case UPDATE_ROWS_EVENT: return "Update_rows";
   case DELETE_ROWS_EVENT: return "Delete_rows";
@@ -1015,6 +1018,8 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
   DBUG_ENTER("Log_event::read_log_event(char*,...)");
   DBUG_ASSERT(description_event != 0);
   DBUG_PRINT("info", ("binlog_version: %d", description_event->binlog_version));
+  DBUG_DUMP("data", (unsigned char*) buf, event_len);
+
   /* Check the integrity */
   if (event_len < EVENT_LEN_OFFSET ||
       buf[EVENT_TYPE_OFFSET] >= ENUM_END_EVENT ||
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index b16af43f24e..12c3b2a6dc3 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1317,6 +1317,7 @@ Old_rows_log_event::Old_rows_log_event(const char *buf, uint event_len,
 		      post_header_len));
 
   const char *post_start= buf + common_header_len;
+  DBUG_DUMP("post_header", (uchar*) post_start, post_header_len);
   post_start+= RW_MAPID_OFFSET;
   if (post_header_len == 6)
   {
@@ -1358,38 +1359,11 @@ Old_rows_log_event::Old_rows_log_event(const char *buf, uint event_len,
     DBUG_VOID_RETURN;
   }
 
-  m_cols_ai.bitmap= m_cols.bitmap; /* See explanation in is_valid() */
-
-  if (event_type == PRE_GA_UPDATE_ROWS_EVENT)
-  {
-    DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
-
-    /* if bitmap_init fails, caught in is_valid() */
-    if (likely(!bitmap_init(&m_cols_ai,
-                            m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
-                            m_width,
-                            false)))
-    {
-      DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
-      memcpy(m_cols_ai.bitmap, ptr_after_width, (m_width + 7) / 8);
-      create_last_word_mask(&m_cols_ai);
-      ptr_after_width+= (m_width + 7) / 8;
-      DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
-                no_bytes_in_map(&m_cols_ai));
-    }
-    else
-    {
-      // Needed because bitmap_init() does not set it to null on failure
-      m_cols_ai.bitmap= 0;
-      DBUG_VOID_RETURN;
-    }
-  }
-
   const uchar* const ptr_rows_data= (const uchar*) ptr_after_width;
-
   size_t const data_size= event_len - (ptr_rows_data - (const uchar *) buf);
   DBUG_PRINT("info",("m_table_id: %lu  m_flags: %d  m_width: %lu  data_size: %lu",
                      m_table_id, m_flags, m_width, (ulong) data_size));
+  DBUG_DUMP("rows_data", (uchar*) ptr_rows_data, data_size);
 
   m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME));
   if (likely((bool)m_rows_buf))
@@ -1419,24 +1393,18 @@ Old_rows_log_event::~Old_rows_log_event()
 
 int Old_rows_log_event::get_data_size()
 {
-  int const type_code= get_type_code();
-
   uchar buf[sizeof(m_width)+1];
   uchar *end= net_store_length(buf, (m_width + 7) / 8);
 
   DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
                   return 6 + no_bytes_in_map(&m_cols) + (end - buf) +
-                  (type_code == PRE_GA_UPDATE_ROWS_EVENT ? no_bytes_in_map(&m_cols_ai) : 0) +
                   (m_rows_cur - m_rows_buf););
   int data_size= ROWS_HEADER_LEN;
   data_size+= no_bytes_in_map(&m_cols);
   data_size+= end - buf;
 
-  if (type_code == PRE_GA_UPDATE_ROWS_EVENT)
-    data_size+= no_bytes_in_map(&m_cols_ai);
-
   data_size+= (m_rows_cur - m_rows_buf);
-  return data_size; 
+  return data_size;
 }
 
 
@@ -2011,16 +1979,6 @@ bool Old_rows_log_event::write_data_body(IO_CACHE*file)
   DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
   res= res || my_b_safe_write(file, (uchar*) m_cols.bitmap,
                               no_bytes_in_map(&m_cols));
-  /*
-    TODO[refactor write]: Remove the "down cast" here (and elsewhere).
-   */
-  if (get_type_code() == PRE_GA_UPDATE_ROWS_EVENT)
-  {
-    DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
-              no_bytes_in_map(&m_cols_ai));
-    res= res || my_b_safe_write(file, (uchar*) m_cols_ai.bitmap,
-                                no_bytes_in_map(&m_cols_ai));
-  }
   DBUG_DUMP("rows", m_rows_buf, data_size);
   res= res || my_b_safe_write(file, m_rows_buf, (size_t) data_size);
 
@@ -2831,38 +2789,10 @@ Update_rows_log_event_old::Update_rows_log_event_old(THD *thd_arg,
 
   // This constructor should not be reached.
   assert(0);
-
-  init(cols);
-}
-
-
-void Update_rows_log_event_old::init(MY_BITMAP const *cols)
-{
-  /* if bitmap_init fails, caught in is_valid() */
-  if (likely(!bitmap_init(&m_cols_ai,
-                          m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
-                          m_width,
-                          false)))
-  {
-    /* Cols can be zero if this is a dummy binrows event */
-    if (likely(cols != NULL))
-    {
-      memcpy(m_cols_ai.bitmap, cols->bitmap, no_bytes_in_map(cols));
-      create_last_word_mask(&m_cols_ai);
-    }
-  }
 }
 #endif /* !defined(MYSQL_CLIENT) */
 
 
-Update_rows_log_event_old::~Update_rows_log_event_old()
-{
-  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().
-}
-
-
 /*
   Constructor used by slave to read the event from the binary log.
  */
diff --git a/sql/log_event_old.h b/sql/log_event_old.h
index efb2be29ee4..719802a80fb 100644
--- a/sql/log_event_old.h
+++ b/sql/log_event_old.h
@@ -175,14 +175,6 @@ protected:
   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 */
 
@@ -442,12 +434,8 @@ public:
   Update_rows_log_event_old(THD*, TABLE*, ulong table_id,
                             MY_BITMAP const *cols,
                             bool is_transactional);
-
-  void init(MY_BITMAP const *cols);
 #endif
 
-  virtual ~Update_rows_log_event_old();
-
 #ifdef HAVE_REPLICATION
   Update_rows_log_event_old(const char *buf, uint event_len,
                             const Format_description_log_event *description_event);
@@ -466,11 +454,6 @@ public:
   }
 #endif
 
-  virtual bool is_valid() const
-  {
-    return Old_rows_log_event::is_valid() && m_cols_ai.bitmap;
-  }
-
 protected:
 #ifdef MYSQL_CLIENT
   void print(FILE *file, PRINT_EVENT_INFO *print_event_info);