summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSachin Agarwal <sachin.z.agarwal@oracle.com>2017-12-05 19:13:12 +0530
committerMarko Mäkelä <marko.makela@mariadb.com>2018-05-11 18:35:03 +0300
commit3d10966b7d5ed408f9c085f5ba9ed9b12a7317aa (patch)
tree5dd3efdac124d1cbb8dcbdb812e87903ef224948
parente26b07dbc6d85733eaf655895648ec08163debb7 (diff)
downloadmariadb-git-3d10966b7d5ed408f9c085f5ba9ed9b12a7317aa.tar.gz
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
-rw-r--r--mysql-test/suite/innodb/r/stored_fk.result66
-rw-r--r--mysql-test/suite/innodb/t/stored_fk.test105
-rw-r--r--storage/innobase/handler/handler0alter.cc10
3 files changed, 179 insertions, 2 deletions
diff --git a/mysql-test/suite/innodb/r/stored_fk.result b/mysql-test/suite/innodb/r/stored_fk.result
new file mode 100644
index 00000000000..6fb1684497f
--- /dev/null
+++ b/mysql-test/suite/innodb/r/stored_fk.result
@@ -0,0 +1,66 @@
+# 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;
diff --git a/mysql-test/suite/innodb/t/stored_fk.test b/mysql-test/suite/innodb/t/stored_fk.test
new file mode 100644
index 00000000000..da8df775523
--- /dev/null
+++ b/mysql-test/suite/innodb/t/stored_fk.test
@@ -0,0 +1,105 @@
+--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;
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index c483e2dea59..2ae4f65efc5 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -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;