mariadb/mysql-test/main/intersect_all.test
Aleksey Midenkov 10643cffe9 MDEV-37325 Incorrect results for INTERSECT ALL in ORACLE mode
Oracle mode has no priority between set-operators but the current
implementation with disable_index_if_needed() can not work with
arbitrary mix of distinct/non-distinct set-operators as the algorithm
is tied to the properly wrapped version of expression. Index can be
disabled only once and cannot be reenabled afterwards.

To adapt Oracle mode for the aforementioned implementation we
prioritize each set operator with parens in the order of
appearance. So the expression:

  S1 op1 S2 op2 S3 op3 S4

will be rewritten like this:

  (((S1 op1 S2) op2 S3) op3 S4).

The rewritten expression is valid for both Oracle and default mode and
renders the same result. Prioritizing is done with
create_priority_nest() but it was tweaked to work with derived to be
the first operand. Originally create_priority_nest() could wrap only
second operand, like this:

  S1 op1 S2 op2 S3 -> S1 op1 (S2 op2 S3).

Now this behaviour is kept by non-NULL attach_to argument. With NULL
attach_to argument it produces this transformation:

  S1 op1 S2 -> (S1 op1 S2), but to be strict it will look like this:
  SELECT .. FROM (S1 op1 S2).

This expression is treated as the first one in the select list, so
nothing to "attach to".

On importance of not making fake_select_lex after
create_priority_nest() in parsed_select_expr_start(). This will fail
nastily in Protocol::valid_handler() check in store_longlong() for
EXPLAIN. This happens because select_options are inherited from newly
made fake_select_lex but without SELECT_DESCRIBE flag which is meant
to be assigned by mysql_explain_union() but union_needs_tmp_table() is
false (because now top-level unit has no set-operator, it is just
select from derived), so SELECT_DESCRIBE assignment is
skipped. Depending on that flag send_result_set_metadata() is
conditionally executed in JOIN::exec_inner(). And originally it is
done via select_describe() branch for top-level select when there is
no set operator (it is select from derived as explained above), not
via direct send_result_set_metadata().

On IS_OR_WAS_ORACLE. Sql_mode_save_for_frm_handling removes MODE_ORACLE
when view is registered or opened. We cannot return it back as this
conflicts with MDEV-12478 (tested by compat/oracle.func_concat). So we
are temporarily adding WAS_ORACLE flag instead. WAS_MODE_ORACLE is for
testing both WAS_ORACLE and MODE_ORACLE simultaneously.
2025-12-23 14:02:55 +03:00

499 lines
19 KiB
Text

create table t1 (a int, b int) engine=MyISAM;
create table t2 (c int, d int) engine=MyISAM;
insert into t1 values (1,1),(2,2),(3,3),(2,2);
insert into t2 values (2,2),(2,2),(5,5);
select * from t1 intersect all select * from t2;
(select a,b from t1) intersect all (select c,d from t2);
select * from ((select a,b from t1) intersect all (select c,d from t2)) t;
select * from ((select a from t1) intersect all (select c from t2)) t;
drop tables t1,t2;
create table t1 (a int, b int) engine=MyISAM;
create table t2 (c int, d int) engine=MyISAM;
create table t3 (e int, f int) engine=MyISAM;
insert into t1 values (1,1),(2,2),(3,3),(2,2);
insert into t2 values (2,2),(3,3),(4,4),(2,2);
insert into t3 values (1,1),(2,2),(5,5),(2,2);
(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
EXPLAIN (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
EXPLAIN extended (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
EXPLAIN extended select * from ((select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3)) a;
EXPLAIN format=json (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
--source include/analyze-format.inc
ANALYZE format=json (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
--source include/analyze-format.inc
ANALYZE format=json select * from ((select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3)) a;
select * from ((select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3)) a;
prepare stmt from "(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);";
execute stmt;
execute stmt;
prepare stmt from "select * from ((select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3)) a";
execute stmt;
execute stmt;
insert into t1 values (2,2),(3,3);
insert into t2 values (2,2),(2,2),(2,2);
(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
(select a,b from t1) intersect (select c,d from t2) intersect all (select e,f from t3);
insert into t3 values (2,2);
(select a,b from t1) intersect all (select c,d from t2) intersect (select e,f from t3);
(select a,b from t1) intersect all (select c,e from t2,t3);
EXPLAIN (select a,b from t1) intersect all (select c,e from t2,t3);
EXPLAIN extended (select a,b from t1) intersect all (select c,e from t2,t3);
EXPLAIN extended select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a;
EXPLAIN format=json (select a,b from t1) intersect all (select c,e from t2,t3);
--source include/analyze-format.inc
ANALYZE format=json (select a,b from t1) intersect all (select c,e from t2,t3);
--source include/analyze-format.inc
ANALYZE format=json select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a;
select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a;
prepare stmt from "(select a,b from t1) intersect all (select c,e from t2,t3);";
execute stmt;
execute stmt;
prepare stmt from "select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a";
execute stmt;
execute stmt;
drop tables t1,t2,t3;
select 1 as a from dual intersect all select 1 from dual;
(select 1 from dual) intersect all (select 1 from dual);
--error ER_PARSE_ERROR
(select 1 from dual into @v) intersect all (select 1 from dual);
--error ER_PARSE_ERROR
select 1 from dual ORDER BY 1 intersect all select 1 from dual;
select 1 as a from dual union all select 1 from dual;
create table t1 (a int, b blob, a1 int, b1 blob);
create table t2 (c int, d blob, c1 int, d1 blob);
insert into t1 values (1,"ddd", 1, "sdfrrwwww"),(2, "fgh", 2, "dffggtt"),(2, "fgh", 2, "dffggtt");
insert into t2 values (2, "fgh", 2, "dffggtt"),(3, "ffggddd", 3, "dfgg"),(2, "fgh", 2, "dffggtt");
(select a,b,b1 from t1) intersect all (select c,d,d1 from t2);
drop tables t1,t2;
create table t1 (a int, b blob) engine=MyISAM;
create table t2 (c int, d blob) engine=MyISAM;
create table t3 (e int, f blob) engine=MyISAM;
insert into t1 values (1,1),(2,2),(3,3),(2,2),(3,3);
insert into t2 values (2,2),(3,3),(4,4),(2,2),(2,2),(2,2);
insert into t3 values (1,1),(2,2),(5,5),(2,2),(5,5);
(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
select * from ((select a,b from t1) intersect all (select c,d from t2) intersect (select e,f from t3)) a;
prepare stmt from "(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);";
execute stmt;
execute stmt;
prepare stmt from "select * from ((select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3)) a";
execute stmt;
execute stmt;
# make sure that blob is used
create table t4 (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
show create table t4;
drop tables t4;
(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4);
(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4) except all (select 2,2);
drop tables t1,t2,t3;
create table t1 (a int, b int);
create table t2 (c int, d int);
create table t3 (e int, f int);
insert into t1 values (1,1),(2,2),(3,3),(2,2),(3,3);
insert into t2 values (2,2),(3,3),(4,4),(2,2),(2,2),(2,2);
insert into t3 values (1,1),(2,2),(5,5),(2,2),(5,5);
(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4);
(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4) except all (select 2,2);
drop tables t1,t2,t3;
--echo #
--echo # INTERSECT precedence
--echo #
create table t1 (a int, b blob) engine=MyISAM;
create table t2 (c int, d blob) engine=MyISAM;
create table t3 (e int, f blob) engine=MyISAM;
insert into t1 values (5,5),(6,6);
insert into t2 values (2,2),(3,3);
insert into t3 values (1,1),(3,3);
(select a,b from t1) union all (select c,d from t2) intersect (select e,f from t3) union all (select 4,4);
(select a,b from t1) union all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4);
explain extended (select a,b from t1) union all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4);
# test result of linear mix operation
insert into t2 values (3,3);
insert into t3 values (3,3);
(select e,f from t3) intersect all (select c,d from t2) union all (select a,b from t1) union all (select 4,4);
explain extended (select e,f from t3) intersect all (select c,d from t2) union all (select a,b from t1) union all (select 4,4);
(/* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union /* select#3 */ select `__3`.`c` AS `c`,`__3`.`d` AS `d` from ((/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) intersect all (/* select#4 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `__3` union (/* select#5 */ select 4 AS `4`,4 AS `4`);
prepare stmt from "(select a,b from t1) union all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4)";
execute stmt;
execute stmt;
create view v1 as (select a,b from t1) union all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4);
select b,a,b+1 from v1;
select b,a,b+1 from v1 where a > 3;
create procedure p1()
select * from v1;
call p1();
call p1();
drop procedure p1;
create procedure p1()
(select a,b from t1) union all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4);
call p1();
call p1();
drop procedure p1;
show create view v1;
drop view v1;
drop tables t1,t2,t3;
CREATE TABLE t (i INT);
INSERT INTO t VALUES (1),(2);
SELECT * FROM t WHERE i != ANY ( SELECT 6 INTERSECT ALL SELECT 3 );
select i from t where
exists ((select 6 as r from dual having t.i <> 6)
intersect all
(select 3 from dual having t.i <> 3));
drop table t;
CREATE TABLE t1 (a varchar(32)) ENGINE=MyISAM;
INSERT INTO t1 VALUES
('Jakarta'),('Lisbon'),('Honolulu'),('Lusaka'),('Barcelona'),('Taipei'),
('Brussels'),('Orlando'),('Osaka'),('Quito'),('Lima'),('Tunis'),
('Unalaska'),('Rotterdam'),('Zagreb'),('Ufa'),('Ryazan'),('Xiamen'),
('London'),('Izmir'),('Samara'),('Bern'),('Zhengzhou'),('Vladivostok'),
('Yangon'),('Victoria'),('Warsaw'),('Luanda'),('Leon'),('Bangkok'),
('Wellington'),('Zibo'),('Qiqihar'),('Delhi'),('Hamburg'),('Ottawa'),
('Vaduz');
CREATE TABLE t2 (b varchar(32)) ENGINE=MyISAM;
INSERT INTO t2 VALUES
('Gaza'),('Jeddah'),('Beirut'),('Incheon'),('Tbilisi'),('Izmir'),
('Quito'),('Riga'),('Freetown'),('Zagreb'),('Caracas'),('Orlando'),
('Kingston'),('Turin'),('Xinyang'),('Osaka'),('Albany'),('Geneva'),
('Omsk'),('Kazan'),('Quezon'),('Indore'),('Odessa'),('Xiamen'),
('Winnipeg'),('Yakutsk'),('Nairobi'),('Ufa'),('Helsinki'),('Vilnius'),
('Aden'),('Liverpool'),('Honolulu'),('Frankfurt'),('Glasgow'),
('Vienna'),('Jackson'),('Jakarta'),('Sydney'),('Oslo'),('Novgorod'),
('Norilsk'),('Izhevsk'),('Istanbul'),('Nice');
CREATE TABLE t3 (c varchar(32)) ENGINE=MyISAM;
INSERT INTO t3 VALUES
('Nicosia'),('Istanbul'),('Richmond'),('Stockholm'),('Dublin'),
('Wichita'),('Warsaw'),('Glasgow'),('Winnipeg'),('Irkutsk'),('Quito'),
('Xiamen'),('Berlin'),('Rome'),('Denver'),('Dallas'),('Kabul'),
('Prague'),('Izhevsk'),('Tirana'),('Sofia'),('Detroit'),('Sorbonne');
select count(*) from (
SELECT * FROM t1 LEFT OUTER JOIN t2 LEFT OUTER JOIN t3 ON b < c ON a > b
INTERSECT
SELECT * FROM t1 LEFT OUTER JOIN t2 LEFT OUTER JOIN t3 ON b < c ON a > b
) a;
select count(*) from (
SELECT * FROM t1 LEFT OUTER JOIN t2 LEFT OUTER JOIN t3 ON b < c ON a > b
INTERSECT ALL
SELECT * FROM t1 LEFT OUTER JOIN t2 LEFT OUTER JOIN t3 ON b < c ON a > b
) a;
insert into t1 values ('Xiamen');
insert into t2 values ('Xiamen'),('Xiamen');
insert into t3 values ('Xiamen');
select count(*) from (
SELECT * FROM t1 LEFT OUTER JOIN t2 LEFT OUTER JOIN t3 ON b < c ON a > b
INTERSECT ALL
SELECT * FROM t1 LEFT OUTER JOIN t2 LEFT OUTER JOIN t3 ON b < c ON a > b
) a;
drop table t1,t2,t3;
CREATE TABLE t1 (a varchar(32) not null) ENGINE=MyISAM;
INSERT INTO t1 VALUES
('Jakarta'),('Lisbon'),('Honolulu'),('Lusaka'),('Barcelona'),('Taipei'),
('Brussels'),('Orlando'),('Osaka'),('Quito'),('Lima'),('Tunis'),
('Unalaska'),('Rotterdam'),('Zagreb'),('Ufa'),('Ryazan'),('Xiamen'),
('London'),('Izmir'),('Samara'),('Bern'),('Zhengzhou'),('Vladivostok'),
('Yangon'),('Victoria'),('Warsaw'),('Luanda'),('Leon'),('Bangkok'),
('Wellington'),('Zibo'),('Qiqihar'),('Delhi'),('Hamburg'),('Ottawa'),
('Vaduz'),('Detroit'),('Detroit');
CREATE TABLE t2 (b varchar(32) not null) ENGINE=MyISAM;
INSERT INTO t2 VALUES
('Gaza'),('Jeddah'),('Beirut'),('Incheon'),('Tbilisi'),('Izmir'),
('Quito'),('Riga'),('Freetown'),('Zagreb'),('Caracas'),('Orlando'),
('Kingston'),('Turin'),('Xinyang'),('Osaka'),('Albany'),('Geneva'),
('Omsk'),('Kazan'),('Quezon'),('Indore'),('Odessa'),('Xiamen'),
('Winnipeg'),('Yakutsk'),('Nairobi'),('Ufa'),('Helsinki'),('Vilnius'),
('Aden'),('Liverpool'),('Honolulu'),('Frankfurt'),('Glasgow'),
('Vienna'),('Jackson'),('Jakarta'),('Sydney'),('Oslo'),('Novgorod'),
('Norilsk'),('Izhevsk'),('Istanbul'),('Nice'),('Detroit'),('Detroit');
CREATE TABLE t3 (c varchar(32) not null) ENGINE=MyISAM;
INSERT INTO t3 VALUES
('Nicosia'),('Istanbul'),('Richmond'),('Stockholm'),('Dublin'),
('Wichita'),('Warsaw'),('Glasgow'),('Winnipeg'),('Irkutsk'),('Quito'),
('Xiamen'),('Berlin'),('Rome'),('Denver'),('Dallas'),('Kabul'),
('Prague'),('Izhevsk'),('Tirana'),('Sofia'),('Detroit'),('Sorbonne'),
('Detroit');
select count(*) from (
SELECT * FROM t1 LEFT OUTER JOIN t2 LEFT OUTER JOIN t3 ON b < c ON a > b
INTERSECT
SELECT * FROM t1 LEFT OUTER JOIN t2 LEFT OUTER JOIN t3 ON b < c ON a > b
) a;
drop table t1,t2,t3;
create table t12(c1 int);
insert into t12 values(1);
insert into t12 values(2);
create table t13(c1 int);
insert into t13 values(1);
insert into t13 values(3);
create table t234(c1 int);
insert into t234 values(2);
insert into t234 values(3);
insert into t234 values(4);
select * from t13 union select * from t234 intersect all select * from t12;
drop table t12,t13,t234;
create table t1 (a int);
insert into t1 values (3), (1), (7), (3), (2), (7), (4);
create table t2 (a int);
insert into t2 values (4), (5), (9), (1), (8), (9), (2), (2);
create table t3 (a int);
insert into t3 values (8), (1), (8), (2), (3), (7), (2);
select * from t1 where a > 4
union all
select * from t2 where a < 5
intersect all
select * from t3 where a < 5;
explain extended
select * from t1 where a > 4
union all
select * from t2 where a < 5
intersect all
select * from t3 where a < 5;
drop table t1,t2,t3;
--echo #
--echo # MDEV-25158 Segfault on INTERSECT ALL with UNION in Oracle mode
--echo #
create table t3 (x int);
create table u3 (x int);
create table i3 (x int);
explain SELECT * from t3 union select * from u3 intersect all select * from i3;
set sql_mode= 'oracle';
explain SELECT * from t3 union select * from u3 intersect all select * from i3;
# TODO: there is a bug in --view protocol, it displays column name as '*' instead of 'x'
--replace_result * x
select * from t3 union select * from u3 intersect select * from i3;
--replace_result * x
SELECT * from t3 union select * from u3 intersect all select * from i3;
insert into t3 values (0);
insert into i3 values (0);
--replace_result * x
Select * from t3 union select * from u3 intersect select * from i3;
--replace_result * x
SELECT * FROM t3 UNION SELECT * FROM u3 INTERSECT ALL SELECT * FROM i3;
# CREATE VIEW still works good
create view v as select * from t3 union select * from u3 intersect select * from i3;
select * from v;
drop tables t3, u3, i3;
drop view v;
--enable_info
--echo # First line of these results is column names, not the result
--echo # (pay attention to "affected rows")
# MSSQL:
# 1 2
# 1 2
values (1, 2) union all values (1, 2);
# MSSQL:
# 1 2
# 4 3
# 4 3
values (1, 2) union all values (1, 2) union values (4, 3) union all values (4, 3);
# MSSQL:
# 1 2
# 4 3
# 4 3
# 1 2
values (1, 2) union all values (1, 2) union values (4, 3) union all values (4, 3) union all values (1, 2);
# MSSQL:
# 1 2
# 4 3
values (1, 2) union all values (1, 2) union values (4, 3) union all values (4, 3) union all values (1, 2) union values (1, 2);
--disable_info
set sql_mode= default;
create table t1 (a int, b int);
create table t2 like t1;
insert t1 values (1, 2), (1, 2), (1, 2), (2, 3), (2, 3), (3, 4), (3, 4);
insert t2 values (1, 2), (1, 2), (2, 3), (2, 3), (2, 3), (2, 3), (4, 5);
select * from t1 intersect all select * from t2;
select * from t1 intersect all select * from t2 union values (1, 2);
select * from t1 intersect all (select * from t2 union values (1, 2));
(select * from t1 intersect all select * from t2) union values (1, 2);
create view v1 as select * from t1 intersect all select * from t2 union values (1, 2);
show create view v1;
select * from v1;
create view v2 as select * from t1 union values (1, 2) intersect all select * from t2;
show create view v2;
select * from v2;
set sql_mode= 'oracle';
select * from t1 intersect select * from t2;
select * from t1 intersect all select * from t2;
--echo # Default: first INTERSECT ALL, then UNION
--echo # Oracle: first UNION, then INTERSECT ALL
# VIEW is stored and executed normal mode (see Sql_mode_save_for_frm_handling)
--disable_view_protocol
select * from t1 union values (1, 2) intersect all select * from t2;
--enable_view_protocol
select * from t1 union (values (1, 2) intersect all select * from t2);
(select * from t1 union values (1, 2)) intersect all select * from t2;
select * from t1 intersect all select * from t2 union values (1, 2);
select * from t1 intersect all (select * from t2 union values (1, 2));
(select * from t1 intersect all select * from t2) union values (1, 2);
explain select * from t1 intersect all select * from t2 union values (1, 2);
show create view v1;
select * from v1;
show create view v2;
select * from v2;
create view v3 as select * from t1 union values (1, 2) intersect all select * from t2;
show create view v3;
select * from v3;
drop tables t1, t2;
drop view v1, v2, v3;
create table t3 (x int);
create table u3 (x int);
create table i3 (x int);
create view v4 as SELECT * from t3 union select * from u3 intersect all select * from i3;
select * from v4;
drop tables t3, u3, i3;
drop view v4;
set sql_mode= default;
--echo #
--echo # MDEV-37325 Incorrect results for INTERSECT ALL in ORACLE mode
--echo #
create table t1 (a int, b int);
create table t2 like t1;
insert t1 values (1, 2), (1, 2), (1, 2), (1, 2);
insert t2 values (1, 2), (1, 2);
select * from t1 except all select * from t2 intersect all values (1, 2);
explain select * from t1 except all select * from t2 intersect all values (1, 2);
Explain select * from (select * from (select * from t1 except all select * from t2) __3 intersect all values (1,2)) __5;
create view v1 as select * from t1 except all select * from t2 intersect all values (1, 2);
show create view v1;
select * from v1;
drop view v1;
create view v1 as ((select * from t1 except all select * from t2) intersect all values (1, 2));
show create view v1;
select * from v1;
drop view v1;
explain select * from ((select * from t1 except all select * from t2) intersect all values (1, 2)) v;
--echo # Oracle: first UNION, then INTERSECT ALL
set sql_mode= 'oracle';
create view v2 as select * from t1 except all select * from t2 intersect all values (1, 2);
show create view v2;
select * from v2;
drop view v2;
EXPLAIN select * from t1 except all select * from t2 intersect all values (1, 2);
select * from t2 union all select * from t2;
select * from t1 except all select * from t2 intersect all values (1, 2) union values (2, 3);
select * from t2 union all select * from t2 except all select * from t2 intersect all values (1, 2) union values (2, 3);
select * from t1 except all select * from t2 union values (2, 3);
--echo # Default: first INTERSECT ALL, then UNION
select * from t1 union values (1, 2) intersect all select * from t2;
select * from t1 union (values (1, 2) intersect all select * from t2);
set sql_mode= default;
select * from t1 union values (1, 2) intersect all select * from t2;
select * from t1 union (values (1, 2) intersect all select * from t2);
set sql_mode= 'oracle';
create or replace table t2 like t1;
insert t2 values (1, 2), (2, 3);
create table t3 select * from t1 except all select * from t2;
select * from t3;
select * from t3 intersect all select * from t1;
show create table t2;
select * from t2 order by a desc;
select * from t1 except all select * from t2;
select * from t1 except all select * from t2 union all values (0, 1);
select * from t1 except all select * from t2 union all values (0, 1) order by a limit 2;
select * from t1 except all select * from t2 intersect all select * from t1;
select * from t1 except all select * from t2 intersect all select * from t1 union all select * from t2;
select * from t1 except all select * from t2 intersect all select * from t1 union all select * from t2 order by a desc limit 3;
drop tables t1, t2, t3;
set sql_mode= default;