MDEV-8605 MariaDB not use DEFAULT value even when inserted NULL for NOT NULLABLE column
NOT NULL constraint must be checked *after* the BEFORE triggers. That is for INSERT and UPDATE statements even NOT NULL fields must be able to store a NULL temporarily at least while BEFORE INSERT/UPDATE triggers are running.
This commit is contained in:
parent
ad5db17e88
commit
0686c34d22
@ -214,12 +214,14 @@ end if;
|
|||||||
end|
|
end|
|
||||||
insert into t3 values (1);
|
insert into t3 values (1);
|
||||||
insert into t1 values (4, "four", 1), (5, "five", 2);
|
insert into t1 values (4, "four", 1), (5, "five", 2);
|
||||||
ERROR 23000: Column 'id' cannot be null
|
Warnings:
|
||||||
|
Warning 1048 Column 'id' cannot be null
|
||||||
select * from t1;
|
select * from t1;
|
||||||
id data fk
|
id data fk
|
||||||
1 one NULL
|
1 one NULL
|
||||||
2 two NULL
|
2 two NULL
|
||||||
4 four 1
|
4 four 1
|
||||||
|
0 five 2
|
||||||
select * from t2;
|
select * from t2;
|
||||||
event
|
event
|
||||||
INSERT INTO t1 id=1 data='one'
|
INSERT INTO t1 id=1 data='one'
|
||||||
|
311
mysql-test/r/trigger_null-8605.result
Normal file
311
mysql-test/r/trigger_null-8605.result
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
set sql_mode=strict_all_tables;
|
||||||
|
set time_zone="+02:00";
|
||||||
|
create table t1 (a int not null, b int, c int);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.a=if(new.a is null,new.b,new.c);
|
||||||
|
insert t1 values (10, NULL, 1);
|
||||||
|
insert t1 values (NULL, 2, NULL);
|
||||||
|
insert t1 values (NULL, NULL, 20);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
insert t1 values (1, 2, NULL);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
insert ignore t1 values (NULL, NULL, 30);
|
||||||
|
Warnings:
|
||||||
|
Warning 1048 Column 'a' cannot be null
|
||||||
|
insert ignore t1 values (1, 3, NULL);
|
||||||
|
Warnings:
|
||||||
|
Warning 1048 Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
0 NULL 30
|
||||||
|
0 3 NULL
|
||||||
|
insert t1 set a=NULL, b=4, c=a;
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
0 NULL 30
|
||||||
|
0 3 NULL
|
||||||
|
4 4 NULL
|
||||||
|
delete from t1;
|
||||||
|
insert t1 (a,c) values (10, 1);
|
||||||
|
insert t1 (a,b) values (NULL, 2);
|
||||||
|
insert t1 (a,c) values (NULL, 20);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
insert t1 (a,b) values (1, 2);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
delete from t1;
|
||||||
|
insert t1 select 10, NULL, 1;
|
||||||
|
insert t1 select NULL, 2, NULL;
|
||||||
|
insert t1 select NULL, NULL, 20;
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
insert t1 select 1, 2, NULL;
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
insert ignore t1 select NULL, NULL, 30;
|
||||||
|
Warnings:
|
||||||
|
Warning 1048 Column 'a' cannot be null
|
||||||
|
insert ignore t1 select 1, 3, NULL;
|
||||||
|
Warnings:
|
||||||
|
Warning 1048 Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
0 NULL 30
|
||||||
|
0 3 NULL
|
||||||
|
delete from t1;
|
||||||
|
insert delayed t1 values (10, NULL, 1);
|
||||||
|
insert delayed t1 values (NULL, 2, NULL);
|
||||||
|
insert delayed t1 values (NULL, NULL, 20);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
insert delayed t1 values (1, 2, NULL);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
insert delayed ignore t1 values (NULL, NULL, 30);
|
||||||
|
Warnings:
|
||||||
|
Warning 1048 Column 'a' cannot be null
|
||||||
|
insert delayed ignore t1 values (1, 3, NULL);
|
||||||
|
Warnings:
|
||||||
|
Warning 1048 Column 'a' cannot be null
|
||||||
|
flush table t1;
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
0 NULL 30
|
||||||
|
0 3 NULL
|
||||||
|
delete from t1;
|
||||||
|
alter table t1 add primary key (a);
|
||||||
|
create trigger trgu before update on t1 for each row set new.a=if(new.a is null,new.b,new.c);
|
||||||
|
insert t1 values (100,100,100), (200,200,200), (300,300,300);
|
||||||
|
insert t1 values (100,100,100) on duplicate key update a=10, b=NULL, c=1;
|
||||||
|
insert t1 values (200,200,200) on duplicate key update a=NULL, b=2, c=NULL;
|
||||||
|
insert t1 values (300,300,300) on duplicate key update a=NULL, b=NULL, c=20;
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
insert t1 values (300,300,300) on duplicate key update a=1, b=2, c=NULL;
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
300 300 300
|
||||||
|
delete from t1;
|
||||||
|
insert t1 values (1,100,1), (2,200,2);
|
||||||
|
replace t1 values (10, NULL, 1);
|
||||||
|
replace t1 values (NULL, 2, NULL);
|
||||||
|
replace t1 values (NULL, NULL, 30);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
replace t1 values (1, 3, NULL);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
delete from t1;
|
||||||
|
insert t1 values (100,100,100), (200,200,200), (300,300,300);
|
||||||
|
update t1 set a=10, b=NULL, c=1 where a=100;
|
||||||
|
update t1 set a=NULL, b=2, c=NULL where a=200;
|
||||||
|
update t1 set a=NULL, b=NULL, c=20 where a=300;
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
update t1 set a=1, b=2, c=NULL where a=300;
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
300 300 300
|
||||||
|
set statement sql_mode='' for update t1 set a=1, b=2, c=NULL where a > 1;
|
||||||
|
ERROR 23000: Duplicate entry '0' for key 'PRIMARY'
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
0 2 NULL
|
||||||
|
300 300 300
|
||||||
|
update t1 set a=NULL, b=4, c=a where a=300;
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
0 2 NULL
|
||||||
|
4 4 NULL
|
||||||
|
delete from t1;
|
||||||
|
create table t2 (d int, e int);
|
||||||
|
insert t1 values (100,100,100), (200,200,200), (300,300,300);
|
||||||
|
insert t2 select a,b from t1;
|
||||||
|
update t1,t2 set a=10, b=NULL, c=1 where b=d and e=100;
|
||||||
|
update t1,t2 set a=NULL, b=2, c=NULL where b=d and e=200;
|
||||||
|
update t1,t2 set a=NULL, b=NULL, c=20 where b=d and e=300;
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
update t1,t2 set a=1, b=2, c=NULL where b=d and e=300;
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
300 300 300
|
||||||
|
update t1,t2 set a=NULL, b=4, c=a where b=d and e=300;
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
4 4 300
|
||||||
|
delete from t1;
|
||||||
|
insert t2 values (2,2);
|
||||||
|
create view v1 as select * from t1, t2 where d=2;
|
||||||
|
insert v1 (a,c) values (10, 1);
|
||||||
|
insert v1 (a,b) values (NULL, 2);
|
||||||
|
insert v1 (a,c) values (NULL, 20);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
insert v1 (a,b) values (1, 2);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
select * from v1;
|
||||||
|
a b c d e
|
||||||
|
1 NULL 1 2 2
|
||||||
|
2 2 NULL 2 2
|
||||||
|
delete from t1;
|
||||||
|
drop view v1;
|
||||||
|
drop table t2;
|
||||||
|
load data infile 'mdev8605.txt' into table t1 fields terminated by ',';
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (a timestamp, b int auto_increment primary key);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.a=if(new.a is null, '2000-10-20 10:20:30', NULL);
|
||||||
|
set statement timestamp=777777777 for insert t1 (a) values (NULL);
|
||||||
|
set statement timestamp=888888888 for insert t1 (a) values ('1999-12-11 10:9:8');
|
||||||
|
select b, a, unix_timestamp(a) from t1;
|
||||||
|
b a unix_timestamp(a)
|
||||||
|
1 2000-10-20 10:20:30 972030030
|
||||||
|
2 1998-03-03 03:34:48 888888888
|
||||||
|
set statement timestamp=999999999 for update t1 set b=3 where b=2;
|
||||||
|
select b, a, unix_timestamp(a) from t1;
|
||||||
|
b a unix_timestamp(a)
|
||||||
|
1 2000-10-20 10:20:30 972030030
|
||||||
|
3 2001-09-09 03:46:39 999999999
|
||||||
|
create trigger trgu before update on t1 for each row set new.a='2011-11-11 11:11:11';
|
||||||
|
update t1 set b=4 where b=3;
|
||||||
|
select b, a, unix_timestamp(a) from t1;
|
||||||
|
b a unix_timestamp(a)
|
||||||
|
1 2000-10-20 10:20:30 972030030
|
||||||
|
4 2011-11-11 11:11:11 1321002671
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (a int auto_increment primary key);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.a=if(new.a is null, 5, NULL);
|
||||||
|
insert t1 values (NULL);
|
||||||
|
insert t1 values (10);
|
||||||
|
select a from t1;
|
||||||
|
a
|
||||||
|
5
|
||||||
|
6
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (a int, b int, c int);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.a=if(new.a is null,new.b,new.c);
|
||||||
|
insert t1 values (10, NULL, 1);
|
||||||
|
insert t1 values (NULL, 2, NULL);
|
||||||
|
insert t1 values (NULL, NULL, 20);
|
||||||
|
insert t1 values (1, 2, NULL);
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 NULL 1
|
||||||
|
2 2 NULL
|
||||||
|
NULL NULL 20
|
||||||
|
NULL 2 NULL
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (a1 tinyint not null, a2 timestamp not null,
|
||||||
|
a3 tinyint not null auto_increment primary key,
|
||||||
|
b tinyint, c int not null);
|
||||||
|
create trigger trgi before insert on t1 for each row
|
||||||
|
begin
|
||||||
|
if new.b=1 then set new.a1=if(new.c,new.c,null); end if;
|
||||||
|
if new.b=2 then set new.a2=if(new.c,new.c,null); end if;
|
||||||
|
if new.b=3 then set new.a3=if(new.c,new.c,null); end if;
|
||||||
|
end|
|
||||||
|
set statement timestamp=777777777 for
|
||||||
|
load data infile 'sep8605.txt' into table t1 fields terminated by ',';
|
||||||
|
ERROR 23000: Column 'a1' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a1 a2 a3 b c
|
||||||
|
1 2010-11-12 01:02:03 10 0 0
|
||||||
|
2 2010-11-12 01:02:03 11 1 2
|
||||||
|
3 1994-08-25 03:22:57 12 0 0
|
||||||
|
4 2000-09-08 07:06:05 13 2 908070605
|
||||||
|
5 1994-08-25 03:22:57 14 2 0
|
||||||
|
6 2010-11-12 01:02:03 15 0 0
|
||||||
|
7 2010-11-12 01:02:03 20 3 20
|
||||||
|
8 2010-11-12 01:02:03 21 3 0
|
||||||
|
delete from t1;
|
||||||
|
set statement timestamp=777777777 for
|
||||||
|
load data infile 'sep8605.txt' into table t1 fields terminated by ','
|
||||||
|
(@a,a2,a3,b,c) set a1=100-@a;
|
||||||
|
ERROR 23000: Column 'a1' cannot be null
|
||||||
|
select 100-a1,a2,a3,b,c from t1;
|
||||||
|
100-a1 a2 a3 b c
|
||||||
|
1 2010-11-12 01:02:03 10 0 0
|
||||||
|
98 2010-11-12 01:02:03 11 1 2
|
||||||
|
3 1994-08-25 03:22:57 12 0 0
|
||||||
|
4 2000-09-08 07:06:05 13 2 908070605
|
||||||
|
5 1994-08-25 03:22:57 14 2 0
|
||||||
|
6 2010-11-12 01:02:03 22 0 0
|
||||||
|
7 2010-11-12 01:02:03 20 3 20
|
||||||
|
8 2010-11-12 01:02:03 23 3 0
|
||||||
|
delete from t1;
|
||||||
|
set statement timestamp=777777777 for
|
||||||
|
load data infile 'fix8605.txt' into table t1 fields terminated by '';
|
||||||
|
ERROR 23000: Column 'a1' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a1 a2 a3 b c
|
||||||
|
1 2010-11-12 01:02:03 10 0 0
|
||||||
|
5 1994-08-25 03:22:57 14 2 0
|
||||||
|
8 2010-11-12 01:02:03 24 3 0
|
||||||
|
delete from t1;
|
||||||
|
set statement timestamp=777777777 for
|
||||||
|
load xml infile 'xml8605.txt' into table t1 rows identified by '<row>';
|
||||||
|
ERROR 23000: Column 'a1' cannot be null
|
||||||
|
select * from t1;
|
||||||
|
a1 a2 a3 b c
|
||||||
|
1 2010-11-12 01:02:03 10 0 0
|
||||||
|
2 2010-11-12 01:02:03 11 1 2
|
||||||
|
3 1994-08-25 03:22:57 12 0 0
|
||||||
|
4 2000-09-08 07:06:05 13 2 908070605
|
||||||
|
5 1994-08-25 03:22:57 14 2 0
|
||||||
|
6 2010-11-12 01:02:03 25 0 0
|
||||||
|
7 2010-11-12 01:02:03 20 3 20
|
||||||
|
8 2010-11-12 01:02:03 26 3 0
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (a int not null default 5, b int, c int);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.b=new.c;
|
||||||
|
insert t1 values (DEFAULT,2,1);
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
5 1 1
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (a int not null, b int not null default 5, c int);
|
||||||
|
create trigger trgi before insert on t1 for each row
|
||||||
|
begin
|
||||||
|
if new.c=1 then set new.a=1, new.b=1; end if;
|
||||||
|
if new.c=2 then set new.a=NULL, new.b=NULL; end if;
|
||||||
|
if new.c=3 then set new.a=2; end if;
|
||||||
|
end|
|
||||||
|
insert t1 values (9, 9, 1);
|
||||||
|
insert t1 values (9, 9, 2);
|
||||||
|
ERROR 23000: Column 'a' cannot be null
|
||||||
|
insert t1 (a,c) values (9, 3);
|
||||||
|
select * from t1;
|
||||||
|
a b c
|
||||||
|
1 1 1
|
||||||
|
2 5 3
|
||||||
|
drop table t1;
|
@ -189,8 +189,6 @@ Update tb3 Set f122='Test 3.5.9.4-trig', f136=NULL, f151=DEFAULT, f163=NULL
|
|||||||
where f122='Test 3.5.9.4';
|
where f122='Test 3.5.9.4';
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1048 Column 'f136' cannot be null
|
Warning 1048 Column 'f136' cannot be null
|
||||||
Update tb3 Set f122='Test 3.5.9.4-trig', f136=0, f151=DEFAULT, f163=NULL
|
|
||||||
where f122='Test 3.5.9.4';
|
|
||||||
select f118, f121, f122, f136, f151, f163 from tb3
|
select f118, f121, f122, f136, f151, f163 from tb3
|
||||||
where f122 like 'Test 3.5.9.4-trig' order by f163;
|
where f122 like 'Test 3.5.9.4-trig' order by f163;
|
||||||
f118 f121 f122 f136 f151 f163
|
f118 f121 f122 f136 f151 f163
|
||||||
@ -198,7 +196,7 @@ a NULL Test 3.5.9.4-trig 00000 999 NULL
|
|||||||
select @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
|
select @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
|
||||||
@tr_var_b4_136, @tr_var_b4_151, @tr_var_b4_163;
|
@tr_var_b4_136, @tr_var_b4_151, @tr_var_b4_163;
|
||||||
@tr_var_b4_118 @tr_var_b4_121 @tr_var_b4_122 @tr_var_b4_136 @tr_var_b4_151 @tr_var_b4_163
|
@tr_var_b4_118 @tr_var_b4_121 @tr_var_b4_122 @tr_var_b4_136 @tr_var_b4_151 @tr_var_b4_163
|
||||||
a NULL Test 3.5.9.4-trig 0 999 NULL
|
a NULL Test 3.5.9.4-trig NULL 999 NULL
|
||||||
select @tr_var_af_118, @tr_var_af_121, @tr_var_af_122,
|
select @tr_var_af_118, @tr_var_af_121, @tr_var_af_122,
|
||||||
@tr_var_af_136, @tr_var_af_151, @tr_var_af_163;
|
@tr_var_af_136, @tr_var_af_151, @tr_var_af_163;
|
||||||
@tr_var_af_118 @tr_var_af_121 @tr_var_af_122 @tr_var_af_136 @tr_var_af_151 @tr_var_af_163
|
@tr_var_af_118 @tr_var_af_121 @tr_var_af_122 @tr_var_af_136 @tr_var_af_151 @tr_var_af_163
|
||||||
|
@ -190,8 +190,6 @@ Update tb3 Set f122='Test 3.5.9.4-trig', f136=NULL, f151=DEFAULT, f163=NULL
|
|||||||
where f122='Test 3.5.9.4';
|
where f122='Test 3.5.9.4';
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1048 Column 'f136' cannot be null
|
Warning 1048 Column 'f136' cannot be null
|
||||||
Update tb3 Set f122='Test 3.5.9.4-trig', f136=0, f151=DEFAULT, f163=NULL
|
|
||||||
where f122='Test 3.5.9.4';
|
|
||||||
select f118, f121, f122, f136, f151, f163 from tb3
|
select f118, f121, f122, f136, f151, f163 from tb3
|
||||||
where f122 like 'Test 3.5.9.4-trig' order by f163;
|
where f122 like 'Test 3.5.9.4-trig' order by f163;
|
||||||
f118 f121 f122 f136 f151 f163
|
f118 f121 f122 f136 f151 f163
|
||||||
@ -199,7 +197,7 @@ a NULL Test 3.5.9.4-trig 00000 999 NULL
|
|||||||
select @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
|
select @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
|
||||||
@tr_var_b4_136, @tr_var_b4_151, @tr_var_b4_163;
|
@tr_var_b4_136, @tr_var_b4_151, @tr_var_b4_163;
|
||||||
@tr_var_b4_118 @tr_var_b4_121 @tr_var_b4_122 @tr_var_b4_136 @tr_var_b4_151 @tr_var_b4_163
|
@tr_var_b4_118 @tr_var_b4_121 @tr_var_b4_122 @tr_var_b4_136 @tr_var_b4_151 @tr_var_b4_163
|
||||||
a NULL Test 3.5.9.4-trig 0 999 NULL
|
a NULL Test 3.5.9.4-trig NULL 999 NULL
|
||||||
select @tr_var_af_118, @tr_var_af_121, @tr_var_af_122,
|
select @tr_var_af_118, @tr_var_af_121, @tr_var_af_122,
|
||||||
@tr_var_af_136, @tr_var_af_151, @tr_var_af_163;
|
@tr_var_af_136, @tr_var_af_151, @tr_var_af_163;
|
||||||
@tr_var_af_118 @tr_var_af_121 @tr_var_af_122 @tr_var_af_136 @tr_var_af_151 @tr_var_af_163
|
@tr_var_af_118 @tr_var_af_121 @tr_var_af_122 @tr_var_af_136 @tr_var_af_151 @tr_var_af_163
|
||||||
|
@ -190,8 +190,6 @@ Update tb3 Set f122='Test 3.5.9.4-trig', f136=NULL, f151=DEFAULT, f163=NULL
|
|||||||
where f122='Test 3.5.9.4';
|
where f122='Test 3.5.9.4';
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1048 Column 'f136' cannot be null
|
Warning 1048 Column 'f136' cannot be null
|
||||||
Update tb3 Set f122='Test 3.5.9.4-trig', f136=0, f151=DEFAULT, f163=NULL
|
|
||||||
where f122='Test 3.5.9.4';
|
|
||||||
select f118, f121, f122, f136, f151, f163 from tb3
|
select f118, f121, f122, f136, f151, f163 from tb3
|
||||||
where f122 like 'Test 3.5.9.4-trig' order by f163;
|
where f122 like 'Test 3.5.9.4-trig' order by f163;
|
||||||
f118 f121 f122 f136 f151 f163
|
f118 f121 f122 f136 f151 f163
|
||||||
@ -199,7 +197,7 @@ a NULL Test 3.5.9.4-trig 00000 999 NULL
|
|||||||
select @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
|
select @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
|
||||||
@tr_var_b4_136, @tr_var_b4_151, @tr_var_b4_163;
|
@tr_var_b4_136, @tr_var_b4_151, @tr_var_b4_163;
|
||||||
@tr_var_b4_118 @tr_var_b4_121 @tr_var_b4_122 @tr_var_b4_136 @tr_var_b4_151 @tr_var_b4_163
|
@tr_var_b4_118 @tr_var_b4_121 @tr_var_b4_122 @tr_var_b4_136 @tr_var_b4_151 @tr_var_b4_163
|
||||||
a NULL Test 3.5.9.4-trig 0 999 NULL
|
a NULL Test 3.5.9.4-trig NULL 999 NULL
|
||||||
select @tr_var_af_118, @tr_var_af_121, @tr_var_af_122,
|
select @tr_var_af_118, @tr_var_af_121, @tr_var_af_122,
|
||||||
@tr_var_af_136, @tr_var_af_151, @tr_var_af_163;
|
@tr_var_af_136, @tr_var_af_151, @tr_var_af_163;
|
||||||
@tr_var_af_118 @tr_var_af_121 @tr_var_af_122 @tr_var_af_136 @tr_var_af_151 @tr_var_af_163
|
@tr_var_af_118 @tr_var_af_121 @tr_var_af_122 @tr_var_af_136 @tr_var_af_151 @tr_var_af_163
|
||||||
|
@ -186,9 +186,6 @@ let $message= Testcase 3.5.9.4:;
|
|||||||
Update tb3 Set f122='Test 3.5.9.4-trig', f136=NULL, f151=DEFAULT, f163=NULL
|
Update tb3 Set f122='Test 3.5.9.4-trig', f136=NULL, f151=DEFAULT, f163=NULL
|
||||||
where f122='Test 3.5.9.4';
|
where f122='Test 3.5.9.4';
|
||||||
|
|
||||||
Update tb3 Set f122='Test 3.5.9.4-trig', f136=0, f151=DEFAULT, f163=NULL
|
|
||||||
where f122='Test 3.5.9.4';
|
|
||||||
|
|
||||||
select f118, f121, f122, f136, f151, f163 from tb3
|
select f118, f121, f122, f136, f151, f163 from tb3
|
||||||
where f122 like 'Test 3.5.9.4-trig' order by f163;
|
where f122 like 'Test 3.5.9.4-trig' order by f163;
|
||||||
select @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
|
select @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
|
||||||
|
@ -39,7 +39,7 @@ select a,name, old_a, old_b, truncate(rand_value,4) from t3;
|
|||||||
a name old_a old_b truncate(rand_value,4)
|
a name old_a old_b truncate(rand_value,4)
|
||||||
100 log 0 0 0.0000
|
100 log 0 0 0.0000
|
||||||
101 t1 1 1 0.3203
|
101 t1 1 1 0.3203
|
||||||
102 t1 0 2 0.5666
|
102 t1 NULL 2 0.5666
|
||||||
103 t2 1 2 0.9164
|
103 t2 1 2 0.9164
|
||||||
104 t2 3 0 0.8826
|
104 t2 3 0 0.8826
|
||||||
105 t2 4 0 0.6635
|
105 t2 4 0 0.6635
|
||||||
|
@ -35,7 +35,7 @@ select a,name, old_a, old_b, truncate(rand_value,4) from t3;
|
|||||||
a name old_a old_b truncate(rand_value,4)
|
a name old_a old_b truncate(rand_value,4)
|
||||||
100 log 0 0 0.0000
|
100 log 0 0 0.0000
|
||||||
101 t1 1 1 0.3203
|
101 t1 1 1 0.3203
|
||||||
102 t1 0 2 0.5666
|
102 t1 NULL 2 0.5666
|
||||||
103 t2 1 2 0.9164
|
103 t2 1 2 0.9164
|
||||||
104 t2 3 0 0.8826
|
104 t2 3 0 0.8826
|
||||||
105 t2 4 0 0.6635
|
105 t2 4 0 0.6635
|
||||||
@ -58,7 +58,7 @@ select a,name, old_a, old_b, truncate(rand_value,4) from t3;
|
|||||||
a name old_a old_b truncate(rand_value,4)
|
a name old_a old_b truncate(rand_value,4)
|
||||||
100 log 0 0 0.0000
|
100 log 0 0 0.0000
|
||||||
101 t1 1 1 0.3203
|
101 t1 1 1 0.3203
|
||||||
102 t1 0 2 0.5666
|
102 t1 NULL 2 0.5666
|
||||||
103 t2 1 2 0.9164
|
103 t2 1 2 0.9164
|
||||||
104 t2 3 0 0.8826
|
104 t2 3 0 0.8826
|
||||||
105 t2 4 0 0.6635
|
105 t2 4 0 0.6635
|
||||||
|
@ -241,7 +241,6 @@ begin
|
|||||||
end|
|
end|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
insert into t3 values (1);
|
insert into t3 values (1);
|
||||||
--error ER_BAD_NULL_ERROR
|
|
||||||
insert into t1 values (4, "four", 1), (5, "five", 2);
|
insert into t1 values (4, "four", 1), (5, "five", 2);
|
||||||
select * from t1;
|
select * from t1;
|
||||||
select * from t2;
|
select * from t2;
|
||||||
|
327
mysql-test/t/trigger_null-8605.test
Normal file
327
mysql-test/t/trigger_null-8605.test
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
#
|
||||||
|
# MDEV-8605 MariaDB not use DEFAULT value even when inserted NULL for NOT NULLABLE column.
|
||||||
|
#
|
||||||
|
|
||||||
|
set sql_mode=strict_all_tables;
|
||||||
|
set time_zone="+02:00";
|
||||||
|
|
||||||
|
create table t1 (a int not null, b int, c int);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.a=if(new.a is null,new.b,new.c);
|
||||||
|
|
||||||
|
# INSERT
|
||||||
|
insert t1 values (10, NULL, 1);
|
||||||
|
insert t1 values (NULL, 2, NULL);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert t1 values (NULL, NULL, 20);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert t1 values (1, 2, NULL);
|
||||||
|
select * from t1;
|
||||||
|
|
||||||
|
# INSERT IGNORE
|
||||||
|
insert ignore t1 values (NULL, NULL, 30);
|
||||||
|
insert ignore t1 values (1, 3, NULL);
|
||||||
|
select * from t1;
|
||||||
|
|
||||||
|
# fields in the value list
|
||||||
|
insert t1 set a=NULL, b=4, c=a;
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
#insert (column list)
|
||||||
|
insert t1 (a,c) values (10, 1);
|
||||||
|
insert t1 (a,b) values (NULL, 2);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert t1 (a,c) values (NULL, 20);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert t1 (a,b) values (1, 2);
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
# insert select
|
||||||
|
|
||||||
|
insert t1 select 10, NULL, 1;
|
||||||
|
insert t1 select NULL, 2, NULL;
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert t1 select NULL, NULL, 20;
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert t1 select 1, 2, NULL;
|
||||||
|
insert ignore t1 select NULL, NULL, 30;
|
||||||
|
insert ignore t1 select 1, 3, NULL;
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
# insert delayed
|
||||||
|
insert delayed t1 values (10, NULL, 1);
|
||||||
|
insert delayed t1 values (NULL, 2, NULL);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert delayed t1 values (NULL, NULL, 20);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert delayed t1 values (1, 2, NULL);
|
||||||
|
select * from t1;
|
||||||
|
insert delayed ignore t1 values (NULL, NULL, 30);
|
||||||
|
insert delayed ignore t1 values (1, 3, NULL);
|
||||||
|
flush table t1; # wait for inserts to finish
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
# insert on dup key update
|
||||||
|
alter table t1 add primary key (a);
|
||||||
|
create trigger trgu before update on t1 for each row set new.a=if(new.a is null,new.b,new.c);
|
||||||
|
|
||||||
|
insert t1 values (100,100,100), (200,200,200), (300,300,300);
|
||||||
|
insert t1 values (100,100,100) on duplicate key update a=10, b=NULL, c=1;
|
||||||
|
insert t1 values (200,200,200) on duplicate key update a=NULL, b=2, c=NULL;
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert t1 values (300,300,300) on duplicate key update a=NULL, b=NULL, c=20;
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert t1 values (300,300,300) on duplicate key update a=1, b=2, c=NULL;
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
# replace
|
||||||
|
insert t1 values (1,100,1), (2,200,2);
|
||||||
|
replace t1 values (10, NULL, 1);
|
||||||
|
replace t1 values (NULL, 2, NULL);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
replace t1 values (NULL, NULL, 30);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
replace t1 values (1, 3, NULL);
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
# update
|
||||||
|
insert t1 values (100,100,100), (200,200,200), (300,300,300);
|
||||||
|
update t1 set a=10, b=NULL, c=1 where a=100;
|
||||||
|
update t1 set a=NULL, b=2, c=NULL where a=200;
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
update t1 set a=NULL, b=NULL, c=20 where a=300;
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
update t1 set a=1, b=2, c=NULL where a=300;
|
||||||
|
select * from t1;
|
||||||
|
# Test UPDATE with NULL violation in many rows
|
||||||
|
--error ER_DUP_ENTRY
|
||||||
|
set statement sql_mode='' for update t1 set a=1, b=2, c=NULL where a > 1;
|
||||||
|
select * from t1;
|
||||||
|
# fields in the value list
|
||||||
|
update t1 set a=NULL, b=4, c=a where a=300;
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
# multi-update
|
||||||
|
|
||||||
|
create table t2 (d int, e int);
|
||||||
|
insert t1 values (100,100,100), (200,200,200), (300,300,300);
|
||||||
|
insert t2 select a,b from t1;
|
||||||
|
update t1,t2 set a=10, b=NULL, c=1 where b=d and e=100;
|
||||||
|
update t1,t2 set a=NULL, b=2, c=NULL where b=d and e=200;
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
update t1,t2 set a=NULL, b=NULL, c=20 where b=d and e=300;
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
update t1,t2 set a=1, b=2, c=NULL where b=d and e=300;
|
||||||
|
select * from t1;
|
||||||
|
# fields in the value list
|
||||||
|
update t1,t2 set a=NULL, b=4, c=a where b=d and e=300;
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
# view
|
||||||
|
insert t2 values (2,2);
|
||||||
|
create view v1 as select * from t1, t2 where d=2;
|
||||||
|
insert v1 (a,c) values (10, 1);
|
||||||
|
insert v1 (a,b) values (NULL, 2);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert v1 (a,c) values (NULL, 20);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert v1 (a,b) values (1, 2);
|
||||||
|
select * from v1;
|
||||||
|
delete from t1;
|
||||||
|
drop view v1;
|
||||||
|
drop table t2;
|
||||||
|
|
||||||
|
# load data
|
||||||
|
let $datadir=`select @@datadir`;
|
||||||
|
--write_file $datadir/test/mdev8605.txt
|
||||||
|
10,\N,1
|
||||||
|
\N,2,\N
|
||||||
|
\N,\N,20
|
||||||
|
EOF
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
load data infile 'mdev8605.txt' into table t1 fields terminated by ',';
|
||||||
|
select * from t1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# timestamps (on NULL = NOW())
|
||||||
|
create table t1 (a timestamp, b int auto_increment primary key);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.a=if(new.a is null, '2000-10-20 10:20:30', NULL);
|
||||||
|
set statement timestamp=777777777 for insert t1 (a) values (NULL);
|
||||||
|
set statement timestamp=888888888 for insert t1 (a) values ('1999-12-11 10:9:8');
|
||||||
|
select b, a, unix_timestamp(a) from t1;
|
||||||
|
set statement timestamp=999999999 for update t1 set b=3 where b=2;
|
||||||
|
select b, a, unix_timestamp(a) from t1;
|
||||||
|
create trigger trgu before update on t1 for each row set new.a='2011-11-11 11:11:11';
|
||||||
|
update t1 set b=4 where b=3;
|
||||||
|
select b, a, unix_timestamp(a) from t1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# auto-increment (on NULL = int)
|
||||||
|
create table t1 (a int auto_increment primary key);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.a=if(new.a is null, 5, NULL);
|
||||||
|
insert t1 values (NULL);
|
||||||
|
insert t1 values (10);
|
||||||
|
select a from t1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# insert, all columns NULLable
|
||||||
|
create table t1 (a int, b int, c int);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.a=if(new.a is null,new.b,new.c);
|
||||||
|
insert t1 values (10, NULL, 1);
|
||||||
|
insert t1 values (NULL, 2, NULL);
|
||||||
|
insert t1 values (NULL, NULL, 20);
|
||||||
|
insert t1 values (1, 2, NULL);
|
||||||
|
select * from t1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# more load data: autoinc and timestamp, different load formats
|
||||||
|
create table t1 (a1 tinyint not null, a2 timestamp not null,
|
||||||
|
a3 tinyint not null auto_increment primary key,
|
||||||
|
b tinyint, c int not null);
|
||||||
|
delimiter |;
|
||||||
|
create trigger trgi before insert on t1 for each row
|
||||||
|
begin
|
||||||
|
if new.b=1 then set new.a1=if(new.c,new.c,null); end if;
|
||||||
|
if new.b=2 then set new.a2=if(new.c,new.c,null); end if;
|
||||||
|
if new.b=3 then set new.a3=if(new.c,new.c,null); end if;
|
||||||
|
end|
|
||||||
|
delimiter ;|
|
||||||
|
|
||||||
|
--write_file $datadir/test/sep8605.txt
|
||||||
|
1,2010-11-12 1:2:3,10,0,0
|
||||||
|
\N,2010-11-12 1:2:3,11,1,2
|
||||||
|
3,\N,12,0,0
|
||||||
|
4,\N,13,2,908070605
|
||||||
|
5,2010-11-12 1:2:3,14,2,0
|
||||||
|
6,2010-11-12 1:2:3,\N,0,0
|
||||||
|
7,2010-11-12 1:2:3,\N,3,20
|
||||||
|
8,2010-11-12 1:2:3,30,3,0
|
||||||
|
99,2010-11-12 1:2:3,0,1,0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
set statement timestamp=777777777 for
|
||||||
|
load data infile 'sep8605.txt' into table t1 fields terminated by ',';
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
set statement timestamp=777777777 for
|
||||||
|
load data infile 'sep8605.txt' into table t1 fields terminated by ','
|
||||||
|
(@a,a2,a3,b,c) set a1=100-@a;
|
||||||
|
select 100-a1,a2,a3,b,c from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
--write_file $datadir/test/fix8605.txt
|
||||||
|
00012010-11-12 01:02:030010000000000000000
|
||||||
|
00052010-11-12 01:02:030014000200000000000
|
||||||
|
00082010-11-12 01:02:030030000300000000000
|
||||||
|
00992010-11-12 01:02:030000000100000000000
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
set statement timestamp=777777777 for
|
||||||
|
load data infile 'fix8605.txt' into table t1 fields terminated by '';
|
||||||
|
select * from t1;
|
||||||
|
delete from t1;
|
||||||
|
|
||||||
|
--write_file $datadir/test/xml8605.txt
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<field name="a1">1</field>
|
||||||
|
<field name="a2">2010-11-12 1:2:3</field>
|
||||||
|
<field name="a3">10</field>
|
||||||
|
<field name="b">0</field>
|
||||||
|
<field name="c">0</field>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<field name="a2">2010-11-12 1:2:3</field>
|
||||||
|
<field name="a3">11</field>
|
||||||
|
<field name="b">1</field>
|
||||||
|
<field name="c">2</field>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<field name="a1">3</field>
|
||||||
|
<field name="a3">12</field>
|
||||||
|
<field name="b">0</field>
|
||||||
|
<field name="c">0</field>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<field name="a1">4</field>
|
||||||
|
<field name="a3">13</field>
|
||||||
|
<field name="b">2</field>
|
||||||
|
<field name="c">908070605</field>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<field name="a1">5</field>
|
||||||
|
<field name="a2">2010-11-12 1:2:3</field>
|
||||||
|
<field name="a3">14</field>
|
||||||
|
<field name="b">2</field>
|
||||||
|
<field name="c">0</field>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<field name="a1">6</field>
|
||||||
|
<field name="a2">2010-11-12 1:2:3</field>
|
||||||
|
<field name="b">0</field>
|
||||||
|
<field name="c">0</field>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<field name="a1">7</field>
|
||||||
|
<field name="a2">2010-11-12 1:2:3</field>
|
||||||
|
<field name="b">3</field>
|
||||||
|
<field name="c">20</field>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<field name="a1">8</field>
|
||||||
|
<field name="a2">2010-11-12 1:2:3</field>
|
||||||
|
<field name="a3">30</field>
|
||||||
|
<field name="b">3</field>
|
||||||
|
<field name="c">0</field>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<field name="a1">99</field>
|
||||||
|
<field name="a2">2010-11-12 1:2:3</field>
|
||||||
|
<field name="a3">0</field>
|
||||||
|
<field name="b">1</field>
|
||||||
|
<field name="c">0</field>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
set statement timestamp=777777777 for
|
||||||
|
load xml infile 'xml8605.txt' into table t1 rows identified by '<row>';
|
||||||
|
select * from t1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# explicit DEFAULT
|
||||||
|
create table t1 (a int not null default 5, b int, c int);
|
||||||
|
create trigger trgi before insert on t1 for each row set new.b=new.c;
|
||||||
|
insert t1 values (DEFAULT,2,1);
|
||||||
|
select * from t1;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Two statements, first fails, second uses an implicit default
|
||||||
|
create table t1 (a int not null, b int not null default 5, c int);
|
||||||
|
delimiter |;
|
||||||
|
create trigger trgi before insert on t1 for each row
|
||||||
|
begin
|
||||||
|
if new.c=1 then set new.a=1, new.b=1; end if;
|
||||||
|
if new.c=2 then set new.a=NULL, new.b=NULL; end if;
|
||||||
|
if new.c=3 then set new.a=2; end if;
|
||||||
|
end|
|
||||||
|
delimiter ;|
|
||||||
|
|
||||||
|
insert t1 values (9, 9, 1);
|
||||||
|
--error ER_BAD_NULL_ERROR
|
||||||
|
insert t1 values (9, 9, 2);
|
||||||
|
insert t1 (a,c) values (9, 3);
|
||||||
|
select * from t1;
|
||||||
|
drop table t1;
|
20
sql/field.h
20
sql/field.h
@ -844,7 +844,7 @@ public:
|
|||||||
my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values -
|
my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values -
|
||||||
table->record[0]);
|
table->record[0]);
|
||||||
memcpy(ptr, ptr + l_offset, pack_length());
|
memcpy(ptr, ptr + l_offset, pack_length());
|
||||||
if (null_ptr)
|
if (maybe_null_in_table())
|
||||||
*null_ptr= ((*null_ptr & (uchar) ~null_bit) |
|
*null_ptr= ((*null_ptr & (uchar) ~null_bit) |
|
||||||
(null_ptr[l_offset] & null_bit));
|
(null_ptr[l_offset] & null_bit));
|
||||||
}
|
}
|
||||||
@ -1024,9 +1024,9 @@ public:
|
|||||||
{ return null_ptr && (null_ptr[row_offset] & null_bit); }
|
{ return null_ptr && (null_ptr[row_offset] & null_bit); }
|
||||||
inline bool is_null_in_record(const uchar *record) const
|
inline bool is_null_in_record(const uchar *record) const
|
||||||
{
|
{
|
||||||
if (!null_ptr)
|
if (maybe_null_in_table())
|
||||||
return 0;
|
return record[(uint) (null_ptr - table->record[0])] & null_bit;
|
||||||
return record[(uint) (null_ptr - table->record[0])] & null_bit;
|
return 0;
|
||||||
}
|
}
|
||||||
inline void set_null(my_ptrdiff_t row_offset= 0)
|
inline void set_null(my_ptrdiff_t row_offset= 0)
|
||||||
{ if (null_ptr) null_ptr[row_offset]|= null_bit; }
|
{ if (null_ptr) null_ptr[row_offset]|= null_bit; }
|
||||||
@ -1035,10 +1035,19 @@ public:
|
|||||||
inline bool maybe_null(void) const
|
inline bool maybe_null(void) const
|
||||||
{ return null_ptr != 0 || table->maybe_null; }
|
{ return null_ptr != 0 || table->maybe_null; }
|
||||||
|
|
||||||
/* @return true if this field is NULL-able, false otherwise. */
|
/* @return true if this field is NULL-able (even if temporarily) */
|
||||||
inline bool real_maybe_null(void) const { return null_ptr != 0; }
|
inline bool real_maybe_null(void) const { return null_ptr != 0; }
|
||||||
uint null_offset(const uchar *record) const
|
uint null_offset(const uchar *record) const
|
||||||
{ return (uint) (null_ptr - record); }
|
{ return (uint) (null_ptr - record); }
|
||||||
|
/*
|
||||||
|
For a NULL-able field (that can actually store a NULL value in a table)
|
||||||
|
null_ptr points to the "null bitmap" in the table->record[0] header. For
|
||||||
|
NOT NULL fields it is either 0 or points outside table->record[0] into the
|
||||||
|
table->triggers->extra_null_bitmap (so that the field can store a NULL
|
||||||
|
value temporarily, only in memory)
|
||||||
|
*/
|
||||||
|
bool maybe_null_in_table() const
|
||||||
|
{ return null_ptr >= table->record[0] && null_ptr <= ptr; }
|
||||||
|
|
||||||
uint null_offset() const
|
uint null_offset() const
|
||||||
{ return null_offset(table->record[0]); }
|
{ return null_offset(table->record[0]); }
|
||||||
@ -3600,6 +3609,7 @@ enum_field_types get_blob_type_from_length(ulong length);
|
|||||||
uint32 calc_pack_length(enum_field_types type,uint32 length);
|
uint32 calc_pack_length(enum_field_types type,uint32 length);
|
||||||
int set_field_to_null(Field *field);
|
int set_field_to_null(Field *field);
|
||||||
int set_field_to_null_with_conversions(Field *field, bool no_conversions);
|
int set_field_to_null_with_conversions(Field *field, bool no_conversions);
|
||||||
|
int convert_null_to_field_value_or_error(Field *field);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following are for the interface with the .frm file
|
The following are for the interface with the .frm file
|
||||||
|
@ -152,6 +152,36 @@ int set_field_to_null(Field *field)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set TIMESTAMP to NOW(), AUTO_INCREMENT to the next number, or report an error
|
||||||
|
|
||||||
|
@param field Field to update
|
||||||
|
|
||||||
|
@retval
|
||||||
|
0 Field could take 0 or an automatic conversion was used
|
||||||
|
@retval
|
||||||
|
-1 Field could not take NULL and no conversion was used.
|
||||||
|
If no_conversion was not set, an error message is printed
|
||||||
|
*/
|
||||||
|
|
||||||
|
int convert_null_to_field_value_or_error(Field *field)
|
||||||
|
{
|
||||||
|
if (field->type() == MYSQL_TYPE_TIMESTAMP)
|
||||||
|
{
|
||||||
|
((Field_timestamp*) field)->set_time();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
field->reset(); // Note: we ignore any potential failure of reset() here.
|
||||||
|
|
||||||
|
if (field == field->table->next_number_field)
|
||||||
|
{
|
||||||
|
field->table->auto_increment_field_not_null= FALSE;
|
||||||
|
return 0; // field is set in fill_record()
|
||||||
|
}
|
||||||
|
return set_bad_null_error(field, ER_BAD_NULL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Set field to NULL or TIMESTAMP or to next auto_increment number.
|
Set field to NULL or TIMESTAMP or to next auto_increment number.
|
||||||
|
|
||||||
@ -186,26 +216,7 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions)
|
|||||||
if (no_conversions)
|
if (no_conversions)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/*
|
return convert_null_to_field_value_or_error(field);
|
||||||
Check if this is a special type, which will get a special walue
|
|
||||||
when set to NULL (TIMESTAMP fields which allow setting to NULL
|
|
||||||
are handled by first check).
|
|
||||||
*/
|
|
||||||
if (field->type() == MYSQL_TYPE_TIMESTAMP)
|
|
||||||
{
|
|
||||||
((Field_timestamp*) field)->set_time();
|
|
||||||
return 0; // Ok to set time to NULL
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: we ignore any potential failure of reset() here.
|
|
||||||
field->reset();
|
|
||||||
|
|
||||||
if (field == field->table->next_number_field)
|
|
||||||
{
|
|
||||||
field->table->auto_increment_field_not_null= FALSE;
|
|
||||||
return 0; // field is set in fill_record()
|
|
||||||
}
|
|
||||||
return set_bad_null_error(field, ER_BAD_NULL_ERROR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
24
sql/item.cc
24
sql/item.cc
@ -2379,6 +2379,24 @@ bool Item_field::update_table_bitmaps_processor(uchar *arg)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void set_field_to_new_field(Field **field, Field **new_field)
|
||||||
|
{
|
||||||
|
if (*field)
|
||||||
|
{
|
||||||
|
Field *newf= new_field[(*field)->field_index];
|
||||||
|
if ((*field)->ptr == newf->ptr)
|
||||||
|
*field= newf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Item_field::switch_to_nullable_fields_processor(uchar *arg)
|
||||||
|
{
|
||||||
|
Field **new_fields= (Field **)arg;
|
||||||
|
set_field_to_new_field(&field, new_fields);
|
||||||
|
set_field_to_new_field(&result_field, new_fields);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *Item_ident::full_name() const
|
const char *Item_ident::full_name() const
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
@ -8191,9 +8209,8 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
|
|||||||
}
|
}
|
||||||
field_arg->set_default();
|
field_arg->set_default();
|
||||||
return
|
return
|
||||||
!field_arg->is_null_in_record(field_arg->table->s->default_values) &&
|
!field_arg->is_null() &&
|
||||||
field_arg->validate_value_in_record_with_warn(thd,
|
field_arg->validate_value_in_record_with_warn(thd, table->record[0]) &&
|
||||||
field_arg->table->s->default_values) &&
|
|
||||||
thd->is_error() ? -1 : 0;
|
thd->is_error() ? -1 : 0;
|
||||||
}
|
}
|
||||||
return Item_field::save_in_field(field_arg, no_conversions);
|
return Item_field::save_in_field(field_arg, no_conversions);
|
||||||
@ -8387,6 +8404,7 @@ bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it)
|
|||||||
int err_code= item->save_in_field(field, 0);
|
int err_code= item->save_in_field(field, 0);
|
||||||
|
|
||||||
field->table->copy_blobs= copy_blobs_saved;
|
field->table->copy_blobs= copy_blobs_saved;
|
||||||
|
field->set_explicit_default(item);
|
||||||
|
|
||||||
return err_code < 0;
|
return err_code < 0;
|
||||||
}
|
}
|
||||||
|
@ -1605,6 +1605,8 @@ public:
|
|||||||
|
|
||||||
virtual bool check_inner_refs_processor(uchar *arg) { return FALSE; }
|
virtual bool check_inner_refs_processor(uchar *arg) { return FALSE; }
|
||||||
|
|
||||||
|
virtual bool switch_to_nullable_fields_processor(uchar *arg) { return FALSE; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For SP local variable returns pointer to Item representing its
|
For SP local variable returns pointer to Item representing its
|
||||||
current value and pointer to current Item otherwise.
|
current value and pointer to current Item otherwise.
|
||||||
@ -2464,6 +2466,7 @@ public:
|
|||||||
bool vcol_in_partition_func_processor(uchar *bool_arg);
|
bool vcol_in_partition_func_processor(uchar *bool_arg);
|
||||||
bool enumerate_field_refs_processor(uchar *arg);
|
bool enumerate_field_refs_processor(uchar *arg);
|
||||||
bool update_table_bitmaps_processor(uchar *arg);
|
bool update_table_bitmaps_processor(uchar *arg);
|
||||||
|
bool switch_to_nullable_fields_processor(uchar *arg);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
Item_equal *get_item_equal() { return item_equal; }
|
Item_equal *get_item_equal() { return item_equal; }
|
||||||
void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; }
|
void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; }
|
||||||
|
@ -8818,7 +8818,61 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
Prepare Item_field's for fill_record_n_invoke_before_triggers()
|
||||||
|
|
||||||
|
This means redirecting from table->field to
|
||||||
|
table->field_to_fill(), if needed.
|
||||||
|
*/
|
||||||
|
void switch_to_nullable_trigger_fields(List<Item> &items, TABLE *table)
|
||||||
|
{
|
||||||
|
Field** field= table->field_to_fill();
|
||||||
|
|
||||||
|
if (field != table->field)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item> it(items);
|
||||||
|
Item *item;
|
||||||
|
|
||||||
|
while ((item= it++))
|
||||||
|
item->walk(&Item::switch_to_nullable_fields_processor, 1, (uchar*)field);
|
||||||
|
table->triggers->reset_extra_null_bitmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Test NOT NULL constraint after BEFORE triggers
|
||||||
|
*/
|
||||||
|
static bool not_null_fields_have_null_values(TABLE *table)
|
||||||
|
{
|
||||||
|
Field **orig_field= table->field;
|
||||||
|
Field **filled_field= table->field_to_fill();
|
||||||
|
|
||||||
|
if (filled_field != orig_field)
|
||||||
|
{
|
||||||
|
THD *thd=table->in_use;
|
||||||
|
for (uint i=0; i < table->s->fields; i++)
|
||||||
|
{
|
||||||
|
Field *of= orig_field[i];
|
||||||
|
Field *ff= filled_field[i];
|
||||||
|
if (ff != of)
|
||||||
|
{
|
||||||
|
// copy after-update flags to of, copy before-update flags to ff
|
||||||
|
swap_variables(uint32, of->flags, ff->flags);
|
||||||
|
if (ff->is_real_null())
|
||||||
|
{
|
||||||
|
ff->set_notnull(); // for next row WHERE condition in UPDATE
|
||||||
|
if (convert_null_to_field_value_or_error(of) || thd->is_error())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
Fill fields in list with values from the list of items and invoke
|
Fill fields in list with values from the list of items and invoke
|
||||||
before triggers.
|
before triggers.
|
||||||
|
|
||||||
@ -8846,9 +8900,13 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, List<Item> &fields,
|
|||||||
{
|
{
|
||||||
bool result;
|
bool result;
|
||||||
Table_triggers_list *triggers= table->triggers;
|
Table_triggers_list *triggers= table->triggers;
|
||||||
result= (fill_record(thd, table, fields, values, ignore_errors) ||
|
|
||||||
(triggers && triggers->process_triggers(thd, event,
|
result= fill_record(thd, table, fields, values, ignore_errors);
|
||||||
TRG_ACTION_BEFORE, TRUE)));
|
|
||||||
|
if (!result && triggers)
|
||||||
|
result= triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, TRUE) ||
|
||||||
|
not_null_fields_have_null_values(table);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Re-calculate virtual fields to cater for cases when base columns are
|
Re-calculate virtual fields to cater for cases when base columns are
|
||||||
updated by the triggers.
|
updated by the triggers.
|
||||||
@ -8994,9 +9052,12 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, Field **ptr,
|
|||||||
{
|
{
|
||||||
bool result;
|
bool result;
|
||||||
Table_triggers_list *triggers= table->triggers;
|
Table_triggers_list *triggers= table->triggers;
|
||||||
result= (fill_record(thd, table, ptr, values, ignore_errors, FALSE) ||
|
|
||||||
(triggers && triggers->process_triggers(thd, event,
|
result= fill_record(thd, table, ptr, values, ignore_errors, FALSE);
|
||||||
TRG_ACTION_BEFORE, TRUE)));
|
|
||||||
|
if (!result && triggers && *ptr)
|
||||||
|
result= triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, TRUE) ||
|
||||||
|
not_null_fields_have_null_values(table);
|
||||||
/*
|
/*
|
||||||
Re-calculate virtual fields to cater for cases when base columns are
|
Re-calculate virtual fields to cater for cases when base columns are
|
||||||
updated by the triggers.
|
updated by the triggers.
|
||||||
|
@ -150,6 +150,7 @@ bool find_and_use_temporary_table(THD *thd, const TABLE_LIST *tl,
|
|||||||
TABLE *find_temporary_table(THD *thd, const char *table_key,
|
TABLE *find_temporary_table(THD *thd, const char *table_key,
|
||||||
uint table_key_length);
|
uint table_key_length);
|
||||||
void close_thread_tables(THD *thd);
|
void close_thread_tables(THD *thd);
|
||||||
|
void switch_to_nullable_trigger_fields(List<Item> &items, TABLE *);
|
||||||
bool fill_record_n_invoke_before_triggers(THD *thd, TABLE *table,
|
bool fill_record_n_invoke_before_triggers(THD *thd, TABLE *table,
|
||||||
List<Item> &fields,
|
List<Item> &fields,
|
||||||
List<Item> &values,
|
List<Item> &values,
|
||||||
|
@ -761,6 +761,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
|||||||
*/
|
*/
|
||||||
table_list->next_local= 0;
|
table_list->next_local= 0;
|
||||||
context->resolve_in_table_list_only(table_list);
|
context->resolve_in_table_list_only(table_list);
|
||||||
|
switch_to_nullable_trigger_fields(*values, table);
|
||||||
|
|
||||||
while ((values= its++))
|
while ((values= its++))
|
||||||
{
|
{
|
||||||
@ -772,6 +773,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
|||||||
}
|
}
|
||||||
if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
|
if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
|
||||||
goto abort;
|
goto abort;
|
||||||
|
switch_to_nullable_trigger_fields(*values, table);
|
||||||
}
|
}
|
||||||
its.rewind ();
|
its.rewind ();
|
||||||
|
|
||||||
@ -870,6 +872,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
|||||||
error= 1;
|
error= 1;
|
||||||
|
|
||||||
table->reset_default_fields();
|
table->reset_default_fields();
|
||||||
|
switch_to_nullable_trigger_fields(fields, table);
|
||||||
|
switch_to_nullable_trigger_fields(update_fields, table);
|
||||||
|
switch_to_nullable_trigger_fields(update_values, table);
|
||||||
|
|
||||||
if (fields.elements || !value_count)
|
if (fields.elements || !value_count)
|
||||||
{
|
{
|
||||||
@ -943,8 +948,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
|||||||
share->default_values[share->null_bytes - 1];
|
share->default_values[share->null_bytes - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fill_record_n_invoke_before_triggers(thd, table, table->field, *values, 0,
|
if (fill_record_n_invoke_before_triggers(thd, table, table->field_to_fill(),
|
||||||
TRG_EVENT_INSERT))
|
*values, 0, TRG_EVENT_INSERT))
|
||||||
{
|
{
|
||||||
if (values_list.elements != 1 && ! thd->is_error())
|
if (values_list.elements != 1 && ! thd->is_error())
|
||||||
{
|
{
|
||||||
@ -3704,8 +3709,8 @@ void select_insert::store_values(List<Item> &values)
|
|||||||
fill_record_n_invoke_before_triggers(thd, table, *fields, values, 1,
|
fill_record_n_invoke_before_triggers(thd, table, *fields, values, 1,
|
||||||
TRG_EVENT_INSERT);
|
TRG_EVENT_INSERT);
|
||||||
else
|
else
|
||||||
fill_record_n_invoke_before_triggers(thd, table, table->field, values, 1,
|
fill_record_n_invoke_before_triggers(thd, table, table->field_to_fill(),
|
||||||
TRG_EVENT_INSERT);
|
values, 1, TRG_EVENT_INSERT);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool select_insert::prepare_eof()
|
bool select_insert::prepare_eof()
|
||||||
|
@ -295,6 +295,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||||||
if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
|
if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
switch_to_nullable_trigger_fields(fields_vars, table);
|
||||||
|
switch_to_nullable_trigger_fields(set_fields, table);
|
||||||
|
switch_to_nullable_trigger_fields(set_values, table);
|
||||||
|
|
||||||
table->prepare_triggers_for_insert_stmt_or_event();
|
table->prepare_triggers_for_insert_stmt_or_event();
|
||||||
table->mark_columns_needed_for_insert();
|
table->mark_columns_needed_for_insert();
|
||||||
|
@ -1073,29 +1073,71 @@ Table_triggers_list::~Table_triggers_list()
|
|||||||
@retval
|
@retval
|
||||||
True error
|
True error
|
||||||
*/
|
*/
|
||||||
bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
|
bool Table_triggers_list::prepare_record_accessors(TABLE *table)
|
||||||
{
|
{
|
||||||
Field **fld, **old_fld;
|
Field **fld, **trg_fld;
|
||||||
|
|
||||||
if (!(record1_field= (Field **)alloc_root(&table->mem_root,
|
if ((bodies[TRG_EVENT_INSERT][TRG_ACTION_BEFORE] ||
|
||||||
(table->s->fields + 1) *
|
bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE])
|
||||||
sizeof(Field*))))
|
&& (table->s->stored_fields != table->s->null_fields))
|
||||||
return 1;
|
|
||||||
|
|
||||||
for (fld= table->field, old_fld= record1_field; *fld; fld++, old_fld++)
|
|
||||||
{
|
{
|
||||||
/*
|
int null_bytes= (table->s->stored_fields - table->s->null_fields + 7)/8;
|
||||||
QQ: it is supposed that it is ok to use this function for field
|
if (!(extra_null_bitmap= (uchar*)alloc_root(&table->mem_root, null_bytes)))
|
||||||
cloning...
|
return 1;
|
||||||
*/
|
if (!(record0_field= (Field **)alloc_root(&table->mem_root,
|
||||||
if (!(*old_fld= (*fld)->make_new_field(&table->mem_root, table,
|
(table->s->fields + 1) *
|
||||||
table == (*fld)->table)))
|
sizeof(Field*))))
|
||||||
return 1;
|
return 1;
|
||||||
(*old_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] -
|
|
||||||
table->record[0]));
|
|
||||||
}
|
|
||||||
*old_fld= 0;
|
|
||||||
|
|
||||||
|
uchar *null_ptr= extra_null_bitmap;
|
||||||
|
uchar null_bit= 1;
|
||||||
|
for (fld= table->field, trg_fld= record0_field; *fld; fld++, trg_fld++)
|
||||||
|
{
|
||||||
|
if (!(*fld)->null_ptr && !(*fld)->vcol_info)
|
||||||
|
{
|
||||||
|
Field *f;
|
||||||
|
if (!(f= *trg_fld= (*fld)->make_new_field(&table->mem_root, table,
|
||||||
|
table == (*fld)->table)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
f->null_ptr= null_ptr;
|
||||||
|
f->null_bit= null_bit;
|
||||||
|
if (null_bit == 128)
|
||||||
|
null_ptr++, null_bit= 1;
|
||||||
|
else
|
||||||
|
null_bit*= 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*trg_fld= *fld;
|
||||||
|
}
|
||||||
|
*trg_fld= 0;
|
||||||
|
DBUG_ASSERT(null_ptr <= extra_null_bitmap + null_bytes);
|
||||||
|
bzero(extra_null_bitmap, null_bytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
record0_field= table->field;
|
||||||
|
|
||||||
|
if (bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE] ||
|
||||||
|
bodies[TRG_EVENT_UPDATE][TRG_ACTION_AFTER] ||
|
||||||
|
bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
|
||||||
|
bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER])
|
||||||
|
{
|
||||||
|
if (!(record1_field= (Field **)alloc_root(&table->mem_root,
|
||||||
|
(table->s->fields + 1) *
|
||||||
|
sizeof(Field*))))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (fld= table->field, trg_fld= record1_field; *fld; fld++, trg_fld++)
|
||||||
|
{
|
||||||
|
if (!(*trg_fld= (*fld)->make_new_field(&table->mem_root, table,
|
||||||
|
table == (*fld)->table)))
|
||||||
|
return 1;
|
||||||
|
(*trg_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] -
|
||||||
|
table->record[0]));
|
||||||
|
}
|
||||||
|
*trg_fld= 0;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1320,13 +1362,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
table->triggers= triggers;
|
table->triggers= triggers;
|
||||||
status_var_increment(thd->status_var.feature_trigger);
|
status_var_increment(thd->status_var.feature_trigger);
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: This could be avoided if there is no triggers
|
|
||||||
for UPDATE and DELETE.
|
|
||||||
*/
|
|
||||||
if (!names_only && triggers->prepare_record1_accessors(table))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
|
|
||||||
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
|
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
|
||||||
List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
|
List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
|
||||||
List_iterator_fast<LEX_STRING> it_client_cs_name(triggers->client_cs_names);
|
List_iterator_fast<LEX_STRING> it_client_cs_name(triggers->client_cs_names);
|
||||||
@ -1539,6 +1574,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
thd->spcont= save_spcont;
|
thd->spcont= save_spcont;
|
||||||
thd->variables.sql_mode= save_sql_mode;
|
thd->variables.sql_mode= save_sql_mode;
|
||||||
|
|
||||||
|
if (!names_only && triggers->prepare_record_accessors(table))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
err_with_lex_cleanup:
|
err_with_lex_cleanup:
|
||||||
@ -2107,13 +2145,13 @@ bool Table_triggers_list::process_triggers(THD *thd,
|
|||||||
if (old_row_is_record1)
|
if (old_row_is_record1)
|
||||||
{
|
{
|
||||||
old_field= record1_field;
|
old_field= record1_field;
|
||||||
new_field= trigger_table->field;
|
new_field= record0_field;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(event == TRG_EVENT_DELETE);
|
DBUG_ASSERT(event == TRG_EVENT_DELETE);
|
||||||
new_field= record1_field;
|
new_field= record1_field;
|
||||||
old_field= trigger_table->field;
|
old_field= record0_field;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
This trigger must have been processed by the pre-locking
|
This trigger must have been processed by the pre-locking
|
||||||
|
@ -67,6 +67,13 @@ class Table_triggers_list: public Sql_alloc
|
|||||||
grouped by event and action_time.
|
grouped by event and action_time.
|
||||||
*/
|
*/
|
||||||
Item_trigger_field *trigger_fields[TRG_EVENT_MAX][TRG_ACTION_MAX];
|
Item_trigger_field *trigger_fields[TRG_EVENT_MAX][TRG_ACTION_MAX];
|
||||||
|
/**
|
||||||
|
Copy of TABLE::Field array which all fields made nullable
|
||||||
|
(using extra_null_bitmap, if needed). Used for NEW values in
|
||||||
|
BEFORE INSERT/UPDATE triggers.
|
||||||
|
*/
|
||||||
|
Field **record0_field;
|
||||||
|
uchar *extra_null_bitmap;
|
||||||
/**
|
/**
|
||||||
Copy of TABLE::Field array with field pointers set to TABLE::record[1]
|
Copy of TABLE::Field array with field pointers set to TABLE::record[1]
|
||||||
buffer instead of TABLE::record[0] (used for OLD values in on UPDATE
|
buffer instead of TABLE::record[0] (used for OLD values in on UPDATE
|
||||||
@ -143,7 +150,8 @@ public:
|
|||||||
/* End of character ser context. */
|
/* End of character ser context. */
|
||||||
|
|
||||||
Table_triggers_list(TABLE *table_arg)
|
Table_triggers_list(TABLE *table_arg)
|
||||||
:record1_field(0), trigger_table(table_arg),
|
:record0_field(0), extra_null_bitmap(0), record1_field(0),
|
||||||
|
trigger_table(table_arg),
|
||||||
m_has_unparseable_trigger(false)
|
m_has_unparseable_trigger(false)
|
||||||
{
|
{
|
||||||
bzero((char *)bodies, sizeof(bodies));
|
bzero((char *)bodies, sizeof(bodies));
|
||||||
@ -211,8 +219,16 @@ public:
|
|||||||
trg_event_type event_type,
|
trg_event_type event_type,
|
||||||
trg_action_time_type action_time);
|
trg_action_time_type action_time);
|
||||||
|
|
||||||
|
Field **nullable_fields() { return record0_field; }
|
||||||
|
void reset_extra_null_bitmap()
|
||||||
|
{
|
||||||
|
int null_bytes= (trigger_table->s->stored_fields -
|
||||||
|
trigger_table->s->null_fields + 7)/8;
|
||||||
|
bzero(extra_null_bitmap, null_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool prepare_record1_accessors(TABLE *table);
|
bool prepare_record_accessors(TABLE *table);
|
||||||
LEX_STRING* change_table_name_in_trignames(const char *old_db_name,
|
LEX_STRING* change_table_name_in_trignames(const char *old_db_name,
|
||||||
const char *new_db_name,
|
const char *new_db_name,
|
||||||
LEX_STRING *new_table_name,
|
LEX_STRING *new_table_name,
|
||||||
@ -234,6 +250,13 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline Field **TABLE::field_to_fill()
|
||||||
|
{
|
||||||
|
return triggers && triggers->nullable_fields() ? triggers->nullable_fields()
|
||||||
|
: field;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern const LEX_STRING trg_action_time_type_names[];
|
extern const LEX_STRING trg_action_time_type_names[];
|
||||||
extern const LEX_STRING trg_event_type_names[];
|
extern const LEX_STRING trg_event_type_names[];
|
||||||
|
|
||||||
|
@ -455,6 +455,8 @@ int mysql_update(THD *thd,
|
|||||||
}
|
}
|
||||||
init_ftfuncs(thd, select_lex, 1);
|
init_ftfuncs(thd, select_lex, 1);
|
||||||
|
|
||||||
|
switch_to_nullable_trigger_fields(fields, table);
|
||||||
|
switch_to_nullable_trigger_fields(values, table);
|
||||||
table->mark_columns_needed_for_update();
|
table->mark_columns_needed_for_update();
|
||||||
|
|
||||||
table->update_const_key_parts(conds);
|
table->update_const_key_parts(conds);
|
||||||
@ -1766,7 +1768,6 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table_count= update.elements;
|
table_count= update.elements;
|
||||||
update_tables= update.first;
|
update_tables= update.first;
|
||||||
|
|
||||||
@ -1802,7 +1803,15 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
|||||||
/* Allocate copy fields */
|
/* Allocate copy fields */
|
||||||
max_fields=0;
|
max_fields=0;
|
||||||
for (i=0 ; i < table_count ; i++)
|
for (i=0 ; i < table_count ; i++)
|
||||||
|
{
|
||||||
set_if_bigger(max_fields, fields_for_table[i]->elements + leaf_table_count);
|
set_if_bigger(max_fields, fields_for_table[i]->elements + leaf_table_count);
|
||||||
|
if (fields_for_table[i]->elements)
|
||||||
|
{
|
||||||
|
TABLE *table= ((Item_field*)(fields_for_table[i]->head()))->field->table;
|
||||||
|
switch_to_nullable_trigger_fields(*fields_for_table[i], table);
|
||||||
|
switch_to_nullable_trigger_fields(*values_for_table[i], table);
|
||||||
|
}
|
||||||
|
}
|
||||||
copy_field= new Copy_field[max_fields];
|
copy_field= new Copy_field[max_fields];
|
||||||
DBUG_RETURN(thd->is_fatal_error != 0);
|
DBUG_RETURN(thd->is_fatal_error != 0);
|
||||||
}
|
}
|
||||||
|
@ -1386,6 +1386,7 @@ public:
|
|||||||
bool prepare_triggers_for_delete_stmt_or_event();
|
bool prepare_triggers_for_delete_stmt_or_event();
|
||||||
bool prepare_triggers_for_update_stmt_or_event();
|
bool prepare_triggers_for_update_stmt_or_event();
|
||||||
|
|
||||||
|
inline Field **field_to_fill();
|
||||||
bool validate_default_values_of_unset_fields(THD *thd) const;
|
bool validate_default_values_of_unset_fields(THD *thd) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user