Commit a896bebf authored by WayneXia's avatar WayneXia

MDEV-18844 Implement EXCEPT ALL and INTERSECT ALL operations

parent afe969ba
......@@ -54,7 +54,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
NULL UNION RESULT <union1,4> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 /* select#1 */ select 1 AS `1` union /* select#4 */ select `__4`.`1` AS `1` from (/* select#2 */ select 1 AS `1` union all /* select#3 */ select 1 AS `1`) `__4`
Note 1003 /* select#1 */ select 1 AS `1` union /* select#4 */ select `__4`.`1` AS `1` from (/* select#2 */ select 1 AS `1` union /* select#3 */ select 1 AS `1`) `__4`
select 1 union select 1 union all select 1;
1
1
......
......@@ -507,8 +507,6 @@ select 1 as a from dual union all select 1 from dual;
a
1
1
select 1 from dual except all select 1 from dual;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'all select 1 from dual' at line 1
create table t1 (a int, b blob, a1 int, b1 blob) engine=MyISAM;
create table t2 (c int, d blob, c1 int, d1 blob) engine=MyISAM;
insert into t1 values (1,"ddd", 1, "sdfrrwwww"),(2, "fgh", 2, "dffggtt");
......
......@@ -67,7 +67,6 @@ select 1 from dual ORDER BY 1 except select 1 from dual;
select 1 as a from dual union all select 1 from dual;
--error ER_PARSE_ERROR
select 1 from dual except all select 1 from dual;
create table t1 (a int, b blob, a1 int, b1 blob) engine=MyISAM;
......
This diff is collapsed.
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),(4,4),(4,4),(4,4);
insert into t2 values (1,1),(1,1),(1,1),(2,2),(3,3),(3,3),(5,5);
select * from t1 except select * from t2;
select * from t1 except all select * from t2;
select * from t1 except all select c+1,d+1 from t2;
(select * from t1) except all (select * from t2);
select * from ((select * from t1) except all (select * from t2)) a;
select * from ((select a from t1) except all (select c from t2)) a;
select * from t1 except all select * from t1 union all select * from t1 union all select * from t1 except select * from t2;
select * from t1 except all select * from t1 union all select * from t1 union all select * from t1 except all select * from t2;
select * from (select * from t1 except all select * from t2) q1 except all select * from (select * from t1 except all select * from t2) q2;
EXPLAIN select * from t1 except all select * from t2;
EXPLAIN format=json select * from t1 except all select * from t2;
EXPLAIN extended (select * from t1) except all (select * from t2);
EXPLAIN extended select * from ((select * from t1) except all (select * from t2)) a;
--source include/analyze-format.inc
ANALYZE format=json select * from ((select a,b from t1) except all (select c,d from t2)) a;
--source include/analyze-format.inc
ANALYZE format=json select * from ((select a from t1) except all (select c from t2)) a;
select * from ((select a from t1) except all (select c from t2)) a;
prepare stmt from "(select a,b from t1) except all (select c,d from t2)";
execute stmt;
execute stmt;
prepare stmt from "select * from ((select a,b from t1) except all (select c,d from t2)) a";
execute stmt;
execute stmt;
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;
create table t4 (g int, h int) engine=MyISAM;
insert into t1 values (1,1),(2,2),(2,2);
insert into t2 values (2,2),(3,3);
insert into t3 values (4,4),(5,5),(4,4);
insert into t4 values (4,4),(7,7),(4,4);
(select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4);
select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
(select * from t1,t3) except all (select * from t2,t4);
(select a,b,e from t1,t3) except all (select c,d,g from t2,t4);
EXPLAIN (select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4);
EXPLAIN select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
EXPLAIN extended select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
EXPLAIN format=json select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
--source include/analyze-format.inc
ANALYZE format=json (select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4);
--source include/analyze-format.inc
ANALYZE format=json select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
prepare stmt from "(select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)";
execute stmt;
execute stmt;
prepare stmt from "select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) a";
execute stmt;
execute stmt;
drop tables t1,t2,t3,t4;
select 1 as a from dual except all select 1 from dual;
(select 1 from dual) except all (select 1 from dual);
--error ER_PARSE_ERROR
(select 1 from dual into @v) except all (select 1 from dual);
--error ER_PARSE_ERROR
select 1 from dual ORDER BY 1 except 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) engine=MyISAM;
create table t2 (c int, d blob, c1 int, d1 blob) engine=MyISAM;
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");
(select a,b,b1 from t1) except all (select c,d,d1 from t2);
# make sure that blob is used
create table t3 (select a,b,b1 from t1) except all (select c,d,d1 from t2);
show create table t3;
drop tables t1,t2,t3;
CREATE TABLE t (i INT);
INSERT INTO t VALUES (1),(2);
SELECT * FROM t WHERE i != ANY ( SELECT 3 EXCEPT ALL SELECT 3 );
drop table t;
\ No newline at end of file
......@@ -504,8 +504,6 @@ select 1 as a from dual union all select 1 from dual;
a
1
1
select 1 from dual intersect all select 1 from dual;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'all select 1 from dual' at line 1
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");
......@@ -607,22 +605,6 @@ NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
NULL UNION RESULT <union1,5,4> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 (/* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union /* select#5 */ select `__5`.`c` AS `c`,`__5`.`d` AS `d` from ((/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) intersect (/* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `__5` union (/* select#4 */ select 4 AS `4`,4 AS `4`)
set SQL_MODE=ORACLE;
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
a b
3 3
4 4
explain extended
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
2 UNION t2 ALL NULL NULL NULL NULL 2 100.00
3 INTERSECT t3 ALL NULL NULL NULL NULL 2 100.00
4 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
NULL UNIT RESULT <unit1,2,3,4> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 (/* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1") union (/* select#2 */ select "test"."t2"."c" AS "c","test"."t2"."d" AS "d" from "test"."t2") intersect (/* select#3 */ select "test"."t3"."e" AS "e","test"."t3"."f" AS "f" from "test"."t3") union (/* select#4 */ select 4 AS "4",4 AS "4")
set SQL_MODE=default;
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
e f
3 3
......@@ -639,24 +621,6 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
NULL UNIT RESULT <unit1,2,3,4> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 (/* select#1 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`) intersect (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) union (/* select#3 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union (/* select#4 */ select 4 AS `4`,4 AS `4`)
set SQL_MODE=ORACLE;
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
e f
3 3
4 4
5 5
6 6
explain extended
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00
2 INTERSECT t2 ALL NULL NULL NULL NULL 2 100.00
3 UNION t1 ALL NULL NULL NULL NULL 2 100.00
4 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
NULL UNIT RESULT <unit1,2,3,4> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 (/* select#1 */ select "test"."t3"."e" AS "e","test"."t3"."f" AS "f" from "test"."t3") intersect (/* select#2 */ select "test"."t2"."c" AS "c","test"."t2"."d" AS "d" from "test"."t2") union (/* select#3 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1") union (/* select#4 */ select 4 AS "4",4 AS "4")
set SQL_MODE=default;
(/* 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 (/* 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`);
a b
3 3
......@@ -820,12 +784,6 @@ create table t234(c1 int);
insert into t234 values(2);
insert into t234 values(3);
insert into t234 values(4);
set SQL_MODE=oracle;
select * from t13 union select * from t234 intersect select * from t12;
c1
1
2
set SQL_MODE=default;
select * from t13 union select * from t234 intersect select * from t12;
c1
1
......@@ -848,9 +806,9 @@ select * from t2 where a < 5
intersect
select * from t3 where a < 5;
a
1
7
7
1
explain extended
select * from t1 where a > 4
union all
......
......@@ -66,7 +66,6 @@ select 1 from dual ORDER BY 1 intersect select 1 from dual;
select 1 as a from dual union all select 1 from dual;
--error ER_PARSE_ERROR
select 1 from dual intersect all select 1 from dual;
......@@ -147,12 +146,6 @@ insert into t3 values (1,1),(3,3);
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
explain extended
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
set SQL_MODE=ORACLE;
--sorted_result
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
explain extended
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
set SQL_MODE=default;
# test result of linear mix operation
......@@ -160,12 +153,6 @@ set SQL_MODE=default;
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
explain extended
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
set SQL_MODE=ORACLE;
--sorted_result
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
explain extended
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
set SQL_MODE=default;
--sorted_result
(/* 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 (/* 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`);
......@@ -310,11 +297,7 @@ create table t234(c1 int);
insert into t234 values(2);
insert into t234 values(3);
insert into t234 values(4);
set SQL_MODE=oracle;
--sorted_result
select * from t13 union select * from t234 intersect select * from t12;
set SQL_MODE=default;
--sorted_result
select * from t13 union select * from t234 intersect select * from t12;
......@@ -333,7 +316,7 @@ insert into t2 values (4), (5), (9), (1), (8), (9);
create table t3 (a int);
insert into t3 values (8), (1), (8), (2), (3), (7), (2);
--sorted_result
select * from t1 where a > 4
union all
select * from t2 where a < 5
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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);
set SQL_MODE=ORACLE;
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
a b
4 4
3 3
explain extended
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
2 UNION t2 ALL NULL NULL NULL NULL 2 100.00
3 INTERSECT t3 ALL NULL NULL NULL NULL 2 100.00
4 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
NULL UNIT RESULT <unit1,2,3,4> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 (/* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1") union (/* select#2 */ select "test"."t2"."c" AS "c","test"."t2"."d" AS "d" from "test"."t2") intersect (/* select#3 */ select "test"."t3"."e" AS "e","test"."t3"."f" AS "f" from "test"."t3") union (/* select#4 */ select 4 AS "4",4 AS "4")
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
e f
5 5
3 3
6 6
4 4
explain extended
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00
2 INTERSECT t2 ALL NULL NULL NULL NULL 2 100.00
3 UNION t1 ALL NULL NULL NULL NULL 2 100.00
4 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
NULL UNIT RESULT <unit1,2,3,4> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 (/* select#1 */ select "test"."t3"."e" AS "e","test"."t3"."f" AS "f" from "test"."t3") intersect (/* select#2 */ select "test"."t2"."c" AS "c","test"."t2"."d" AS "d" from "test"."t2") union (/* select#3 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1") union (/* select#4 */ select 4 AS "4",4 AS "4")
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 select * from t12;
c1
1
2
set SQL_MODE=default;
drop table t1,t2,t3;
drop table t12,t13, t234;
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);
set SQL_MODE=ORACLE;
(select a,b from t1) union all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4);
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'all (select e,f from t3) union all (select 4,4)' at line 1
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);
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'all (select e,f from t3) union all (select 4,4)' at line 1
(select e,f from t3) intersect all (select c,d from t2) union all (select a,b from t1) union all (select 4,4);
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'all (select c,d from t2) union all (select a,b from t1) union all (select 4,4)' at line 1
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);
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'all (select c,d from t2) union all (select a,b from t1) union all (select 4,4)' at line 1
set SQL_MODE=default;
drop table t1,t2,t3;
set SQL_MODE=oracle;
select * from t13 union select * from t234 intersect all select * from t12;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'all select * from t12' at line 1
set SQL_MODE=default;
# from intersect.test
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);
set SQL_MODE=ORACLE;
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
explain extended
(select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
explain extended
(select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
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 select * from t12;
set SQL_MODE=default;
drop table t1,t2,t3;
drop table t12,t13, t234;
#from intersect_all.test
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);
set SQL_MODE=ORACLE;
#(select a,b from t1) union all (select c,d from t2) intersect (select e,f from t3) union all (select 4,4);
--error ER_PARSE_ERROR
(select a,b from t1) union all (select c,d from t2) intersect all (select e,f from t3) union all (select 4,4);
--error ER_PARSE_ERROR
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);
--error ER_PARSE_ERROR
(select e,f from t3) intersect all (select c,d from t2) union all (select a,b from t1) union all (select 4,4);
--error ER_PARSE_ERROR
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);
set SQL_MODE=default;
drop table t1,t2,t3;
set SQL_MODE=oracle;
--error ER_PARSE_ERROR
select * from t13 union select * from t234 intersect all select * from t12;
set SQL_MODE=default;
\ No newline at end of file
......@@ -5708,17 +5708,18 @@ class TMP_TABLE_PARAM :public Sql_alloc
class select_unit :public select_result_interceptor
{
public:
uint curr_step, prev_step, curr_sel;
enum sub_select_type step;
public:
Item_int *intersect_mark;
TMP_TABLE_PARAM tmp_table_param;
/* Number of additional (hidden) field of the used temporary table */
int addon_cnt;
int write_err; /* Error code from the last send_data->ha_write_row call. */
TABLE *table;
select_unit(THD *thd_arg):
select_result_interceptor(thd_arg),
intersect_mark(0), table(0)
select_result_interceptor(thd_arg), addon_cnt(0), table(0)
{
init();
tmp_table_param.init();
......@@ -5735,6 +5736,9 @@ class select_unit :public select_result_interceptor
virtual bool postponed_prepare(List<Item> &types)
{ return false; }
int send_data(List<Item> &items);
int write_record();
int update_counter(Field *counter, longlong value);
int delete_record();
bool send_eof();
virtual bool flush();
void cleanup();
......@@ -5753,7 +5757,148 @@ class select_unit :public select_result_interceptor
step= UNION_TYPE;
write_err= 0;
}
virtual void change_select();
virtual bool force_enable_index_if_needed() { return false; }
};
/**
@class select_unit_ext
The class used when processing rows produced by operands of query expressions
containing INTERSECT ALL and/or EXCEPT all operations. One or two extra fields
of the temporary to store the rows of the partial and final result can be employed.
Both of them contain counters. The second additional field is used only when
the processed query expression contains INTERSECT ALL.
Consider how these extra fields are used.
Let
table t1 (f char(8))
table t2 (f char(8))
table t3 (f char(8))
contain the following sets:
("b"),("a"),("d"),("c"),("b"),("a"),("c"),("a")
("c"),("b"),("c"),("c"),("a"),("b"),("g")
("c"),("a"),("b"),("d"),("b"),("e")
- Let's demonstrate how the the set operation INTERSECT ALL is proceesed
for the query
SELECT f FROM t1 INTERSECT ALL SELECT f FROM t2
When send_data() is called for the rows of the first operand we put
the processed record into the temporary table if there was no such record
setting dup_cnt field to 1 and add_cnt field to 0 and increment the
counter in the dup_cnt field by one otherwise. We get
|add_cnt|dup_cnt| f |
|0 |2 |b |
|0 |3 |a |
|0 |1 |d |
|0 |2 |c |
The call of send_eof() for the first operand swaps the values stored in
dup_cnt and add_cnt. After this, we'll see the following rows in the
temporary table
|add_cnt|dup_cnt| f |
|2 |0 |b |
|3 |0 |a |
|1 |0 |d |
|2 |0 |c |
When send_data() is called for the rows of the second operand we increment
the counter in dup_cnt if the processed row is found in the table and do
nothing otherwise. As a result we get
|add_cnt|dup_cnt| f |
|2 |2 |b |
|3 |1 |a |
|1 |0 |d |
|2 |3 |c |
At the call of send_eof() for the second operand first we disable index.
Then for each record, the minimum of counters from dup_cnt and add_cnt m is
taken. If m == 0 then the record is deleted. Otherwise record is replaced
with m copies of it. Yet the counter in this copies are set to 1 for
dup_cnt and to 0 for add_cnt
|add_cnt|dup_cnt| f |
|0 |1 |b |
|0 |1 |b |
|0 |1 |a |
|0 |1 |c |
|0 |1 |c |
- Let's demonstrate how the the set operation EXCEPT ALL is proceesed
for the query
SELECT f FROM t1 EXCEPT ALL SELECT f FROM t3
Only one additional counter field dup_cnt is used for EXCEPT ALL.
After the first operand has been processed we have in the temporary table
|dup_cnt| f |
|2 |b |
|3 |a |
|1 |d |
|2 |c |
When send_data() is called for the rows of the second operand we decrement
the counter in dup_cnt if the processed row is found in the table and do
nothing otherwise. If the counter becomes 0 we delete the record
|dup_cnt| f |
|2 |a |
|1 |c |
Finally at the call of send_eof() for the second operand we disable index
unfold rows adding duplicates
|dup_cnt| f |
|1 |a |
|1 |a |
|1 |c |
*/
class select_unit_ext :public select_unit
{
public:
select_unit_ext(THD *thd_arg):
select_unit(thd_arg), increment(0), is_index_enabled(TRUE),
curr_op_type(UNSPECIFIED)
{
};
int send_data(List<Item> &items);
void change_select();
int unfold_record(int cnt);
bool send_eof();
bool force_enable_index_if_needed()
{
is_index_enabled= true;
return true;
}
bool disable_index_if_needed(SELECT_LEX *curr_sl);
/*
How to change increment/decrement the counter in duplicate_cnt field
when processing a record produced by the current operand in send_data().
The value can be 1 or -1
*/
int increment;
/* TRUE <=> the index of the result temporary table is enabled */
bool is_index_enabled;
/* The type of the set operation currently executed */
enum set_op_type curr_op_type;
/*
Points to the extra field of the temporary table where
duplicate counters are stored
*/
Field *duplicate_cnt;
/*
Points to the extra field of the temporary table where additional
counters used only for INTERSECT ALL operations are stored
*/
Field *additional_cnt;
};
class select_union_recursive :public select_unit
......
......@@ -2354,6 +2354,7 @@ void st_select_lex_unit::init_query()
offset_limit_cnt= 0;
union_distinct= 0;
prepared= optimized= optimized_2= executed= 0;
bag_set_op_optimized= 0;
optimize_started= 0;
item= 0;
union_result= 0;
......@@ -2369,8 +2370,8 @@ void st_select_lex_unit::init_query()
with_clause= 0;
with_element= 0;
columns_are_renamed= false;
intersect_mark= NULL;
with_wrapped_tvc= false;
have_except_all_or_intersect_all= false;
}
void st_select_lex::init_query()
......@@ -2468,6 +2469,7 @@ void st_select_lex::init_select()
curr_tvc_name= 0;
in_tvc= false;
versioned_tables= 0;
nest_flags= 0;
}
/*
......@@ -2986,7 +2988,6 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
void st_select_lex_unit::print(String *str, enum_query_type query_type)
{
bool union_all= !union_distinct;
if (with_clause)
with_clause->print(str, query_type);
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
......@@ -2999,8 +3000,6 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type)
DBUG_ASSERT(0);
case UNION_TYPE:
str->append(STRING_WITH_LEN(" union "));
if (union_all)
str->append(STRING_WITH_LEN("all "));
break;
case INTERSECT_TYPE:
str->append(STRING_WITH_LEN(" intersect "));
......@@ -3009,8 +3008,8 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN(" except "));
break;
}
if (sl == union_distinct)
union_all= TRUE;
if (!sl->distinct)
str->append(STRING_WITH_LEN("all "));
}
if (sl->braces)
str->append('(');
......@@ -3523,6 +3522,8 @@ bool st_select_lex_unit::union_needs_tmp_table()
with_wrapped_tvc= true;
break;
}
if (sl != first_select() && sl->linkage != UNION_TYPE)
return true;
}
}
if (with_wrapped_tvc)
......@@ -5394,7 +5395,7 @@ LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit)
Name_resolution_context *context= &wrapping_sel->context;
context->init();
wrapping_sel->automatic_brackets= FALSE;
wrapping_sel->mark_as_unit_nest();
wrapping_sel->register_unit(unit, context);
/* stuff dummy SELECT * FROM (...) */
......
......@@ -207,6 +207,14 @@ enum sub_select_type
GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE, OLAP_TYPE
};
enum set_op_type
{
UNSPECIFIED,
UNION_DISTINCT, UNION_ALL,
EXCEPT_DISTINCT, EXCEPT_ALL,
INTERSECT_DISTINCT, INTERSECT_ALL
};
inline int cmp_unit_op(enum sub_select_type op1, enum sub_select_type op2)
{
DBUG_ASSERT(op1 >= UNION_TYPE && op1 <= EXCEPT_TYPE);
......@@ -841,8 +849,8 @@ class st_select_lex_unit: public st_select_lex_node {
// Ensures that at least all members used during cleanup() are initialized.
st_select_lex_unit()
: union_result(NULL), table(NULL), result(NULL),
cleaned(false),
fake_select_lex(NULL)
cleaned(false), bag_set_op_optimized(false),
have_except_all_or_intersect_all(false), fake_select_lex(NULL)
{
}
......@@ -853,9 +861,11 @@ class st_select_lex_unit: public st_select_lex_node {
optimized, // optimize phase already performed for UNION (unit)
optimized_2,
executed, // already executed
cleaned;
cleaned,
bag_set_op_optimized;
bool optimize_started;
bool have_except_all_or_intersect_all;
// list of fields which points to temporary table for union
List<Item> item_list;
......@@ -867,11 +877,6 @@ class st_select_lex_unit: public st_select_lex_node {
any SELECT of this unit execution
*/
List<Item> types;
/**
There is INTERSECT and it is item used in creating temporary
table for it
*/
Item_int *intersect_mark;
/**
TRUE if the unit contained TVC at the top level that has been wrapped
into SELECT:
......@@ -928,8 +933,9 @@ class st_select_lex_unit: public st_select_lex_node {
fake_select_lex is used.
*/
st_select_lex *saved_fake_select_lex;
st_select_lex *union_distinct; /* pointer to the last UNION DISTINCT */
/* pointer to the last node before last subsequence of UNION ALL */
st_select_lex *union_distinct;
bool describe; /* union exec() called for EXPLAIN */
Procedure *last_procedure; /* Pointer to procedure, if such exists */
......@@ -955,6 +961,7 @@ class st_select_lex_unit: public st_select_lex_node {
bool prepare(TABLE_LIST *derived_arg, select_result *sel_result,
ulong additional_options);
bool optimize();
void optimize_bag_operation(bool is_outer_distinct);
bool exec();
bool exec_recursive();
bool cleanup();
......@@ -1025,7 +1032,7 @@ Field_pair *find_matching_field_pair(Item *item, List<Field_pair> pair_list);
#define TOUCHED_SEL_COND 1/* WHERE/HAVING/ON should be reinited before use */
#define TOUCHED_SEL_DERIVED (1<<1)/* derived should be reinited before use */
#define UNIT_NEST_FL 1
/*
SELECT_LEX - store information of parsed SELECT statment
*/
......@@ -1048,7 +1055,7 @@ class st_select_lex: public st_select_lex_node
select1->first_nested points to select1.
*/
st_select_lex *first_nested;
uint8 nest_flags;
Name_resolution_context context;
LEX_CSTRING db;
Item *where, *having; /* WHERE & HAVING clauses */
......@@ -1524,6 +1531,13 @@ class st_select_lex: public st_select_lex_node
select_handler *find_select_handler(THD *thd);
bool is_set_op()
{
return linkage == UNION_TYPE ||
linkage == EXCEPT_TYPE ||
linkage == INTERSECT_TYPE;
}
private:
bool m_non_agg_field_used;
bool m_agg_func_used;
......@@ -1570,6 +1584,8 @@ class st_select_lex: public st_select_lex_node
void add_statistics(SELECT_LEX_UNIT *unit);
bool make_unique_derived_name(THD *thd, LEX_CSTRING *alias);
void lex_start(LEX *plex);
bool is_unit_nest() { return (nest_flags & UNIT_NEST_FL); }
void mark_as_unit_nest() { nest_flags= UNIT_NEST_FL; }
};
typedef class st_select_lex SELECT_LEX;
......
......@@ -751,6 +751,7 @@ st_select_lex *wrap_tvc_with_tail(THD *thd, st_select_lex *tvc_sl)
{
wrapper_sl->master_unit()->union_distinct= wrapper_sl;
}
wrapper_sl->distinct= tvc_sl->distinct;
thd->lex->current_select= wrapper_sl;
return wrapper_sl;
}
......
This diff is collapsed.
......@@ -17577,10 +17577,10 @@ release:
unit_type_decl:
UNION_SYM union_option
{ $$.unit_type= UNION_TYPE; $$.distinct= $2; }
| INTERSECT_SYM
{ $$.unit_type= INTERSECT_TYPE; $$.distinct= 1; }
| EXCEPT_SYM
{ $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; }
| INTERSECT_SYM union_option
{ $$.unit_type= INTERSECT_TYPE; $$.distinct= $2; }
| EXCEPT_SYM union_option
{ $$.unit_type= EXCEPT_TYPE; $$.distinct= $2; }
;
/*
......
......@@ -145,21 +145,21 @@ static uchar *next_free_record_pos(HP_SHARE *info)
DBUG_PRINT("exit",("Used old position: %p", pos));
DBUG_RETURN(pos);
}
if ((info->records > info->max_records && info->max_records) ||
(info->data_length + info->index_length >= info->max_table_size))
{
DBUG_PRINT("error",
("record file full. records: %lu max_records: %lu "
"data_length: %llu index_length: %llu "
"max_table_size: %llu",
info->records, info->max_records,
info->data_length, info->index_length,
info->max_table_size));
my_errno=HA_ERR_RECORD_FILE_FULL;
DBUG_RETURN(NULL);
}
if (!(block_pos=(info->records % info->block.records_in_block)))
{
if ((info->records > info->max_records && info->max_records) ||
(info->data_length + info->index_length >= info->max_table_size))
{
DBUG_PRINT("error",
("record file full. records: %lu max_records: %lu "
"data_length: %llu index_length: %llu "
"max_table_size: %llu",
info->records, info->max_records,
info->data_length, info->index_length,
info->max_table_size));
my_errno=HA_ERR_RECORD_FILE_FULL;
DBUG_RETURN(NULL);
}
if (hp_get_new_block(info, &info->block,&length))
DBUG_RETURN(NULL);
info->data_length+=length;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment