Commit 68c1fbfc authored by Nikita Malyavin's avatar Nikita Malyavin

MDEV-25370 Update for portion changes autoincrement key in bi-temp table

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).
parent 21f18bd9
......@@ -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;
......@@ -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;
......@@ -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]);
......
......@@ -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,
......
......@@ -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);
......
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