1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-12067 flashback does not correcly revert update/replace statements

Problem
-------
For one-statement contains multiple row events, Flashback didn't reverse the
sequence of row events inside one-statement.

Solution
--------
Using a new array 'events_in_stmt' to store the row events of one-statement,
when parsed the last one event, then print from the last one to the first one.

In the same time, fixed another bug, without -vv will not insert the table_map
into print_event_info->m_table_map, then change_to_flashback_event() will not
execute because of Table_map_log_event is empty.
This commit is contained in:
Lixun Peng
2017-07-03 14:48:07 +08:00
parent 92f1837a27
commit 007d3ed905
5 changed files with 459 additions and 47 deletions

View File

@@ -6,7 +6,7 @@ DROP TABLE IF EXISTS t1;
# We need a fixed timestamp to avoid varying results.
#
SET timestamp=1000000000;
#
# < CASE 1 >
# Delete all existing binary logs.
#
RESET MASTER;
@@ -20,22 +20,22 @@ c06 char(10),
c07 varchar(20),
c08 TEXT
) ENGINE=InnoDB;
#
# < CASE 1 >
# Insert data to t1
#
INSERT INTO t1 VALUES(0,0,0,0,0,'','','');
INSERT INTO t1 VALUES(1,2,3,4,5, "abc", "abcdefg", "abcedfghijklmnopqrstuvwxyz");
INSERT INTO t1 VALUES(127, 32767, 8388607, 2147483647, 9223372036854775807, repeat('a', 10), repeat('a', 20), repeat('a', 255));
#
# < CASE 1 >
# Update t1
#
UPDATE t1 SET c01=100 WHERE c02=0 OR c03=3;
#
# < CASE 1 >
# Clear t1
#
DELETE FROM t1;
FLUSH LOGS;
#
# < CASE 1 >
# Show mysqlbinlog result without -B
#
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
@@ -258,7 +258,7 @@ DELIMITER ;
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
#
# < CASE 1 >
# Show mysqlbinlog result with -B
#
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
@@ -426,14 +426,14 @@ DELIMITER ;
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
#
# < CASE 1 >
# Insert data to t1
#
TRUNCATE TABLE t1;
INSERT INTO t1 VALUES(0,0,0,0,0,'','','');
INSERT INTO t1 VALUES(1,2,3,4,5, "abc", "abcdefg", "abcedfghijklmnopqrstuvwxyz");
INSERT INTO t1 VALUES(127, 32767, 8388607, 2147483647, 9223372036854775807, repeat('a', 10), repeat('a', 20), repeat('a', 60));
#
# < CASE 1 >
# Delete all existing binary logs.
#
RESET MASTER;
@@ -442,7 +442,7 @@ c01 c02 c03 c04 c05 c06 c07 c08
0 0 0 0 0
1 2 3 4 5 abc abcdefg abcedfghijklmnopqrstuvwxyz
127 32767 8388607 2147483647 9223372036854775807 aaaaaaaaaa aaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
#
# < CASE 1 >
# Operate some data
#
UPDATE t1 SET c01=20;
@@ -450,7 +450,7 @@ UPDATE t1 SET c02=200;
UPDATE t1 SET c03=2000;
DELETE FROM t1;
FLUSH LOGS;
#
# < CASE 1 >
# Flashback & Check the result
#
SELECT * FROM t1;
@@ -459,7 +459,7 @@ c01 c02 c03 c04 c05 c06 c07 c08
1 2 3 4 5 abc abcdefg abcedfghijklmnopqrstuvwxyz
0 0 0 0 0
RESET MASTER;
#
# < CASE 2 >
# UPDATE multi-rows in one event
#
BEGIN;
@@ -467,7 +467,7 @@ UPDATE t1 SET c01=10 WHERE c01=0;
UPDATE t1 SET c01=20 WHERE c01=10;
COMMIT;
FLUSH LOGS;
#
# < CASE 2 >
# Flashback & Check the result
#
SELECT * FROM t1;
@@ -476,7 +476,7 @@ c01 c02 c03 c04 c05 c06 c07 c08
1 2 3 4 5 abc abcdefg abcedfghijklmnopqrstuvwxyz
0 0 0 0 0
DROP TABLE t1;
#
# < CASE 3 >
# Self-referencing foreign keys
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT, FOREIGN KEY my_fk(b) REFERENCES t1(a)) ENGINE=InnoDB;
@@ -493,7 +493,7 @@ a b
RESET MASTER;
DELETE FROM t1 ORDER BY a DESC;
FLUSH LOGS;
#
# < CASE 3 >
# Flashback & Check the result
#
SELECT * FROM t1;
@@ -502,9 +502,180 @@ a b
2 1
3 2
4 3
DROP TABLE t1;
# < CASE 4 >
# Trigger
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
BEGIN;
INSERT INTO t1 VALUES (1, NULL);
INSERT INTO t1 VALUES (2, 1), (3, 2), (4, 3);
INSERT INTO t2 VALUES (6, 7), (7, 8), (8, 9);
COMMIT;
SELECT * FROM t1;
a b
1 NULL
2 1
3 2
4 3
SELECT * FROM t2;
a b
6 7
7 8
8 9
CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW DELETE FROM t2 WHERE a = NEW.b;
RESET MASTER;
INSERT INTO t1 VALUES (5, 6), (7, 8);
SELECT * FROM t1;
a b
1 NULL
2 1
3 2
4 3
5 6
7 8
SELECT * FROM t2;
a b
7 8
FLUSH LOGS;
# < CASE 4 >
# Flashback & Check the result
#
SELECT * FROM t1;
a b
1 NULL
2 1
3 2
4 3
SELECT * FROM t2;
a b
6 7
7 8
8 9
DROP TRIGGER trg1;
DROP TABLE t1;
DROP TABLE t2;
# < CASE 5 >
# REPLCAE Queries
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT, UNIQUE uk(b)) ENGINE=InnoDB;
BEGIN;
INSERT INTO t1 VALUES (1, NULL);
INSERT INTO t1 VALUES (2, 1), (3, 2), (4, 3);
INSERT INTO t1 VALUES (5, 4), (6, 5), (7, 6);
COMMIT;
SELECT * FROM t1;
a b
1 NULL
2 1
3 2
4 3
5 4
6 5
7 6
RESET MASTER;
REPLACE INTO t1 VALUES (3, 100);
REPLACE INTO t1 SET a=4, b=200;
SELECT * FROM t1;
a b
1 NULL
2 1
5 4
6 5
7 6
3 100
4 200
REPLACE INTO t1 VALUES (5,5);
SELECT * FROM t1;
a b
1 NULL
2 1
5 5
7 6
3 100
4 200
FLUSH LOGS;
# < CASE 5 >
# Flashback & Check the result
#
SELECT * FROM t1;
a b
1 NULL
2 1
3 2
4 3
5 4
6 5
7 6
DROP TABLE t1;
# < CASE 6 >
# Test Case from MDEV-21067
#
CREATE DATABASE world;
CREATE TABLE world.City (
ID INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(64),
CountryCode VARCHAR(64),
District VARCHAR(64),
Population INT
) ENGINE=InnoDB;
CREATE TABLE test.test (
ID INT AUTO_INCREMENT PRIMARY KEY,
REC VARCHAR(64),
ts TIMESTAMP
) ENGINE=InnoDB;
INSERT INTO world.City VALUES (NULL, 'Davenport', 'USA', 'Iowa', 100);
INSERT INTO world.City VALUES (NULL, 'Boulder', 'USA', 'Colorado', 1000);
INSERT INTO world.City VALUES (NULL, 'Gweru', 'ZWE', 'Midlands', 10000);
RESET MASTER;
CHECKSUM TABLE world.City;
Table Checksum
world.City 563256876
INSERT INTO test.test VALUES (NULL, 'Good record 1', CURRENT_TIMESTAMP());
INSERT INTO world.City VALUES (NULL, 'Wrong value 1', '000', 'Wrong', 0);
INSERT INTO world.City VALUES (NULL, 'Wrong value 2', '000', 'Wrong', 0) , (NULL, 'Wrong value 3', '000', 'Wrong', 0);
INSERT INTO test.test VALUES (NULL, 'Good record 2', CURRENT_TIMESTAMP());
UPDATE world.City SET Population = 99999999 WHERE ID IN (1, 2, 3);
INSERT INTO test.test VALUES (NULL, 'Good record 3', CURRENT_TIMESTAMP());
DELETE FROM world.City WHERE ID BETWEEN 1 AND 2;
INSERT INTO test.test VALUES (NULL, 'Good record 5', CURRENT_TIMESTAMP());
REPLACE INTO world.City VALUES (4074, 'Wrong value 4', '000', 'Wrong', 0);
REPLACE INTO world.City VALUES (4078, 'Wrong value 5', '000', 'Wrong', 0), (NULL, 'Wrong value 6', '000', 'Wrong', 0);
INSERT INTO test.test VALUES (NULL, 'Good record 6', CURRENT_TIMESTAMP());
INSERT INTO world.City
SELECT NULL, Name, CountryCode, District, Population FROM world.City WHERE ID BETWEEN 2 AND 10;
INSERT INTO test.test VALUES (NULL, 'Good record 7', CURRENT_TIMESTAMP());
INSERT INTO test.test VALUES (NULL, 'Good record 8', CURRENT_TIMESTAMP());
DELETE FROM world.City;
INSERT INTO test.test VALUES (NULL, 'Good record 9', CURRENT_TIMESTAMP());
FLUSH LOGS;
# < CASE 6 >
# Flashback & Check the result
#
SELECT * FROM world.City;
ID Name CountryCode District Population
1 Davenport USA Iowa 100
2 Boulder USA Colorado 1000
3 Gweru ZWE Midlands 10000
SELECT * FROM test.test;
ID REC ts
1 Good record 1 2001-09-09 09:46:40
2 Good record 2 2001-09-09 09:46:40
3 Good record 3 2001-09-09 09:46:40
4 Good record 5 2001-09-09 09:46:40
5 Good record 6 2001-09-09 09:46:40
6 Good record 7 2001-09-09 09:46:40
7 Good record 8 2001-09-09 09:46:40
8 Good record 9 2001-09-09 09:46:40
CHECKSUM TABLE world.City;
Table Checksum
world.City 563256876
DROP TABLE test.test;
DROP TABLE world.City;
DROP DATABASE world;
SET binlog_format=statement;
Warnings:
Warning 1105 MariaDB Galera and flashback do not support binlog format: STATEMENT
SET GLOBAL binlog_format=statement;
ERROR HY000: Flashback does not support binlog_format STATEMENT
DROP TABLE t1;