diff --git a/mysql-test/suite/period/r/overlaps.result b/mysql-test/suite/period/r/overlaps.result index 78b1ac18b8d..36a9086f02b 100644 --- a/mysql-test/suite/period/r/overlaps.result +++ b/mysql-test/suite/period/r/overlaps.result @@ -449,3 +449,85 @@ VALUES ('2000-01-01 00:00:00.000000', '2001-01-01 00:00:00.000000', 'abc'); ERROR 23000: Duplicate entry 'abc-2001-01-01 00:00:00.000000-2000-01-01 00:00:00.000000' for key 'index_name' DROP TABLE t1; +# MDEV-25370 Update for portion changes autoincrement key in period table +create or replace table cars(id int auto_increment, +price int, s date, e date, +period for p(s,e), +primary key(id, p without overlaps)); +insert into cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); +select * from cars; +id price s e +1 1000 2018-01-01 2020-01-01 +update cars for portion of p from '2019-01-01' to '2019-12-01' set price= 1100; +select * from cars; +id price s e +1 1000 2018-01-01 2019-01-01 +1 1000 2019-12-01 2020-01-01 +1 1100 2019-01-01 2019-12-01 +delete from cars for portion of p from '2019-12-10' to '2019-12-20'; +select * from cars; +id price s e +1 1000 2018-01-01 2019-01-01 +1 1000 2019-12-01 2019-12-10 +1 1000 2019-12-20 2020-01-01 +1 1100 2019-01-01 2019-12-01 +# AUTO_INCREMENT field is separate from WITHOUT OVERLAPS +create or replace table cars(id int primary key auto_increment, +car_id int, +price int, s date, e date, +period for p(s,e), +unique(car_id, p without overlaps)); +insert cars(car_id, price, s, e) values (1, 1000, '2018-01-01', '2020-01-01'); +select * from cars; +id car_id price s e +1 1 1000 2018-01-01 2020-01-01 +update cars for portion of p from '2019-01-01' to '2019-12-01' set price= 1100; +select * from cars; +id car_id price s e +1 1 1100 2019-01-01 2019-12-01 +2 1 1000 2018-01-01 2019-01-01 +3 1 1000 2019-12-01 2020-01-01 +delete from cars for portion of p from '2019-12-10' to '2019-12-20'; +select * from cars; +id car_id price s e +1 1 1100 2019-01-01 2019-12-01 +2 1 1000 2018-01-01 2019-01-01 +4 1 1000 2019-12-01 2019-12-10 +5 1 1000 2019-12-20 2020-01-01 +# AUTO_INCREMENT field is both standalone and in WITHOUT OVERLAPS +create or replace table cars(id int primary key auto_increment, +price int, s date, e date, +period for p(s,e), +unique(id, p without overlaps)); +insert cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); +insert cars(price, s, e) values (1000, '2021-01-01', '2022-01-01'); +update cars for portion of p from '2019-01-01' to '2019-12-01' set price= 1100; +# autoincrement index is: id int primary key +# id increments each time. +select * from cars; +id price s e +1 1100 2019-01-01 2019-12-01 +2 1000 2021-01-01 2022-01-01 +3 1000 2018-01-01 2019-01-01 +4 1000 2019-12-01 2020-01-01 +truncate cars; +insert cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); +delete from cars for portion of p from '2019-12-10' to '2019-12-20'; +select * from cars; +id price s e +2 1000 2018-01-01 2019-12-10 +3 1000 2019-12-20 2020-01-01 +create or replace table cars(id int unique auto_increment, +price int, s date, e date, +period for p(s,e), +primary key (id, p without overlaps)); +insert cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); +# autoincrement index is: primary key (id, p without overlaps) +# id is not incremented, hence duplication error +update cars for portion of p from '2019-01-01' to '2019-12-01' set price= 1100; +ERROR 23000: Duplicate entry '1' for key 'id' +truncate cars; +insert cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); +delete from cars for portion of p from '2019-12-10' to '2019-12-20'; +ERROR 23000: Duplicate entry '1' for key 'id' +drop table cars; diff --git a/mysql-test/suite/period/t/overlaps.test b/mysql-test/suite/period/t/overlaps.test index 4e71d64d595..b762743be24 100644 --- a/mysql-test/suite/period/t/overlaps.test +++ b/mysql-test/suite/period/t/overlaps.test @@ -458,3 +458,80 @@ VALUES ('2000-01-01 00:00:00.000000', '2001-01-01 00:00:00.000000', 'abc '), ('2000-01-01 00:00:00.000000', '2001-01-01 00:00:00.000000', 'abc'); DROP TABLE t1; + +--echo # MDEV-25370 Update for portion changes autoincrement key in period table +create or replace table cars(id int auto_increment, + price int, s date, e date, + period for p(s,e), + primary key(id, p without overlaps)); + +insert into cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); +select * from cars; + +update cars for portion of p from '2019-01-01' to '2019-12-01' set price= 1100; +--sorted_result +select * from cars; + +delete from cars for portion of p from '2019-12-10' to '2019-12-20'; +--sorted_result +select * from cars; + +--echo # AUTO_INCREMENT field is separate from WITHOUT OVERLAPS +create or replace table cars(id int primary key auto_increment, + car_id int, + price int, s date, e date, + period for p(s,e), + unique(car_id, p without overlaps)); + +insert cars(car_id, price, s, e) values (1, 1000, '2018-01-01', '2020-01-01'); +select * from cars; + +update cars for portion of p from '2019-01-01' to '2019-12-01' set price= 1100; +--sorted_result +select * from cars; + +delete from cars for portion of p from '2019-12-10' to '2019-12-20'; +--sorted_result +select * from cars; + + +--echo # AUTO_INCREMENT field is both standalone and in WITHOUT OVERLAPS +create or replace table cars(id int primary key auto_increment, + price int, s date, e date, + period for p(s,e), + unique(id, p without overlaps)); + +insert cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); +insert cars(price, s, e) values (1000, '2021-01-01', '2022-01-01'); + +update cars for portion of p from '2019-01-01' to '2019-12-01' set price= 1100; +--echo # autoincrement index is: id int primary key +--echo # id increments each time. +--sorted_result +select * from cars; + +truncate cars; +insert cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); + +delete from cars for portion of p from '2019-12-10' to '2019-12-20'; +--sorted_result +select * from cars; + +create or replace table cars(id int unique auto_increment, + price int, s date, e date, + period for p(s,e), + primary key (id, p without overlaps)); + +insert cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); +--echo # autoincrement index is: primary key (id, p without overlaps) +--echo # id is not incremented, hence duplication error +--error ER_DUP_ENTRY +update cars for portion of p from '2019-01-01' to '2019-12-01' set price= 1100; + +truncate cars; +insert cars(price, s, e) values (1000, '2018-01-01', '2020-01-01'); + +--error ER_DUP_ENTRY +delete from cars for portion of p from '2019-12-10' to '2019-12-20'; + +drop table cars; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index ab0d5d35927..945385e114d 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -254,7 +254,10 @@ int update_portion_of_time(THD *thd, TABLE *table, res= src->save_in_field(table->field[dst_fieldno], true); if (likely(!res)) + { + table->period_prepare_autoinc(); res= table->update_generated_fields(); + } if(likely(!res)) res= table->file->ha_update_row(table->record[1], table->record[0]); diff --git a/sql/table.cc b/sql/table.cc index f3d186f4d9d..6633aa1ee04 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8899,10 +8899,9 @@ int TABLE::update_default_fields(bool ignore_errors) int TABLE::update_generated_fields() { int res= 0; - if (found_next_number_field) + if (next_number_field) { - next_number_field= found_next_number_field; - res= found_next_number_field->set_default(); + res= next_number_field->set_default(); if (likely(!res)) res= file->update_auto_increment(); next_number_field= NULL; @@ -8917,6 +8916,18 @@ int TABLE::update_generated_fields() return res; } +void TABLE::period_prepare_autoinc() +{ + if (!found_next_number_field) + return; + /* Don't generate a new value if the autoinc index is WITHOUT OVERLAPS */ + DBUG_ASSERT(s->next_number_index != (uint)-1); + if (key_info[s->next_number_index].without_overlaps) + return; + + next_number_field= found_next_number_field; +} + int TABLE::period_make_insert(Item *src, Field *dst) { THD *thd= in_use; @@ -8926,7 +8937,10 @@ int TABLE::period_make_insert(Item *src, Field *dst) int res= src->save_in_field(dst, true); if (likely(!res)) + { + period_prepare_autoinc(); res= update_generated_fields(); + } if (likely(!res) && triggers) res= triggers->process_triggers(thd, TRG_EVENT_INSERT, diff --git a/sql/table.h b/sql/table.h index 9d659bb71ed..a63eae88cb6 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1808,6 +1808,7 @@ public: ulonglong vers_end_id() const; int update_generated_fields(); + void period_prepare_autoinc(); int period_make_insert(Item *src, Field *dst); int insert_portion_of_time(THD *thd, const vers_select_conds_t &period_conds, ha_rows *rows_inserted);