MDEV-29761 Bulk insert fails to rollback during insert..select

- InnoDB should do partial rollback when error happens during
buffered bulk insert write operation.
parent 2e3d08ef
......@@ -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;
......@@ -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;
......@@ -496,6 +496,13 @@ class trx_mod_table_time_t
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 @@ struct trx_t : ilist_node<>
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 @@ struct trx_t : ilist_node<>
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;
}
......
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