Commit 007d3ed9 authored by Lixun Peng's avatar Lixun Peng

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.
parent 92f1837a
......@@ -68,6 +68,7 @@ CHARSET_INFO* system_charset_info= &my_charset_utf8_general_ci;
/* Needed for Flashback */
DYNAMIC_ARRAY binlog_events; // Storing the events output string
DYNAMIC_ARRAY events_in_stmt; // Storing the events that in one statement
String stop_event_string; // Storing the STOP_EVENT output string
char server_version[SERVER_VERSION_LENGTH];
......@@ -894,6 +895,25 @@ static bool print_row_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
print_event_info->m_table_map_ignored.get_table(table_id);
bool skip_event= (ignored_map != NULL);
if (opt_flashback)
{
Rows_log_event *e= (Rows_log_event*) ev;
// The last Row_log_event will be the first event in Flashback
if (is_stmt_end)
e->clear_flags(Rows_log_event::STMT_END_F);
// The first Row_log_event will be the last event in Flashback
if (events_in_stmt.elements == 0)
e->set_flags(Rows_log_event::STMT_END_F);
// Update the temp_buf
e->update_flags();
if (insert_dynamic(&events_in_stmt, (uchar *) &ev))
{
error("Out of memory: can't allocate memory to store the flashback events.");
exit(1);
}
}
/*
end of statement check:
i) destroy/free ignored maps
......@@ -945,7 +965,36 @@ static bool print_row_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
if (skip_event)
return 0;
return print_base64(print_event_info, ev);
if (!opt_flashback)
return print_base64(print_event_info, ev);
else
{
if (is_stmt_end)
{
bool res= false;
Log_event *e= NULL;
// Print the row_event from the last one to the first one
for (uint i= events_in_stmt.elements; i > 0; --i)
{
e= *(dynamic_element(&events_in_stmt, i - 1, Log_event**));
res= res || print_base64(print_event_info, e);
}
// Copy all output into the Log_event
ev->output_buf.copy(e->output_buf);
// Delete Log_event
for (uint i= 0; i < events_in_stmt.elements-1; ++i)
{
e= *(dynamic_element(&events_in_stmt, i, Log_event**));
delete e;
}
reset_dynamic(&events_in_stmt);
return res;
}
}
return 0;
}
......@@ -1386,6 +1435,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
}
if (print_base64(print_event_info, ev))
goto err;
if (opt_flashback)
reset_dynamic(&events_in_stmt);
break;
}
case WRITE_ROWS_EVENT:
......@@ -1402,9 +1453,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
case DELETE_ROWS_COMPRESSED_EVENT_V1:
{
Rows_log_event *e= (Rows_log_event*) ev;
bool is_stmt_end= e->get_flags(Rows_log_event::STMT_END_F);
if (print_row_event(print_event_info, ev, e->get_table_id(),
e->get_flags(Rows_log_event::STMT_END_F)))
goto err;
if (!is_stmt_end)
destroy_evt= FALSE;
break;
}
case PRE_GA_WRITE_ROWS_EVENT:
......@@ -1412,9 +1466,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
case PRE_GA_UPDATE_ROWS_EVENT:
{
Old_rows_log_event *e= (Old_rows_log_event*) ev;
bool is_stmt_end= e->get_flags(Rows_log_event::STMT_END_F);
if (print_row_event(print_event_info, ev, e->get_table_id(),
e->get_flags(Old_rows_log_event::STMT_END_F)))
goto err;
if (!is_stmt_end)
destroy_evt= FALSE;
break;
}
case START_ENCRYPTION_EVENT:
......@@ -1459,7 +1516,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
&my_charset_bin);
else
{
if (push_dynamic(&binlog_events, (uchar *) &tmp_str))
if (insert_dynamic(&binlog_events, (uchar *) &tmp_str))
{
error("Out of memory: can't allocate memory to store the flashback events.");
exit(1);
......@@ -2915,9 +2972,12 @@ int main(int argc, char** argv)
my_set_max_open_files(open_files_limit);
if (opt_flashback)
{
my_init_dynamic_array(&binlog_events, sizeof(LEX_STRING), 1024, 1024,
MYF(0));
my_init_dynamic_array(&events_in_stmt, sizeof(Rows_log_event*), 1024, 1024,
MYF(0));
}
if (opt_stop_never)
to_last_remote_log= TRUE;
......@@ -3031,6 +3091,7 @@ int main(int argc, char** argv)
}
fprintf(result_file, "COMMIT\n/*!*/;\n");
delete_dynamic(&binlog_events);
delete_dynamic(&events_in_stmt);
}
/* Set delimiter back to semicolon */
......
......@@ -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,110 @@ a b
RESET MASTER;
DELETE FROM t1 ORDER BY a DESC;
FLUSH LOGS;
# < CASE 3 >
# Flashback & Check the result
#
SELECT * FROM t1;
a b
1 NULL
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;
......@@ -502,9 +605,77 @@ a b
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;
......@@ -13,12 +13,11 @@ DROP TABLE IF EXISTS t1;
--echo #
SET timestamp=1000000000;
--echo #
--echo # < CASE 1 >
--echo # Delete all existing binary logs.
--echo #
RESET MASTER;
CREATE TABLE t1 (
c01 tinyint,
c02 smallint,
......@@ -30,7 +29,7 @@ CREATE TABLE t1 (
c08 TEXT
) ENGINE=InnoDB;
--echo #
--echo # < CASE 1 >
--echo # Insert data to t1
--echo #
INSERT INTO t1 VALUES(0,0,0,0,0,'','','');
......@@ -38,19 +37,19 @@ 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));
--echo #
--echo # < CASE 1 >
--echo # Update t1
--echo #
UPDATE t1 SET c01=100 WHERE c02=0 OR c03=3;
--echo #
--echo # < CASE 1 >
--echo # Clear t1
--echo #
DELETE FROM t1;
FLUSH LOGS;
--echo #
--echo # < CASE 1 >
--echo # Show mysqlbinlog result without -B
--echo #
......@@ -59,7 +58,7 @@ let $MYSQLD_DATADIR= `select @@datadir`;
--replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ /exec_time=[0-9]*/exec_time=#/ /end_log_pos [0-9]*/end_log_pos #/ /# at [0-9]*/# at #/ /Xid = [0-9]*/Xid = #/ /thread_id=[0-9]*/thread_id=#/ /table id [0-9]*/table id #/ /mapped to number [0-9]*/mapped to number #/ /server v [^ ]*/server v #.##.##/ /CRC32 0x[0-9a-f]*/CRC32 XXX/
--exec $MYSQL_BINLOG --base64-output=decode-rows -v -v $MYSQLD_DATADIR/master-bin.000001
--echo #
--echo # < CASE 1 >
--echo # Show mysqlbinlog result with -B
--echo #
......@@ -68,7 +67,7 @@ let $MYSQLD_DATADIR= `select @@datadir`;
--replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ /exec_time=[0-9]*/exec_time=#/ /end_log_pos [0-9]*/end_log_pos #/ /# at [0-9]*/# at #/ /Xid = [0-9]*/Xid = #/ /thread_id=[0-9]*/thread_id=#/ /table id [0-9]*/table id #/ /mapped to number [0-9]*/mapped to number #/ /server v [^ ]*/server v #.##.##/ /CRC32 0x[0-9a-f]*/CRC32 XXX/
--exec $MYSQL_BINLOG -B --base64-output=decode-rows -v -v $MYSQLD_DATADIR/master-bin.000001
--echo #
--echo # < CASE 1 >
--echo # Insert data to t1
--echo #
TRUNCATE TABLE t1;
......@@ -76,13 +75,13 @@ 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));
--echo #
--echo # < CASE 1 >
--echo # Delete all existing binary logs.
--echo #
RESET MASTER;
SELECT * FROM t1;
--echo #
--echo # < CASE 1 >
--echo # Operate some data
--echo #
......@@ -94,12 +93,13 @@ DELETE FROM t1;
FLUSH LOGS;
--echo #
--echo # < CASE 1 >
--echo # Flashback & Check the result
--echo #
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--exec $MYSQL_BINLOG -vv $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_original_1.sql
--exec $MYSQL_BINLOG -B -vv $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_1.sql
--exec $MYSQL -e "SET binlog_format= ROW; source $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_1.sql;"
......@@ -107,9 +107,10 @@ SELECT * FROM t1;
RESET MASTER;
--echo #
--echo # < CASE 2 >
--echo # UPDATE multi-rows in one event
--echo #
BEGIN;
UPDATE t1 SET c01=10 WHERE c01=0;
UPDATE t1 SET c01=20 WHERE c01=10;
......@@ -117,12 +118,13 @@ COMMIT;
FLUSH LOGS;
--echo #
--echo # < CASE 2 >
--echo # Flashback & Check the result
--echo #
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--exec $MYSQL_BINLOG -vv $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_original_2.sql
--exec $MYSQL_BINLOG -B -vv $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_2.sql
--exec $MYSQL -e "SET binlog_format= ROW; source $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_2.sql;"
......@@ -130,9 +132,10 @@ SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # < CASE 3 >
--echo # Self-referencing foreign keys
--echo #
CREATE TABLE t1 (a INT PRIMARY KEY, b INT, FOREIGN KEY my_fk(b) REFERENCES t1(a)) ENGINE=InnoDB;
BEGIN;
......@@ -149,19 +152,191 @@ DELETE FROM t1 ORDER BY a DESC;
FLUSH LOGS;
--echo #
--echo # < CASE 3 >
--echo # Flashback & Check the result
--echo #
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--exec $MYSQL_BINLOG -vv $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_original_3.sql
--exec $MYSQL_BINLOG -B -vv $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_3.sql
--exec $MYSQL -e "SET binlog_format= ROW; source $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_3.sql;"
SELECT * FROM t1;
DROP TABLE t1;
--echo # < CASE 4 >
--echo # Trigger
--echo #
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;
SELECT * FROM t2;
CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW DELETE FROM t2 WHERE a = NEW.b;
# New binlog
RESET MASTER;
INSERT INTO t1 VALUES (5, 6), (7, 8);
SELECT * FROM t1;
SELECT * FROM t2;
FLUSH LOGS;
--echo # < CASE 4 >
--echo # Flashback & Check the result
--echo #
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--exec $MYSQL_BINLOG -vv $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_original_4.sql
--exec $MYSQL_BINLOG -B $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_4.sql
--exec $MYSQL -e "SET binlog_format= ROW; source $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_4.sql;"
SELECT * FROM t1;
SELECT * FROM t2;
DROP TRIGGER trg1;
DROP TABLE t1;
DROP TABLE t2;
--echo # < CASE 5 >
--echo # REPLCAE Queries
--echo #
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;
# New binlog
RESET MASTER;
REPLACE INTO t1 VALUES (3, 100);
REPLACE INTO t1 SET a=4, b=200;
SELECT * FROM t1;
REPLACE INTO t1 VALUES (5,5);
SELECT * FROM t1;
FLUSH LOGS;
--echo # < CASE 5 >
--echo # Flashback & Check the result
--echo #
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--exec $MYSQL_BINLOG -vv $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_original_5.sql
--exec $MYSQL_BINLOG -B $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_5.sql
--exec $MYSQL -e "SET binlog_format= ROW; source $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_5.sql;"
SELECT * FROM t1;
DROP TABLE t1;
--echo # < CASE 6 >
--echo # Test Case from MDEV-21067
--echo #
# Init Structure
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;
# Insert test data
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;
--echo # < CASE 6 >
--echo # Flashback & Check the result
--echo #
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--exec $MYSQL_BINLOG --database=world --table=City -vv $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_original_6.sql
--exec $MYSQL_BINLOG --database=world --table=City -B $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_6.sql
--exec $MYSQL -e "SET binlog_format= ROW; source $MYSQLTEST_VARDIR/tmp/mysqlbinlog_row_flashback_6.sql;"
SELECT * FROM world.City;
SELECT * FROM test.test;
CHECKSUM TABLE world.City;
DROP TABLE test.test;
DROP TABLE world.City;
DROP DATABASE world;
## Clear
SET binlog_format=statement;
--error ER_FLASHBACK_NOT_SUPPORTED
SET GLOBAL binlog_format=statement;
DROP TABLE t1;
......@@ -3477,7 +3477,8 @@ void Log_event::print_base64(IO_CACHE* file,
#ifdef WHEN_FLASHBACK_REVIEW_READY
if (print_event_info->verbose || need_flashback_review)
#else
if (print_event_info->verbose)
// Flashback need the table_map to parse the event
if (print_event_info->verbose || is_flashback)
#endif
{
Rows_log_event *ev= NULL;
......@@ -3564,7 +3565,8 @@ void Log_event::print_base64(IO_CACHE* file,
close_cached_file(&tmp_cache);
}
#else
ev->print_verbose(file, print_event_info);
if (print_event_info->verbose)
ev->print_verbose(file, print_event_info);
#endif
delete ev;
}
......@@ -10251,6 +10253,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len,
post_start+= RW_FLAGS_OFFSET;
}
m_flags_pos= post_start - buf;
m_flags= uint2korr(post_start);
post_start+= 2;
......@@ -11299,18 +11302,18 @@ void Rows_log_event::print_helper(FILE *file,
if (get_flags(STMT_END_F))
{
reinit_io_cache(head, READ_CACHE, 0L, FALSE, FALSE);
output_buf.append(head, head->end_of_file);
reinit_io_cache(head, WRITE_CACHE, 0, FALSE, TRUE);
reinit_io_cache(body, READ_CACHE, 0L, FALSE, FALSE);
output_buf.append(body, body->end_of_file);
reinit_io_cache(body, WRITE_CACHE, 0, FALSE, TRUE);
LEX_STRING tmp_str;
copy_event_cache_to_string_and_reinit(head, &tmp_str);
output_buf.append(&tmp_str);
my_free(tmp_str.str);
copy_event_cache_to_string_and_reinit(body, &tmp_str);
output_buf.append(&tmp_str);
my_free(tmp_str.str);
#ifdef WHEN_FLASHBACK_REVIEW_READY
reinit_io_cache(sql, READ_CACHE, 0L, FALSE, FALSE);
output_buf.append(sql, sql->end_of_file);
reinit_io_cache(sql, WRITE_CACHE, 0, FALSE, TRUE);
copy_event_cache_to_string_and_reinit(sql, &tmp_str);
output_buf.append(&tmp_str);
my_free(tmp_str.str);
#endif
}
}
......
......@@ -4397,6 +4397,7 @@ class Rows_log_event : public Log_event
void set_flags(flag_set flags_arg) { m_flags |= flags_arg; }
void clear_flags(flag_set flags_arg) { m_flags &= ~flags_arg; }
flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; }
void update_flags() { int2store(temp_buf + m_flags_pos, m_flags); }
Log_event_type get_type_code() { return m_type; } /* Specific type (_V1 etc) */
virtual Log_event_type get_general_type_code() = 0; /* General rows op type, no version */
......@@ -4555,6 +4556,7 @@ class Rows_log_event : public Log_event
uchar *m_rows_end; /* One-after the end of the allocated space */
size_t m_rows_before_size; /* The length before m_rows_buf */
size_t m_flags_pos; /* The position of the m_flags */
flag_set m_flags; /* Flags for row-level events */
......
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