diff --git a/mysql-test/suite/innodb/r/insert_into_empty.result b/mysql-test/suite/innodb/r/insert_into_empty.result index 29c5ef48da9..412606b021c 100644 --- a/mysql-test/suite/innodb/r/insert_into_empty.result +++ b/mysql-test/suite/innodb/r/insert_into_empty.result @@ -314,3 +314,45 @@ PARTITION pn VALUES LESS THAN (20)); INSERT INTO t1 VALUES (1),(21); ERROR HY000: Table has no partition for value 21 DROP TABLE t1; +# +# MDEV-29761 Bulk insert fails to rollback +# during insert..select +# +CREATE TABLE t1 (f1 INT)ENGINE=InnoDB; +CREATE TABLE t2 (f1 INT, UNIQUE INDEX(f1)) ENGINE=InnoDB; +CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES(1); +BEGIN; +INSERT t1 SELECT 1 FROM seq_1_to_2; +COMMIT; +SELECT * FROM t1; +f1 +SELECT * FROM t2; +f1 +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +CHECK TABLE t2; +Table Op Msg_type Msg_text +test.t2 check status OK +DROP TABLE t1, t2; +# +# MDEV-29801 Inconsistent ER_TOO_BIG_ROWSIZE during bulk +# insert operation +# +call mtr.add_suppression("InnoDB: Cannot add field `c11` in table"); +SET @format= @@innodb_default_row_format; +CREATE TABLE t1 (pk int primary key, c01 text, c02 text, c03 text, +c04 text, c05 text, c06 text, c07 text, c08 text, +c09 text, c10 text, c11 text, c12 text) ENGINE=InnoDB; +SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= COMPACT; +ALTER TABLE t1 FORCE; +Warnings: +Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. +INSERT IGNORE INTO t1 VALUES +(1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)), +(2, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= @format; diff --git a/mysql-test/suite/innodb/t/insert_into_empty.test b/mysql-test/suite/innodb/t/insert_into_empty.test index 420af61c6de..8cfee28c5f9 100644 --- a/mysql-test/suite/innodb/t/insert_into_empty.test +++ b/mysql-test/suite/innodb/t/insert_into_empty.test @@ -327,3 +327,38 @@ CREATE TABLE t1 (pk INT PRIMARY KEY) ENGINE=InnoDB INSERT INTO t1 VALUES (1),(21); # Cleanup DROP TABLE t1; + +--echo # +--echo # MDEV-29761 Bulk insert fails to rollback +--echo # during insert..select +--echo # +CREATE TABLE t1 (f1 INT)ENGINE=InnoDB; +CREATE TABLE t2 (f1 INT, UNIQUE INDEX(f1)) ENGINE=InnoDB; +CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES(1); +BEGIN; +INSERT t1 SELECT 1 FROM seq_1_to_2; +COMMIT; +SELECT * FROM t1; +SELECT * FROM t2; +CHECK TABLE t1; +CHECK TABLE t2; +DROP TABLE t1, t2; + +--echo # +--echo # MDEV-29801 Inconsistent ER_TOO_BIG_ROWSIZE during bulk +--echo # insert operation +--echo # +call mtr.add_suppression("InnoDB: Cannot add field `c11` in table"); + +SET @format= @@innodb_default_row_format; +CREATE TABLE t1 (pk int primary key, c01 text, c02 text, c03 text, + c04 text, c05 text, c06 text, c07 text, c08 text, + c09 text, c10 text, c11 text, c12 text) ENGINE=InnoDB; +SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= COMPACT; +ALTER TABLE t1 FORCE; +INSERT IGNORE INTO t1 VALUES +(1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)), +(2, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)); +CHECK TABLE t1; +DROP TABLE t1; +SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= @format; diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 57cf7041295..a901605c207 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -496,6 +496,13 @@ public: return false; } + /** @return the first undo record that modified the table */ + undo_no_t get_first() const + { + ut_ad(valid()); + return LIMIT & first; + } + /** Add the tuple to the transaction bulk buffer for the given index. @param entry tuple to be inserted @param index bulk insert for the index @@ -1126,6 +1133,22 @@ public: return &it->second; } + /** Rollback all bulk insert operations */ + void bulk_rollback() + { + undo_no_t low_limit= UINT64_MAX; + for (auto& t : mod_tables) + { + if (!t.second.is_bulk_insert()) + continue; + if (t.second.get_first() < low_limit) + low_limit= t.second.get_first(); + } + + trx_savept_t bulk_save{low_limit}; + rollback(&bulk_save); + } + /** Do the bulk insert for the buffered insert operation for the transaction. @return DB_SUCCESS or error code */ @@ -1138,7 +1161,10 @@ public: for (auto& t : mod_tables) if (t.second.is_bulk_insert()) if (dberr_t err= t.second.write_bulk(t.first, this)) + { + bulk_rollback(); return err; + } return DB_SUCCESS; }