summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Malyavin <nikitamalyavin@gmail.com>2020-09-24 21:59:28 +1000
committerNikita Malyavin <nikitamalyavin@gmail.com>2020-11-02 14:11:42 +1000
commitd543363f25f96a6cf1779904ea483c59effa1796 (patch)
tree011c8cb83fe492bfc1abd864a1ea9f2dce52cb4f
parent30894fe9a9024d4dfe85f7fc93cf702040a9ef67 (diff)
downloadmariadb-git-d543363f25f96a6cf1779904ea483c59effa1796.tar.gz
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.
-rw-r--r--mysql-test/suite/period/r/overlaps.result9
-rw-r--r--mysql-test/suite/period/t/overlaps.test14
-rw-r--r--sql/handler.cc15
3 files changed, 32 insertions, 6 deletions
diff --git a/mysql-test/suite/period/r/overlaps.result b/mysql-test/suite/period/r/overlaps.result
index fcd54a0a942..f5839a84e4b 100644
--- a/mysql-test/suite/period/r/overlaps.result
+++ b/mysql-test/suite/period/r/overlaps.result
@@ -320,4 +320,13 @@ t1 CREATE TABLE `t1` (
PARTITION `pn` CURRENT ENGINE = InnoDB)
insert into t1 values (1,'2013-01-12','2015-11-04'),
(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;
diff --git a/mysql-test/suite/period/t/overlaps.test b/mysql-test/suite/period/t/overlaps.test
index 30032f9898c..ef2161d27a2 100644
--- a/mysql-test/suite/period/t/overlaps.test
+++ b/mysql-test/suite/period/t/overlaps.test
@@ -299,5 +299,19 @@ insert into t1 values (1,'2013-01-12','2015-11-04'),
(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;
diff --git a/sql/handler.cc b/sql/handler.cc
index c33dcb192d8..aa04b0bce1c 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -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(old_data == table->record[1]);
- if ((error= ha_check_overlaps(old_data, new_data)))
- return error;
+ uint saved_status= table->status;
+ error= ha_check_overlaps(old_data, new_data);
MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
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;
- }
+
TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, 0,
{ error= update_row(old_data, new_data);})