Commit d543363f authored by Nikita Malyavin's avatar Nikita Malyavin

MDEV-22714 Assertion failed upon multi-update on table WITHOUT OVERLAPS

The problem here was that ha_check_overlaps internally uses ha_index_read,
which in case of fail overwrites table->status. Even though the handlers
are different, they share a common table, so the value is anyway spoiled.
This is bad, and table->status is badly designed and overweighted by
functionality, but nothing can be done with it, since the code related to
this logic is ancient and it's impossible to extract it with normal effort.

So let's just save and restore the value in ha_update_row before and after
the checks.

Other operations like INSERT and simple UPDATE are not in risk, since they
don't use this table->status approach.
DELETE does not do any unique checks, so it's also safe.
parent 30894fe9
...@@ -320,4 +320,13 @@ t1 CREATE TABLE `t1` ( ...@@ -320,4 +320,13 @@ t1 CREATE TABLE `t1` (
PARTITION `pn` CURRENT ENGINE = InnoDB) PARTITION `pn` CURRENT ENGINE = InnoDB)
insert into t1 values (1,'2013-01-12','2015-11-04'), insert into t1 values (1,'2013-01-12','2015-11-04'),
(2,'2016-03-15','2024-11-09'); (2,'2016-03-15','2024-11-09');
# MDEV-22714 Assertion `index->table->is_instant()' failed upon
# multi-update on table with WITHOUT OVERLAPS
create or replace table t (a int);
insert into t values (0),(null),(0);
create or replace table t1 (f int, s date, e date, period for p(s,e),
unique(f, p without overlaps));
insert into t1 values (0,'2026-02-12','2036-09-16'),
(null,'2025-03-09','2032-12-05');
update ignore t join t1 set f = a;
drop table t, t1; drop table t, t1;
...@@ -299,5 +299,19 @@ insert into t1 values (1,'2013-01-12','2015-11-04'), ...@@ -299,5 +299,19 @@ insert into t1 values (1,'2013-01-12','2015-11-04'),
(2,'2016-03-15','2024-11-09'); (2,'2016-03-15','2024-11-09');
--echo # MDEV-22714 Assertion `index->table->is_instant()' failed upon
--echo # multi-update on table with WITHOUT OVERLAPS
create or replace table t (a int);
insert into t values (0),(null),(0);
create or replace table t1 (f int, s date, e date, period for p(s,e),
unique(f, p without overlaps));
insert into t1 values (0,'2026-02-12','2036-09-16'),
(null,'2025-03-09','2032-12-05');
update ignore t join t1 set f = a;
drop table t, t1; drop table t, t1;
...@@ -7182,17 +7182,20 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) ...@@ -7182,17 +7182,20 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data)
DBUG_ASSERT(new_data == table->record[0]); DBUG_ASSERT(new_data == table->record[0]);
DBUG_ASSERT(old_data == table->record[1]); DBUG_ASSERT(old_data == table->record[1]);
if ((error= ha_check_overlaps(old_data, new_data))) uint saved_status= table->status;
return error; error= ha_check_overlaps(old_data, new_data);
MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write(); mark_trx_read_write();
increment_statistics(&SSV::ha_update_count); increment_statistics(&SSV::ha_update_count);
if (table->s->long_unique_table && this == table->file &&
(error= check_duplicate_long_entries_update(new_data))) if (!error && table->s->long_unique_table && this == table->file)
{ error= check_duplicate_long_entries_update(new_data);
table->status= saved_status;
if (error)
return error; return error;
}
TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, 0, TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, 0,
{ error= update_row(old_data, new_data);}) { error= update_row(old_data, new_data);})
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment