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 c1
SET sort_buffer_size=@save_sort_buffer_size; SET sort_buffer_size=@save_sort_buffer_size;
DROP TABLE t1; 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; SET sort_buffer_size=@save_sort_buffer_size;
DROP TABLE t1; 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); MEM_STRIP_BUF_SIZE);
THD_STAGE_INFO(thd, stage_searching_rows_for_update); THD_STAGE_INFO(thd, stage_searching_rows_for_update);
while (!(error=info.read_record()) && !thd->killed && while (!(error=info.read_record()) && !thd->killed && !thd->is_error())
! thd->is_error())
{ {
if (record_should_be_deleted(thd, table, select, explain, delete_history)) if (record_should_be_deleted(thd, table, select, explain, delete_history))
{ {
table->file->position(table->record[0]); table->file->position(table->record[0]);
if (unlikely((error= if ((error= deltempfile->unique_add((char*) table->file->ref)))
deltempfile->unique_add((char*) table->file->ref)))) break;
{
error= 1;
goto terminate_delete;
}
if (!--tmplimit && using_limit) if (!--tmplimit && using_limit)
break; break;
} }
} }
end_read_record(&info); end_read_record(&info);
if (unlikely(deltempfile->get(table)) || if (table->file->ha_index_or_rnd_end() || error > 0 ||
unlikely(table->file->ha_index_or_rnd_end()) || deltempfile->get(table) ||
unlikely(init_read_record(&info, thd, table, 0, &deltempfile->sort, 0, init_read_record(&info, thd, table, 0, &deltempfile->sort, 0, 1, 0))
1, false)))
{ {
error= 1; error= 1;
goto terminate_delete; goto terminate_delete;

View File

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