MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Alfranio Correia Date:October 22 2009 12:15am
Subject:bzr commit into mysql-5.1-bugteam branch (alfranio.correia:3189)
Bug#48091
View as plain text  
#At file:///home/acorreia/workspace.sun/repository.mysql/bzrwork/bug-48091/mysql-5.1-bugteam/ based on revid:alfranio.correia@stripped

 3189 Alfranio Correia	2009-10-22
      BUG#48091 valgrind errors when slave has double not null and master has double null
            
      Backporting BUG#43789 to mysql-5.1-bugteam
                                    
      The replication was generating corrupted data, warning messages on Valgrind
      and aborting on debug mode while replicating a "null" to "not null" field.
      Specifically the unpack_row routine, was considering the slave's table
      definition and trying to retrieve a field value, where there was nothing to be
      retrieved, ignoring the fact that the value was defined as "null" by the master.
                                    
      To fix the problem, we proceed as follows:
                                    
      1 - If it is not STRICT sql_mode, implicit default values are used, regardless
      if it is multi-row or single-row statement.
                                    
      2 - However, if it is STRICT mode, then a we do what follows:
                                    
      2.1 If it is a transactional engine, we do a rollback on the first NULL that is
      to be set into a NOT NULL column and return an error.
                                    
      2.2 If it is a non-transactional engine and it is the first row to be inserted
      with multi-row, we also return the error. Otherwise, we proceed with the
      execution, use implicit default values and print out warning messages.
                              
      Unfortunately, the current patch cannot mimic the behavior showed by the master
      for updates on multi-tables and multi-row inserts. This happens because such
      statements are unfolded in different row events. For instance, considering the
      following updates and strict mode:
                              
      (master)
      create table t1 (a int);
      create table t2 (a int not null);
      insert into t1 values (1);
      insert into t2 values (2);
      update t1, t2 SET t1.a=10, t2.a=NULL;
                              
      t1 would have (10) and t2 would have (0) as this would be handled as a
      multi-row update. On the other hand, if we had the following updates:
                              
      (master)
      create table t1 (a int);
      create table t2 (a int);
                              
      (slave)
      create table t1 (a int);
      create table t2 (a int not null);
                              
      (master)
      insert into t1 values (1);
      insert into t2 values (2);
      update t1, t2 SET t1.a=10, t2.a=NULL;
                              
      On the master t1 would have (10) and t2 would have (NULL). On
      the slave, t1 would have (10) but the update on t1 would fail.

    added:
      mysql-test/extra/rpl_tests/rpl_not_null.test
      mysql-test/suite/rpl/r/rpl_not_null_innodb.result
      mysql-test/suite/rpl/r/rpl_not_null_myisam.result
      mysql-test/suite/rpl/t/rpl_not_null_innodb.test
      mysql-test/suite/rpl/t/rpl_not_null_myisam.test
    modified:
      sql/log_event.cc
      sql/log_event.h
      sql/rpl_record.cc
      sql/rpl_record.h
=== added file 'mysql-test/extra/rpl_tests/rpl_not_null.test'
--- a/mysql-test/extra/rpl_tests/rpl_not_null.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_not_null.test	2009-10-22 00:15:45 +0000
@@ -0,0 +1,364 @@
+#################################################################################
+# This test checks if the replication between "null" fields to either "null"
+# fields or "not null" fields works properly. In the first case, the execution
+# should work fine. In the second case, it may fail according to the sql_mode
+# being used.
+#
+# The test is devided in three main parts:
+#
+# 1 - NULL --> NULL (no failures)
+# 2 - NULL --> NOT NULL ( sql-mode  = STRICT and failures)
+# 3 - NULL --> NOT NULL ( sql-mode != STRICT and no failures)
+#
+#################################################################################
+connection master;
+
+SET SQL_LOG_BIN= 0;
+eval CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL,
+`c` INT DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+
+eval CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+
+eval CREATE TABLE t3(`a` INT, `b` DATE DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+
+eval CREATE TABLE t4(`a` INT, `b` DATE DEFAULT NULL,
+`c` INT DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+SET SQL_LOG_BIN= 1;
+
+connection slave;
+
+eval CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL,
+`c` INT DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+
+eval CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+
+eval CREATE TABLE t3(`a` INT, `b` DATE DEFAULT '0000-00-00',
+`c` INT DEFAULT 500, 
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+
+eval CREATE TABLE t4(`a` INT, `b` DATE DEFAULT '0000-00-00',
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+
+--echo ************* EXECUTION WITH INSERTS *************
+connection master;
+INSERT INTO t1(a,b,c) VALUES (1, null, 1);
+INSERT INTO t1(a,b,c) VALUES (2,'1111-11-11', 2);
+INSERT INTO t1(a,b) VALUES (3, null);
+INSERT INTO t1(a,c) VALUES (4, 4);
+INSERT INTO t1(a) VALUES (5);
+
+INSERT INTO t2(a,b) VALUES (1, null);
+INSERT INTO t2(a,b) VALUES (2,'1111-11-11');
+INSERT INTO t2(a) VALUES (3);
+
+INSERT INTO t3(a,b) VALUES (1, null);
+INSERT INTO t3(a,b) VALUES (2,'1111-11-11');
+INSERT INTO t3(a) VALUES (3);
+
+INSERT INTO t4(a,b,c) VALUES (1, null, 1);
+INSERT INTO t4(a,b,c) VALUES (2,'1111-11-11', 2);
+INSERT INTO t4(a,b) VALUES (3, null);
+INSERT INTO t4(a,c) VALUES (4, 4);
+INSERT INTO t4(a) VALUES (5);
+
+--echo ************* SHOWING THE RESULT SETS WITH INSERTS *************
+sync_slave_with_master;
+
+--echo TABLES t1 and t2 must be equal otherwise an error will be thrown. 
+let $diff_table_1=master:test.t1;
+let $diff_table_2=slave:test.t1;
+source include/diff_tables.inc;
+ 
+let $diff_table_1=master:test.t2;
+let $diff_table_2=slave:test.t2;
+source include/diff_tables.inc;
+
+--echo TABLES t2 and t3 must be different.
+connection master;
+SELECT * FROM t3;
+connection slave;
+SELECT * FROM t3;
+connection master;
+SELECT * FROM t4;
+connection slave;
+SELECT * FROM t4;
+
+--echo ************* EXECUTION WITH UPDATES and REPLACES *************
+connection master;
+DELETE FROM t1;
+INSERT INTO t1(a,b,c) VALUES (1,'1111-11-11', 1);
+REPLACE INTO t1(a,b,c) VALUES (2,'1111-11-11', 2);
+UPDATE t1 set b= NULL, c= 300 where a= 1;
+REPLACE INTO t1(a,b,c) VALUES (2, NULL, 300);
+
+--echo ************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES *************
+sync_slave_with_master;
+
+--echo TABLES t1 and t2 must be equal otherwise an error will be thrown. 
+let $diff_table_1=master:test.t1;
+let $diff_table_2=slave:test.t1;
+source include/diff_tables.inc;
+
+--echo ************* CLEANING *************
+connection master;
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
+
+sync_slave_with_master;
+  
+connection master;
+
+SET SQL_LOG_BIN= 0;
+eval CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT NULL, `c` BIT DEFAULT NULL, 
+PRIMARY KEY (`a`)) ENGINE= $engine;
+SET SQL_LOG_BIN= 1;
+
+connection slave;
+
+eval CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT b'01', `c` BIT DEFAULT NULL,
+PRIMARY KEY (`a`)) ENGINE= $engine;
+
+--echo ************* EXECUTION WITH INSERTS *************
+connection master;
+INSERT INTO t1(a,b,c) VALUES (1, null, b'01');
+INSERT INTO t1(a,b,c) VALUES (2,b'00', b'01');
+INSERT INTO t1(a,b) VALUES (3, null);
+INSERT INTO t1(a,c) VALUES (4, b'01');
+INSERT INTO t1(a) VALUES (5);
+
+--echo ************* SHOWING THE RESULT SETS WITH INSERTS *************
+--echo TABLES t1 and t2 must be different.
+sync_slave_with_master;
+connection master;
+SELECT a,b+0,c+0 FROM t1;
+connection slave;
+SELECT a,b+0,c+0 FROM t1;
+
+--echo ************* EXECUTION WITH UPDATES and REPLACES *************
+connection master;
+DELETE FROM t1;
+INSERT INTO t1(a,b,c) VALUES (1,b'00', b'01');
+REPLACE INTO t1(a,b,c) VALUES (2,b'00',b'01');
+UPDATE t1 set b= NULL, c= b'00' where a= 1;
+REPLACE INTO t1(a,b,c) VALUES (2, NULL, b'00');
+
+--echo ************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES *************
+--echo TABLES t1 and t2 must be equal otherwise an error will be thrown. 
+sync_slave_with_master;
+let $diff_table_1=master:test.t1;
+let $diff_table_2=slave:test.t1;
+source include/diff_tables.inc;
+ 
+connection master;
+
+DROP TABLE t1;
+
+sync_slave_with_master;
+  
+--echo ################################################################################
+--echo #                       NULL ---> NOT NULL (STRICT MODE)
+--echo #                    UNCOMMENT THIS AFTER FIXING BUG#43992
+--echo ################################################################################
+#connection slave;
+#SET GLOBAL sql_mode="TRADITIONAL";
+#
+#STOP SLAVE;
+#--source include/wait_for_slave_to_stop.inc
+#START SLAVE;
+#--source include/wait_for_slave_to_start.inc
+#
+#let $y=0;
+#while (`select $y < 6`)
+#{
+#  connection master;
+#
+#  SET SQL_LOG_BIN= 0;
+#  eval CREATE TABLE t1(`a` INT NOT NULL, `b` INT,
+#  PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+#  eval CREATE TABLE t2(`a` INT NOT NULL, `b` INT,
+#  PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+#  eval CREATE TABLE t3(`a` INT NOT NULL, `b` INT,
+#  PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+#  SET SQL_LOG_BIN= 1;
+#  
+#  connection slave;
+#  
+#  eval CREATE TABLE t1(`a` INT NOT NULL, `b` INT NOT NULL, 
+#  `c` INT NOT NULL,
+#  PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+#  eval CREATE TABLE t2(`a` INT NOT NULL, `b` INT NOT NULL,
+#  `c` INT, 
+#  PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+#  eval CREATE TABLE t3(`a` INT NOT NULL, `b` INT NOT NULL,
+#  `c` INT DEFAULT 500, 
+#  PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+#  
+#  if (`select $y=0`)
+#  {
+#    --echo ************* EXECUTION WITH INSERTS *************
+#    connection master;
+#    INSERT INTO t1(a) VALUES (1);
+#  }
+#  
+#  if (`select $y=1`)
+#  {
+#    --echo ************* EXECUTION WITH INSERTS *************
+#    connection master;
+#    INSERT INTO t1(a, b) VALUES (1, NULL);
+#  }
+#  
+#  if (`select $y=2`)
+#  {
+#    --echo ************* EXECUTION WITH UPDATES *************
+#    connection master;
+#    INSERT INTO t3(a, b) VALUES (1, 1);
+#    INSERT INTO t3(a, b) VALUES (2, 1);
+#    UPDATE t3 SET b = NULL where a= 1;
+#  }
+#  
+#  if (`select $y=3`)
+#  {
+#    --echo ************* EXECUTION WITH INSERTS/REPLACES *************
+#    connection master;
+#    REPLACE INTO t3(a, b) VALUES (1, null);
+#  }
+#   
+#  if (`select $y=4`)
+#  {
+#    --echo ************* EXECUTION WITH UPDATES/REPLACES *************
+#    connection master;
+#    INSERT INTO t3(a, b) VALUES (1, 1);
+#    REPLACE INTO t3(a, b) VALUES (1, null);
+#  }
+#   
+#  if (`select $y=5`)
+#  {
+#    --echo ************* EXECUTION WITH MULTI-ROW INSERTS *************
+#    connection master;
+#
+#    SET SQL_LOG_BIN= 0;
+#    INSERT INTO t2(a, b) VALUES (1, 1);
+#    INSERT INTO t2(a, b) VALUES (2, 1);
+#    INSERT INTO t2(a, b) VALUES (3, null);
+#    INSERT INTO t2(a, b) VALUES (4, 1);
+#    INSERT INTO t2(a, b) VALUES (5, 1);
+#    SET SQL_LOG_BIN= 1;
+#
+#    INSERT INTO t2 SELECT a + 10, b from t2;
+#    --echo The statement below is just executed to stop processing
+#    INSERT INTO t1(a) VALUES (1);
+#  }
+#  
+#  --echo ************* SHOWING THE RESULT SETS *************
+#  connection slave;
+#  --source include/wait_for_slave_sql_to_stop.inc
+#  connection master;
+#  SELECT * FROM t1;
+#  connection slave;
+#  SELECT * FROM t1;
+#  connection master;
+#  SELECT * FROM t2;
+#  connection slave;
+#  SELECT * FROM t2;
+#  connection master;
+#  SELECT * FROM t3;
+#  connection slave;
+#  SELECT * FROM t3;
+#  --source include/reset_master_and_slave.inc
+#  
+#  connection master;
+#  
+#  DROP TABLE t1;
+#  DROP TABLE t2;
+#  DROP TABLE t3;
+#  
+#  sync_slave_with_master;
+#
+#  inc $y;
+#}
+#connection slave;
+#SET GLOBAL sql_mode="";
+#
+#STOP SLAVE;
+#source include/wait_for_slave_to_stop.inc;
+#START SLAVE;
+#--source include/wait_for_slave_to_start.inc
+
+--echo ################################################################################
+--echo #                       NULL ---> NOT NULL (NON-STRICT MODE)
+--echo ################################################################################
+connection master;
+
+SET SQL_LOG_BIN= 0;
+eval CREATE TABLE t1(`a` INT NOT NULL, `b` INT,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+eval CREATE TABLE t2(`a` INT NOT NULL, `b` INT,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+eval CREATE TABLE t3(`a` INT NOT NULL, `b` INT,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+SET SQL_LOG_BIN= 1;
+
+connection slave;
+
+eval CREATE TABLE t1(`a` INT NOT NULL, `b` INT NOT NULL, 
+`c` INT NOT NULL,
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+eval CREATE TABLE t2(`a` INT NOT NULL, `b` INT NOT NULL,
+`c` INT, 
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+eval CREATE TABLE t3(`a` INT NOT NULL, `b` INT NOT NULL,
+`c` INT DEFAULT 500, 
+PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1;
+
+--echo ************* EXECUTION WITH INSERTS *************
+connection master;
+INSERT INTO t1(a) VALUES (1);
+INSERT INTO t1(a, b) VALUES (2, NULL);
+INSERT INTO t1(a, b) VALUES (3, 1);
+
+INSERT INTO t2(a) VALUES (1);
+INSERT INTO t2(a, b) VALUES (2, NULL);
+INSERT INTO t2(a, b) VALUES (3, 1);
+
+INSERT INTO t3(a) VALUES (1);
+INSERT INTO t3(a, b) VALUES (2, NULL);
+INSERT INTO t3(a, b) VALUES (3, 1);
+INSERT INTO t3(a, b) VALUES (4, 1);
+REPLACE INTO t3(a, b) VALUES (5, null);
+
+REPLACE INTO t3(a, b) VALUES (3, null);
+UPDATE t3 SET b = NULL where a = 4;
+
+--echo ************* SHOWING THE RESULT SETS *************
+connection master;
+sync_slave_with_master;
+
+connection master;
+SELECT * FROM t1;
+connection slave;
+SELECT * FROM t1;
+connection master;
+SELECT * FROM t2;
+connection slave;
+SELECT * FROM t2;
+connection master;
+SELECT * FROM t3;
+connection slave;
+SELECT * FROM t3;
+
+connection master;
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+
+sync_slave_with_master;

=== added file 'mysql-test/suite/rpl/r/rpl_not_null_innodb.result'
--- a/mysql-test/suite/rpl/r/rpl_not_null_innodb.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_not_null_innodb.result	2009-10-22 00:15:45 +0000
@@ -0,0 +1,202 @@
+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 SQL_LOG_BIN= 0;
+CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL,
+`c` INT DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t3(`a` INT, `b` DATE DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t4(`a` INT, `b` DATE DEFAULT NULL,
+`c` INT DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+SET SQL_LOG_BIN= 1;
+CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL,
+`c` INT DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t3(`a` INT, `b` DATE DEFAULT '0000-00-00',
+`c` INT DEFAULT 500, 
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t4(`a` INT, `b` DATE DEFAULT '0000-00-00',
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+************* EXECUTION WITH INSERTS *************
+INSERT INTO t1(a,b,c) VALUES (1, null, 1);
+INSERT INTO t1(a,b,c) VALUES (2,'1111-11-11', 2);
+INSERT INTO t1(a,b) VALUES (3, null);
+INSERT INTO t1(a,c) VALUES (4, 4);
+INSERT INTO t1(a) VALUES (5);
+INSERT INTO t2(a,b) VALUES (1, null);
+INSERT INTO t2(a,b) VALUES (2,'1111-11-11');
+INSERT INTO t2(a) VALUES (3);
+INSERT INTO t3(a,b) VALUES (1, null);
+INSERT INTO t3(a,b) VALUES (2,'1111-11-11');
+INSERT INTO t3(a) VALUES (3);
+INSERT INTO t4(a,b,c) VALUES (1, null, 1);
+INSERT INTO t4(a,b,c) VALUES (2,'1111-11-11', 2);
+INSERT INTO t4(a,b) VALUES (3, null);
+INSERT INTO t4(a,c) VALUES (4, 4);
+INSERT INTO t4(a) VALUES (5);
+************* SHOWING THE RESULT SETS WITH INSERTS *************
+TABLES t1 and t2 must be equal otherwise an error will be thrown. 
+Comparing tables master:test.t1 and slave:test.t1
+Comparing tables master:test.t2 and slave:test.t2
+TABLES t2 and t3 must be different.
+SELECT * FROM t3;
+a	b
+1	NULL
+2	1111-11-11
+3	NULL
+SELECT * FROM t3;
+a	b	c
+1	NULL	500
+2	1111-11-11	500
+3	NULL	500
+SELECT * FROM t4;
+a	b	c
+1	NULL	1
+2	1111-11-11	2
+3	NULL	NULL
+4	NULL	4
+5	NULL	NULL
+SELECT * FROM t4;
+a	b
+1	NULL
+2	1111-11-11
+3	NULL
+4	NULL
+5	NULL
+************* EXECUTION WITH UPDATES and REPLACES *************
+DELETE FROM t1;
+INSERT INTO t1(a,b,c) VALUES (1,'1111-11-11', 1);
+REPLACE INTO t1(a,b,c) VALUES (2,'1111-11-11', 2);
+UPDATE t1 set b= NULL, c= 300 where a= 1;
+REPLACE INTO t1(a,b,c) VALUES (2, NULL, 300);
+************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES *************
+TABLES t1 and t2 must be equal otherwise an error will be thrown. 
+Comparing tables master:test.t1 and slave:test.t1
+************* CLEANING *************
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
+SET SQL_LOG_BIN= 0;
+CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT NULL, `c` BIT DEFAULT NULL, 
+PRIMARY KEY (`a`)) ENGINE= Innodb;
+SET SQL_LOG_BIN= 1;
+CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT b'01', `c` BIT DEFAULT NULL,
+PRIMARY KEY (`a`)) ENGINE= Innodb;
+************* EXECUTION WITH INSERTS *************
+INSERT INTO t1(a,b,c) VALUES (1, null, b'01');
+INSERT INTO t1(a,b,c) VALUES (2,b'00', b'01');
+INSERT INTO t1(a,b) VALUES (3, null);
+INSERT INTO t1(a,c) VALUES (4, b'01');
+INSERT INTO t1(a) VALUES (5);
+************* SHOWING THE RESULT SETS WITH INSERTS *************
+TABLES t1 and t2 must be different.
+SELECT a,b+0,c+0 FROM t1;
+a	b+0	c+0
+1	NULL	1
+2	0	1
+3	NULL	NULL
+4	NULL	1
+5	NULL	NULL
+SELECT a,b+0,c+0 FROM t1;
+a	b+0	c+0
+1	NULL	1
+2	0	1
+3	NULL	NULL
+4	NULL	1
+5	NULL	NULL
+************* EXECUTION WITH UPDATES and REPLACES *************
+DELETE FROM t1;
+INSERT INTO t1(a,b,c) VALUES (1,b'00', b'01');
+REPLACE INTO t1(a,b,c) VALUES (2,b'00',b'01');
+UPDATE t1 set b= NULL, c= b'00' where a= 1;
+REPLACE INTO t1(a,b,c) VALUES (2, NULL, b'00');
+************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES *************
+TABLES t1 and t2 must be equal otherwise an error will be thrown. 
+Comparing tables master:test.t1 and slave:test.t1
+DROP TABLE t1;
+################################################################################
+#                       NULL ---> NOT NULL (STRICT MODE)
+#                    UNCOMMENT THIS AFTER FIXING BUG#43992
+################################################################################
+################################################################################
+#                       NULL ---> NOT NULL (NON-STRICT MODE)
+################################################################################
+SET SQL_LOG_BIN= 0;
+CREATE TABLE t1(`a` INT NOT NULL, `b` INT,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t2(`a` INT NOT NULL, `b` INT,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t3(`a` INT NOT NULL, `b` INT,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+SET SQL_LOG_BIN= 1;
+CREATE TABLE t1(`a` INT NOT NULL, `b` INT NOT NULL, 
+`c` INT NOT NULL,
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t2(`a` INT NOT NULL, `b` INT NOT NULL,
+`c` INT, 
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+CREATE TABLE t3(`a` INT NOT NULL, `b` INT NOT NULL,
+`c` INT DEFAULT 500, 
+PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1;
+************* EXECUTION WITH INSERTS *************
+INSERT INTO t1(a) VALUES (1);
+INSERT INTO t1(a, b) VALUES (2, NULL);
+INSERT INTO t1(a, b) VALUES (3, 1);
+INSERT INTO t2(a) VALUES (1);
+INSERT INTO t2(a, b) VALUES (2, NULL);
+INSERT INTO t2(a, b) VALUES (3, 1);
+INSERT INTO t3(a) VALUES (1);
+INSERT INTO t3(a, b) VALUES (2, NULL);
+INSERT INTO t3(a, b) VALUES (3, 1);
+INSERT INTO t3(a, b) VALUES (4, 1);
+REPLACE INTO t3(a, b) VALUES (5, null);
+REPLACE INTO t3(a, b) VALUES (3, null);
+UPDATE t3 SET b = NULL where a = 4;
+************* SHOWING THE RESULT SETS *************
+SELECT * FROM t1;
+a	b
+1	NULL
+2	NULL
+3	1
+SELECT * FROM t1;
+a	b	c
+1	0	0
+2	0	0
+3	1	0
+SELECT * FROM t2;
+a	b
+1	NULL
+2	NULL
+3	1
+SELECT * FROM t2;
+a	b	c
+1	0	NULL
+2	0	NULL
+3	1	NULL
+SELECT * FROM t3;
+a	b
+1	NULL
+2	NULL
+3	NULL
+4	NULL
+5	NULL
+SELECT * FROM t3;
+a	b	c
+1	0	500
+2	0	500
+3	0	500
+4	0	500
+5	0	500
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;

=== added file 'mysql-test/suite/rpl/r/rpl_not_null_myisam.result'
--- a/mysql-test/suite/rpl/r/rpl_not_null_myisam.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_not_null_myisam.result	2009-10-22 00:15:45 +0000
@@ -0,0 +1,202 @@
+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 SQL_LOG_BIN= 0;
+CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL,
+`c` INT DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t3(`a` INT, `b` DATE DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t4(`a` INT, `b` DATE DEFAULT NULL,
+`c` INT DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+SET SQL_LOG_BIN= 1;
+CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL,
+`c` INT DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t3(`a` INT, `b` DATE DEFAULT '0000-00-00',
+`c` INT DEFAULT 500, 
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t4(`a` INT, `b` DATE DEFAULT '0000-00-00',
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+************* EXECUTION WITH INSERTS *************
+INSERT INTO t1(a,b,c) VALUES (1, null, 1);
+INSERT INTO t1(a,b,c) VALUES (2,'1111-11-11', 2);
+INSERT INTO t1(a,b) VALUES (3, null);
+INSERT INTO t1(a,c) VALUES (4, 4);
+INSERT INTO t1(a) VALUES (5);
+INSERT INTO t2(a,b) VALUES (1, null);
+INSERT INTO t2(a,b) VALUES (2,'1111-11-11');
+INSERT INTO t2(a) VALUES (3);
+INSERT INTO t3(a,b) VALUES (1, null);
+INSERT INTO t3(a,b) VALUES (2,'1111-11-11');
+INSERT INTO t3(a) VALUES (3);
+INSERT INTO t4(a,b,c) VALUES (1, null, 1);
+INSERT INTO t4(a,b,c) VALUES (2,'1111-11-11', 2);
+INSERT INTO t4(a,b) VALUES (3, null);
+INSERT INTO t4(a,c) VALUES (4, 4);
+INSERT INTO t4(a) VALUES (5);
+************* SHOWING THE RESULT SETS WITH INSERTS *************
+TABLES t1 and t2 must be equal otherwise an error will be thrown. 
+Comparing tables master:test.t1 and slave:test.t1
+Comparing tables master:test.t2 and slave:test.t2
+TABLES t2 and t3 must be different.
+SELECT * FROM t3;
+a	b
+1	NULL
+2	1111-11-11
+3	NULL
+SELECT * FROM t3;
+a	b	c
+1	NULL	500
+2	1111-11-11	500
+3	NULL	500
+SELECT * FROM t4;
+a	b	c
+1	NULL	1
+2	1111-11-11	2
+3	NULL	NULL
+4	NULL	4
+5	NULL	NULL
+SELECT * FROM t4;
+a	b
+1	NULL
+2	1111-11-11
+3	NULL
+4	NULL
+5	NULL
+************* EXECUTION WITH UPDATES and REPLACES *************
+DELETE FROM t1;
+INSERT INTO t1(a,b,c) VALUES (1,'1111-11-11', 1);
+REPLACE INTO t1(a,b,c) VALUES (2,'1111-11-11', 2);
+UPDATE t1 set b= NULL, c= 300 where a= 1;
+REPLACE INTO t1(a,b,c) VALUES (2, NULL, 300);
+************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES *************
+TABLES t1 and t2 must be equal otherwise an error will be thrown. 
+Comparing tables master:test.t1 and slave:test.t1
+************* CLEANING *************
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
+SET SQL_LOG_BIN= 0;
+CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT NULL, `c` BIT DEFAULT NULL, 
+PRIMARY KEY (`a`)) ENGINE= MyISAM;
+SET SQL_LOG_BIN= 1;
+CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT b'01', `c` BIT DEFAULT NULL,
+PRIMARY KEY (`a`)) ENGINE= MyISAM;
+************* EXECUTION WITH INSERTS *************
+INSERT INTO t1(a,b,c) VALUES (1, null, b'01');
+INSERT INTO t1(a,b,c) VALUES (2,b'00', b'01');
+INSERT INTO t1(a,b) VALUES (3, null);
+INSERT INTO t1(a,c) VALUES (4, b'01');
+INSERT INTO t1(a) VALUES (5);
+************* SHOWING THE RESULT SETS WITH INSERTS *************
+TABLES t1 and t2 must be different.
+SELECT a,b+0,c+0 FROM t1;
+a	b+0	c+0
+1	NULL	1
+2	0	1
+3	NULL	NULL
+4	NULL	1
+5	NULL	NULL
+SELECT a,b+0,c+0 FROM t1;
+a	b+0	c+0
+1	NULL	1
+2	0	1
+3	NULL	NULL
+4	NULL	1
+5	NULL	NULL
+************* EXECUTION WITH UPDATES and REPLACES *************
+DELETE FROM t1;
+INSERT INTO t1(a,b,c) VALUES (1,b'00', b'01');
+REPLACE INTO t1(a,b,c) VALUES (2,b'00',b'01');
+UPDATE t1 set b= NULL, c= b'00' where a= 1;
+REPLACE INTO t1(a,b,c) VALUES (2, NULL, b'00');
+************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES *************
+TABLES t1 and t2 must be equal otherwise an error will be thrown. 
+Comparing tables master:test.t1 and slave:test.t1
+DROP TABLE t1;
+################################################################################
+#                       NULL ---> NOT NULL (STRICT MODE)
+#                    UNCOMMENT THIS AFTER FIXING BUG#43992
+################################################################################
+################################################################################
+#                       NULL ---> NOT NULL (NON-STRICT MODE)
+################################################################################
+SET SQL_LOG_BIN= 0;
+CREATE TABLE t1(`a` INT NOT NULL, `b` INT,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t2(`a` INT NOT NULL, `b` INT,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t3(`a` INT NOT NULL, `b` INT,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+SET SQL_LOG_BIN= 1;
+CREATE TABLE t1(`a` INT NOT NULL, `b` INT NOT NULL, 
+`c` INT NOT NULL,
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t2(`a` INT NOT NULL, `b` INT NOT NULL,
+`c` INT, 
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+CREATE TABLE t3(`a` INT NOT NULL, `b` INT NOT NULL,
+`c` INT DEFAULT 500, 
+PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1;
+************* EXECUTION WITH INSERTS *************
+INSERT INTO t1(a) VALUES (1);
+INSERT INTO t1(a, b) VALUES (2, NULL);
+INSERT INTO t1(a, b) VALUES (3, 1);
+INSERT INTO t2(a) VALUES (1);
+INSERT INTO t2(a, b) VALUES (2, NULL);
+INSERT INTO t2(a, b) VALUES (3, 1);
+INSERT INTO t3(a) VALUES (1);
+INSERT INTO t3(a, b) VALUES (2, NULL);
+INSERT INTO t3(a, b) VALUES (3, 1);
+INSERT INTO t3(a, b) VALUES (4, 1);
+REPLACE INTO t3(a, b) VALUES (5, null);
+REPLACE INTO t3(a, b) VALUES (3, null);
+UPDATE t3 SET b = NULL where a = 4;
+************* SHOWING THE RESULT SETS *************
+SELECT * FROM t1;
+a	b
+1	NULL
+2	NULL
+3	1
+SELECT * FROM t1;
+a	b	c
+1	0	0
+2	0	0
+3	1	0
+SELECT * FROM t2;
+a	b
+1	NULL
+2	NULL
+3	1
+SELECT * FROM t2;
+a	b	c
+1	0	NULL
+2	0	NULL
+3	1	NULL
+SELECT * FROM t3;
+a	b
+1	NULL
+2	NULL
+3	NULL
+4	NULL
+5	NULL
+SELECT * FROM t3;
+a	b	c
+1	0	500
+2	0	500
+3	0	500
+4	0	500
+5	0	500
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;

=== added file 'mysql-test/suite/rpl/t/rpl_not_null_innodb.test'
--- a/mysql-test/suite/rpl/t/rpl_not_null_innodb.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_not_null_innodb.test	2009-10-22 00:15:45 +0000
@@ -0,0 +1,19 @@
+#################################################################################
+# This test checks if the replication between "null" fields to either "null"
+# fields or "not null" fields works properly. In the first case, the execution
+# should work fine. In the second case, it may fail according to the sql_mode
+# being used.
+#
+# The test is devided in three main parts:
+#
+# 1 - NULL --> NULL (no failures)
+# 2 - NULL --> NOT NULL ( sql-mode  = STRICT and failures)
+# 3 - NULL --> NOT NULL ( sql-mode != STRICT and no failures)
+#
+#################################################################################
+--source include/master-slave.inc
+--source include/have_innodb.inc
+--source include/have_binlog_format_row.inc
+
+let $engine=Innodb;
+--source extra/rpl_tests/rpl_not_null.test

=== added file 'mysql-test/suite/rpl/t/rpl_not_null_myisam.test'
--- a/mysql-test/suite/rpl/t/rpl_not_null_myisam.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_not_null_myisam.test	2009-10-22 00:15:45 +0000
@@ -0,0 +1,18 @@
+#################################################################################
+# This test checks if the replication between "null" fields to either "null"
+# fields or "not null" fields works properly. In the first case, the execution
+# should work fine. In the second case, it may fail according to the sql_mode
+# being used.
+#
+# The test is devided in three main parts:
+#
+# 1 - NULL --> NULL (no failures)
+# 2 - NULL --> NOT NULL ( sql-mode  = STRICT and failures)
+# 3 - NULL --> NOT NULL ( sql-mode != STRICT and no failures)
+#
+#################################################################################
+--source include/master-slave.inc
+--source include/have_binlog_format_row.inc
+
+let $engine=MyISAM;
+--source extra/rpl_tests/rpl_not_null.test

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2009-10-22 00:10:42 +0000
+++ b/sql/log_event.cc	2009-10-22 00:15:45 +0000
@@ -8450,16 +8450,17 @@ Rows_log_event::write_row(const Relay_lo
   auto_afree_ptr<char> key(NULL);
 
   /* fill table->record[0] with default values */
-
+  bool abort_on_warnings= (rli->sql_thd->variables.sql_mode &
+                           (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES));
   if ((error= prepare_record(table, m_width,
                              table->file->ht->db_type != DB_TYPE_NDBCLUSTER,
-                             (rli->sql_thd->variables.sql_mode &
-                               (MODE_STRICT_TRANS_TABLES |
-                                MODE_STRICT_ALL_TABLES)))))
+                             abort_on_warnings, m_curr_row == m_rows_buf)))
     DBUG_RETURN(error);
   
   /* unpack row into table->record[0] */
-  error= unpack_current_row(rli); // TODO: how to handle errors?
+  if ((error= unpack_current_row(rli, abort_on_warnings)))
+    DBUG_RETURN(error);
+
   if (m_curr_row == m_rows_buf)
   {
     /* this is the first row to be inserted, we estimate the rows with
@@ -9256,8 +9257,12 @@ Update_rows_log_event::do_exec_row(const
 
   store_record(m_table,record[1]);
 
+  bool abort_on_warnings= (rli->sql_thd->variables.sql_mode &
+                           (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES));
   m_curr_row= m_curr_row_end;
-  error= unpack_current_row(rli); // this also updates m_curr_row_end
+  /* this also updates m_curr_row_end */
+  if ((error= unpack_current_row(rli, abort_on_warnings)))
+    return error;
 
   /*
     Now we have the right row to update.  The old row (the one we're

=== modified file 'sql/log_event.h'
--- a/sql/log_event.h	2009-09-28 12:41:10 +0000
+++ b/sql/log_event.h	2009-10-22 00:15:45 +0000
@@ -3541,12 +3541,16 @@ protected:
   int write_row(const Relay_log_info *const, const bool);
 
   // Unpack the current row into m_table->record[0]
-  int unpack_current_row(const Relay_log_info *const rli)
+  int unpack_current_row(const Relay_log_info *const rli,
+                         const bool abort_on_warning= TRUE)
   { 
     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);
     int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols,
-                                   &m_curr_row_end, &m_master_reclength);
+                                   &m_curr_row_end, &m_master_reclength,
+                                   abort_on_warning, first_row);
     if (m_curr_row_end > m_rows_end)
       my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0));
     ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);

=== modified file 'sql/rpl_record.cc'
--- a/sql/rpl_record.cc	2009-10-22 00:10:42 +0000
+++ b/sql/rpl_record.cc	2009-10-22 00:15:45 +0000
@@ -180,7 +180,8 @@ int
 unpack_row(Relay_log_info const *rli,
            TABLE *table, uint const colcnt,
            uchar const *const row_data, MY_BITMAP const *cols,
-           uchar const **const row_end, ulong *const master_reclength)
+           uchar const **const row_end, ulong *const master_reclength,
+           const bool abort_on_warning, const bool first_row)
 {
   DBUG_ENTER("unpack_row");
   DBUG_ASSERT(row_data);
@@ -224,8 +225,35 @@ unpack_row(Relay_log_info const *rli,
       /* Field...::unpack() cannot return 0 */
       DBUG_ASSERT(pack_ptr != NULL);
 
-      if ((null_bits & null_mask) && f->maybe_null())
-        f->set_null();
+      if (null_bits & null_mask)
+      {
+        if (f->maybe_null())
+        {
+          DBUG_PRINT("debug", ("Was NULL; null mask: 0x%x; null bits: 0x%x",
+                               null_mask, null_bits));
+          f->set_null();
+        }
+        else
+        {
+          MYSQL_ERROR::enum_warning_level error_type=
+            MYSQL_ERROR::WARN_LEVEL_NOTE;
+          if (abort_on_warning && (table->file->has_transactions() ||
+                                   first_row))
+          {
+            error = HA_ERR_ROWS_EVENT_APPLY;
+            error_type= MYSQL_ERROR::WARN_LEVEL_ERROR;
+          }
+          else
+          {
+            f->set_default();
+            error_type= MYSQL_ERROR::WARN_LEVEL_WARN;
+          }
+          push_warning_printf(current_thd, error_type,
+                              ER_BAD_NULL_ERROR,
+                              ER(ER_BAD_NULL_ERROR),
+                              f->field_name);
+        }
+      }
       else
       {
         f->set_notnull();
@@ -315,7 +343,7 @@ unpack_row(Relay_log_info const *rli,
  */ 
 int prepare_record(TABLE *const table, 
                    const uint skip, const bool check,
-                   const bool abort_on_warning)
+                   const bool abort_on_warning, const bool first_row)
 {
   DBUG_ENTER("prepare_record");
 
@@ -343,14 +371,24 @@ int prepare_record(TABLE *const table, 
     if ((f->flags &  NO_DEFAULT_VALUE_FLAG) &&
         (f->real_type() != MYSQL_TYPE_ENUM))
     {
-      push_warning_printf(current_thd, abort_on_warning?
-                          MYSQL_ERROR::WARN_LEVEL_ERROR :
-                          MYSQL_ERROR::WARN_LEVEL_WARN,
+
+      MYSQL_ERROR::enum_warning_level error_type=
+        MYSQL_ERROR::WARN_LEVEL_NOTE;
+      if (abort_on_warning && (table->file->has_transactions() ||
+                               first_row))
+      {
+        error= HA_ERR_ROWS_EVENT_APPLY;
+        error_type= MYSQL_ERROR::WARN_LEVEL_ERROR;
+      }
+      else
+      {
+        f->set_default();
+        error_type= MYSQL_ERROR::WARN_LEVEL_WARN;
+      }
+      push_warning_printf(current_thd, error_type,
                           ER_NO_DEFAULT_FOR_FIELD,
                           ER(ER_NO_DEFAULT_FOR_FIELD),
                           f->field_name);
-      if (abort_on_warning)
-        error = HA_ERR_ROWS_EVENT_APPLY;
     }
   }
 

=== modified file 'sql/rpl_record.h'
--- a/sql/rpl_record.h	2009-10-22 00:10:42 +0000
+++ b/sql/rpl_record.h	2009-10-22 00:15:45 +0000
@@ -27,11 +27,13 @@ size_t pack_row(TABLE* table, MY_BITMAP 
 int unpack_row(Relay_log_info const *rli,
                TABLE *table, uint const colcnt,
                uchar const *const row_data, MY_BITMAP const *cols,
-               uchar const **const row_end, ulong *const master_reclength);
+               uchar const **const row_end, ulong *const master_reclength,
+               const bool abort_on_warning= TRUE, const bool first_row= TRUE);
 
 // Fill table's record[0] with default values.
 int prepare_record(TABLE *const table, const uint skip, const bool check,
-                   const bool abort_on_warning= FALSE);
+                   const bool abort_on_warning= TRUE,
+                   const bool first_row= TRUE);
 #endif
 
 #endif


Attachment: [text/bzr-bundle]
Thread
bzr commit into mysql-5.1-bugteam branch (alfranio.correia:3189)Bug#48091Alfranio Correia22 Oct