diff --git a/mysql-test/main/query_cache_innodb.result b/mysql-test/main/query_cache_innodb.result index 62424ac362b..e5569c53d5f 100644 --- a/mysql-test/main/query_cache_innodb.result +++ b/mysql-test/main/query_cache_innodb.result @@ -85,7 +85,7 @@ t2id id use test; drop database `#mysql50#-`; SET NAMES default; -FOUND 8 /\[ERROR\] Invalid \(old\?\) table or database name/ in mysqld.1.err +FOUND 10 /\[ERROR\] Invalid \(old\?\) table or database name/ in mysqld.1.err set global query_cache_type=DEFAULT; set global query_cache_size=@save_query_cache_size; End of 10.2 tests diff --git a/mysql-test/suite/gcol/r/innodb_virtual_basic.result b/mysql-test/suite/gcol/r/innodb_virtual_basic.result index 5b599dc3520..3823887186b 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_basic.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_basic.result @@ -1077,7 +1077,7 @@ KEY `a_2` (`a`,`vbidxcol`), KEY `vbidxcol_2` (`vbidxcol`,`d`), CONSTRAINT `fk_16` FOREIGN KEY (`a`) REFERENCES `ibstd_16` (`a`) ON DELETE SET NULL ) ENGINE=InnoDB; -DROP TABLE ibstd_16_fk; +ERROR HY000: Function or expression 'a' cannot be used in the GENERATED ALWAYS AS clause of `vadcol` CREATE TABLE `ibstd_16_fk` ( `a` int(11) DEFAULT NULL, `d` int(11) DEFAULT NULL, diff --git a/mysql-test/suite/gcol/t/innodb_virtual_basic.test b/mysql-test/suite/gcol/t/innodb_virtual_basic.test index 00b942739b0..b64daa2bcdb 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_basic.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_basic.test @@ -1014,7 +1014,7 @@ CREATE TABLE `ibstd_16` ( ) ENGINE=INNODB; # Block when FK constraint on base column of stored column. -#--error ER_CANNOT_ADD_FOREIGN +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED CREATE TABLE `ibstd_16_fk` ( `a` int(11) DEFAULT NULL, `d` int(11) DEFAULT NULL, @@ -1033,7 +1033,6 @@ CREATE TABLE `ibstd_16_fk` ( KEY `vbidxcol_2` (`vbidxcol`,`d`), CONSTRAINT `fk_16` FOREIGN KEY (`a`) REFERENCES `ibstd_16` (`a`) ON DELETE SET NULL ) ENGINE=InnoDB; -DROP TABLE ibstd_16_fk; # Take out "KEY `a_2` (`a`,`vbidxcol`)", this should then be successful CREATE TABLE `ibstd_16_fk` ( diff --git a/mysql-test/suite/innodb/r/stored_fk.result b/mysql-test/suite/innodb/r/stored_fk.result index fc48f346656..542d362f3cf 100644 --- a/mysql-test/suite/innodb/r/stored_fk.result +++ b/mysql-test/suite/innodb/r/stored_fk.result @@ -1,19 +1,21 @@ -# 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: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed") -# adding new stored column during alter table copy operation. create table t1(f1 int primary key) engine=innodb; +# Create statement with FK on base column of stored column +create table t2(f1 int not null, f2 int as (f1) stored, +foreign key(f1) references t1(f1) on update cascade)engine=innodb; +ERROR HY000: Function or expression 'f1' cannot be used in the GENERATED ALWAYS AS clause of `f2` +create table t2(f1 int not null, f2 int as (f1) virtual, f3 int as (f2) stored, +foreign key(f1) references t1(f1) on update cascade)engine=innodb; +ERROR HY000: Function or expression 'f2' cannot be used in the GENERATED ALWAYS AS clause of `f3` +# adding new stored column during alter table copy operation. 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: Function or expression 'f1' cannot be used in the GENERATED ALWAYS AS clause of `f3` show create table t2; Table Create Table t2 CREATE TABLE `t2` ( `f1` int(11) NOT NULL, `f2` int(11) GENERATED ALWAYS AS (`f1`) VIRTUAL, - `f3` int(11) GENERATED ALWAYS AS (`f1`) STORED, - `f4` int(11) GENERATED ALWAYS AS (`f1`) VIRTUAL, KEY `f1` (`f1`), CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f1`) REFERENCES `t1` (`f1`) ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci @@ -21,26 +23,25 @@ drop table t2; # adding foreign key constraint for base columns during alter copy. create table t2(f1 int not null, f2 int as (f1) stored) engine=innodb; alter table t2 add foreign key(f1) references t1(f1) on update cascade, algorithm=copy; +ERROR HY000: Function or expression 'f1' cannot be used in the GENERATED ALWAYS AS clause of `f2` show create table t2; Table Create Table t2 CREATE TABLE `t2` ( `f1` int(11) NOT NULL, - `f2` int(11) GENERATED ALWAYS AS (`f1`) STORED, - KEY `f1` (`f1`), - CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f1`) REFERENCES `t1` (`f1`) ON UPDATE CASCADE + `f2` int(11) GENERATED ALWAYS AS (`f1`) STORED ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci drop table t2; # adding foreign key constraint for base columns during online alter. create table t2(f1 int not null, f2 int as (f1) stored) engine=innodb; set foreign_key_checks = 0; alter table t2 add foreign key(f1) references t1(f1) on update cascade, algorithm=inplace; -ERROR 0A000: Cannot add foreign key on the base column of stored column +ERROR HY000: Function or expression 'f1' cannot be used in the GENERATED ALWAYS AS clause of `f2` drop table t2; # adding stored column via online alter. 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 +ERROR HY000: Function or expression 'f1' cannot be used in the GENERATED ALWAYS AS clause of `f2` drop table t2, t1; # # BUG#26731689 FK ON TABLE WITH GENERATED COLS: ASSERTION POS < N_DEF diff --git a/mysql-test/suite/innodb/t/stored_fk.test b/mysql-test/suite/innodb/t/stored_fk.test index b9c7c934555..571ca030d65 100644 --- a/mysql-test/suite/innodb/t/stored_fk.test +++ b/mysql-test/suite/innodb/t/stored_fk.test @@ -1,24 +1,28 @@ --source include/have_innodb.inc +create table t1(f1 int primary key) engine=innodb; + --echo # Create statement with FK on base column of stored column ---error ER_CANT_CREATE_TABLE -create table t1(f1 int, f2 int as(f1) stored, - foreign key(f1) references t2(f1) on delete cascade)engine=innodb; +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create table t2(f1 int not null, f2 int as (f1) stored, + foreign key(f1) references t1(f1) on update cascade)engine=innodb; + +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create table t2(f1 int not null, f2 int as (f1) virtual, f3 int as (f2) stored, + foreign key(f1) references t1(f1) on update cascade)engine=innodb; --echo # adding new stored column during alter table copy operation. -create table t1(f1 int primary key) engine=innodb; create table t2(f1 int not null, f2 int as (f1) virtual, foreign key(f1) references t1(f1) on update cascade)engine=innodb; -# MySQL 5.7 would refuse this -#--error ER_ERROR_ON_RENAME +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED alter table t2 add column f3 int as (f1) stored, add column f4 int as (f1) virtual; show create table t2; drop table t2; --echo # adding foreign key constraint for base columns during alter copy. create table t2(f1 int not null, f2 int as (f1) stored) engine=innodb; -# MySQL 5.7 would refuse this +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED alter table t2 add foreign key(f1) references t1(f1) on update cascade, algorithm=copy; show create table t2; drop table t2; @@ -26,14 +30,14 @@ drop table t2; --echo # adding foreign key constraint for base columns during online alter. create table t2(f1 int not null, f2 int as (f1) stored) engine=innodb; set foreign_key_checks = 0; ---error 138 +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED alter table t2 add foreign key(f1) references t1(f1) on update cascade, algorithm=inplace; drop table t2; --echo # adding stored column via online alter. create table t2(f1 int not null, foreign key(f1) references t1(f1) on update cascade)engine=innodb; ---error ER_ALTER_OPERATION_NOT_SUPPORTED +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED alter table t2 add column f2 int as (f1) stored, algorithm=inplace; drop table t2, t1; diff --git a/mysql-test/suite/vcol/r/innodb_virtual_fk.result b/mysql-test/suite/vcol/r/innodb_virtual_fk.result index 58db12583e2..5c0f717642f 100644 --- a/mysql-test/suite/vcol/r/innodb_virtual_fk.result +++ b/mysql-test/suite/vcol/r/innodb_virtual_fk.result @@ -10,3 +10,73 @@ select * from t2; id drop table t2; drop table t1; +# +# End of 10.2 tests +# +# +# MDEV-18114 Foreign Key Constraint actions don't affect Virtual Column +# +create table t1 (id int primary key); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on delete cascade); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on update cascade); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on delete set null); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on update set null); +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on delete cascade); +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on update cascade); +ERROR HY000: Function or expression 'id' cannot be used in the GENERATED ALWAYS AS clause of `id2` +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on delete set null); +ERROR HY000: Function or expression 'id' cannot be used in the GENERATED ALWAYS AS clause of `id2` +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on update set null); +ERROR HY000: Function or expression 'id' cannot be used in the GENERATED ALWAYS AS clause of `id2` +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on delete cascade); +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on update cascade); +ERROR HY000: Function or expression 'id2' cannot be used in the GENERATED ALWAYS AS clause of `id3` +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on delete set null); +ERROR HY000: Function or expression 'id2' cannot be used in the GENERATED ALWAYS AS clause of `id3` +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on update set null); +ERROR HY000: Function or expression 'id2' cannot be used in the GENERATED ALWAYS AS clause of `id3` +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on delete cascade); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on update cascade); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on delete set null); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on update set null); +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on delete cascade); +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on update cascade); +ERROR HY000: Function or expression 'id' cannot be used in the CHECK clause of `id2` +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on delete set null); +ERROR HY000: Function or expression 'id' cannot be used in the CHECK clause of `id2` +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on update set null); +ERROR HY000: Function or expression 'id' cannot be used in the CHECK clause of `id2` +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on delete cascade); +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on update cascade); +ERROR HY000: Function or expression 'id' cannot be used in the CHECK clause of `CONSTRAINT_1` +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on delete set null); +ERROR HY000: Function or expression 'id' cannot be used in the CHECK clause of `CONSTRAINT_1` +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on update set null); +ERROR HY000: Function or expression 'id' cannot be used in the CHECK clause of `CONSTRAINT_1` +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on delete cascade); +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on update cascade); +ERROR HY000: Function or expression 'id2' cannot be used in the CHECK clause of `CONSTRAINT_1` +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on delete set null); +ERROR HY000: Function or expression 'id2' cannot be used in the CHECK clause of `CONSTRAINT_1` +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on update set null); +ERROR HY000: Function or expression 'id2' cannot be used in the CHECK clause of `CONSTRAINT_1` +drop table if exists t2, t1; +Warnings: +Note 1051 Unknown table 'test.t2' +# +# End of 10.5 tests +# diff --git a/mysql-test/suite/vcol/r/vcol_syntax.result b/mysql-test/suite/vcol/r/vcol_syntax.result index f1a850e8f7c..144d4ab335d 100644 --- a/mysql-test/suite/vcol/r/vcol_syntax.result +++ b/mysql-test/suite/vcol/r/vcol_syntax.result @@ -54,22 +54,22 @@ set session sql_mode=@OLD_SQL_MODE; # create table t2 (x int); create table t1 (x int, y int generated always as (t2.x)); -ERROR 42S22: Unknown column '`t2`.`x`' in 'GENERATED ALWAYS' +ERROR HY000: Function or expression 't2.x' cannot be used in the GENERATED ALWAYS AS clause of `y` create table t1 (x int, y int check (y > t2.x)); -ERROR 42S22: Unknown column '`t2`.`x`' in 'CHECK' +ERROR HY000: Function or expression 't2.x' cannot be used in the CHECK clause of `y` create table t1 (x int, y int default t2.x); -ERROR 42S22: Unknown column '`t2`.`x`' in 'DEFAULT' +ERROR HY000: Function or expression 't2.x' cannot be used in the DEFAULT clause of `y` create table t1 (x int, check (t2.x > 0)); -ERROR 42S22: Unknown column '`t2`.`x`' in 'CHECK' +ERROR HY000: Function or expression 't2.x' cannot be used in the CHECK clause of `CONSTRAINT_1` create table t1 (x int); alter table t1 add column y int generated always as (t2.x); -ERROR 42S22: Unknown column '`t2`.`x`' in 'GENERATED ALWAYS' +ERROR HY000: Function or expression 't2.x' cannot be used in the GENERATED ALWAYS AS clause of `y` alter table t1 add column y int check (z > t2.x); -ERROR 42S22: Unknown column '`t2`.`x`' in 'CHECK' +ERROR HY000: Function or expression 't2.x' cannot be used in the CHECK clause of `y` alter table t1 add column y int default t2.x; -ERROR 42S22: Unknown column '`t2`.`x`' in 'DEFAULT' +ERROR HY000: Function or expression 't2.x' cannot be used in the DEFAULT clause of `y` alter table t1 add constraint check (t2.x > 0); -ERROR 42S22: Unknown column '`t2`.`x`' in 'CHECK' +ERROR HY000: Function or expression 't2.x' cannot be used in the CHECK clause of `CONSTRAINT_1` create or replace table t1 (x int, y int generated always as (t1.x)); create or replace table t1 (x int, y int check (y > t1.x)); create or replace table t1 (x int, y int default t1.x); @@ -80,13 +80,13 @@ create or replace table t1 (x int, y int default test.t1.x); create or replace table t1 (x int, check (test.t1.x > 0)); drop tables t1, t2; create table t1 (x int, y int generated always as (test2.t1.x)); -ERROR 42S22: Unknown column '`test2`.`t1`.`x`' in 'GENERATED ALWAYS' +ERROR HY000: Function or expression 'test2.t1.x' cannot be used in the GENERATED ALWAYS AS clause of `y` create table t1 (x int, y int check (y > test2.t1.x)); -ERROR 42S22: Unknown column '`test2`.`t1`.`x`' in 'CHECK' +ERROR HY000: Function or expression 'test2.t1.x' cannot be used in the CHECK clause of `y` create table t1 (x int, y int default test2.t1.x); -ERROR 42S22: Unknown column '`test2`.`t1`.`x`' in 'DEFAULT' +ERROR HY000: Function or expression 'test2.t1.x' cannot be used in the DEFAULT clause of `y` create table t1 (x int, check (test2.t1.x > 0)); -ERROR 42S22: Unknown column '`test2`.`t1`.`x`' in 'CHECK' +ERROR HY000: Function or expression 'test2.t1.x' cannot be used in the CHECK clause of `CONSTRAINT_1` # # MDEV-25672 table alias from previous statement interferes later commands # diff --git a/mysql-test/suite/vcol/t/innodb_virtual_fk.test b/mysql-test/suite/vcol/t/innodb_virtual_fk.test index c364adaa613..ed1d9c6c0cf 100644 --- a/mysql-test/suite/vcol/t/innodb_virtual_fk.test +++ b/mysql-test/suite/vcol/t/innodb_virtual_fk.test @@ -14,3 +14,92 @@ select * from t1; select * from t2; drop table t2; drop table t1; + +--echo # +--echo # End of 10.2 tests +--echo # + +--echo # +--echo # MDEV-18114 Foreign Key Constraint actions don't affect Virtual Column +--echo # +create table t1 (id int primary key); + +# note that RESTRICT, NO ACTION, and DELETE CASCADE are fine +# because they don't change values of referenced columns + +# virtual indexed +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on delete cascade); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on update cascade); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on delete set null); +create or replace table t2 (id int, id2 int as (id) virtual, key(id2), foreign key (id) references t1 (id) on update set null); + +# stored +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on delete cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on update cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on delete set null); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int as (id) stored, foreign key (id) references t1 (id) on update set null); + +# stored indirect +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on delete cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on update cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on delete set null); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int as (id) virtual, id3 int as (id2) stored, foreign key (id) references t1 (id) on update set null); + +# default +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on delete cascade); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on update cascade); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on delete set null); +create or replace table t2 (id int, id2 int default (id), foreign key (id) references t1 (id) on update set null); + +# field check +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on delete cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on update cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on delete set null); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int check (id), foreign key (id) references t1 (id) on update set null); + +# table check +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on delete cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on update cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on delete set null); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int, check (id), foreign key (id) references t1 (id) on update set null); + +# table check indirect +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on update restrict); +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on update no action); +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on delete cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on update cascade); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on delete set null); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t2 (id int, id2 int as (id) virtual, check (id2), foreign key (id) references t1 (id) on update set null); + +drop table if exists t2, t1; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/mysql-test/suite/vcol/t/vcol_syntax.test b/mysql-test/suite/vcol/t/vcol_syntax.test index cb741bc6def..da2ad27d37d 100644 --- a/mysql-test/suite/vcol/t/vcol_syntax.test +++ b/mysql-test/suite/vcol/t/vcol_syntax.test @@ -29,23 +29,23 @@ set session sql_mode=@OLD_SQL_MODE; --echo # create table t2 (x int); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create table t1 (x int, y int generated always as (t2.x)); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create table t1 (x int, y int check (y > t2.x)); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create table t1 (x int, y int default t2.x); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create table t1 (x int, check (t2.x > 0)); create table t1 (x int); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED alter table t1 add column y int generated always as (t2.x); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED alter table t1 add column y int check (z > t2.x); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED alter table t1 add column y int default t2.x; ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED alter table t1 add constraint check (t2.x > 0); create or replace table t1 (x int, y int generated always as (t1.x)); @@ -60,13 +60,13 @@ create or replace table t1 (x int, check (test.t1.x > 0)); drop tables t1, t2; ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create table t1 (x int, y int generated always as (test2.t1.x)); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create table t1 (x int, y int check (y > test2.t1.x)); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create table t1 (x int, y int default test2.t1.x); ---error ER_BAD_FIELD_ERROR +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create table t1 (x int, check (test2.t1.x > 0)); --echo # diff --git a/sql/item.h b/sql/item.h index d0f44f7218e..0c9c317ebba 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2005,15 +2005,6 @@ public: return 0; } - /** - Check db/table_name if they defined in item and match arg values - - @param arg Pointer to Check_table_name_prm structure - - @retval true Match failed - @retval false Match succeeded - */ - virtual bool check_table_name_processor(void *arg) { return false; } /* TRUE if the expression depends only on the table indicated by tab_map or can be converted to such an exression using equalities. @@ -2213,15 +2204,6 @@ public: bool collect; }; - struct Check_table_name_prm - { - LEX_CSTRING db; - LEX_CSTRING table_name; - String field; - Check_table_name_prm(LEX_CSTRING _db, LEX_CSTRING _table_name) : - db(_db), table_name(_table_name) {} - }; - /* For SP local variable returns pointer to Item representing its current value and pointer to current Item otherwise. @@ -3592,24 +3574,6 @@ public: } return 0; } - bool check_table_name_processor(void *arg) override - { - Check_table_name_prm &p= *static_cast(arg); - if (!field && p.table_name.length && table_name.length) - { - DBUG_ASSERT(p.db.length); - if ((db_name.length && - my_strcasecmp(table_alias_charset, p.db.str, db_name.str)) || - my_strcasecmp(table_alias_charset, p.table_name.str, table_name.str)) - { - print(&p.field, (enum_query_type) (QT_ITEM_ORIGINAL_FUNC_NULLIF | - QT_NO_DATA_EXPANSION | - QT_TO_SYSTEM_CHARSET)); - return true; - } - } - return false; - } void cleanup() override; Item_equal *get_item_equal() override { return item_equal; } void set_item_equal(Item_equal *item_eq) override { item_equal= item_eq; } diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 8bfd591532f..1d2e0b779a7 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -254,12 +254,25 @@ Alter_info::algorithm(const THD *thd) const uint Alter_info::check_vcol_field(Item_field *item) const { + if (!item->field && + ((item->db_name.length && !db.streq(item->db_name)) || + (item->table_name.length && !table_name.streq(item->table_name)))) + { + char *ptr= (char*)current_thd->alloc(item->db_name.length + + item->table_name.length + + item->field_name.length + 3); + strxmov(ptr, safe_str(item->db_name.str), item->db_name.length ? "." : "", + item->table_name.str, ".", item->field_name.str, NullS); + item->field_name.str= ptr; + return VCOL_IMPOSSIBLE; + } for (Key &k: key_list) { if (k.type != Key::FOREIGN_KEY) continue; Foreign_key *fk= (Foreign_key*) &k; - if (fk->update_opt != FK_OPTION_CASCADE) + if (fk->update_opt < FK_OPTION_CASCADE && + fk->delete_opt < FK_OPTION_SET_NULL) continue; for (Key_part_spec& kp: fk->columns) { @@ -267,6 +280,11 @@ uint Alter_info::check_vcol_field(Item_field *item) const return VCOL_NON_DETERMINISTIC; } } + for (Create_field &cf: create_list) + { + if (item->field_name.streq(cf.field_name)) + return cf.vcol_info ? cf.vcol_info->flags : 0; + } return 0; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 327d2bad3ac..f1eec6b22a6 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4452,7 +4452,6 @@ without_overlaps_err: create_info->null_bits= null_fields; /* Check fields. */ - Item::Check_table_name_prm walk_prm(alter_info->db, alter_info->table_name); it.rewind(); while ((sql_field=it++)) { @@ -4510,33 +4509,22 @@ without_overlaps_err: if (create_simple) { - /* - NOTE: we cannot do this in check_vcol_func_processor() as there is - already no table name qualifier in expression. - */ if (sql_field->vcol_info && sql_field->vcol_info->expr && - sql_field->vcol_info->expr->walk(&Item::check_table_name_processor, - false, &walk_prm)) - { - my_error(ER_BAD_FIELD_ERROR, MYF(0), walk_prm.field.c_ptr(), "GENERATED ALWAYS"); + check_expression(sql_field->vcol_info, &sql_field->field_name, + sql_field->vcol_info->stored_in_db + ? VCOL_GENERATED_STORED : VCOL_GENERATED_VIRTUAL, + alter_info)) DBUG_RETURN(TRUE); - } if (sql_field->default_value && - sql_field->default_value->expr->walk(&Item::check_table_name_processor, - false, &walk_prm)) - { - my_error(ER_BAD_FIELD_ERROR, MYF(0), walk_prm.field.c_ptr(), "DEFAULT"); + check_expression(sql_field->default_value, &sql_field->field_name, + VCOL_DEFAULT, alter_info)) DBUG_RETURN(TRUE); - } if (sql_field->check_constraint && - sql_field->check_constraint->expr->walk(&Item::check_table_name_processor, - false, &walk_prm)) - { - my_error(ER_BAD_FIELD_ERROR, MYF(0), walk_prm.field.c_ptr(), "CHECK"); + check_expression(sql_field->check_constraint, &sql_field->field_name, + VCOL_CHECK_FIELD, alter_info)) DBUG_RETURN(TRUE); - } } } @@ -4546,12 +4534,6 @@ without_overlaps_err: List_iterator_fast c_it(alter_info->check_constraint_list); while (Virtual_column_info *check= c_it++) { - if (create_simple && check->expr->walk(&Item::check_table_name_processor, - false, &walk_prm)) - { - my_error(ER_BAD_FIELD_ERROR, MYF(0), walk_prm.field.c_ptr(), "CHECK"); - DBUG_RETURN(TRUE); - } if (check->name.length && !check->automatic_name) { /* Check that there's no repeating table CHECK constraint names. */ @@ -8438,6 +8420,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, List new_create_tail; /* New key definitions are added here */ List new_key_list; + List fk_list; List rename_key_list(alter_info->alter_rename_key_list); List_iterator drop_it(alter_info->drop_list); List_iterator def_it(alter_info->create_list); @@ -8460,12 +8443,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, bool drop_period= false; LEX_CSTRING period_start_name= {nullptr, 0}; LEX_CSTRING period_end_name= {nullptr, 0}; + DBUG_ENTER("mysql_prepare_alter_table"); + if (table->s->period.name) { period_start_name= table->s->period_start_field()->field_name; period_end_name= table->s->period_end_field()->field_name; } - DBUG_ENTER("mysql_prepare_alter_table"); /* Merge incompatible changes flag in case of upgrade of a table from an @@ -8526,6 +8510,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, create_info->option_list= merge_engine_table_options(table->s->option_list, create_info->option_list, thd->mem_root); + table->file->get_foreign_key_list(thd, &fk_list); + /* First collect all fields from table which isn't in drop_list */ @@ -9168,6 +9154,30 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, re_setup_keyinfo_hash(key_info); } } + { + // add existing foreign keys + for (auto &fk : fk_list) + { + Alter_drop *drop; + for(drop_it.rewind(); (drop=drop_it++); ) + if (drop->type == Alter_drop::FOREIGN_KEY && + !my_strcasecmp(system_charset_info, fk.foreign_id->str, drop->name)) + break; + if (drop) + continue; + List cols, ref_cols; + for (LEX_CSTRING &c : fk.foreign_fields) + cols.push_back(new (thd->mem_root) Key_part_spec(&c, 0)); + for (LEX_CSTRING &c : fk.referenced_fields) + ref_cols.push_back(new (thd->mem_root) Key_part_spec(&c, 0)); + auto key= new (thd->mem_root) + Foreign_key(fk.foreign_id, &cols, fk.foreign_id, fk.referenced_db, + fk.referenced_table, &ref_cols, fk.delete_method, fk.update_method, + Foreign_key::FK_MATCH_UNDEF, DDL_options()); + key->old= true; + new_key_list.push_back(key, thd->mem_root); + } + } { Key *key; while ((key=key_it++)) // Add new keys @@ -9291,10 +9301,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, if (!alter_info->check_constraint_list.is_empty()) { /* Check the table FOREIGN KEYs for name duplications. */ - List fk_child_key_list; FOREIGN_KEY_INFO *f_key; - table->file->get_foreign_key_list(thd, &fk_child_key_list); - List_iterator fk_key_it(fk_child_key_list); + List_iterator fk_key_it(fk_list); while ((f_key= fk_key_it++)) { List_iterator_fast