Commit 3d10966b authored by Sachin Agarwal's avatar Sachin Agarwal Committed by Marko Mäkelä

Bug #26731689 FK ON TABLE WITH GENERATED COLS: ASSERTION POS < N_DEF

Problem:

During ALTER, when filling stored column info, wrong column number is used.
This is because we ignored virtual column when iterating over columns in
table and lead to debug assertion.

Fix:

In InnoDB table cache object, vcols are on stored on one list, stored and
normal columns are stored in another list.
When looking for stored column, ignore the virtual columns to get the right
column number of stored column.

Reviewed by: Thiru <thirunarayanan.balathandayuth@oracle.com>,
             Satya <satya.bodapati@oracle.com>
RB: 17939
parent e26b07db
# Create statement with FK on base column of stored column
create table t1(f1 int, f2 int as(f1) stored,
foreign key(f1) references t2(f1) on delete cascade)engine=innodb;
ERROR HY000: Cannot add foreign key constraint
# adding new stored column during alter table copy operation.
create table t1(f1 int primary key);
create table t2(f1 int not null, f2 int as (f1) virtual,
foreign key(f1) references t1(f1) on update cascade)engine=innodb;
alter table t2 add column f3 int as (f1) stored, add column f4 int as (f1) virtual;
ERROR HY000: Error on rename of 'OLD_FILE_NAME' to 'NEW_FILE_NAME' (errno: 150 - Foreign key constraint is incorrectly formed)
drop table t2, t1;
# adding foreign key constraint for base columns during alter copy.
create table t1(f1 int primary key);
create table t2(f1 int not null, f2 int as (f1) stored);
alter table t2 add foreign key(f1) references t1(f1) on update cascade, algorithm=copy;
ERROR HY000: Cannot add foreign key constraint
drop table t2, t1;
# adding foreign key constraint for base columns during online alter.
create table t1(f1 int primary key);
create table t2(f1 int not null, f2 int as (f1) stored);
set foreign_key_checks = 0;
alter table t2 add foreign key(f1) references t1(f1) on update cascade, algorithm=inplace;
ERROR HY000: Cannot add foreign key on the base column of stored column.
drop table t2, t1;
# adding stored column via online alter.
create table t1(f1 int primary key);
create table t2(f1 int not null,
foreign key(f1) references t1(f1) on update cascade)engine=innodb;
alter table t2 add column f2 int as (f1) stored, algorithm=inplace;
ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY.
drop table t2, t1;
set foreign_key_checks = 1;
#
# BUG#26731689 FK ON TABLE WITH GENERATED COLS: ASSERTION POS < N_DEF
#
SET @foreign_key_checks_saved = @@foreign_key_checks;
SET foreign_key_checks=0;
DROP TABLE IF EXISTS s,t;
CREATE TABLE s (a INT, b INT GENERATED ALWAYS AS (0) STORED, c INT,
d INT GENERATED ALWAYS AS (0) VIRTUAL, e INT) ENGINE=innodb;
CREATE TABLE t (a INT) ENGINE=innodb;
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (e) REFERENCES t(a) ON UPDATE SET null;
ERROR HY000: Failed to add the foreign key constaint. Missing index for constraint 'c' in the referenced table 't'
ALTER TABLE t ADD PRIMARY KEY(a);
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (e) REFERENCES t(a) ON UPDATE SET null;
DROP TABLE s,t;
CREATE TABLE s (a INT GENERATED ALWAYS AS (0) VIRTUAL,
b INT GENERATED ALWAYS AS (0) STORED, c INT) ENGINE=innodb;
CREATE TABLE t (a INT) ENGINE=innodb;
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (c) REFERENCES t(a) ON UPDATE SET null;
ERROR HY000: Failed to add the foreign key constaint. Missing index for constraint 'c' in the referenced table 't'
ALTER TABLE t ADD PRIMARY KEY(a);
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (c) REFERENCES t(a) ON UPDATE SET null;
DROP TABLE s,t;
CREATE TABLE s (a INT, b INT GENERATED ALWAYS AS (0) STORED) ENGINE=innodb;
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=innodb;
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (a) REFERENCES t(a) ON UPDATE SET null;
DROP TABLE s,t;
CREATE TABLE s (a INT, b INT) ENGINE=innodb;
CREATE TABLE t (a INT) ENGINE=innodb;
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (a) REFERENCES t(a) ON UPDATE SET null;
ERROR HY000: Failed to add the foreign key constaint. Missing index for constraint 'c' in the referenced table 't'
ALTER TABLE t ADD PRIMARY KEY(a);
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (a) REFERENCES t(a) ON UPDATE SET null;
DROP TABLE s,t;
SET @@foreign_key_checks = @foreign_key_checks_saved;
--source include/have_innodb.inc
--echo # Create statement with FK on base column of stored column
--error ER_CANNOT_ADD_FOREIGN
create table t1(f1 int, f2 int as(f1) stored,
foreign key(f1) references t2(f1) on delete cascade)engine=innodb;
--echo # adding new stored column during alter table copy operation.
create table t1(f1 int primary key);
create table t2(f1 int not null, f2 int as (f1) virtual,
foreign key(f1) references t1(f1) on update cascade)engine=innodb;
--replace_regex /Error on rename of '.*' to '.*'/Error on rename of 'OLD_FILE_NAME' to 'NEW_FILE_NAME'/
--error ER_ERROR_ON_RENAME
alter table t2 add column f3 int as (f1) stored, add column f4 int as (f1) virtual;
drop table t2, t1;
--echo # adding foreign key constraint for base columns during alter copy.
create table t1(f1 int primary key);
create table t2(f1 int not null, f2 int as (f1) stored);
--error ER_CANNOT_ADD_FOREIGN
alter table t2 add foreign key(f1) references t1(f1) on update cascade, algorithm=copy;
drop table t2, t1;
--echo # adding foreign key constraint for base columns during online alter.
create table t1(f1 int primary key);
create table t2(f1 int not null, f2 int as (f1) stored);
set foreign_key_checks = 0;
--error ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED
alter table t2 add foreign key(f1) references t1(f1) on update cascade, algorithm=inplace;
drop table t2, t1;
--echo # adding stored column via online alter.
create table t1(f1 int primary key);
create table t2(f1 int not null,
foreign key(f1) references t1(f1) on update cascade)engine=innodb;
--error ER_ALTER_OPERATION_NOT_SUPPORTED
alter table t2 add column f2 int as (f1) stored, algorithm=inplace;
drop table t2, t1;
set foreign_key_checks = 1;
--echo #
--echo # BUG#26731689 FK ON TABLE WITH GENERATED COLS: ASSERTION POS < N_DEF
--echo #
SET @foreign_key_checks_saved = @@foreign_key_checks;
SET foreign_key_checks=0;
--disable_warnings
DROP TABLE IF EXISTS s,t;
--enable_warnings
CREATE TABLE s (a INT, b INT GENERATED ALWAYS AS (0) STORED, c INT,
d INT GENERATED ALWAYS AS (0) VIRTUAL, e INT) ENGINE=innodb;
CREATE TABLE t (a INT) ENGINE=innodb;
# This would fail. No corresponding index
--error ER_FK_NO_INDEX_PARENT
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (e) REFERENCES t(a) ON UPDATE SET null;
ALTER TABLE t ADD PRIMARY KEY(a);
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (e) REFERENCES t(a) ON UPDATE SET null;
DROP TABLE s,t;
CREATE TABLE s (a INT GENERATED ALWAYS AS (0) VIRTUAL,
b INT GENERATED ALWAYS AS (0) STORED, c INT) ENGINE=innodb;
CREATE TABLE t (a INT) ENGINE=innodb;
# This would fail. No corresponding index
--error ER_FK_NO_INDEX_PARENT
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (c) REFERENCES t(a) ON UPDATE SET null;
ALTER TABLE t ADD PRIMARY KEY(a);
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (c) REFERENCES t(a) ON UPDATE SET null;
DROP TABLE s,t;
CREATE TABLE s (a INT, b INT GENERATED ALWAYS AS (0) STORED) ENGINE=innodb;
CREATE TABLE t (a INT PRIMARY KEY) ENGINE=innodb;
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (a) REFERENCES t(a) ON UPDATE SET null;
DROP TABLE s,t;
CREATE TABLE s (a INT, b INT) ENGINE=innodb;
CREATE TABLE t (a INT) ENGINE=innodb;
# This would fail. No corresponding index
--error ER_FK_NO_INDEX_PARENT
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (a) REFERENCES t(a) ON UPDATE SET null;
ALTER TABLE t ADD PRIMARY KEY(a);
ALTER TABLE s ADD CONSTRAINT c FOREIGN KEY (a) REFERENCES t(a) ON UPDATE SET null;
DROP TABLE s,t;
SET @@foreign_key_checks = @foreign_key_checks_saved;
......@@ -5434,18 +5434,24 @@ alter_fill_stored_column(
dict_s_col_list** s_cols,
mem_heap_t** s_heap)
{
ulint n_cols = altered_table->s->fields;
ulint n_cols = altered_table->s->fields;
ulint stored_col_no = 0;
for (ulint i = 0; i < n_cols; i++) {
Field* field = altered_table->field[i];
dict_s_col_t s_col;
if (!innobase_is_v_fld(field)) {
stored_col_no++;
}
if (!innobase_is_s_fld(field)) {
continue;
}
ulint num_base = 0;
dict_col_t* col = dict_table_get_nth_col(table, i);
dict_col_t* col = dict_table_get_nth_col(table,
stored_col_no);
s_col.m_col = col;
s_col.s_pos = i;
......
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