diff --git a/mysql-test/main/cte_update_delete.result b/mysql-test/main/cte_update_delete.result new file mode 100644 index 0000000000000..bcc89cea11469 --- /dev/null +++ b/mysql-test/main/cte_update_delete.result @@ -0,0 +1,982 @@ +# +# MDEV-37220 Allow UPDATE/DELETE to read from a CTE +# +create table t1 +( +a int not null, +b int, +c int, +d int, +amount decimal, +key t1_ix1 (a,b) +); +insert into t1 values (0, NULL, 0, NULL, 10.0000), (1, 1, 1, 1, 10.0000), +(2, 2, 2, 2, 20.0000), (3, 3, 3, 3, 30.0000), (4, 4, 4, 4, 40.0000), +(5, 5, 5, 5, NULL), (6, 6, 6, 6, NULL), (7, 7, 7, 7, 70.0000), +(8, 8, 8, 8, 80.0000); +create table t2 +( +a int NOT NULL, +b int, +name varchar(50), +key t2_ix1 (a,b) +); +insert into t2 values (0, NULL, 'a'), (1, NULL, 'A'), (2, 2, 'B'), (3,3, 'C'), +(4,4, 'D'), (5,5, NULL), (6,6, NULL), (7,7, 'E'), (8,8, 'F'), (9,9, 'G'), +(10,10,'H'), (11,11, NULL), (12,12, NULL); +create table t3 +( +a int, +b int, +description varchar(50) +); +create table t4 as select * from t1; +create table t5 as select * from t2; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +select * from t3; +a b description +1 1 iron +2 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +# update, single table syntax, subq in set +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 +set t3.a = (select a from cte where b in (select b from cte2) and d = t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 +4 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using where +4 DEPENDENT SUBQUERY t2 index NULL t2_ix1 9 NULL 13 Using where; Using index; FirstMatch(t1); Using join buffer (flat, BNL join) +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 +set t3.a = (select a from cte where b in (select b from cte2) and d = t3.a); +select * from t3; +a b description +NULL 1 iron +2 2 wood +NULL NULL gold +NULL 3 silver +NULL 4 lead +NULL 5 tin +NULL 6 platinum +NULL 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +create procedure p() with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 +set t3.a = (select a from cte where b in (select b from cte2) and d = t3.a); +call p(); +drop procedure p; +select * from t3; +a b description +NULL 1 iron +2 2 wood +NULL NULL gold +NULL 3 silver +NULL 4 lead +NULL 5 tin +NULL 6 platinum +NULL 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +prepare s from 'with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 +set t3.a = (select a from cte where b in (select b from cte2) and d = t3.a)'; +execute s; +select * from t3; +a b description +NULL 1 iron +2 2 wood +NULL NULL gold +NULL 3 silver +NULL 4 lead +NULL 5 tin +NULL 6 platinum +NULL 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +execute s; +select * from t3; +a b description +NULL 1 iron +2 2 wood +NULL NULL gold +NULL 3 silver +NULL 4 lead +NULL 5 tin +NULL 6 platinum +NULL 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop prepare s; +# update, single table syntax, subq in set, cte used twice +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 +set t3.a = (select a from cte +where +(b in (select b from cte2 where cte2.a = cte.a) or +b in (select b from cte2 where cte2.b = cte.a)) and +d = t3.a +); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 +4 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using where +6 DEPENDENT SUBQUERY t2 index t2_ix1 t2_ix1 9 NULL 13 Using where; Using index +5 DEPENDENT SUBQUERY t2 ref t2_ix1 t2_ix1 9 test.t1.a,func 1 Using where; Using index +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 +set t3.a = (select a from cte +where +(b in (select b from cte2 where cte2.a = cte.a) or +b in (select b from cte2 where cte2.b = cte.a)) and +d = t3.a +); +select * from t3; +a b description +NULL 1 iron +2 2 wood +NULL NULL gold +NULL 3 silver +NULL 4 lead +NULL 5 tin +NULL 6 platinum +NULL 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +create procedure p() with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 +set t3.a = (select a from cte +where +(b in (select b from cte2 where cte2.a = cte.a) or +b in (select b from cte2 where cte2.b = cte.a)) and +d = t3.a +); +call p(); +drop procedure p; +select * from t3; +a b description +NULL 1 iron +2 2 wood +NULL NULL gold +NULL 3 silver +NULL 4 lead +NULL 5 tin +NULL 6 platinum +NULL 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +prepare s from 'with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 +set t3.a = (select a from cte +where +(b in (select b from cte2 where cte2.a = cte.a) or +b in (select b from cte2 where cte2.b = cte.a)) and +d = t3.a +)'; +execute s; +select * from t3; +a b description +NULL 1 iron +2 2 wood +NULL NULL gold +NULL 3 silver +NULL 4 lead +NULL 5 tin +NULL 6 platinum +NULL 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +execute s; +select * from t3; +a b description +NULL 1 iron +2 2 wood +NULL NULL gold +NULL 3 silver +NULL 4 lead +NULL 5 tin +NULL 6 platinum +NULL 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop prepare s; +# multi table syntax, subq in set and where +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3,cte +set t3.a = cte.a+1 where cte.b in (select b from cte2) and d = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 5 test.t3.a 1 Using where +1 PRIMARY t2 index NULL t2_ix1 9 NULL 13 Using where; Using index; FirstMatch() +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3,cte +set t3.a = cte.a+1 where cte.b in (select b from cte2) and d = t3.a; +select * from t3; +a b description +1 1 iron +3 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +create procedure p() with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3,cte +set t3.a = cte.a+1 where cte.b in (select b from cte2) and d = t3.a; +call p(); +drop procedure p; +select * from t3; +a b description +1 1 iron +3 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +# multi table syntax, subq in set and where, more complex CTEs +explain with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), +cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +update t3,cte, t4 +set t3.a = cte.a+1, t4.a = cte.a+2 +where cte.b in (select b from cte2) and cte.d = t3.a and cte.b = t4.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 5 test.t3.a 8 Using where +1 PRIMARY ref key0 key0 5 cte.b 1 FirstMatch() +1 PRIMARY t4 ALL NULL NULL NULL NULL 9 Using where +3 DERIVED t2 ALL NULL NULL NULL NULL 13 Using where +3 DERIVED t5 ALL NULL NULL NULL NULL 13 Using where; Using join buffer (flat, BNL join) +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +2 DERIVED t4 ALL NULL NULL NULL NULL 9 Using where; Using join buffer (flat, BNL join) +with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), +cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +update t3,cte, t4 +set t3.a = cte.a+1, t4.a = cte.a+2 +where cte.b in (select b from cte2) and cte.d = t3.a and cte.b = t4.a; +select * from t3; +a b description +1 1 iron +3 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +select * from t4; +a b c d amount +0 NULL 0 NULL 10 +1 1 1 1 10 +4 2 2 2 20 +3 3 3 3 30 +4 4 4 4 40 +5 5 5 5 NULL +6 6 6 6 NULL +7 7 7 7 70 +8 8 8 8 80 +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop table t4; +create table t4 as select * from t1; +create procedure p() with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), +cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +update t3,cte, t4 +set t3.a = cte.a+1, t4.a = cte.a+2 +where cte.b in (select b from cte2) and cte.d = t3.a and cte.b = t4.a; +call p(); +drop procedure p; +select * from t3; +a b description +1 1 iron +3 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +select * from t4; +a b c d amount +0 NULL 0 NULL 10 +1 1 1 1 10 +4 2 2 2 20 +3 3 3 3 30 +4 4 4 4 40 +5 5 5 5 NULL +6 6 6 6 NULL +7 7 7 7 70 +8 8 8 8 80 +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop table t4; +create table t4 as select * from t1; +prepare s from 'with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), +cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +update t3,cte, t4 +set t3.a = cte.a+1, t4.a = cte.a+2 +where cte.b in (select b from cte2) and cte.d = t3.a and cte.b = t4.a'; +execute s; +select * from t3; +a b description +1 1 iron +3 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +select * from t4; +a b c d amount +0 NULL 0 NULL 10 +1 1 1 1 10 +4 2 2 2 20 +3 3 3 3 30 +4 4 4 4 40 +5 5 5 5 NULL +6 6 6 6 NULL +7 7 7 7 70 +8 8 8 8 80 +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop table t4; +create table t4 as select * from t1; +execute s; +select * from t3; +a b description +1 1 iron +3 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +select * from t4; +a b c d amount +0 NULL 0 NULL 10 +1 1 1 1 10 +4 2 2 2 20 +3 3 3 3 30 +4 4 4 4 40 +5 5 5 5 NULL +6 6 6 6 NULL +7 7 7 7 70 +8 8 8 8 80 +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop prepare s; +drop table t4; +create table t4 as select * from t1; +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 left join cte on t3.b = cte.b +set t3.a = cte.a+1 where cte.b in (select b from cte2) and d = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 10 test.t3.b,test.t3.a 1 +1 PRIMARY t2 index NULL t2_ix1 9 NULL 13 Using where; Using index; FirstMatch() +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3 left join cte on t3.b = cte.b +set t3.a = cte.a+1 where cte.b in (select b from cte2) and d = t3.a; +select * from t3; +a b description +1 1 iron +3 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3, cte, cte2 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 5 test.t3.a 1 Using where +1 PRIMARY ref key0 key0 5 cte.b 1 +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +3 DERIVED t2 ALL NULL NULL NULL NULL 13 Using where +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update t3, cte, cte2 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +select * from t3; +a b description +1 1 iron +4 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key1 key1 5 test.t3.a 1 Using where +1 PRIMARY ref key0 key0 5 cte.b 1 +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +3 DERIVED t2 ALL NULL NULL NULL NULL 13 Using where +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +select * from t3; +a b description +1 1 iron +4 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +explain with cte as (select * from t1 where c < 5 group by a), +cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key1 key1 5 test.t3.a 1 Using where +1 PRIMARY ref key0 key0 5 cte.b 1 +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where; Using temporary; Using filesort +3 DERIVED t2 ALL NULL NULL NULL NULL 13 Using where; Using temporary; Using filesort +with cte as (select * from t1 where c < 5 group by a), +cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +select * from t3; +a b description +1 1 iron +4 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +create view v1 as select * from t1; +explain with cte as (select * from v1 where c < 5 group by a), +cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key1 key1 5 test.t3.a 1 Using where +1 PRIMARY ref key0 key0 5 cte.b 1 +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where; Using temporary; Using filesort +3 DERIVED t2 ALL NULL NULL NULL NULL 13 Using where; Using temporary; Using filesort +with cte as (select * from v1 where c < 5 group by a), +cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +select * from t3; +a b description +1 1 iron +4 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +with T as (select * from t1) update T set T.a=3; +ERROR HY000: The target table T of the UPDATE is not updatable +with T as (select * from v1) update T set T.a=3; +ERROR HY000: The target table T of the UPDATE is not updatable +with T as (select * from t1) delete from T where a=3; +ERROR HY000: The target table T of the DELETE is not updatable +with T as (select * from v1) delete from T where a=3; +ERROR HY000: The target table T of the DELETE is not updatable +drop view v1; +create view v1 as select * from t1 where b IS NOT NULL limit 1; +explain with cte as (select * from v1 where c < 5 group by a), +cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where d = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 5 test.t3.a 1 +1 PRIMARY ALL NULL NULL NULL NULL 13 +2 DERIVED ALL NULL NULL NULL NULL 2 Using where; Using temporary; Using filesort +4 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +3 DERIVED t2 ALL NULL NULL NULL NULL 13 Using where; Using temporary; Using filesort +with cte as (select * from v1 where c < 5 group by a), +cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where d = t3.a; +select * from t3; +a b description +3 1 iron +2 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop view v1; +CREATE FUNCTION f1 () RETURNS BLOB RETURN 1; +CREATE TABLE tf (f1 DATE); +INSERT INTO tf VALUES('2001-01-01'); +explain with cte as (select f1 as a, f1() as b, 2 as d from tf), +cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY system NULL NULL NULL NULL 1 +1 PRIMARY ref key0 key0 5 const 1 Using where +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +2 DERIVED tf system NULL NULL NULL NULL 1 +3 DERIVED t2 ALL NULL NULL NULL NULL 13 Using where; Using temporary; Using filesort +with cte as (select f1 as a, f1() as b, 2 as d from tf), +cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +select * from t3; +a b description +1 1 iron +2 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop function f1; +drop table tf; +# delete single table syntax +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +where t3.a = (select a from cte where b in (select b from cte2)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +4 SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using where +4 SUBQUERY t2 index NULL t2_ix1 9 NULL 13 Using where; Using index; FirstMatch(t1); Using join buffer (flat, BNL join) +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +where t3.a = (select a from cte where b in (select b from cte2)); +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +create procedure p() with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +where t3.a = (select a from cte where b in (select b from cte2)); +call p(); +drop procedure p; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +# delete multi table syntax +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 4 test.t3.a 1 Using where +1 PRIMARY t2 index NULL t2_ix1 9 NULL 13 Using where; Using index; FirstMatch() +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2); +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +create procedure p() with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2); +call p(); +drop procedure p; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +# delete multi table syntax, multi table delete +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3, t4 +using t3, t4, cte +where t3.a = cte.a and cte.b in (select b from cte2) +and t4.a = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 4 test.t3.a 1 Using where +1 PRIMARY t2 index NULL t2_ix1 9 NULL 13 Using where; Using index; FirstMatch() +1 PRIMARY t4 ALL NULL NULL NULL NULL 9 Using where +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3, t4 +using t3, t4, cte +where t3.a = cte.a and cte.b in (select b from cte2) +and t4.a = t3.a; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +select * from t4; +a b c d amount +0 NULL 0 NULL 10 +1 1 1 1 10 +3 3 3 3 30 +4 4 4 4 40 +5 5 5 5 NULL +6 6 6 6 NULL +7 7 7 7 70 +8 8 8 8 80 +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +create procedure p() with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3, t4 +using t3, t4, cte +where t3.a = cte.a and cte.b in (select b from cte2) +and t4.a = t3.a; +call p(); +drop procedure p; +select * from t3; +a b description +1 1 iron +2 2 wood +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +# delete multi table syntax, multi table CTEs +explain with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), +cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 4 test.t3.a 8 Using where +1 PRIMARY ref key0 key0 5 cte.b 1 FirstMatch() +3 DERIVED t2 ALL NULL NULL NULL NULL 13 Using where +3 DERIVED t5 ALL NULL NULL NULL NULL 13 Using where; Using join buffer (flat, BNL join) +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +2 DERIVED t4 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) +with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), +cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2); +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +create procedure p() with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), +cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2); +call p(); +drop procedure p; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +prepare s from 'with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), +cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2)'; +execute s; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +execute s; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop prepare s; +# delete multi table syntax, limit clause in delete +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2) limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 4 test.t3.a 1 Using where +1 PRIMARY t2 index NULL t2_ix1 9 NULL 13 Using where; Using index; FirstMatch() +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2) limit 1; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +create procedure p() with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2) limit 1; +call p(); +drop procedure p; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +prepare s from 'with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +using t3, cte +where t3.a = cte.a and cte.b in (select b from cte2) limit 1'; +execute s; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +execute s; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop prepare s; +explain with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +using t3, cte, cte2 +where t3.a = cte.a and cte.b = cte2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 8 Using where +1 PRIMARY ref key0 key0 4 test.t3.a 1 Using where +1 PRIMARY ref key0 key0 5 cte.b 1 +2 DERIVED t1 ALL NULL NULL NULL NULL 9 Using where +3 DERIVED t2 ALL NULL NULL NULL NULL 13 Using where +with cte as (select * from t1 where c < 5), +cte2 as (select * from t2 where b < 3) +delete from t3 +using t3, cte, cte2 +where t3.a = cte.a and cte.b = cte2.b; +select * from t3; +a b description +1 1 iron +0 NULL gold +3 3 silver +4 4 lead +5 5 tin +6 6 platinum +7 7 aluminium +truncate t3; +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); +drop table t1, t2, t3, t4, t5; +# End of 12.2 tests diff --git a/mysql-test/main/cte_update_delete.test b/mysql-test/main/cte_update_delete.test new file mode 100644 index 0000000000000..3d5fa62d2de5d --- /dev/null +++ b/mysql-test/main/cte_update_delete.test @@ -0,0 +1,402 @@ +--echo # +--echo # MDEV-37220 Allow UPDATE/DELETE to read from a CTE +--echo # + +create table t1 +( + a int not null, + b int, + c int, + d int, + amount decimal, + key t1_ix1 (a,b) +); + +insert into t1 values (0, NULL, 0, NULL, 10.0000), (1, 1, 1, 1, 10.0000), +(2, 2, 2, 2, 20.0000), (3, 3, 3, 3, 30.0000), (4, 4, 4, 4, 40.0000), +(5, 5, 5, 5, NULL), (6, 6, 6, 6, NULL), (7, 7, 7, 7, 70.0000), +(8, 8, 8, 8, 80.0000); + +create table t2 +( + a int NOT NULL, + b int, + name varchar(50), + key t2_ix1 (a,b) +); + +insert into t2 values (0, NULL, 'a'), (1, NULL, 'A'), (2, 2, 'B'), (3,3, 'C'), +(4,4, 'D'), (5,5, NULL), (6,6, NULL), (7,7, 'E'), (8,8, 'F'), (9,9, 'G'), +(10,10,'H'), (11,11, NULL), (12,12, NULL); + +create table t3 +( + a int, + b int, + description varchar(50) +); + +let $empty_t3= +truncate t3; +let $fill_t3= +insert into t3 values (1, 1, 'iron'),(2,2,'wood'),(0,NULL, 'gold'), +(3, 3, 'silver'), (4, 4, 'lead'), (5, 5, 'tin'), (6, 6, 'platinum'), +(7, 7, 'aluminium'); + +create table t4 as select * from t1; +create table t5 as select * from t2; + +eval $fill_t3; + +select * from t3; + +--echo # update, single table syntax, subq in set +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +update t3 + set t3.a = (select a from cte where b in (select b from cte2) and d = t3.a); +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval create procedure p() $q; +call p(); +drop procedure p; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval prepare s from '$q'; +execute s; +select * from t3; +eval $empty_t3; +eval $fill_t3; +execute s; +select * from t3; +eval $empty_t3; +eval $fill_t3; +drop prepare s; + +--echo # update, single table syntax, subq in set, cte used twice +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +update t3 + set t3.a = (select a from cte + where + (b in (select b from cte2 where cte2.a = cte.a) or + b in (select b from cte2 where cte2.b = cte.a)) and + d = t3.a + ); +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval create procedure p() $q; +call p(); +drop procedure p; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval prepare s from '$q'; +execute s; +select * from t3; +eval $empty_t3; +eval $fill_t3; +execute s; +select * from t3; +eval $empty_t3; +eval $fill_t3; +drop prepare s; + +--echo # multi table syntax, subq in set and where +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +update t3,cte + set t3.a = cte.a+1 where cte.b in (select b from cte2) and d = t3.a; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval create procedure p() $q; +call p(); +drop procedure p; +select * from t3; +eval $empty_t3; +eval $fill_t3; + +--echo # multi table syntax, subq in set and where, more complex CTEs +let $q= +with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), + cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +update t3,cte, t4 + set t3.a = cte.a+1, t4.a = cte.a+2 + where cte.b in (select b from cte2) and cte.d = t3.a and cte.b = t4.a; +eval explain $q; +eval $q; +select * from t3; +select * from t4; +eval $empty_t3; +eval $fill_t3; +drop table t4; +create table t4 as select * from t1; + +eval create procedure p() $q; +call p(); +drop procedure p; +select * from t3; +select * from t4; +eval $empty_t3; +eval $fill_t3; +drop table t4; +create table t4 as select * from t1; +eval prepare s from '$q'; +execute s; +select * from t3; +select * from t4; +eval $empty_t3; +eval $fill_t3; +drop table t4; +create table t4 as select * from t1; +execute s; +select * from t3; +select * from t4; +eval $empty_t3; +eval $fill_t3; +drop prepare s; + +drop table t4; +create table t4 as select * from t1; + +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +update t3 left join cte on t3.b = cte.b + set t3.a = cte.a+1 where cte.b in (select b from cte2) and d = t3.a; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; + +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +update t3, cte, cte2 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; + +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; + +let $q= +with cte as (select * from t1 where c < 5 group by a), + cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; + +create view v1 as select * from t1; +let $q= +with cte as (select * from v1 where c < 5 group by a), + cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; + +--error 1288 +with T as (select * from t1) update T set T.a=3; + +--error 1288 +with T as (select * from v1) update T set T.a=3; + +--error 1288 +with T as (select * from t1) delete from T where a=3; + +--error 1288 +with T as (select * from v1) delete from T where a=3; + +drop view v1; + +create view v1 as select * from t1 where b IS NOT NULL limit 1; +let $q= +with cte as (select * from v1 where c < 5 group by a), + cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where d = t3.a; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; +drop view v1; + +CREATE FUNCTION f1 () RETURNS BLOB RETURN 1; +CREATE TABLE tf (f1 DATE); +INSERT INTO tf VALUES('2001-01-01'); +let $q= +with cte as (select f1 as a, f1() as b, 2 as d from tf), + cte2 as (select * from t2 where b < 3 group by a) +update cte, cte2, t3 set t3.a = cte.a+2 where cte.b = cte2.b and d = t3.a; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; +drop function f1; +drop table tf; + +--echo # delete single table syntax +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +delete from t3 + where t3.a = (select a from cte where b in (select b from cte2)); + +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval create procedure p() $q; +call p(); +drop procedure p; +select * from t3; +eval $empty_t3; +eval $fill_t3; + + +--echo # delete multi table syntax +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +delete from t3 + using t3, cte + where t3.a = cte.a and cte.b in (select b from cte2); +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval create procedure p() $q; +call p(); +drop procedure p; +select * from t3; +eval $empty_t3; +eval $fill_t3; + +--echo # delete multi table syntax, multi table delete +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +delete from t3, t4 + using t3, t4, cte + where t3.a = cte.a and cte.b in (select b from cte2) + and t4.a = t3.a; +eval explain $q; +eval $q; +select * from t3; +select * from t4; +eval $empty_t3; +eval $fill_t3; +eval create procedure p() $q; +call p(); +drop procedure p; +select * from t3; +eval $empty_t3; +eval $fill_t3; + +--echo # delete multi table syntax, multi table CTEs +let $q= +with cte as (select t1.* from t1 left join t4 on t1.d = t4.d where t1.c < 5), + cte2 as (select t2.* from t2, t5 where t2.b < 3 and t2.name = t5.name limit 1) +delete from t3 + using t3, cte + where t3.a = cte.a and cte.b in (select b from cte2); +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval create procedure p() $q; +call p(); +drop procedure p; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval prepare s from '$q'; +execute s; +select * from t3; +eval $empty_t3; +eval $fill_t3; +execute s; +select * from t3; +eval $empty_t3; +eval $fill_t3; +drop prepare s; + + + +--echo # delete multi table syntax, limit clause in delete +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +delete from t3 + using t3, cte + where t3.a = cte.a and cte.b in (select b from cte2) limit 1; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval create procedure p() $q; +call p(); +drop procedure p; +select * from t3; +eval $empty_t3; +eval $fill_t3; +eval prepare s from '$q'; +execute s; +select * from t3; +eval $empty_t3; +eval $fill_t3; +execute s; +select * from t3; +eval $empty_t3; +eval $fill_t3; +drop prepare s; + +let $q= +with cte as (select * from t1 where c < 5), + cte2 as (select * from t2 where b < 3) +delete from t3 + using t3, cte, cte2 + where t3.a = cte.a and cte.b = cte2.b; +eval explain $q; +eval $q; +select * from t3; +eval $empty_t3; +eval $fill_t3; + +drop table t1, t2, t3, t4, t5; + +--echo # End of 12.2 tests diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index d5cb96dc55bea..db8b47c55726f 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -153,6 +153,18 @@ bool LEX::resolve_references_to_cte(TABLE_LIST *tables, { With_element *with_elem= 0; + /* + Add back the tables collected during definition of the CTEs, but cleared + during mysql_init_delete + */ + if (save_list.elements) + { + for (TABLE_LIST *saved= save_list.first; saved; saved= saved->next_global) + add_to_query_tables(saved); + save_list.empty(); + last_table()->next_global= nullptr; + } + for (TABLE_LIST *tbl= tables; tbl != *tables_last; tbl= tbl->next_global) { if (tbl->derived) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 83b3c5ae43c8f..bbf4ac009db12 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3348,7 +3348,13 @@ struct LEX: public Query_tables_list uint select_stack_outer_barrier; SQL_I_List proc_list; - SQL_I_List auxiliary_table_list, save_list; + SQL_I_List auxiliary_table_list; + /* + save_list is used by + - Parsing CREATE TABLE t0 (...) UNION = (t1, t2, t3) + - CTEs for DELETE, see mysql_init_delete(). + */ + SQL_I_List save_list; Column_definition *last_field; Table_function_json_table *json_table; Item_sum *in_sum_func; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ef4a7e37eb67d..55a1206ad6d76 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6070,6 +6070,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) thd->variables.default_master_connection.str) thd->lex->mi.connection_name= null_clex_str; + lex->save_list.empty(); if (lex->sql_command != SQLCOM_SET_OPTION) DEBUG_SYNC(thd, "end_of_statement"); DBUG_RETURN(res || thd->is_error()); @@ -7619,6 +7620,12 @@ void create_select_for_variable(THD *thd, LEX_CSTRING *var_name) void mysql_init_delete(LEX *lex) { + if (lex->with_cte_resolution) + { + // Save and clear lex->query_tables. + lex->save_list.insert(lex->query_tables, &lex->query_tables); + lex->query_tables_last= &lex->query_tables; + } lex->init_select(); lex->first_select_lex()->limit_params.clear(); lex->unit.lim.clear(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index edb8088e6d8cf..db10a59d762bc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -23812,7 +23812,8 @@ free_tmp_table(THD *thd, TABLE *entry) if (entry->pos_in_table_list && entry->pos_in_table_list->table) { - DBUG_ASSERT(entry->pos_in_table_list->table == entry); + DBUG_ASSERT(entry->pos_in_table_list->table == entry || + entry->pos_in_table_list->merged_for_insert); entry->pos_in_table_list->table= NULL; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 0e26b379f2d3b..754f696272b0e 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1886,7 +1886,7 @@ int multi_update::prepare(List ¬_used_values, { TABLE_LIST *table_ref; SQL_I_List update_list; - Item_field *item; + Item *item; List_iterator_fast field_it(*fields); List_iterator_fast value_it(*values); uint i, max_fields; @@ -1975,15 +1975,16 @@ int multi_update::prepare(List ¬_used_values, /* Split fields into fields_for_table[] and values_by_table[] */ - while ((item= (Item_field *) field_it++)) + while ((item= field_it++)) { + Item_field *item_field= (Item_field *)item->real_item(); Item *value= value_it++; - uint offset= item->field->table->pos_in_table_list->shared; + uint offset= item_field->field->table->pos_in_table_list->shared; - if (value->associate_with_target_field(thd, item)) + if (value->associate_with_target_field(thd, item_field)) DBUG_RETURN(1); - fields_for_table[offset]->push_back(item, thd->mem_root); + fields_for_table[offset]->push_back(item_field, thd->mem_root); values_for_table[offset]->push_back(value, thd->mem_root); } if (unlikely(thd->is_fatal_error)) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index dd742bc47f523..5aed54f243c7d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1974,7 +1974,7 @@ rule: '-' '+' '*' '/' '%' '(' ')' ',' '!' '{' '}' '&' '|' -%type with_clause +%type with_clause opt_with_clause %type with_element_head @@ -14092,15 +14092,19 @@ update_table_list: /* Update rows in a table */ update: + opt_with_clause UPDATE_SYM opt_optimizer_hint { LEX *lex= Lex; if (Lex->main_select_push()) MYSQL_YYABORT; lex->init_select(); - Lex->first_select_lex()->set_optimizer_hints($2); + Lex->first_select_lex()->set_optimizer_hints($3); lex->sql_command= SQLCOM_UPDATE; lex->duplicates= DUP_ERROR; + Lex->first_select_lex()->master_unit()->set_with_clause($1); + if ($1) + $1->attach_to(Lex->first_select_lex()); } opt_low_priority opt_ignore update_table_list SET update_list @@ -14128,12 +14132,12 @@ update: be too pessimistic. We will decrease lock level if possible later while processing the statement. */ - slex->set_lock_for_tables($4, slex->table_list.elements == 1, false); + slex->set_lock_for_tables($5, slex->table_list.elements == 1, false); } opt_where_clause opt_order_clause delete_limit_clause { - if ($11) - Select->order_list= *($11); + if ($12) + Select->order_list= *($12); } stmt_end {} ; @@ -14181,6 +14185,7 @@ opt_low_priority: /* Delete rows from a table */ delete: + opt_with_clause DELETE_SYM opt_optimizer_hint { LEX *lex= Lex; @@ -14191,7 +14196,10 @@ delete: mysql_init_delete(lex); lex->ignore= 0; lex->first_select_lex()->order_list.empty(); - lex->first_select_lex()->set_optimizer_hints($2); + lex->first_select_lex()->set_optimizer_hints($3); + lex->first_select_lex()->master_unit()->set_with_clause($1); + if ($1) + $1->attach_to(lex->first_select_lex()); } delete_part2 { @@ -15895,6 +15903,11 @@ temporal_literal: } ; +opt_with_clause: + /* empty */ { $$= NULL; } + | with_clause { $$= $1; } + ; + with_clause: WITH opt_recursive { diff --git a/sql/table.cc b/sql/table.cc index cd5b15421dd39..8f9c6398f07af 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6190,7 +6190,8 @@ bool TABLE_LIST::create_field_translation(THD *thd) It's needed because some items in the select list, like IN subselects, might be substituted for optimized ones. */ - if (is_view() && get_unit()->prepared && !field_translation_updated) + if (is_merged_derived() && + get_unit()->prepared && !field_translation_updated) { field_translation_updated= TRUE; if (static_cast(field_translation_end - field_translation) <