Commit e53e7cd1 authored by Aleksey Midenkov's avatar Aleksey Midenkov

MDEV-20545 Assertion col.vers_sys_end() in dict_index_t::vers_history_row

Index values for row_start/row_end was wrongly calculated for inplace
ALTER for some layout of virtual fields.

Possible impact

  1. history row is not detected upon build clustered index for
     inplace ALTER which may lead to duplicate key errors on
     auto-increment and FTS index add.
  2. foreign key constraint may falsely fail.
  3. after inplace ALTER before server restart trx-based system
     versioning can cause server crash or incorrect data written upon
     UPDATE.
parent 1710b645
......@@ -786,3 +786,62 @@ with system versioning,
modify row_start varchar(8);
ERROR HY000: PERIOD FOR SYSTEM_TIME must use columns `row_start` and `row_end`
drop table t1;
#
# MDEV-20545 Assertion (col.vers_sys_end()) upon inplace ALTER with virtual columns
#
create table t1 (
a int,
va int as (a) virtual,
b int,
vb int as (b) virtual,
c int,
vc int as (c) virtual,
d int,
e int,
index(va)
) engine=innodb with system versioning;
replace into t1 () values (),();
set statement system_versioning_alter_history=keep for alter table t1 drop e;
alter table t1 algorithm=inplace, drop system versioning;
drop table t1;
#
# MDEV-20765 Assertion (type.vers_sys_end()) upon inplace ALTER with virtual columns
#
create table t1 (
a int,
b int as (a) virtual,
c int,
d int as (c) virtual,
e int,
f int as (e) virtual,
g int,
h int,
i int,
index(d),
key(h),
foreign key (g) references t1 (h)
) engine=innodb with system versioning;
set system_versioning_alter_history= keep;
alter table t1 drop column i;
insert into t1 (g,h) values (1,1);
drop table t1;
#
# MDEV-29034 Assertion (o->ind == vers_start) upon inplace ALTER with virtual columns
#
create table b (
pk integer auto_increment,
col_int_key integer,
col_varchar_key varchar(1),
o bit, n bit,
h float as ( n + 2 ) virtual,
v bit,
primary key (pk),
key (col_varchar_key, col_int_key)
) engine = innodb;
set `system_versioning_alter_history`= keep;
alter table `b` add system versioning;
alter table `b` add column if not exists ( w bit, v serial );
Warnings:
Note 1060 Duplicate column name 'v'
alter table `b` add column if not exists ( p bit );
drop table `b`;
......@@ -677,3 +677,65 @@ alter table t1
modify row_start varchar(8);
# cleanup
drop table t1;
--echo #
--echo # MDEV-20545 Assertion (col.vers_sys_end()) upon inplace ALTER with virtual columns
--echo #
create table t1 (
a int,
va int as (a) virtual,
b int,
vb int as (b) virtual,
c int,
vc int as (c) virtual,
d int,
e int,
index(va)
) engine=innodb with system versioning;
replace into t1 () values (),();
set statement system_versioning_alter_history=keep for alter table t1 drop e;
alter table t1 algorithm=inplace, drop system versioning;
# cleanup
drop table t1;
--echo #
--echo # MDEV-20765 Assertion (type.vers_sys_end()) upon inplace ALTER with virtual columns
--echo #
create table t1 (
a int,
b int as (a) virtual,
c int,
d int as (c) virtual,
e int,
f int as (e) virtual,
g int,
h int,
i int,
index(d),
key(h),
foreign key (g) references t1 (h)
) engine=innodb with system versioning;
set system_versioning_alter_history= keep;
alter table t1 drop column i;
insert into t1 (g,h) values (1,1);
# cleanup
drop table t1;
--echo #
--echo # MDEV-29034 Assertion (o->ind == vers_start) upon inplace ALTER with virtual columns
--echo #
create table b (
pk integer auto_increment,
col_int_key integer,
col_varchar_key varchar(1),
o bit, n bit,
h float as ( n + 2 ) virtual,
v bit,
primary key (pk),
key (col_varchar_key, col_int_key)
) engine = innodb;
set `system_versioning_alter_history`= keep;
alter table `b` add system versioning;
alter table `b` add column if not exists ( w bit, v serial );
alter table `b` add column if not exists ( p bit );
drop table `b`;
......@@ -1612,6 +1612,16 @@ class Field: public Value_source
return flags & (VERS_ROW_START | VERS_ROW_END);
}
bool vers_sys_start() const
{
return flags & VERS_ROW_START;
}
bool vers_sys_end() const
{
return flags & VERS_ROW_END;
}
bool vers_update_unversioned() const
{
return flags & VERS_UPDATE_UNVERSIONED_FLAG;
......
......@@ -4556,10 +4556,12 @@ innobase_build_col_map(
col_map[old_i - num_old_v] = i;
if (old_table->versioned()
&& altered_table->versioned()) {
if (old_i == old_table->vers_start) {
new_table->vers_start = i + num_v;
} else if (old_i == old_table->vers_end) {
new_table->vers_end = i + num_v;
if (old_i - num_old_v == old_table->vers_start) {
ut_ad(field->vers_sys_start());
new_table->vers_start = i;
} else if (old_i - num_old_v == old_table->vers_end) {
ut_ad(field->vers_sys_end());
new_table->vers_end = i;
}
}
goto found_col;
......
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