summaryrefslogtreecommitdiff
path: root/sql/log_event.cc
diff options
context:
space:
mode:
authorAndrei Elkin <aelkin@mysql.com>2009-03-25 12:53:56 +0200
committerAndrei Elkin <aelkin@mysql.com>2009-03-25 12:53:56 +0200
commit67f9a6d1782ff9f00769816fdf3dfb1e9763bba7 (patch)
treed96b69ccd9147ab28ede5b29b49d423d7e1d29ea /sql/log_event.cc
parent6c0abff9284511914e14ae9339f858101feca99a (diff)
downloadmariadb-git-67f9a6d1782ff9f00769816fdf3dfb1e9763bba7.tar.gz
Bug#42977 RBR logs for rows with more than 250 column results in corrupt binlog
The issue happened to be two-fold. The table map event was recorded into binlog having an incorrect size when number of columns exceeded 251. The Row-based event had incorrect recording and restoring m_width member within the same as above conditions. Fixed with correcting m_data_size and m_width. mysql-test/suite/rpl/r/rpl_row_wide_table.result: the new test results. mysql-test/suite/rpl/t/rpl_row_wide_table.test: regression test for bug#42977. sql/log_event.cc: 0. all buffers that used in net_store_length() are augmented with 1 for safety to be able to contain the magic and the content of ulonglong as well; 1. Rows_log_event::get_data_size() yieled incorrect size |m_width/8| whereas it should be m_width; 2. Table_map_log_event::Table_map_log_event yieled incorrect value for `m_data_size' probably presuming 1-byte integer max for the column number; sql/rpl_utility.h: DBUG_PRINT_BITSET() macro is left 256-cols limited but has made safe and commented.
Diffstat (limited to 'sql/log_event.cc')
-rw-r--r--sql/log_event.cc14
1 files changed, 9 insertions, 5 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc
index aa7e8c84a0f..6220bc276a6 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -6993,8 +6993,8 @@ int 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);
+ uchar buf[sizeof(m_width) + 1];
+ uchar *end= net_store_length(buf, m_width);
DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
return 6 + no_bytes_in_map(&m_cols) + (end - buf) +
@@ -7583,7 +7583,7 @@ bool Rows_log_event::write_data_body(IO_CACHE*file)
Note that this should be the number of *bits*, not the number of
bytes.
*/
- uchar sbuf[sizeof(m_width)];
+ uchar sbuf[sizeof(m_width) + 1];
my_ptrdiff_t const data_size= m_rows_cur - m_rows_buf;
bool res= false;
uchar *const sbuf_end= net_store_length(sbuf, (size_t) m_width);
@@ -7745,6 +7745,8 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
m_null_bits(0),
m_meta_memory(NULL)
{
+ uchar cbuf[sizeof(m_colcnt) + 1];
+ uchar *cbuf_end;
DBUG_ASSERT(m_table_id != ~0UL);
/*
In TABLE_SHARE, "db" and "table_name" are 0-terminated (see this comment in
@@ -7761,7 +7763,9 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master", m_data_size= 6;);
m_data_size+= m_dblen + 2; // Include length and terminating \0
m_data_size+= m_tbllen + 2; // Include length and terminating \0
- m_data_size+= 1 + m_colcnt; // COLCNT and column types
+ cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
+ DBUG_ASSERT((cbuf_end - cbuf) <= sizeof(cbuf));
+ m_data_size+= (cbuf_end - cbuf) + m_colcnt; // COLCNT and column types
/* If malloc fails, caught in is_valid() */
if ((m_memory= (uchar*) my_malloc(m_colcnt, MYF(MY_WME))))
@@ -8053,7 +8057,7 @@ bool Table_map_log_event::write_data_body(IO_CACHE *file)
uchar const dbuf[]= { (uchar) m_dblen };
uchar const tbuf[]= { (uchar) m_tbllen };
- uchar cbuf[sizeof(m_colcnt)];
+ uchar cbuf[sizeof(m_colcnt) + 1];
uchar *const cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));