Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
MDEV-14477 InnoDB update_time is wrongly updated after partial rollba…
…ck or internal COMMIT The non-persistent UPDATE_TIME for InnoDB tables was not being updated consistently at transaction commit. If a transaction is partly rolled back so that in the end it will not modify a table that it intended to modify, the update_time will be updated nevertheless. This will also happen when InnoDB fails to write an undo log record for the intended modification. If a transaction is committed internally in InnoDB, instead of being committed from the SQL interface, then the trx_t::mod_tables will not be applied to the update_time of the tables. trx_t::mod_tables: Replace the std::set<dict_table_t*> with std::map<dict_table_t*,undo_no_t>, so that the very first modification within the transaction is identified. trx_undo_report_row_operation(): Update mod_tables for every operation after the undo log record was successfully written. trx_rollback_to_savepoint_low(): After partial rollback, erase from trx_t::mod_tables any tables for which all changes were rolled back. trx_commit_in_memory(): Tighten some assertions and simplify conditions. Invoke trx_update_mod_tables_timestamp() if persistent tables were affected. trx_commit_for_mysql(): Remove the call to trx_update_mod_tables_timestamp(), as it is now invoked at the lower level, in trx_commit_in_memory(). trx_rollback_finish(): Clear mod_tables before invoking trx_commit(), because the trx_commit_in_memory() would otherwise wrongly process mod_tables after a full ROLLBACK.
- Loading branch information
Showing
7 changed files
with
493 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,228 @@ | ||
| CREATE TABLE tab1(c1 int,c2 varchar(30), c3 BLOB) ENGINE=InnoDB; | ||
| CREATE TABLE tab1u LIKE tab1; | ||
| CREATE TABLE tab1d LIKE tab1; | ||
| CREATE TABLE tab1i LIKE tab1; | ||
| CREATE TABLE tab3(c1 int,c2 varchar(30)) ENGINE=InnoDB; | ||
| CREATE TABLE tab4(c1 int,c2 varchar(30)) ENGINE=InnoDB; | ||
| CREATE TABLE tab5(c1 int,c2 varchar(30)) ENGINE=InnoDB; | ||
| INSERT INTO tab1u VALUES(1,'Testing the wl6658','Testing the wl6658'); | ||
| INSERT INTO tab1d VALUES(1,'Updated','Updated'); | ||
| INSERT INTO tab4 VALUES(1,'Test for Update'); | ||
| INSERT INTO tab5 VALUES(1,'Test for Delete'); | ||
| CREATE TRIGGER test_trig BEFORE INSERT ON tab1 | ||
| FOR EACH ROW BEGIN | ||
| INSERT INTO tab3 VALUES(1,'Inserted From Trigger'); | ||
| UPDATE tab4 SET c2='Updated from Trigger' WHERE c1=1; | ||
| DELETE FROM tab5; | ||
| END | | ||
| CREATE TABLE tab2( | ||
| id INT NOT NULL, | ||
| store_name VARCHAR(30), | ||
| parts VARCHAR(30), | ||
| store_id INT | ||
| ) ENGINE=InnoDB | ||
| PARTITION BY LIST(store_id) ( | ||
| PARTITION pNorth VALUES IN (10,20,30), | ||
| PARTITION pEast VALUES IN (40,50,60), | ||
| PARTITION pWest VALUES IN (70,80,100) | ||
| ); | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab2'; | ||
| update_time | ||
| NULL | ||
| CREATE PROCEDURE proc_wl6658() | ||
| BEGIN | ||
| INSERT INTO tab2 VALUES(1,'ORACLE','NUTT',10); | ||
| INSERT INTO tab2 VALUES(2,'HUAWEI','BOLT',40); | ||
| COMMIT; | ||
| END | | ||
| CALL proc_wl6658; | ||
| SELECT * FROM tab2 ORDER BY id,store_id; | ||
| id store_name parts store_id | ||
| 1 ORACLE NUTT 10 | ||
| 2 HUAWEI BOLT 40 | ||
| SELECT COUNT(update_time) | ||
| FROM information_schema.tables WHERE table_name='tab2'; | ||
| COUNT(update_time) | ||
| 1 | ||
| TRUNCATE TABLE tab2; | ||
| SELECT COUNT(update_time) | ||
| FROM information_schema.tables WHERE table_name='tab2'; | ||
| COUNT(update_time) | ||
| 1 | ||
| CREATE TABLE tab7(c1 INT NOT NULL, PRIMARY KEY (c1)) ENGINE=INNODB; | ||
| CREATE TABLE tab8(c1 INT PRIMARY KEY,c2 INT, | ||
| FOREIGN KEY (c2) REFERENCES tab7(c1) ON DELETE CASCADE ) | ||
| ENGINE=INNODB; | ||
| SELECT table_name,update_time | ||
| FROM information_schema.tables WHERE table_name IN ('tab7','tab8') | ||
| GROUP BY table_name ORDER BY table_name; | ||
| table_name update_time | ||
| tab7 NULL | ||
| tab8 NULL | ||
| INSERT INTO tab7 VALUES(1); | ||
| INSERT INTO tab8 VALUES(1,1); | ||
| SELECT table_name,COUNT(update_time) | ||
| FROM information_schema.tables WHERE table_name IN ('tab7','tab8') | ||
| GROUP BY table_name ORDER BY table_name; | ||
| table_name COUNT(update_time) | ||
| tab7 1 | ||
| tab8 1 | ||
| #restart the server | ||
| SELECT table_name,update_time | ||
| FROM information_schema.tables | ||
| WHERE table_name IN ('tab1','tab2','tab3','tab4','tab5','tab7','tab8') | ||
| ORDER BY table_name; | ||
| table_name update_time | ||
| tab1 NULL | ||
| tab2 NULL | ||
| tab3 NULL | ||
| tab4 NULL | ||
| tab5 NULL | ||
| tab7 NULL | ||
| tab8 NULL | ||
| #case1: | ||
| BEGIN WORK; | ||
| INSERT INTO tab1 | ||
| VALUES(1,'Testing the wl6658', 'Testing the wl6658'); | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab1'; | ||
| update_time | ||
| NULL | ||
| COMMIT; | ||
| SELECT * FROM tab1; | ||
| c1 c2 c3 | ||
| 1 Testing the wl6658 Testing the wl6658 | ||
| SELECT * FROM tab3; | ||
| c1 c2 | ||
| 1 Inserted From Trigger | ||
| SELECT * FROM tab4; | ||
| c1 c2 | ||
| 1 Updated from Trigger | ||
| SELECT * FROM tab5; | ||
| c1 c2 | ||
| SELECT table_name,COUNT(update_time) | ||
| FROM information_schema.tables | ||
| WHERE table_name IN ('tab1','tab3','tab4','tab5') | ||
| GROUP BY table_name ORDER BY table_name; | ||
| table_name COUNT(update_time) | ||
| tab1 1 | ||
| tab3 1 | ||
| tab4 1 | ||
| tab5 1 | ||
| Testcase with UPDATE stmt and transaction | ||
| SELECT * FROM tab1u; | ||
| c1 c2 c3 | ||
| 1 Testing the wl6658 Testing the wl6658 | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab1u'; | ||
| update_time | ||
| NULL | ||
| #case2: | ||
| START TRANSACTION; | ||
| UPDATE tab1u SET c2='Updated',c3='Updated' WHERE c1=1; | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab1u'; | ||
| update_time | ||
| NULL | ||
| COMMIT; | ||
| SELECT * FROM tab1u; | ||
| c1 c2 c3 | ||
| 1 Updated Updated | ||
| SELECT COUNT(update_time) | ||
| FROM information_schema.tables WHERE table_name='tab1u'; | ||
| COUNT(update_time) | ||
| 1 | ||
| SELECT * FROM tab1d; | ||
| c1 c2 c3 | ||
| 1 Updated Updated | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab1d'; | ||
| update_time | ||
| NULL | ||
| #case3: | ||
| START TRANSACTION; | ||
| DELETE FROM tab1d; | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab1d'; | ||
| update_time | ||
| NULL | ||
| COMMIT; | ||
| SELECT * FROM tab1d; | ||
| c1 c2 c3 | ||
| SELECT COUNT(update_time) | ||
| FROM information_schema.tables WHERE table_name='tab1d'; | ||
| COUNT(update_time) | ||
| 1 | ||
| SELECT * FROM tab1i; | ||
| c1 c2 c3 | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab1i'; | ||
| update_time | ||
| NULL | ||
| #case4: | ||
| START TRANSACTION; | ||
| INSERT INTO tab1i | ||
| VALUES(1,'Testing the wl6658', 'Testing the wl6658'); | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab1i'; | ||
| update_time | ||
| NULL | ||
| ROLLBACK; | ||
| SELECT * FROM tab1i; | ||
| c1 c2 c3 | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab1i'; | ||
| update_time | ||
| NULL | ||
| BEGIN WORK; | ||
| DELETE FROM tab1i; | ||
| SAVEPOINT A; | ||
| INSERT INTO tab2 VALUES(1,'Oracle','NUTT',10); | ||
| INSERT INTO tab2 VALUES(2,'HUAWEI','BOLT',40); | ||
| SAVEPOINT B; | ||
| INSERT INTO tab2 VALUES(3,'IBM','NAIL',70); | ||
| SAVEPOINT C; | ||
| ROLLBACK to A; | ||
| SELECT * FROM tab2; | ||
| id store_name parts store_id | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab2'; | ||
| update_time | ||
| NULL | ||
| #execute DDL instead of commit | ||
| create table tab6(c1 int); | ||
| SELECT update_time | ||
| FROM information_schema.tables WHERE table_name='tab2'; | ||
| update_time | ||
| NULL | ||
| START TRANSACTION; | ||
| DELETE FROM tab7; | ||
| ROLLBACK; | ||
| SELECT * FROM tab7; | ||
| c1 | ||
| 1 | ||
| SELECT * FROM tab8; | ||
| c1 c2 | ||
| 1 1 | ||
| SELECT table_name,update_time | ||
| FROM information_schema.tables WHERE table_name IN ('tab7','tab8') | ||
| GROUP BY table_name ORDER BY table_name; | ||
| table_name update_time | ||
| tab7 NULL | ||
| tab8 NULL | ||
| DELETE FROM tab7; | ||
| SELECT * FROM tab7; | ||
| c1 | ||
| SELECT * FROM tab8; | ||
| c1 c2 | ||
| SELECT table_name,COUNT(update_time) | ||
| FROM information_schema.tables WHERE table_name IN ('tab7','tab8') | ||
| GROUP BY table_name ORDER BY table_name; | ||
| table_name COUNT(update_time) | ||
| tab7 1 | ||
| tab8 1 | ||
| #cleanup | ||
| DROP TRIGGER test_trig; | ||
| DROP TABLE tab1,tab1u,tab1d,tab1i,tab2,tab3,tab4,tab5,tab6,tab8,tab7; | ||
| DROP PROCEDURE proc_wl6658; |
Oops, something went wrong.