#At file:///home/lsoares/Workspace/bzr/work/features/wl5092/mysql-5.1-rpl-wl5092/ based on revid:luis.soares@stripped
3183 Luis Soares 2010-03-29
BUG#49100: RBR: Unexpected behavior when AI contains no usable data
for slave columns
This is a (pretty complete) sketch of a patch for this bug
built on top of:
- mysql-5.1-rpl-wl5092 (for server changes)
luis.soares@stripped
- WL#5096 tests (for test case facilities)
http://lists.mysql.com/commits/104427 (needs this cset on
top of revision aforementioned for mysql-5.1-rpl-wl5092).
modified:
mysql-test/suite/rpl/r/rpl_row_img.result
mysql-test/suite/rpl/t/rpl_row_img.test
sql/log_event.cc
sql/log_event.h
sql/rpl_record.cc
=== modified file 'mysql-test/suite/rpl/r/rpl_row_img.result'
--- a/mysql-test/suite/rpl/r/rpl_row_img.result 2010-03-26 11:09:50 +0000
+++ b/mysql-test/suite/rpl/r/rpl_row_img.result 2010-03-29 18:31:30 +0000
@@ -24083,3 +24083,163 @@ FLUSH TABLES;
SHOW VARIABLES LIKE 'binlog_row_image';
Variable_name Value
binlog_row_image FULL
+include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+RESET MASTER;
+RESET SLAVE;
+include/start_slave.inc
+include/start_slave.inc
+DROP TABLE IF EXISTS t1;
+CON: 'mysqld_a', IMG: 'MINIMAL', RESTART SLAVE: 'N'
+SET SESSION binlog_row_image= 'MINIMAL';
+SET GLOBAL binlog_row_image= 'MINIMAL';
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name Value
+binlog_row_image MINIMAL
+CON: 'mysqld_b', IMG: 'MINIMAL', RESTART SLAVE: 'Y'
+SET SESSION binlog_row_image= 'MINIMAL';
+SET GLOBAL binlog_row_image= 'MINIMAL';
+include/stop_slave.inc
+include/start_slave.inc
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name Value
+binlog_row_image MINIMAL
+CON: 'mysqld_c', IMG: 'MINIMAL', RESTART SLAVE: 'Y'
+SET SESSION binlog_row_image= 'MINIMAL';
+SET GLOBAL binlog_row_image= 'MINIMAL';
+include/stop_slave.inc
+include/start_slave.inc
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name Value
+binlog_row_image MINIMAL
+#### case #1: empty write set in both master and slave
+CREATE TABLE t1 (c1 int DEFAULT 100);
+INSERT INTO t1 VALUES ();
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 1
+SELECT * FROM t1;
+c1
+100
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 2
+SELECT * FROM t1;
+c1
+100
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 3
+SELECT * FROM t1;
+c1
+100
+DROP TABLE t1;
+#### case #2: not empty write set, but slave does not have usable data
+#### for its columns (INSERT)
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int, primary key(c2));
+SET SQL_LOG_BIN=1;
+INSERT INTO t1(c2) VALUES (1);
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 1
+SELECT * FROM t1;
+c1 c2
+100 1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 2
+SELECT * FROM t1;
+c1
+100
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 3
+SELECT * FROM t1;
+c1
+100
+DROP TABLE t1;
+#### case #3: not empty write set, but slave does not have usable data
+#### for its columns (UPDATE)
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int);
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES (1,1);
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 1
+SELECT * FROM t1;
+c1 c2
+1 1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 2
+SELECT * FROM t1;
+c1
+1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 3
+SELECT * FROM t1;
+c1
+1
+UPDATE t1 SET c2=2 WHERE c1=1 AND c2=1;
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 1
+SELECT * FROM t1;
+c1 c2
+1 2
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 2
+SELECT * FROM t1;
+c1
+1
+SHOW VARIABLES LIKE 'server_id';
+Variable_name Value
+server_id 3
+SELECT * FROM t1;
+c1
+1
+DROP TABLE t1;
+CON: 'mysqld_a', IMG: 'FULL', RESTART SLAVE: 'N'
+SET SESSION binlog_row_image= 'FULL';
+SET GLOBAL binlog_row_image= 'FULL';
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name Value
+binlog_row_image FULL
+CON: 'mysqld_b', IMG: 'FULL', RESTART SLAVE: 'Y'
+SET SESSION binlog_row_image= 'FULL';
+SET GLOBAL binlog_row_image= 'FULL';
+include/stop_slave.inc
+include/start_slave.inc
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name Value
+binlog_row_image FULL
+CON: 'mysqld_c', IMG: 'FULL', RESTART SLAVE: 'Y'
+SET SESSION binlog_row_image= 'FULL';
+SET GLOBAL binlog_row_image= 'FULL';
+include/stop_slave.inc
+include/start_slave.inc
+FLUSH TABLES;
+SHOW VARIABLES LIKE 'binlog_row_image';
+Variable_name Value
+binlog_row_image FULL
=== modified file 'mysql-test/suite/rpl/t/rpl_row_img.test'
--- a/mysql-test/suite/rpl/t/rpl_row_img.test 2010-03-26 11:09:50 +0000
+++ b/mysql-test/suite/rpl/t/rpl_row_img.test 2010-03-29 18:31:30 +0000
@@ -1,12 +1,15 @@
#
+# This file contains tests for WL#5096 and bug fixes.
+#
# Test Description
# ================
-#
+#
+# WL#5096 Tests.
+#
# In this file we will run tests that mix engines, indexes
# and blobs.
-#
-# See WL#5096 for details.
#
+
-- source suite/rpl/include/rpl_chained_3_hosts.inc
-- source include/have_binlog_format_row.inc
@@ -41,3 +44,133 @@
-- echo ###################################################################
-- let $row_img_test_script= extra/rpl_tests/rpl_row_img_blobs.test
-- source suite/rpl/include/rpl_row_img_general_loop.inc
+
+#
+# BUG#49100: RBR: Unexpected behavior when AI contains no usable data
+# for slave columns
+#
+
+-- connection mysqld_c
+-- source include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+
+-- connection mysqld_b
+-- source include/stop_slave.inc
+RESET MASTER;
+RESET SLAVE;
+
+-- connection mysqld_a
+RESET MASTER;
+RESET SLAVE;
+
+-- connection mysqld_c
+-- source include/start_slave.inc
+
+-- connection mysqld_b
+-- source include/start_slave.inc
+
+-- disable_warnings
+DROP TABLE IF EXISTS t1;
+-- enable_warnings
+-- source suite/rpl/include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_a
+
+-- let $row_img_set=mysqld_a:MINIMAL:N,mysqld_b:MINIMAL:Y,mysqld_c:MINIMAL:Y
+-- source suite/rpl/include/rpl_row_img_set.inc
+
+-- echo #### case #1: empty write set in both master and slave
+
+CREATE TABLE t1 (c1 int DEFAULT 100);
+INSERT INTO t1 VALUES ();
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source suite/rpl/include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+DROP TABLE t1;
+-- source suite/rpl/include/rpl_chained_3_hosts_sync.inc
+
+-- echo #### case #2: not empty write set, but slave does not have usable data
+-- echo #### for its columns (INSERT)
+
+-- connection mysqld_c
+CREATE TABLE t1 (c1 int DEFAULT 100);
+
+-- connection mysqld_b
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+
+-- connection mysqld_a
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int, primary key(c2));
+SET SQL_LOG_BIN=1;
+
+INSERT INTO t1(c2) VALUES (1);
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source suite/rpl/include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+DROP TABLE t1;
+-- source suite/rpl/include/rpl_chained_3_hosts_sync.inc
+
+-- echo #### case #3: not empty write set, but slave does not have usable data
+-- echo #### for its columns (UPDATE)
+
+-- connection mysqld_c
+CREATE TABLE t1 (c1 int DEFAULT 100);
+
+-- connection mysqld_b
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100);
+SET SQL_LOG_BIN=1;
+
+-- connection mysqld_a
+SET SQL_LOG_BIN=0;
+CREATE TABLE t1 (c1 int DEFAULT 100, c2 int);
+SET SQL_LOG_BIN=1;
+
+INSERT INTO t1 VALUES (1,1);
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source suite/rpl/include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+UPDATE t1 SET c2=2 WHERE c1=1 AND c2=1;
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- source suite/rpl/include/rpl_chained_3_hosts_sync.inc
+-- connection mysqld_b
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+-- connection mysqld_c
+SHOW VARIABLES LIKE 'server_id';
+SELECT * FROM t1;
+
+-- connection mysqld_a
+DROP TABLE t1;
+-- source suite/rpl/include/rpl_chained_3_hosts_sync.inc
+
+-- let $row_img_set=mysqld_a:FULL:N,mysqld_b:FULL:Y,mysqld_c:FULL:Y
+-- source suite/rpl/include/rpl_row_img_set.inc
+
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2010-03-04 17:00:32 +0000
+++ b/sql/log_event.cc 2010-03-29 18:31:30 +0000
@@ -7636,7 +7636,7 @@ int Rows_log_event::do_apply_event(Relay
// row processing loop
- while (error == 0 && m_curr_row < m_rows_end)
+ while (error == 0)
{
/* in_use can have been set to NULL in close_tables_for_reopen */
THD* old_thd= table->in_use;
@@ -7687,7 +7687,7 @@ int Rows_log_event::do_apply_event(Relay
// at this moment m_curr_row_end should be set
DBUG_ASSERT(error || m_curr_row_end != NULL);
- DBUG_ASSERT(error || m_curr_row < m_curr_row_end);
+ DBUG_ASSERT(error || m_curr_row <= m_curr_row_end);
DBUG_ASSERT(error || m_curr_row_end <= m_rows_end);
m_curr_row= m_curr_row_end;
@@ -7695,6 +7695,9 @@ int Rows_log_event::do_apply_event(Relay
if (error == 0 && !transactional_table)
thd->transaction.all.modified_non_trans_table=
thd->transaction.stmt.modified_non_trans_table= TRUE;
+
+ if (m_curr_row == m_rows_end)
+ break;
} // row processing loop
{/**
@@ -8695,7 +8698,11 @@ Rows_log_event::write_row(const Relay_lo
/* this is the first row to be inserted, we estimate the rows with
the size of the first row and use that value to initialize
storage engine for bulk insertion */
- ulong estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
+ DBUG_ASSERT(!(m_curr_row > m_curr_row_end));
+
+ ulong estimated_rows= 1;
+ if (m_curr_row < m_curr_row_end)
+ estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
m_table->file->ha_start_bulk_insert(estimated_rows);
}
=== modified file 'sql/log_event.h'
--- a/sql/log_event.h 2010-03-04 17:00:32 +0000
+++ b/sql/log_event.h 2010-03-29 18:31:30 +0000
@@ -3628,7 +3628,7 @@ protected:
DBUG_ASSERT(m_table);
bool first_row= (m_curr_row == m_rows_buf);
- ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
+ ASSERT_OR_RETURN_ERROR(m_curr_row <= m_rows_end, HA_ERR_CORRUPT_EVENT);
int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, cols,
&m_curr_row_end, &m_master_reclength,
abort_on_warning, first_row);
=== modified file 'sql/rpl_record.cc'
--- a/sql/rpl_record.cc 2010-03-04 17:00:32 +0000
+++ b/sql/rpl_record.cc 2010-03-29 18:31:30 +0000
@@ -208,6 +208,20 @@ unpack_row(Relay_log_info const *rli,
uchar const *null_ptr= row_data;
uchar const *pack_ptr= row_data + master_null_byte_count;
+ if (bitmap_is_clear_all(cols))
+ {
+ /**
+ There was no data sent from the master, so there is
+ nothing to unpack. In case we are unpacking an AI (for
+ update or insert purposes), we just use the default
+ values from the slave to do the insert.
+ */
+ *row_end= pack_ptr;
+ *master_reclength= 0;
+ DBUG_RETURN(error);
+ }
+
+
Field **const begin_ptr = table->field;
Field **field_ptr;
Field **const end_ptr= begin_ptr + colcnt;
Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20100329183130-0pxspka854bw5z11.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-rpl-wl5092 branch (luis.soares:3183)Bug#49100 | Luis Soares | 29 Mar |