MDEV-35944 DELETE fails to notice transaction abort, violating ACID

Process errors of read_record().

Also, add an assert that Marko requested
This commit is contained in:
Sergei Golubchik 2025-01-27 19:22:20 +01:00
parent d5e7bce14b
commit 03d2328785
4 changed files with 73 additions and 12 deletions

View File

@ -24,3 +24,30 @@ SELECT * FROM t1;
c1
SET sort_buffer_size=@save_sort_buffer_size;
DROP TABLE t1;
#
# MDEV-35944 DELETE fails to notice transaction abort, violating ACID
#
CREATE TABLE t1 (id INT PRIMARY KEY, col_varchar VARCHAR(8)) ENGINE=InnoDB;
INSERT INTO t1 (id) VALUES (1),(2);
CREATE TABLE t2 (id INT, f INT, s DATE, e DATE, PERIOD FOR p(s,e), PRIMARY KEY(id, p WITHOUT OVERLAPS)) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1,0,'2000-01-01','2000-01-02');
CREATE TABLE t3 (id INT, f BLOB, UNIQUE(f)) ENGINE=InnoDB;
connection default;
SET innodb_lock_wait_timeout=1;
START TRANSACTION;
DELETE FROM t1;
connect con1,localhost,root,,;
START TRANSACTION;
UPDATE t2 SET f = 20;
connection default;
DELETE FROM t2 FOR PORTION OF p FROM '2000-01-01' TO '2000-01-02';
connection con1;
INSERT INTO t3 (id) VALUES (1), (2);
UPDATE t1 SET col_varchar = 'bar';
COMMIT;
connection default;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
COMMIT;
UPDATE t3 SET f = 'foo' ORDER BY f LIMIT 1;
DROP TABLE t1, t2, t3;
# End of 10.5 tests

View File

@ -20,3 +20,42 @@ SELECT * FROM t1;
SET sort_buffer_size=@save_sort_buffer_size;
DROP TABLE t1;
--echo #
--echo # MDEV-35944 DELETE fails to notice transaction abort, violating ACID
--echo #
CREATE TABLE t1 (id INT PRIMARY KEY, col_varchar VARCHAR(8)) ENGINE=InnoDB;
INSERT INTO t1 (id) VALUES (1),(2);
CREATE TABLE t2 (id INT, f INT, s DATE, e DATE, PERIOD FOR p(s,e), PRIMARY KEY(id, p WITHOUT OVERLAPS)) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1,0,'2000-01-01','2000-01-02');
CREATE TABLE t3 (id INT, f BLOB, UNIQUE(f)) ENGINE=InnoDB;
--connection default
SET innodb_lock_wait_timeout=1;
START TRANSACTION;
DELETE FROM t1;
--connect (con1,localhost,root,,)
START TRANSACTION;
UPDATE t2 SET f = 20;
--connection default
--send
DELETE FROM t2 FOR PORTION OF p FROM '2000-01-01' TO '2000-01-02';
--connection con1
INSERT INTO t3 (id) VALUES (1), (2);
UPDATE t1 SET col_varchar = 'bar';
COMMIT;
--connection default
--error ER_LOCK_DEADLOCK
--reap
COMMIT;
UPDATE t3 SET f = 'foo' ORDER BY f LIMIT 1;
# Cleanup
DROP TABLE t1, t2, t3;
--echo # End of 10.5 tests

View File

@ -773,27 +773,21 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
MEM_STRIP_BUF_SIZE);
THD_STAGE_INFO(thd, stage_searching_rows_for_update);
while (!(error=info.read_record()) && !thd->killed &&
! thd->is_error())
while (!(error=info.read_record()) && !thd->killed && !thd->is_error())
{
if (record_should_be_deleted(thd, table, select, explain, delete_history))
{
table->file->position(table->record[0]);
if (unlikely((error=
deltempfile->unique_add((char*) table->file->ref))))
{
error= 1;
goto terminate_delete;
}
if ((error= deltempfile->unique_add((char*) table->file->ref)))
break;
if (!--tmplimit && using_limit)
break;
}
}
end_read_record(&info);
if (unlikely(deltempfile->get(table)) ||
unlikely(table->file->ha_index_or_rnd_end()) ||
unlikely(init_read_record(&info, thd, table, 0, &deltempfile->sort, 0,
1, false)))
if (table->file->ha_index_or_rnd_end() || error > 0 ||
deltempfile->get(table) ||
init_read_record(&info, thd, table, 0, &deltempfile->sort, 0, 1, 0))
{
error= 1;
goto terminate_delete;

View File

@ -16313,6 +16313,7 @@ ha_innobase::external_lock(
case F_UNLCK:
DEBUG_SYNC_C("ha_innobase_end_statement");
m_mysql_has_locked = false;
ut_a(trx->n_mysql_tables_in_use);
if (--trx->n_mysql_tables_in_use) {
break;