Skip to content

Commit

Permalink
MDEV-25370 Update for portion changes autoincrement key in bi-temp table
Browse files Browse the repository at this point in the history
According to the standard, the autoincrement column (i.e. *identity
column*) should be advanced each insert implicitly made by
UPDATE/DELETE ... FOR PORTION.

This is very unconvenient use in several notable cases. Concider a
WITHOUT OVERLAPS key with an autoinc column:
id int auto_increment, unique(id, p without overlaps)

An update or delete with FOR PORTION creates a sense that id will remain
unchanged in such case.

The standard's IDENTITY reminds MariaDB's AUTO_INCREMENT, however
the generation rules differ in many ways. For example, there's also a
notion autoincrement index, which is bound to the autoincrement field.

We will define our own generation rule for the PORTION OF operations
involving AUTO_INCREMENT:
* If an autoincrement index contains WITHOUT OVERLAPS specification, then
a new value should not be generated, otherwise it should.

Apart from WITHOUT OVERLAPS there is also another notable case, referred
by the reporter - a unique key that has an autoincrement column and a field
from the period specification:
  id int auto_increment, unique(id, s), period for p(s, e)

for this case, no exception is made, and the autoincrementing rules will be
proceeded accordung to the standard (i.e. the value will be advanced on
implicit inserts).
  • Loading branch information
FooBarrior committed Jan 31, 2024
1 parent 21f18bd commit 68c1fbf
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 3 deletions.
82 changes: 82 additions & 0 deletions mysql-test/suite/period/r/overlaps.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;
77 changes: 77 additions & 0 deletions mysql-test/suite/period/t/overlaps.test
Original file line number Diff line number Diff line change
Expand Up @@ -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;
3 changes: 3 additions & 0 deletions sql/sql_delete.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
20 changes: 17 additions & 3 deletions sql/table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions sql/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,7 @@ struct TABLE
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);
Expand Down

0 comments on commit 68c1fbf

Please sign in to comment.