Commit da09ae05 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-18114 Foreign Key Constraint actions don't affect Virtual Column

* invoke check_expression() for all vcol_info's in
  mysql_prepare_create_table() to check for FK CASCADE
* also check for SET NULL and SET DEFAULT
* to check against existing FKs when a vcol is added in ALTER TABLE,
  old FKs must be added to the new_key_list just like other indexes are
* check columns recursively, if vcol1 references vcol2,
  flags of vcol2 must be taken into account
* remove check_table_name_processor(), put that logic under
  check_vcol_func_processor() to avoid walking the tree twice
parent ab1191c0
......@@ -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
......@@ -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,
......
......@@ -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` (
......
create table t1(f1 int primary key) engine=innodb;
# 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")
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 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;
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
......
--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;
......
......@@ -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
#
......@@ -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
#
......
......@@ -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 #
......@@ -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 #
......
......@@ -2005,15 +2005,6 @@ class Item: public Value_source,
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 @@ class Item: public Value_source,
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 @@ class Item_field :public Item_ident,
}
return 0;
}
bool check_table_name_processor(void *arg) override
{
Check_table_name_prm &p= *static_cast<Check_table_name_prm*>(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; }
......
......@@ -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;
}
......
......@@ -4452,7 +4452,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
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 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
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 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
List_iterator_fast<Virtual_column_info> 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<Create_field> new_create_tail;
/* New key definitions are added here */
List<Key> new_key_list;
List<FOREIGN_KEY_INFO> fk_list;
List<Alter_rename_key> rename_key_list(alter_info->alter_rename_key_list);
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
List_iterator<Create_field> 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<Key_part_spec> 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 <FOREIGN_KEY_INFO> fk_child_key_list;
FOREIGN_KEY_INFO *f_key;
table->file->get_foreign_key_list(thd, &fk_child_key_list);
List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_list);
while ((f_key= fk_key_it++))
{
List_iterator_fast<Virtual_column_info>
......
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