1
0
mirror of https://github.com/MariaDB/server.git synced 2025-11-09 11:41:36 +03:00

MDEV-37312 ASAN errors or assertion failure upon attempt to UPDATE FOR PORTION violating long unique under READ COMMITTED

in case of a long unique conflict ha_write_row() used delete_row()
to remove the newly inserted row, and it used rnd_pos() to position
the cursor before deletion. This rnd_pos() was freeing and reallocating
blobs in record[0]. So when the code for FOR PORTION OF did
  store_record(record[2]);
  ha_write_row()
  restore_record(record[2]);
it ended up with blob pointers to a freed memory.

Let's use lookup_handler for deletion.
This commit is contained in:
Sergei Golubchik
2025-07-26 10:26:16 +02:00
parent f49a5beb30
commit 633417308f
3 changed files with 44 additions and 7 deletions

View File

@@ -15,3 +15,20 @@ INSERT INTO t1 VALUES (1,'foo','2022-01-01', '2025-01-01');
DELETE FROM t1 FOR PORTION OF app FROM '2023-01-01' TO '2024-01-01';
ERROR 23000: Duplicate entry 'foo' for key 'b'
DROP TABLE t1;
# End of 10.5 tests
#
# MDEV-37312 ASAN errors or assertion failure upon attempt to UPDATE FOR PORTION violating long unique under READ COMMITTED
#
create table t1 (a int, f text unique, s datetime, e datetime, period for p(s,e)) engine=innodb;
insert into t1 values (1,'foo','1900-01-01','2000-01-01'),(2,'bar','1900-01-01','2000-01-01');
set transaction isolation level read committed;
update t1 for portion of p from '1980-01-01' to '1980-01-02' set a = 1;
ERROR 23000: Duplicate entry 'foo' for key 'f'
drop table t1;
create table t1 (a int, f text unique, s datetime, e datetime, period for p(s,e)) engine=innodb partition by hash (a);
insert into t1 values (1,'foo','1900-01-01','2000-01-01'),(2,'bar','1900-01-01','2000-01-01');
set transaction isolation level read committed;
update t1 for portion of p from '1980-01-01' to '1980-01-02' set a = 1;
ERROR 23000: Duplicate entry 'foo' for key 'f'
drop table t1;
# End of 10.6 tests

View File

@@ -1,3 +1,4 @@
--source include/have_innodb.inc
--source include/have_partition.inc
--echo #
@@ -21,3 +22,23 @@ INSERT INTO t1 VALUES (1,'foo','2022-01-01', '2025-01-01');
DELETE FROM t1 FOR PORTION OF app FROM '2023-01-01' TO '2024-01-01';
DROP TABLE t1;
--echo # End of 10.5 tests
--echo #
--echo # MDEV-37312 ASAN errors or assertion failure upon attempt to UPDATE FOR PORTION violating long unique under READ COMMITTED
--echo #
create table t1 (a int, f text unique, s datetime, e datetime, period for p(s,e)) engine=innodb;
insert into t1 values (1,'foo','1900-01-01','2000-01-01'),(2,'bar','1900-01-01','2000-01-01');
set transaction isolation level read committed;
--error ER_DUP_ENTRY
update t1 for portion of p from '1980-01-01' to '1980-01-02' set a = 1;
drop table t1;
create table t1 (a int, f text unique, s datetime, e datetime, period for p(s,e)) engine=innodb partition by hash (a);
insert into t1 values (1,'foo','1900-01-01','2000-01-01'),(2,'bar','1900-01-01','2000-01-01');
set transaction isolation level read committed;
--error ER_DUP_ENTRY
update t1 for portion of p from '1980-01-01' to '1980-01-02' set a = 1;
drop table t1;
--echo # End of 10.6 tests

View File

@@ -3367,7 +3367,7 @@ int handler::create_lookup_handler()
if (!(tmp= clone(table->s->normalized_path.str, table->in_use->mem_root)))
return 1;
lookup_handler= tmp;
return lookup_handler->ha_external_lock(table->in_use, F_RDLCK);
return lookup_handler->ha_external_lock(table->in_use, F_WRLCK);
}
LEX_CSTRING *handler::engine_name()
@@ -7774,16 +7774,16 @@ int handler::ha_write_row(const uchar *buf)
if (lookup_handler != this) // INSERT IGNORE or REPLACE or ODKU
{
int olderror= error;
if ((error= rnd_init(0)))
if ((error= lookup_handler->rnd_init(0)))
goto err;
position(buf);
if ((error= rnd_pos(lookup_buffer, ref)))
if ((error= lookup_handler->rnd_pos(lookup_buffer, ref)))
goto err;
increment_statistics(&SSV::ha_delete_count);
TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, MAX_KEY, error,
{ error= delete_row(buf);})
rnd_end();
{ error= lookup_handler->delete_row(buf);})
lookup_handler->rnd_end();
if (!error)
error= olderror;
}
@@ -7916,8 +7916,7 @@ int handler::ha_delete_row(const uchar *buf)
/*
Normally table->record[0] is used, but sometimes table->record[1] is used.
*/
DBUG_ASSERT(buf == table->record[0] ||
buf == table->record[1]);
DBUG_ASSERT(buf == table->record[0] || buf == table->record[1]);
MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();