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:
@@ -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';
|
DELETE FROM t1 FOR PORTION OF app FROM '2023-01-01' TO '2024-01-01';
|
||||||
ERROR 23000: Duplicate entry 'foo' for key 'b'
|
ERROR 23000: Duplicate entry 'foo' for key 'b'
|
||||||
DROP TABLE t1;
|
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
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
--source include/have_innodb.inc
|
||||||
--source include/have_partition.inc
|
--source include/have_partition.inc
|
||||||
|
|
||||||
--echo #
|
--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';
|
DELETE FROM t1 FOR PORTION OF app FROM '2023-01-01' TO '2024-01-01';
|
||||||
DROP TABLE t1;
|
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
|
||||||
|
|||||||
@@ -3367,7 +3367,7 @@ int handler::create_lookup_handler()
|
|||||||
if (!(tmp= clone(table->s->normalized_path.str, table->in_use->mem_root)))
|
if (!(tmp= clone(table->s->normalized_path.str, table->in_use->mem_root)))
|
||||||
return 1;
|
return 1;
|
||||||
lookup_handler= tmp;
|
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()
|
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
|
if (lookup_handler != this) // INSERT IGNORE or REPLACE or ODKU
|
||||||
{
|
{
|
||||||
int olderror= error;
|
int olderror= error;
|
||||||
if ((error= rnd_init(0)))
|
if ((error= lookup_handler->rnd_init(0)))
|
||||||
goto err;
|
goto err;
|
||||||
position(buf);
|
position(buf);
|
||||||
if ((error= rnd_pos(lookup_buffer, ref)))
|
if ((error= lookup_handler->rnd_pos(lookup_buffer, ref)))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
increment_statistics(&SSV::ha_delete_count);
|
increment_statistics(&SSV::ha_delete_count);
|
||||||
TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, MAX_KEY, error,
|
TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, MAX_KEY, error,
|
||||||
{ error= delete_row(buf);})
|
{ error= lookup_handler->delete_row(buf);})
|
||||||
rnd_end();
|
lookup_handler->rnd_end();
|
||||||
if (!error)
|
if (!error)
|
||||||
error= olderror;
|
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.
|
Normally table->record[0] is used, but sometimes table->record[1] is used.
|
||||||
*/
|
*/
|
||||||
DBUG_ASSERT(buf == table->record[0] ||
|
DBUG_ASSERT(buf == table->record[0] || buf == table->record[1]);
|
||||||
buf == table->record[1]);
|
|
||||||
|
|
||||||
MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str);
|
MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str);
|
||||||
mark_trx_read_write();
|
mark_trx_read_write();
|
||||||
|
|||||||
Reference in New Issue
Block a user