Skip to content

Commit dd9da61

Browse files
MDEV-29761 Bulk insert fails to rollback during insert..select
- InnoDB should do partial rollback when error happens during buffered bulk insert write operation.
1 parent 2e3d08e commit dd9da61

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

mysql-test/suite/innodb/r/insert_into_empty.result

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,45 @@ PARTITION pn VALUES LESS THAN (20));
314314
INSERT INTO t1 VALUES (1),(21);
315315
ERROR HY000: Table has no partition for value 21
316316
DROP TABLE t1;
317+
#
318+
# MDEV-29761 Bulk insert fails to rollback
319+
# during insert..select
320+
#
321+
CREATE TABLE t1 (f1 INT)ENGINE=InnoDB;
322+
CREATE TABLE t2 (f1 INT, UNIQUE INDEX(f1)) ENGINE=InnoDB;
323+
CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES(1);
324+
BEGIN;
325+
INSERT t1 SELECT 1 FROM seq_1_to_2;
326+
COMMIT;
327+
SELECT * FROM t1;
328+
f1
329+
SELECT * FROM t2;
330+
f1
331+
CHECK TABLE t1;
332+
Table Op Msg_type Msg_text
333+
test.t1 check status OK
334+
CHECK TABLE t2;
335+
Table Op Msg_type Msg_text
336+
test.t2 check status OK
337+
DROP TABLE t1, t2;
338+
#
339+
# MDEV-29801 Inconsistent ER_TOO_BIG_ROWSIZE during bulk
340+
# insert operation
341+
#
342+
call mtr.add_suppression("InnoDB: Cannot add field `c11` in table");
343+
SET @format= @@innodb_default_row_format;
344+
CREATE TABLE t1 (pk int primary key, c01 text, c02 text, c03 text,
345+
c04 text, c05 text, c06 text, c07 text, c08 text,
346+
c09 text, c10 text, c11 text, c12 text) ENGINE=InnoDB;
347+
SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= COMPACT;
348+
ALTER TABLE t1 FORCE;
349+
Warnings:
350+
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.
351+
INSERT IGNORE INTO t1 VALUES
352+
(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)),
353+
(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));
354+
CHECK TABLE t1;
355+
Table Op Msg_type Msg_text
356+
test.t1 check status OK
357+
DROP TABLE t1;
358+
SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= @format;

mysql-test/suite/innodb/t/insert_into_empty.test

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,38 @@ CREATE TABLE t1 (pk INT PRIMARY KEY) ENGINE=InnoDB
327327
INSERT INTO t1 VALUES (1),(21);
328328
# Cleanup
329329
DROP TABLE t1;
330+
331+
--echo #
332+
--echo # MDEV-29761 Bulk insert fails to rollback
333+
--echo # during insert..select
334+
--echo #
335+
CREATE TABLE t1 (f1 INT)ENGINE=InnoDB;
336+
CREATE TABLE t2 (f1 INT, UNIQUE INDEX(f1)) ENGINE=InnoDB;
337+
CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES(1);
338+
BEGIN;
339+
INSERT t1 SELECT 1 FROM seq_1_to_2;
340+
COMMIT;
341+
SELECT * FROM t1;
342+
SELECT * FROM t2;
343+
CHECK TABLE t1;
344+
CHECK TABLE t2;
345+
DROP TABLE t1, t2;
346+
347+
--echo #
348+
--echo # MDEV-29801 Inconsistent ER_TOO_BIG_ROWSIZE during bulk
349+
--echo # insert operation
350+
--echo #
351+
call mtr.add_suppression("InnoDB: Cannot add field `c11` in table");
352+
353+
SET @format= @@innodb_default_row_format;
354+
CREATE TABLE t1 (pk int primary key, c01 text, c02 text, c03 text,
355+
c04 text, c05 text, c06 text, c07 text, c08 text,
356+
c09 text, c10 text, c11 text, c12 text) ENGINE=InnoDB;
357+
SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= COMPACT;
358+
ALTER TABLE t1 FORCE;
359+
INSERT IGNORE INTO t1 VALUES
360+
(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)),
361+
(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));
362+
CHECK TABLE t1;
363+
DROP TABLE t1;
364+
SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= @format;

storage/innobase/include/trx0trx.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,13 @@ class trx_mod_table_time_t
496496
return false;
497497
}
498498

499+
/** @return the first undo record that modified the table */
500+
undo_no_t get_first() const
501+
{
502+
ut_ad(valid());
503+
return LIMIT & first;
504+
}
505+
499506
/** Add the tuple to the transaction bulk buffer for the given index.
500507
@param entry tuple to be inserted
501508
@param index bulk insert for the index
@@ -1126,6 +1133,22 @@ struct trx_t : ilist_node<>
11261133
return &it->second;
11271134
}
11281135

1136+
/** Rollback all bulk insert operations */
1137+
void bulk_rollback()
1138+
{
1139+
undo_no_t low_limit= UINT64_MAX;
1140+
for (auto& t : mod_tables)
1141+
{
1142+
if (!t.second.is_bulk_insert())
1143+
continue;
1144+
if (t.second.get_first() < low_limit)
1145+
low_limit= t.second.get_first();
1146+
}
1147+
1148+
trx_savept_t bulk_save{low_limit};
1149+
rollback(&bulk_save);
1150+
}
1151+
11291152
/** Do the bulk insert for the buffered insert operation
11301153
for the transaction.
11311154
@return DB_SUCCESS or error code */
@@ -1138,7 +1161,10 @@ struct trx_t : ilist_node<>
11381161
for (auto& t : mod_tables)
11391162
if (t.second.is_bulk_insert())
11401163
if (dberr_t err= t.second.write_bulk(t.first, this))
1164+
{
1165+
bulk_rollback();
11411166
return err;
1167+
}
11421168
return DB_SUCCESS;
11431169
}
11441170

0 commit comments

Comments
 (0)