Commit 63278c56 authored by Alfranio Correia's avatar Alfranio Correia

BUG#43789 different master/slave table defs cause crash: text/varchar null

          vs not null

NOTE: Backporting the patch to next-mr.
                        
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.
parent bbc830f7
#################################################################################
# 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;
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;
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;
#################################################################################
# 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
#################################################################################
# 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
...@@ -8444,16 +8444,17 @@ Rows_log_event::write_row(const Relay_log_info *const rli, ...@@ -8444,16 +8444,17 @@ Rows_log_event::write_row(const Relay_log_info *const rli,
auto_afree_ptr<char> key(NULL); auto_afree_ptr<char> key(NULL);
/* fill table->record[0] with default values */ /* 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, if ((error= prepare_record(table, m_width,
table->file->ht->db_type != DB_TYPE_NDBCLUSTER, table->file->ht->db_type != DB_TYPE_NDBCLUSTER,
(rli->sql_thd->variables.sql_mode & abort_on_warnings, m_curr_row == m_rows_buf)))
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)))))
DBUG_RETURN(error); DBUG_RETURN(error);
/* unpack row into table->record[0] */ /* 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) if (m_curr_row == m_rows_buf)
{ {
/* this is the first row to be inserted, we estimate the rows with /* this is the first row to be inserted, we estimate the rows with
...@@ -9250,8 +9251,12 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) ...@@ -9250,8 +9251,12 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
store_record(m_table,record[1]); 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; 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 Now we have the right row to update. The old row (the one we're
......
...@@ -3541,12 +3541,16 @@ class Rows_log_event : public Log_event ...@@ -3541,12 +3541,16 @@ class Rows_log_event : public Log_event
int write_row(const Relay_log_info *const, const bool); int write_row(const Relay_log_info *const, const bool);
// Unpack the current row into m_table->record[0] // 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); 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, &m_cols, 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) if (m_curr_row_end > m_rows_end)
my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0)); my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0));
ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
......
...@@ -180,7 +180,8 @@ int ...@@ -180,7 +180,8 @@ int
unpack_row(Relay_log_info const *rli, unpack_row(Relay_log_info const *rli,
TABLE *table, uint const colcnt, TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols, 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_ENTER("unpack_row");
DBUG_ASSERT(row_data); DBUG_ASSERT(row_data);
...@@ -224,8 +225,35 @@ unpack_row(Relay_log_info const *rli, ...@@ -224,8 +225,35 @@ unpack_row(Relay_log_info const *rli,
/* Field...::unpack() cannot return 0 */ /* Field...::unpack() cannot return 0 */
DBUG_ASSERT(pack_ptr != NULL); DBUG_ASSERT(pack_ptr != NULL);
if ((null_bits & null_mask) && f->maybe_null()) if (null_bits & null_mask)
f->set_null(); {
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 else
{ {
f->set_notnull(); f->set_notnull();
...@@ -315,7 +343,7 @@ unpack_row(Relay_log_info const *rli, ...@@ -315,7 +343,7 @@ unpack_row(Relay_log_info const *rli,
*/ */
int prepare_record(TABLE *const table, int prepare_record(TABLE *const table,
const uint skip, const bool check, const uint skip, const bool check,
const bool abort_on_warning) const bool abort_on_warning, const bool first_row)
{ {
DBUG_ENTER("prepare_record"); DBUG_ENTER("prepare_record");
...@@ -343,14 +371,24 @@ int prepare_record(TABLE *const table, ...@@ -343,14 +371,24 @@ int prepare_record(TABLE *const table,
if ((f->flags & NO_DEFAULT_VALUE_FLAG) && if ((f->flags & NO_DEFAULT_VALUE_FLAG) &&
(f->real_type() != MYSQL_TYPE_ENUM)) (f->real_type() != MYSQL_TYPE_ENUM))
{ {
push_warning_printf(current_thd, abort_on_warning?
MYSQL_ERROR::WARN_LEVEL_ERROR : MYSQL_ERROR::enum_warning_level error_type=
MYSQL_ERROR::WARN_LEVEL_WARN, 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_NO_DEFAULT_FOR_FIELD,
ER(ER_NO_DEFAULT_FOR_FIELD), ER(ER_NO_DEFAULT_FOR_FIELD),
f->field_name); f->field_name);
if (abort_on_warning)
error = HA_ERR_ROWS_EVENT_APPLY;
} }
} }
......
...@@ -27,11 +27,13 @@ size_t pack_row(TABLE* table, MY_BITMAP const* cols, ...@@ -27,11 +27,13 @@ size_t pack_row(TABLE* table, MY_BITMAP const* cols,
int unpack_row(Relay_log_info const *rli, int unpack_row(Relay_log_info const *rli,
TABLE *table, uint const colcnt, TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols, 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. // Fill table's record[0] with default values.
int prepare_record(TABLE *const table, const uint skip, const bool check, 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
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment